package polyglot.ext.jl.ast; import polyglot.ast.*; import polyglot.types.*; import polyglot.util.Position; import polyglot.visit.ContextVisitor; /** * Utility class which is used to disambiguate ambiguous * AST nodes (Expr, Type, Receiver, Qualifier, Prefix). */ public class Disamb_c implements Disamb { protected ContextVisitor v; protected Position pos; protected Prefix prefix; protected String name; protected NodeFactory nf; protected TypeSystem ts; protected Context c; protected Ambiguous amb; /** * Disambiguate the prefix and name into a unambiguous node. * @return An unambiguous AST node, or null if disambiguation * fails. */ public Node disambiguate(Ambiguous amb, ContextVisitor v, Position pos, Prefix prefix, String name) throws SemanticException { this.v = v; this.pos = pos; this.prefix = prefix; this.name = name; this.amb = amb; nf = v.nodeFactory(); ts = v.typeSystem(); c = v.context(); if (prefix instanceof Ambiguous) { throw new SemanticException( "Cannot disambiguate node with ambiguous prefix."); } if (prefix instanceof PackageNode) { PackageNode pn = (PackageNode) prefix; return disambiguatePackagePrefix(pn); } else if (prefix instanceof TypeNode) { TypeNode tn = (TypeNode) prefix; return disambiguateTypeNodePrefix(tn); } else if (prefix instanceof Expr) { Expr e = (Expr) prefix; return disambiguateExprPrefix(e); } else if (prefix == null) { return disambiguateNoPrefix(); } return null; } protected Node disambiguatePackagePrefix(PackageNode pn) throws SemanticException { Resolver pc = ts.packageContextResolver(c.outerResolver(), pn.package_()); Named n = pc.find(name); Qualifier q = null; if (n instanceof Qualifier) { q = (Qualifier) n; } else { return null; } if (q.isPackage() && packageOK()) { return nf.PackageNode(pos, q.toPackage()); } else if (q.isType() && typeOK()) { return nf.CanonicalTypeNode(pos, q.toType()); } return null; } protected Node disambiguateTypeNodePrefix(TypeNode tn) throws SemanticException { // Try static fields. Type t = tn.type(); if (t.isReference() && exprOK()) { try { FieldInstance fi = ts.findField(t.toReference(), name, c); return nf.Field(pos, tn, name).fieldInstance(fi); } catch (NoMemberException e) { if (e.getKind() != e.FIELD) { // something went wrong... throw e; } // ignore so we can check if we're a member class. } } // Try member classes. if (t.isClass() && typeOK()) { Resolver tc = ts.classContextResolver(t.toClass()); Named n = tc.find(name); if (n instanceof Type) { Type type = (Type) n; return nf.CanonicalTypeNode(pos, type); } } return null; } protected Node disambiguateExprPrefix(Expr e) throws SemanticException { // Must be a non-static field. if (exprOK()) { return nf.Field(pos, e, name); } return null; } protected Node disambiguateNoPrefix() throws SemanticException { // First try local variables and fields. VarInstance vi = c.findVariableSilent(name); if (vi != null && exprOK()) { Node n = disambiguateVarInstance(vi); if (n != null) return n; } // no variable found. try types. if (typeOK()) { try { Named n = c.find(name); if (n instanceof Type) { Type type = (Type) n; return nf.CanonicalTypeNode(pos, type); } } catch (NoClassException e) { if (!name.equals(e.getClassName())) { // hmm, something else must have gone wrong // rethrow the exception throw e; } // couldn't find a type named name. // It must be a package--ignore the exception. } } // Must be a package then... if (packageOK()) { return nf.PackageNode(pos, ts.packageForName(name)); } return null; } protected Node disambiguateVarInstance(VarInstance vi) throws SemanticException { if (vi instanceof FieldInstance) { FieldInstance fi = (FieldInstance) vi; Receiver r = makeMissingFieldTarget(fi); return nf.Field(pos, r, name).fieldInstance(fi).targetImplicit(true); } else if (vi instanceof LocalInstance) { LocalInstance li = (LocalInstance) vi; return nf.Local(pos, name).localInstance(li); } return null; } protected Receiver makeMissingFieldTarget(FieldInstance fi) throws SemanticException { Receiver r; if (fi.flags().isStatic()) { r = nf.CanonicalTypeNode(pos, fi.container()); } else { // The field is non-static, so we must prepend with // "this", but we need to determine if the "this" // should be qualified. Get the enclosing class which // brought the field into scope. This is different // from fi.container(). fi.container() returns a super // type of the class we want. ClassType scope = c.findFieldScope(name); if (! ts.equals(scope, c.currentClass())) { r = nf.This(pos, nf.CanonicalTypeNode(pos, scope)); } else { r = nf.This(pos); } } return r; } protected boolean typeOK() { return ! (amb instanceof Expr) && (amb instanceof TypeNode || amb instanceof QualifierNode || amb instanceof Receiver || amb instanceof Prefix); } protected boolean packageOK() { return ! (amb instanceof Receiver) && (amb instanceof QualifierNode || amb instanceof Prefix); } protected boolean exprOK() { return ! (amb instanceof QualifierNode) && (amb instanceof Expr || amb instanceof Receiver || amb instanceof Prefix); } }