slcom/slangc/model/InnerTypeScope.sauce

352 lines
11 KiB
Plaintext

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<String, TypeModel> innerTypes = new Map<String, TypeModel>();
InnerTypeScope owner;
protected Map<Branch, SourceScope> sourceScopes = null;
InnerTypeScope(InnerTypeScope owner) {
this.owner = owner;
}
public SourceScope innerScopeForSource(Branch b) {
if (sourceScopes == null) {
sourceScopes = new Map<Branch, SourceScope>();
}
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<TypeModel> results = new List<TypeModel>();
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<TemplateArgument> list = new List<TemplateArgument>();
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<TypeModel> inners = new List<TypeModel>();
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;
}
}