package slangc.api; import slangc.codegraph.DynamicSet; import slangc.codegraph.DynamicWorld; import slangc.model.BuiltinTypeBehaviour; import slangc.model.PackageModel; import slangc.model.SystemModel; import slangc.model.TypeModel; import slangc.model.MethodModel; import slangc.model.UserTypeModel; import slangc.parser.Language; import slangc.parser.Source; public class CompilerWorld extends DynamicWorld { private Reporter reporter = null; private Unit[] includedSources = new Unit[0]; private Unit[] referencedSources = new Unit[0]; private DynamicSet referencedSet; private DynamicSet includedSet; private Language language = new Language(); private CompilerTarget target = null; private String[] sourceExtensions = new String[0]; private String[] dataExtensions = new String[0]; private String[] ignoreExtensions = new String[0]; private DataFile[] dataFiles = new DataFile[0]; private ProvidesOrDepends[] providesDepends = new ProvidesOrDepends[0]; private String[] globalImports = new String[0]; private MetaOrAlias[] aliasTypes = new MetaOrAlias[0]; private MetaOrAlias[] aliasPackages = new MetaOrAlias[0]; private MetaOrAlias[] importantMeta = new MetaOrAlias[0]; private MetaOrAlias[] otherMeta = new MetaOrAlias[0]; private TypeOption[] typeOptions = new TypeOption[0]; private String[] mainTypes = new String[0]; private CacheManager cacheManager = new CacheManager(); public CompilerWorld() { referencedSet = new DynamicSet(); referencedSet.setSimpleName(""); appendNamedElement(referencedSet); includedSet = new DynamicSet(); includedSet.setSimpleName(""); appendNamedElement(includedSet); } public CacheManager getCacheManager() { return cacheManager; } public void setCacheManager(CacheManager m) { cacheManager = m; } private int errorVerbosity = 5; public void setErrorVerbosity(int i) { errorVerbosity = i; } public String[] arrayLengthNames = null; public void addArrayLengthName(String n) { // NOTE: Adding any names will clear the default "length" definition! if (arrayLengthNames == null) { arrayLengthNames = new String[]{n}; } else { String[] narr = new String[arrayLengthNames.length + 1]; for (int i = 0; i < arrayLengthNames.length; i++) { narr[i] = arrayLengthNames[i]; } narr[narr.length-1] = n; arrayLengthNames = narr; } } public void setTarget(CompilerTarget t) { this.target = t; } public CompilerTarget getTarget() { return target; } private String[] addPatternArray(String[] arr, String ext) { for (int i = 0; i < arr.length; i++) { if (arr[i].equals(ext)) { return arr; // No need to add. } } String[] r = new String[arr.length + 1]; for (int i = 0; i < r.length; i++) { if (i < arr.length) { r[i] = arr[i]; } else { r[i] = ext; } } return r; } public void addSourcePattern(String ext) { sourceExtensions = addPatternArray(sourceExtensions, ext); } public void addDataPattern(String ext) { dataExtensions = addPatternArray(dataExtensions, ext); } public void addIgnorePattern(String ext) { ignoreExtensions = addPatternArray(ignoreExtensions, ext); } private boolean matchesPatternArray(String[] exts, String name) { for (int i = 0; i < exts.length; i++) { if (exts[i].startsWith("*")) { //System.err.println("Testing '" + name + "' against extension '" + exts[i].sub(1) + "'"); if (name.endsWith(exts[i].sub(1))) { return true; } } else { //System.err.println("Testing '" + name + "' against '" + exts[i] + "'"); if (name.equals(exts[i])) { return true; } } } return false; } public boolean matchesSourcePattern(String filename) { return matchesPatternArray(sourceExtensions, filename); } public boolean matchesDataPattern(String filename) { return matchesPatternArray(dataExtensions, filename); } public boolean matchesIgnorePattern(String filename) { return matchesPatternArray(ignoreExtensions, filename); } public void addGlobalImport(String x) { String[] newarr = new String[globalImports.length + 1]; for (int i = 0; i < newarr.length; i++) { if (i < globalImports.length) { newarr[i] = globalImports[i]; } else { newarr[i] = x; } } globalImports = newarr; } private void addProvidesOrdepends(ProvidesOrDepends x) { ProvidesOrDepends[] newarr = new ProvidesOrDepends[providesDepends.length + 1]; for (int i = 0; i < newarr.length; i++) { if (i < providesDepends.length) { newarr[i] = providesDepends[i]; } else { newarr[i] = x; } } providesDepends = newarr; } public void addProvidesVersion(String name, String version) { addProvidesOrdepends(new ProvidesOrDepends(true, name, version)); } public void addDependsVersion(String name, String version) { addProvidesOrdepends(new ProvidesOrDepends(false, name, version)); } private void addTypeOption(TypeOption o) { TypeOption[] r = new TypeOption[typeOptions.length + 1]; for (int i = 0; i < r.length; i++) { if (i < typeOptions.length) { r[i] = typeOptions[i]; } else { r[i] = o; } } typeOptions = r; } public void addSpecialType(TypeOption.Kind kind, String typename, String formatOptions) { addTypeOption(new TypeOption(kind, typename, formatOptions)); } public void addBuiltinType(TypeOption.Kind kind, String typename, String formatOptions, boolean isDuck, boolean isNumber, boolean isFloat, boolean isSigned, int nbits) { addTypeOption(new TypeOption(kind, typename, formatOptions, true, isDuck, isNumber, isFloat, isSigned, nbits)); } public void addBuiltinType(TypeOption.Kind kind, String typename, String formatOptions) { switch (kind) { case TypeOption.Kind.BIT: addBuiltinType(kind, typename, formatOptions, false, false, false, false, 1); break; case TypeOption.Kind.INT8: addBuiltinType(kind, typename, formatOptions, false, true, false, true, 8); break; case TypeOption.Kind.INT16: addBuiltinType(kind, typename, formatOptions, false, true, false, true, 16); break; case TypeOption.Kind.INT32: addBuiltinType(kind, typename, formatOptions, false, true, false, true, 32); break; case TypeOption.Kind.INT64: addBuiltinType(kind, typename, formatOptions, false, true, false, true, 64); break; case TypeOption.Kind.UINT8: addBuiltinType(kind, typename, formatOptions, false, true, false, false, 8); break; case TypeOption.Kind.UINT16: addBuiltinType(kind, typename, formatOptions, false, true, false, false, 16); break; case TypeOption.Kind.UINT32: addBuiltinType(kind, typename, formatOptions, false, true, false, false, 32); break; case TypeOption.Kind.UINT64: addBuiltinType(kind, typename, formatOptions, false, true, false, false, 64); break; case TypeOption.Kind.FLOAT32: addBuiltinType(kind, typename, formatOptions, false, true, true, true, 32); break; case TypeOption.Kind.FLOAT64: addBuiltinType(kind, typename, formatOptions, false, true, true, true, 64); break; case TypeOption.Kind.DUCK: addBuiltinType(kind, typename, formatOptions, false, true, true, true, 64); break; default: throw new Error("No default behaviour for " + kind + " as a builtin type, must provide specific behaviour information"); } /* * system.addBuiltinType("fencom.stdlib", "bit", new BuiltinTypeBehaviour()); system.addBuiltinType("fencom.stdlib", "int8", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 8)); system.addBuiltinType("fencom.stdlib", "int16", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 16)); system.addBuiltinType("fencom.stdlib", "int32", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 32)); system.addBuiltinType("fencom.stdlib", "int64", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 64)); system.addBuiltinType("fencom.stdlib", "uint8", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 8)); system.addBuiltinType("fencom.stdlib", "uint16", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 16)); system.addBuiltinType("fencom.stdlib", "uint32", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 32)); system.addBuiltinType("fencom.stdlib", "uint64", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 64)); system.addBuiltinType("fencom.stdlib", "float32", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 32)); system.addBuiltinType("fencom.stdlib", "float64", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 64)); */ } private MetaOrAlias[] addMetaOrAliasArray(MetaOrAlias[] arr, MetaOrAlias ext) { MetaOrAlias[] r = new MetaOrAlias[arr.length + 1]; for (int i = 0; i < r.length; i++) { if (i < arr.length) { r[i] = arr[i]; } else { r[i] = ext; } } return r; } public void addMeta(boolean important, String key, String value) { if (important) { importantMeta = addMetaOrAliasArray(importantMeta, new MetaOrAlias(key, value)); } else { otherMeta = addMetaOrAliasArray(otherMeta, new MetaOrAlias(key, value)); } } public void addAliasType(String aliasName, String targetName) { aliasTypes = addMetaOrAliasArray(aliasTypes, new MetaOrAlias(aliasName, targetName)); } public void addAliasPackage(String aliasName, String targetName) { aliasPackages = addMetaOrAliasArray(aliasPackages, new MetaOrAlias(aliasName, targetName)); } public void addMainType(String typeName) { String[] newarr = new String[mainTypes.length + 1]; for (int i = 0; i < newarr.length; i++) { if (i < mainTypes.length) { newarr[i] = mainTypes[i]; } else { newarr[i] = typeName; } } mainTypes = newarr; } public void addDataFile(String packagename, String innername, byte[] data, String typeinfo, String debugname) { DataFile[] newarr = new DataFile[dataFiles.length + 1]; for (int i = 0; i < newarr.length; i++) { if (i < dataFiles.length) { newarr[i] = dataFiles[i]; } else { newarr[i] = new DataFile(packagename, innername, data, typeinfo, debugname); } } dataFiles = newarr; } public void addSource(Source source, boolean referenceOnly) { if (referenceOnly) { Unit[] nsources = new Unit[referencedSources.length + 1]; for (int i = 0; i < referencedSources.length; i++) { nsources[i] = referencedSources[i]; } nsources[nsources.length - 1] = new Unit(this, source); referencedSources = nsources; } else { Unit[] nsources = new Unit[includedSources.length + 1]; for (int i = 0; i < includedSources.length; i++) { nsources[i] = includedSources[i]; } nsources[nsources.length - 1] = new Unit(this, source); includedSources = nsources; } } @Override public CompilerSet getNamedElement(int index) { return (CompilerSet) super.getNamedElement(index); } public Reporter getReporter() { if (reporter == null) { reporter = new NullReporter(); } return reporter; } public void setReporter(Reporter reporter) { this.reporter = reporter; } public static String pkgname(String fullname) { int l = fullname.searchLast("."); if (l < 0) { return ""; } else { return fullname.sub(0, l); } } public static String typname(String fullname) { int l = fullname.searchLast("."); if (l < 0) { return ""; } else { return fullname.sub(l + 1); } } /** Builds the sources, returning true if completed or false otherwise (errors will be reported to the reporter). * * @return true if completed successfully, false otherwise. */ public boolean build() { int i; // Reused for many small top-level loops. /* getReporter().note("STAGE", "Scanning referenced sources"); for (i = 0; i < referencedSources.length; i++) { getReporter().note("STAGE-PART", referencedSources[i].getFilename()); referencedSources[i].scan(); } getReporter().note("STAGE", "Scanning included sources"); for (i = 0; i < includedSources.length; i++) { getReporter().note("STAGE-PART", includedSources[i].getFilename()); includedSources[i].scan(); } */ getReporter().note("STAGE", "Parsing referenced sources"); for (i = 0; i < referencedSources.length; i++) { getReporter().note("STAGE-PART", referencedSources[i].getFilename()); referencedSources[i].parse(); try { getReporter().note("CACHE", "Using cache filename " + referencedSources[i].getCacheName() + " for " + referencedSources[i].getFilename()); if (referencedSources[i].updateCache()) { getReporter().note("CACHE", "Updated cache"); } else { getReporter().note("CACHE", "Skipped updating cache"); } } catch (Error e) { getReporter().note("CACHE", "Cache failed for " + referencedSources[i].getFilename()); e.log(); } } getReporter().note("STAGE", "Parsing included sources"); for (i = 0; i < includedSources.length; i++) { getReporter().note("STAGE-PART", includedSources[i].getFilename()); includedSources[i].parse(); try { getReporter().note("CACHE", "Using cache filename " + includedSources[i].getCacheName() + " for " + includedSources[i].getFilename()); if (includedSources[i].updateCache()) { getReporter().note("CACHE", "Updated cache"); } else { getReporter().note("CACHE", "Skipped updating cache"); } } catch (Error e) { getReporter().note("CACHE", "Cache failed for " + includedSources[i].getFilename()); e.log(); } } getReporter().note("STAGE", "Checking referenced sources"); int totalerrors = 0; for (i = 0; i < referencedSources.length; i++) { int e = referencedSources[i].checkErrors(errorVerbosity); if (e != 0) { getReporter().note("ERRORS", "Found " + e + " errors in '" + referencedSources[i].getFilename() + "'"); } totalerrors += e; } getReporter().note("STAGE", "Checking included sources"); int ngood = 0; int nbad = 0; for (i = 0; i < includedSources.length; i++) { int e = includedSources[i].checkErrors(errorVerbosity); if (e != 0) { nbad++; getReporter().note("ERRORS", "Found " + e + " errors in '" + includedSources[i].getFilename() + "'"); } else { ngood++; } totalerrors += e; } double ratiogood = ((double) ngood) / ((double) ngood + nbad); int percentgood = (int) (ratiogood * 100); getReporter().note("SUMMARY", "" + ngood + " good files and " + nbad + " bad files (" + percentgood + "% good)"); if (totalerrors != 0) { getReporter().note("TERMINATED", "Scanning/parsing/checking of sources resulted in " + totalerrors + " errors"); return false; } SystemModel system = new SystemModel(); getReporter().note("STAGE", "Configuring runtime types"); String core = "kebab0.core"; system.addBuiltinType(core, "bit", new BuiltinTypeBehaviour()); system.addBuiltinType(core, "duck", new BuiltinTypeBehaviour.DuckBehaviour()); system.addBuiltinType(core, "int8", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 8)); system.addBuiltinType(core, "int16", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 16)); system.addBuiltinType(core, "int32", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 32)); system.addBuiltinType(core, "int64", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 64)); system.addBuiltinType(core, "uint8", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 8)); system.addBuiltinType(core, "uint16", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 16)); system.addBuiltinType(core, "uint32", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 32)); system.addBuiltinType(core, "uint64", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 64)); system.addBuiltinType(core, "float32", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 32)); system.addBuiltinType(core, "float64", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 64)); system.addBuiltinType(core, "pointer", new BuiltinTypeBehaviour()); //system.addBuiltinType(core, "word", new BuiltinTypeBehaviour()); /*for (i = 0; i < typeOptions.length; i++) { TypeOption o = typeOptions[i]; if (o.isBuiltin) { } else { } }*/ system.setTypeOptions(typeOptions); /* The built-in types should be quite specific. For general-purpose use, aliases comparable to * standard C/D/Java/C# types are provided. These just point to the underlying built-in types. */ system.addAliasType(core, "boolean", core, "bit"); system.addAliasType(core, "byte", core, "int8"); system.addAliasType(core, "short", core, "int16"); system.addAliasType(core, "char", core, "uint16"); system.addAliasType(core, "int", core, "int32"); system.addAliasType(core, "long", core, "int64"); system.addAliasType(core, "float", core, "float32"); system.addAliasType(core, "double", core, "float64"); for (i = 0; i < aliasTypes.length; i++) { MetaOrAlias a = aliasTypes[i]; system.addAliasType(pkgname(a.key), typname(a.key), pkgname(a.value), typname(a.value)); } for (i = 0; i < aliasPackages.length; i++) { MetaOrAlias a = aliasPackages[i]; system.addAliasPackage(a.key, a.value); } /* system.addGlobalImport("fencom.stdlib"); system.addGlobalImport("java.lang"); */ for (i = 0; i < globalImports.length; i++) { if (globalImports[i].endsWith("*")) { system.addGlobalImport(pkgname(globalImports[i])); } else { system.addGlobalImport(pkgname(globalImports[i]), typname(globalImports[i])); } } if (arrayLengthNames != null) { getReporter().note("STAGE", "Overriding some magical options"); system.setArrayLengthNames(arrayLengthNames); } getReporter().note("STAGE", "Adding referenced sources"); for (i = 0; i < referencedSources.length; i++) { system.addUnit(referencedSources[i], false); } getReporter().note("STAGE", "Adding included sources"); for (i = 0; i < includedSources.length; i++) { system.addUnit(includedSources[i], true); } getReporter().note("STAGE", "Checking for initial errors"); if (system.countErrors() != 0) { getReporter().note("TERMINATED", "Unpacking into internal model resulted in " + system.countErrors() + " errors"); } //system.dump(getReporter()); int expandStage = 1; boolean keepExpanding = true; while (keepExpanding) { getReporter().note("STAGE", "Expanding internal model (phase " + expandStage + ")"); int nexpanded = system.expand(); getReporter().note("NOTE", "Expanded " + nexpanded + " items"); //system.dump(getReporter()); if (system.countErrors() != 0) { keepExpanding = false; getReporter().note("TERMINATED", "Expanding internal model resulted in " + system.countErrors() + " errors"); //return false; } if (nexpanded == 0) { keepExpanding = false; } expandStage++; } int resolveStage = 1; boolean keepResolving = true; int maxErrorRetries = 100; int errorRetries = 0; int maxNoExpandRetries = 100; while (keepResolving) { getReporter().note("STAGE", "Resolving types (phase " + resolveStage + ")"); int nexpanded = system.resolveTypes(); getReporter().note("NOTE", "Resolved " + nexpanded + " items"); //system.dump(getReporter()); if (system.countErrors() != 0) { //if (errorRetries > maxErrorRetries) { keepResolving = false; getReporter().note("TERMINATED", "Resolving types resulted in " + system.countErrors() + " errors"); //return false; /*} else { getReporter().note("RETRYING", "Failed to resolve some types, I wiil retry assuming further expansion is necessary to find them"); system.deleteErrors(); errorRetries++; }*/ } if (nexpanded == 0) { getReporter().note("NOT-RETRYING", "Maximum number of internal no-expand retries exceded"); keepResolving = false; } resolveStage++; } for (int tmp = 0; tmp < 10; tmp++) { getReporter().note("NOTE", "Extra check stage " + tmp); if (system.resolveTypes() != 0) { getReporter().note("WARNING", "Extra expansion is necessary???"); } } //system.dump(getReporter()); if (checkErrors() != 0) { getReporter().note("FAILED-IN", "Seems to have failed in the type-expansion stage"); return false; } resolveStage = 1; keepResolving = true; while (keepResolving) { getReporter().note("STAGE", "Resolving expressions (phase " + resolveStage + ")"); int nexpanded = system.resolveExpressions(false); // NOTE: The parameter controls whether or not references are checked too getReporter().note("NOTE", "Resolved " + nexpanded + " items"); //system.dump(getReporter()); if (system.countErrors() != 0) { keepResolving = false; getReporter().note("TERMINATED", "Resolving expressions resulted in " + system.countErrors() + " errors"); //return false; } if (nexpanded == 0) { keepResolving = false; } resolveStage++; } if (checkErrors() != 0) { getReporter().note("FAILED-IN", "Seems to have failed in the expression-reslolving stage"); return false; } /* This isn't finished yet (disabled for now in favour of a cleaner/slower expression resolution stage) CTarget.transpile(system, "foo.h", new LineOutput() { @Override public void line(String line) { System.err.println("HDR> " + line); } @Override public void endOfFile() { System.err.println("HDR END"); } }, new LineOutput() { @Override public void line(String line) { System.err.println("SRC> " + line); } @Override public void endOfFile() { System.err.println("SRC END"); } });*/ if (getTarget() == null) { getReporter().note("ABORTED", "No target to write to"); return false; } else { getTarget().setSystem(system); int total = 0; String[] pkgs = system.getPackageNames(); for (i = 0; i < providesDepends.length; i++) { ProvidesOrDepends x = providesDepends[i]; getReporter().note("REGISTERING", (x.provides ? "provides" : "depends") + " name '" + x.name + "' version '" + x.version + "'"); getTarget().visitProvidesOrDepends(x); } int mainTypesFound = 0; for (i = 0; i < pkgs.length; i++) { PackageModel p = system.getPackage(pkgs[i]); String[] typs = p.getTypeNames(); for (int j = 0; j < typs.length; j++) { TypeModel m = p.getType(typs[j]); MethodModel[] constrs = m.getInstanceConstructors(); //for (int x = 0; x < constrs.length; x++) { // Log.line("Type " + m.fullName() + "[" + typs[j] + "] has constr #" + x + ": " + constrs[x].toString()); //} if (m instanceof UserTypeModel && m.existsAtRuntime() && !m.isReferenceOnly()) { String name = m.fullName(); boolean isMain = false; getReporter().note("COMPILING", "#" + total + ": " + name); for (int x = 0; x < mainTypes.length; x++) { if (name.equals(mainTypes[x])) { mainTypesFound++; isMain = true; getReporter().note("NOTE", "Adding " + name + " to main list"); } } getTarget().visitType((UserTypeModel) m, isMain); total++; } } } if (mainTypesFound != mainTypes.length) { getReporter().note("WARNING", "Couldn't find main types (expecting " + mainTypes.length + " found " + mainTypesFound); } for (i = 0; i < dataFiles.length; i++) { getReporter().note("INSERTING", "#" + total + ": " + dataFiles[i].packagename + "." + dataFiles[i].innername); getTarget().visitDataFile(dataFiles[i]); total++; } for (i = 0; i < importantMeta.length; i++) { getTarget().visitMeta(true, importantMeta[i].key, importantMeta[i].value); } for (i = 0; i < otherMeta.length; i++) { getTarget().visitMeta(false, otherMeta[i].key, otherMeta[i].value); } for (i = 0; i < typeOptions.length; i++) { getTarget().visitTypeOption(typeOptions[i]); } if (total > 0) { if (checkErrors() != 0) { getReporter().note("FINISHING", "Producing (WITH ERRORS) a total of " + total + " type-level objects: " + getTarget().quickReport()); getTarget().finish(); getReporter().note("PARTIAL-SUCCESS", "Target has been produced (WITH ERRORS)."); return false; } else { getReporter().note("FINISHING", "Producing a total of " + total + " toplevels: " + getTarget().quickReport()); Log.line("In CompilerWorld"); getTarget().finish(); getReporter().note("SUCCESS", "Target has been produced."); return true; } } else { getReporter().note("ABORTED", "Producing empty target."); getTarget().finish(); return false; } } } public int checkErrors() { getReporter().note("CHECK", "Checking referenced sources for errors"); int terrors = 0; for (int i = 0; i < referencedSources.length; i++) { int e = referencedSources[i].checkErrors(errorVerbosity); if (e != 0) { getReporter().note("ERRORS", "Found " + e + " errors in '" + referencedSources[i].getFilename() + "'"); } terrors += e; } if (terrors != 0) { getReporter().note("FAILED", "Checking of referenced sources resulted in " + terrors + " errors"); return terrors; } getReporter().note("CHECK", "Checking included sources for errors"); for (int i = 0; i < includedSources.length; i++) { int e = includedSources[i].checkErrors(errorVerbosity); if (e != 0) { getReporter().note("ERRORS", "Found " + e + " errors in '" + includedSources[i].getFilename() + "'"); } terrors += e; } // Some random syntax tests were inserted here just to see how they behave // on the plaform which shall not be named: //String[] foo = {"foo","bar"}; //Object[] bar = foo; //int[] x = {1,2,3}; //long[] y = x; // Some weird behaviour I found in some random code (binary operators on booleans): //int wtf1 = 0, wtf2 = 0, wtf3 = 0, wtf4 = 0; //getReporter().note("TEST", "" + (wtf1 < wtf2-1 & (wtf1 != wtf3-1 | wtf4 == 0))); if (terrors != 0) { getReporter().note("FAILED", "Checking of included sources resulted in " + terrors + " errors"); return terrors; } return terrors; } public Language getLanguage() { return language; } public void setLanguage(Language l) { language = l; } }