/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * This file was originally derived from the Polyglot extensible compiler framework. * * (C) Copyright 2000-2007 Polyglot project group, Cornell University * (C) Copyright IBM Corporation 2007-2012. */ package polyglot.ast; import java.util.Iterator; import java.util.List; import polyglot.frontend.Globals; import polyglot.frontend.Goal; import polyglot.types.*; import polyglot.types.Package; import polyglot.util.Position; import polyglot.visit.ContextVisitor; import x10.errors.Errors; import x10.extension.X10Ext; import x10.types.MethodInstance; import x10.ast.X10CanonicalTypeNode; /** * Utility class which is used to disambiguate ambiguous * AST nodes (Expr, Type, Receiver, Qualifier, Prefix). */ public abstract class Disamb_c implements Disamb { protected ContextVisitor v; protected Position pos; protected Node prefix; protected Id 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 { return disambiguate(amb, v, pos, prefix, v.nodeFactory().Id(pos, name)); } /** * 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, Node prefix, Id 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 Errors.CannotDisambiguateNodeWithAmbiguousPrefix(pos); } Node result = null; if (prefix instanceof PackageNode) { PackageNode pn = (PackageNode) prefix; result = disambiguatePackagePrefix(pn); } else if (prefix instanceof TypeNode) { TypeNode tn = (TypeNode) prefix; result = disambiguateTypeNodePrefix(tn); } else if (prefix instanceof Expr) { Expr e = (Expr) prefix; result = disambiguateExprPrefix(e); } else if (prefix == null) { result = disambiguateNoPrefix(); } assert ! (result instanceof Ambiguous); return result; } protected Node disambiguatePackagePrefix(PackageNode pn) throws SemanticException { Resolver pc = ts.packageContextResolver(pn.package_().get()); List<Type> n; try { n = pc.find(ts.TypeMatcher(name.id())); } catch (SemanticException e) { n = null; } Qualifier q = null; if (n != null) { if (n.size() > 1) { StringBuffer sb = new StringBuffer(); // FIXME: copied from TypeSystem_c.findTypeDef() for (Iterator<Type> i = n.iterator(); i.hasNext();) { Type ma = i.next(); sb.append(n.toString()); if (i.hasNext()) { if (n.size() == 2) { sb.append(" and "); } else { sb.append(", "); } } } throw new SemanticException("Reference to " + name.id() + " is ambiguous, multiple type defintions match: " + sb.toString()); } for (Type t : n) { q = t; break; } } if (q == null) { Package p = ts.createPackage(pn.package_(), name.id()); q = p; } if (q.isPackage() && packageOK()) { return nf.PackageNode(pos, Types.ref(q.toPackage())); } else if (q.isType() && typeOK()) { return makeTypeNode(q.toType()); } return null; } protected Node disambiguateTypeNodePrefix(TypeNode tn) throws SemanticException { // Try static fields. Type t = tn.type(); if (exprOK()) { try { FieldInstance fi = ts.findField(t, t, name.id(), c); return nf.Field(pos, tn, name).fieldInstance(fi); } catch (NoMemberException e) { if (e.getKind() != NoMemberException.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 = t.toClass().resolver(); List<Type> tl; try { tl = tc.find(ts.MemberTypeMatcher(t, name.id(), c)); } catch (NoClassException e) { return null; } for (Type n : tl) { if (n.isClass()) { return makeTypeNode(n); } } } 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 abstract Node disambiguateNoPrefix() throws SemanticException; 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 abstract Receiver makeMissingFieldTarget(FieldInstance fi) throws SemanticException; protected abstract Receiver makeMissingMethodTarget(MethodInstance mi) throws SemanticException; 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 TypeNode) && (amb instanceof Expr || amb instanceof Receiver || amb instanceof Prefix); } protected Node makeTypeNode(Type t) { CanonicalTypeNode res = null; if (amb instanceof TypeNode) { TypeNode tn = (TypeNode) amb; if (tn.typeRef() instanceof LazyRef<?>) { LazyRef<Type> sym = (LazyRef<Type>) tn.typeRef(); sym.update(t); // Reset the resolver goal to one that can run when the ref is deserialized. Goal resolver = v.job().extensionInfo().scheduler().LookupGlobalType(sym); resolver.update(Goal.Status.SUCCESS); sym.setResolver(resolver); res = nf.CanonicalTypeNode(pos, sym); } } if (res==null) res = nf.CanonicalTypeNode(pos, t); final Node node = res.ext((X10Ext) amb.ext().copy()); return node; } public abstract String toString(); }