package slangc.model; import slang.data.ComparisonOp; import slang.data.List; import slang.data.Map; import slangc.api.CompilerWorld; import slangc.api.Reporter; import slangc.api.TypeOption; import slangc.api.Unit; import slangc.bytecode.TypeSignature; public class SystemModel { //Map sources = new Map(); //Map types = new Map(); Map packages = new Map(); Map packageAliases = new Map(); List globalImports = new List(); CombinedImportModel combinedGlobalImports = null; TypeOption[] typeOptions; private String defaultBasePackage = "kebab0.base"; //"rt"; private String defaultBaseType = "Object"; private String defaultTypePackage = "kebab0.base"; //"rt"; private String defaultTypeType = "Class"; private String defaultStringPackage = "kebab0.base"; //"rt"; private String defaultStringType = "String"; private String defaultBooleanPackage = "kebab0.core"; //"rt"; private String defaultBooleanType = "bit"; private String defaultInt32Package = "kebab0.core"; //"rt"; private String defaultInt32Type = "int32"; private String defaultInt64Package = "kebab0.core"; //"rt"; private String defaultInt64Type = "int64"; private String defaultFloat32Package = "kebab0.core"; //"rt"; private String defaultFloat32Type = "float32"; private String defaultFloat64Package = "kebab0.core"; //"rt"; private String defaultFloat64Type = "float64"; private String defaultDuckPackage = "kebab0.core"; private String defaultDuckType = "duck"; private String defaultVoidPackage = "kebab0.core"; private String defaultVoidType = "void"; private String[] arrayLengthNames = new String[] {"length"}; public void setArrayLengthNames(String[] names) { arrayLengthNames = names; } public String[] getArrayLengthNames() { return arrayLengthNames; } public boolean isArrayLengthName(String n) { for (int i = 0; i < arrayLengthNames.length; i++) { if (arrayLengthNames[i].equals(n)) { return true; } } return false; } public SourceModel addUnit(Unit unit, boolean isIncluded) { //Branch u = unit.parse(); return getOrCreatePackage(unit.getPackageName(), true).addSource(unit.getFilename(), unit.parse(), isIncluded); /*int count = u.countSubnodes(); for (int i = 0; i < count; i++) { Node n = u.getSubnode(i); Log.line("Got a '" + n.getNodeType() + "'"); }*/ } public PackageImportModel addGlobalImport(String packageName) { PackageImportModel m = new PackageImportModel(this, true, packageName); combinedGlobalImports = null; globalImports.append(m); return m; } public TypeImportModel addGlobalImport(String packageName, String typeName) { TypeImportModel m = new TypeImportModel(this, packageName, typeName); combinedGlobalImports = null; globalImports.append(m); return m; } public CombinedImportModel getGlobalImports() { if (combinedGlobalImports == null) { ImportModel[] imports = globalImports.arrayCopy(); combinedGlobalImports = new CombinedImportModel(this, true, imports); } return combinedGlobalImports; } public BuiltinTypeModel addBuiltinType(String packageName, String typeName, BuiltinTypeBehaviour builtinTypeBehaviour) { PackageModel p = getOrCreatePackage(packageName, true); /*if (p.hasType(typeName)) { throw new Error("Internal error/TODO: Type with same name as builtin '" + typeName + "' already exists in package '" + packageName + "'"); }*/ BuiltinTypeModel t = new BuiltinTypeModel(p, typeName, TypeLevel.OUTER, null, builtinTypeBehaviour); p.addSyntheticType(t); return t; } public AliasTypeModel addAliasType(String packageName, String typeName, String targetPackageName, String targetTypeName) { PackageModel p = getOrCreatePackage(packageName, true); AliasTypeModel t = new AliasTypeModel(p, typeName, TypeLevel.OUTER, null, getOrCreatePackage(targetPackageName, true), targetTypeName); p.addSyntheticType(t); return t; } public AliasTypeModel addInnerAliasType(UserTypeModel outer, String innerTypeName, String targetPackageName, String targetTypeName) { PackageModel p = outer.getPackage(); AliasTypeModel t = new AliasTypeModel(p, innerTypeName, TypeLevel.INNER, outer, getOrCreatePackage(targetPackageName, true), targetTypeName); p.addSyntheticType(t); outer.registerInnerType(t); return t; } public void addAliasPackage(String packageName, String targetPackageName) { PackageModel tpkg = getOrCreatePackage(targetPackageName, true); packageAliases.set(packageName, tpkg); } public void setTypeOptions(TypeOption[] typeOptions) { this.typeOptions = typeOptions; for (int i = 0; i < typeOptions.length; i++) { TypeOption o = typeOptions[i]; if (o.isBuiltin) { if (o.isNumber) { addBuiltinType(CompilerWorld.pkgname(o.typeName), CompilerWorld.typname(o.typeName), new BuiltinTypeBehaviour.NumberBehaviour(o.isFloat, o.isSigned, o.nbits)); } else if (o.isDuck) { addBuiltinType(CompilerWorld.pkgname(o.typeName), CompilerWorld.typname(o.typeName), new BuiltinTypeBehaviour.DuckBehaviour()); } else { addBuiltinType(CompilerWorld.pkgname(o.typeName), CompilerWorld.typname(o.typeName), new BuiltinTypeBehaviour()); } } } } public TypeOption findTypeOption(TypeOption.Kind k) { for (int i = 0; i < typeOptions.length; i++) { if (typeOptions[i].kind == k) { return typeOptions[i]; } } return null; } public boolean matchesTypeOption(TypeOption.Kind kind, TypeSignature type) { TypeOption o = findTypeOption(kind); if (o != null) { if (o.getTypeSignature().mappableEquals(type)) { return true; } } return false; } /*public void setDefaultBaseType(String packageName, String typeName) { this.defaultBasePackage = packageName; this.defaultBaseType = typeName; }*/ public TypeModel getDefaultBaseType() { TypeOption o = findTypeOption(TypeOption.Kind.OBJECT); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultBasePackage, true).getType(defaultBaseType); } public TypeModel getDefaultEnumBaseType() { TypeOption o = findTypeOption(TypeOption.Kind.ENUMBASE); if (o == null) { return getDefaultBaseType(); // Fall back to "Object" or equivalent if there is no enum base type? } else { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } } public TypeModel getDefaultTypeType() { TypeOption o = findTypeOption(TypeOption.Kind.TYPE); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultTypePackage, true).getType(defaultTypeType); } public TypeModel getDefaultStringType() { TypeOption o = findTypeOption(TypeOption.Kind.STRING); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultStringPackage, true).getType(defaultStringType); } public TypeModel getDefaultBooleanType() { TypeOption o = findTypeOption(TypeOption.Kind.BIT); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultBooleanPackage, true).getType(defaultBooleanType); } public TypeModel getDefaultInt32Type() { TypeOption o = findTypeOption(TypeOption.Kind.INT32); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultInt32Package, true).getType(defaultInt32Type); } public TypeModel getDefaultInt64Type() { TypeOption o = findTypeOption(TypeOption.Kind.INT64); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultInt64Package, true).getType(defaultInt64Type); } public TypeModel getDefaultUint32Type() { TypeOption o = findTypeOption(TypeOption.Kind.UINT32); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } else { throw new Error("Uint64 type does not seem to have been enabled!"); } } public TypeModel getDefaultUint64Type() { TypeOption o = findTypeOption(TypeOption.Kind.UINT64); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } else { throw new Error("Uint64 type does not seem to have been enabled!"); } } public TypeModel getDefaultFloat32Type() { TypeOption o = findTypeOption(TypeOption.Kind.FLOAT32); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultFloat32Package, true).getType(defaultFloat32Type); } public TypeModel getDefaultFloat64Type() { TypeOption o = findTypeOption(TypeOption.Kind.FLOAT64); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultFloat64Package, true).getType(defaultFloat64Type); } public TypeModel getDefaultDuckType() { TypeOption o = findTypeOption(TypeOption.Kind.DUCK); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultDuckPackage, true).getType(defaultDuckType); } public TypeModel getDefaultVoidType() { TypeOption o = findTypeOption(TypeOption.Kind.VOID); if (o != null) { return getOrCreatePackage(CompilerWorld.pkgname(o.typeName), true).getType(CompilerWorld.typname(o.typeName)); } return getOrCreatePackage(defaultVoidPackage, true).getType(defaultVoidType); } public boolean hasPackage(String name) { return packages.hasKey(name) || packageAliases.hasKey(name); } public PackageModel getOrCreatePackage(String name, boolean createIfNeeded) { if (packages.hasKey(name)) { return packages.get(name); } else if (packageAliases.hasKey(name)) { return packageAliases.get(name); } else if (createIfNeeded) { PackageModel p = new PackageModel(this, name); packages.set(name, p); return p; } else { return null; } } public PackageModel getPackage(String name) { if (hasPackage(name)) { return packages.hasKey(name) ? packages.get(name) : packageAliases.get(name); } else { throw new Error("Internal error/TODO: Package '" + name + "' doesn't exist"); } } public String[] getPackageNames() { List list = new List(); list.appendList(packages.keys()); list.sort(String.getDefaultComparisonOp()); return list.arrayCopy(); } public int countErrors() { int total = 0; PackageModel[] pkgs = packages.values().arrayCopy(); for(int i = 0; i < pkgs.length; i++) { PackageModel p = pkgs[i]; total += p.countErrors(); } return total; } public int deleteErrors() { int total = 0; PackageModel[] pkgs = packages.values().arrayCopy(); for(int i = 0; i < pkgs.length; i++) { PackageModel p = pkgs[i]; total += p.deleteErrors(); } return total; } public int expand() { int total = 0; PackageModel[] pkgs = packages.values().arrayCopy(); for(int i = 0; i < pkgs.length; i++) { PackageModel p = pkgs[i]; total += p.expand(); } return total; } public int resolveTypes() { int total = 0; PackageModel[] pkgs = packages.values().arrayCopy(); for(int i = 0; i < pkgs.length; i++) { PackageModel p = pkgs[i]; total += p.resolveTypes(); } return total; } public int resolveExpressions(boolean includingReferences) { int total = 0; PackageModel[] pkgs = packages.values().arrayCopy(); for(int i = 0; i < pkgs.length; i++) { PackageModel p = pkgs[i]; total += p.resolveExpressions(includingReferences); } return total; } public void dump(Reporter reporter) { dump(reporter, "", " "); } public void dump(Reporter reporter, String indent, String incrindent) { reporter.note("DUMP", indent + "> System"); String[] pkgs = getPackageNames(); for (int i = 0; i < pkgs.length; i++) { getPackage(pkgs[i]).dump(reporter, indent + incrindent, incrindent); } } public TypeModel getType(TypeSignature s) { return getPackage(s.packageName).getType(s.typeName); } }