352 lines
11 KiB
Plaintext
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;
|
|
}
|
|
}
|