package slangc.model; import slang.data.Map; import slang.data.List; import slangc.parser.Branch; import slangc.parser.ErrorType; import slangc.parser.Node; import slangc.parser.NodeType; import slangc.parser.Token; public class InnerTypeScope { public static class SourceScope extends InnerTypeScope { public final Branch source; SourceScope(InnerTypeScope owner, Branch source) { super(owner); this.source = source; } } protected Map innerTypes = new Map(); InnerTypeScope owner; protected Map sourceScopes = null; InnerTypeScope(InnerTypeScope owner) { this.owner = owner; } public SourceScope innerScopeForSource(Branch b) { if (sourceScopes == null) { sourceScopes = new Map(); } if (!sourceScopes.hasKey(b)) { sourceScopes.set(b, new SourceScope(this, b)); } return sourceScopes.get(b); } public boolean hasInnerScopeForSource(Branch b) { return sourceScopes != null && sourceScopes.hasKey(b); } public SourceScope getInnerScopeForSource(Branch b) { //System.err.println("Looking up inner scope for " + b + " in " + this); if (hasInnerScopeForSource(b)) { //System.err.println("Found"); return sourceScopes.get(b); } else { //System.err.println("Not found"); return null; } } public String getOuterName() { return owner.getOuterName(); } private boolean dirtyHackRecursing = false; public TypeModel resolveTypeName(String name) { //System.err.println("Looking up '" + name + "' in " + this); /*if (this instanceof UserTypeModel) { if (!dirtyHackRecursing) { System.err.println("RESORTING TO DIRTY HACK"); dirtyHackRecursing = true; UserTypeModel dirtyHack = (UserTypeModel) this; dirtyHack.resolveTypes(); dirtyHack.resolveTypes(); dirtyHack.resolveTypes(); dirtyHack.resolveTypes(); dirtyHack.resolveTypes(); dirtyHackRecursing = false; } }*/ if (innerTypes.hasKey(name)) { //System.err.println("Got it!"); return innerTypes.get(name); } else if (owner != null) { return owner.resolveTypeName(name); } else { // TODO: Handle super-types here? return null; } } public static String plainName(Node nameNode) { if (nameNode.getNodeType() == NodeType.NAME) { Token t = (Token) ((Branch)nameNode).getSubnode(0); return t.getSnippet().getSource(); } else if (nameNode.getNodeType() == NodeType.INDEXED_NAME) { //throw new Error("TODO"); return plainName(((Branch) nameNode).getSubnode(0)); } else if (nameNode.getNodeType() == NodeType.TYPE || nameNode.getNodeType() == NodeType.TYPE_REFERENCE) { //System.err.println("TODO: Add array information to associated type!"); return plainName(((Branch) nameNode).getSubnode(0)); } else if (nameNode instanceof Token) { return ((Token)nameNode).getSnippet().getSource(); } else { throw new Error("Internal error/TODO: Not a plain name: " + nameNode.getNodeType()); } } public InnerTypeScope getOwner() { return owner; } public PackageModel getPackage() { return owner.getPackage(); } public TypeModel getNearestType() { if (this instanceof TypeModel) { return (TypeModel) this; } else { return owner.getNearestType(); } } /* public TypeModel resolveTypeReference(Node subnode) { try { String n = plainName(subnode); TypeModel t = resolveTypeName(n); if (t == null) { return getOwner().resolveTypeReference(subnode); } else { return t; } } catch (Error e) { System.err.println(e); return getOwner().resolveTypeReference(subnode); } }*/ public TypeModel[] resolveClassReferences(Node typeRefs) { if (typeRefs.getNodeType() == NodeType.CLASS_IMPLEMENTS || typeRefs.getNodeType() == NodeType.INTERFACE_BASES) { return resolveClassReferences(((Branch)typeRefs).getSubnode(1)); } else if (typeRefs.getNodeType() == NodeType.TYPE_REFERENCES) { Branch b = (Branch) typeRefs; List results = new List(); for (int i = 0; i < b.countSubnodes(); i++) { //System.out.println("SUBREFS GOT A " + b.getSubnode(i).getNodeType()); if (b.getSubnode(i).getNodeType() != NodeType.COMMA) { results.append(resolveTypeReference(b.getSubnode(i))); } } return results.arrayCopy(); } else { throw new Error("Internal error/TODO: Unrecognised type references container " + typeRefs.getNodeType()); } } public TemplateArgument parseOneTemplateArgument(Node targ) { if (targ.getNodeType() != NodeType.GENERIC_VALUE && targ.getNodeType() != NodeType.TYPE) { throw new Error("Internal error/TODO: Not a generic typeName: " + targ.getNodeType()); } TypeModel type = resolveTypeReference(((Branch)targ).getSubnode(0)); if (type == null) { targ.annotate(ErrorType.INTERNAL_ERROR, "Couldn't resolve this template argument"); } return new TypeTemplateArgument(type); } public TemplateArguments parseTemplateArguments(Node targs) { if (targs.getNodeType() == NodeType.GENERIC_ARGUMENTS) { return parseTemplateArguments(((Branch)targs).getSubnode(1)); } else if (targs.getNodeType() == NodeType.GENERIC_EXPRESSIONS) { Branch b = (Branch) targs; List list = new List(); for (int i = 0; i < b.countSubnodes(); i++) { if (b.getSubnode(i).getNodeType() != NodeType.COMMA) { TemplateArgument ta = parseOneTemplateArgument(b.getSubnode(i)); if (ta == null) { return null; } list.append(ta); } } return new TemplateArguments(list.arrayCopy()); } else { throw new Error("Internal error/TODO: Not a generic sizeExpression node: " + targs.getNodeType()); } } public TypeModel resolveTypeReference(Node typeReference) { return resolveTypeReference(typeReference, true); } public TypeModel resolveTypeReference(Node typeReference, boolean simplify) { TypeModel result = innerResolveTypeReference(typeReference); if (simplify && (result != null)) { result = result.simplify(); } return result; } public TypeModel innerResolveGlobal(String globalName) { if (!globalName.search(".")) { return null; } String pkg = globalName.sub(0, globalName.searchLast(".")); String typ = globalName.sub(globalName.searchLast(".") + 1); if (!getPackage().getSystem().hasPackage(pkg)) { return null; } PackageModel p = getPackage().getSystem().getPackage(pkg); if (!p.hasType(typ)) { return null; } return p.getType(typ); } public TypeModel innerResolveTypeReference(Node typeReference) { if (typeReference.getNodeType() == NodeType.TYPE_REFERENCE) { InnerTypeScope outer = this; TypeModel result = null; String unresolved = ""; if (((Branch)typeReference).countSubnodes() < 1) { throw new Error("wtf? Empty name?"); } for (int i = 0; i < ((Branch)typeReference).countSubnodes(); i++) { Node node = ((Branch)typeReference).getSubnode(i); if (node.getNodeType() == NodeType.DOT) { unresolved += "."; } else { String n; boolean isGenericInstance = false; TemplateArguments targs = null; if (node.getNodeType() == NodeType.GENERIC_NAME) { n = plainName(((Branch)node).getSubnode(0)); targs = parseTemplateArguments(((Branch)node).getSubnode(1)); isGenericInstance = true; n += targs.genericString(); } else { n = plainName(node); } unresolved += n; //System.err.println("I be working with '" + unresolved + "'"); TypeModel tmp = null; if (outer != null) { //System.err.println("I be resolving outer"); tmp = outer.resolveTypeName(n); } if (tmp == null) { //System.err.println("I be resolving inner"); tmp = innerResolveGlobal(unresolved); } if (tmp == null) { //System.err.println("I still null"); outer = null; result = null; //throw new Error("Can't find type '" + n + "' within " + outer.fullName()); //node.annotate(ErrorType.INTERNAL_ERROR, "Can't find type '" + n + "' within " + outer.fullName()); //return null; } else if (isGenericInstance) { //System.err.println("I is generic???"); if (targs == null) { node.annotate(ErrorType.INTERNAL_ERROR, "Failed to decode template sizeExpression"); return null; } TypeModel inst = tmp.getOrCreateTemplateInstance(targs); if (inst == null) { node.annotate(ErrorType.INTERNAL_ERROR, "Unable to instantiate " + tmp.fullName() + " with sizeExpression " + targs); return null; } outer = inst; result = inst; } else { //System.err.println("I is done? " + tmp); tmp = tmp.simplify(); //System.err.println("I is simplified? " + tmp); outer = tmp; result = tmp; } } } if (result == null) { if (this == getNearestType()) { //throw new Error("???" + unresolved); typeReference.annotate(ErrorType.INTERNAL_ERROR, "Unable to resolve " + unresolved); } else { getOwner().innerResolveTypeReference(typeReference); } } return result; //return resolveTypeReference(((Branch)typeReference).getSubnode(0)); } else if (typeReference.getNodeType() == NodeType.NAME) { Token t = (Token) ((Branch)typeReference).getSubnode(0); String n = t.getSnippet().getSource(); TypeModel result = resolveTypeName(n); if (result == null) { throw new Error("Failed to lookup name '" + n + "'"); //t.annotate(ErrorType.INTERNAL_ERROR, "Failed to lookup name '" + n + "'"); } return result; } else if (typeReference.getNodeType() == NodeType.TOKEN) { Token t = (Token) typeReference; String n = t.getSnippet().getSource(); TypeModel result = resolveTypeName(n); if (result == null) { throw new Error("Failed to lookup name '" + n + "'"); //t.annotate(ErrorType.INTERNAL_ERROR, "Failed to lookup name '" + n + "'"); } return result; } else if (typeReference.getNodeType() == NodeType.TYPE) { return resolveTypeReference(((Branch)typeReference).getSubnode(0)); } else if (typeReference.getNodeType() == NodeType.ARRAY_TYPE) { TypeModel b = resolveTypeReference(((Branch)typeReference).getSubnode(0)); if (b == null) { return null; // Should have already warned if base type not found } return b.getOrCreateArrayInstance(); } else { throw new Error("Unrecognised type reference node: " + typeReference.getNodeType()); } } public boolean hasInnerType(String name) { return innerTypes.hasKey(name); } public TypeModel getInnerType(String name) { if (hasInnerType(name)) { return innerTypes.get(name); } else { return null; } } public boolean hasInnerTypeForSource(Branch source) { return getInnerTypeForSource(source) != null; } public TypeModel getInnerTypeForSource(Branch source) { List inners = new List(); inners.appendList(innerTypes.values()); for (int i = 0; i < inners.count(); i++) { if (inners.get(i) instanceof UserTypeModel) { UserTypeModel t = (UserTypeModel) inners.get(i); if (t.parsed == source) { return t; } } } return null; } }