/*
* 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
*
* (C) Copyright IBM Corporation 2006-2010.
*/
package x10.ast;
import java.util.Collections;
import java.util.Map;
import polyglot.ast.AmbTypeNode;
import polyglot.ast.AmbTypeNode_c;
import polyglot.ast.CanonicalTypeNode;
import polyglot.ast.Disamb;
import polyglot.ast.Expr;
import polyglot.ast.Id;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.PackageNode;
import polyglot.ast.Prefix;
import polyglot.ast.TypeNode;
import polyglot.frontend.Globals;
import polyglot.frontend.Goal;
import polyglot.types.Context;
import polyglot.types.Flags;
import polyglot.types.LazyRef;
import polyglot.types.QName;
import polyglot.types.Ref;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.Types;
import polyglot.util.CodeWriter;
import polyglot.util.CodedErrorInfo;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;
import polyglot.visit.TypeCheckPreparer;
import polyglot.visit.TypeChecker;
import x10.errors.Errors;
import x10.extension.X10Del;
import x10.extension.X10Del_c;
import x10.types.ConstrainedType;
import x10.types.MacroType;
import x10.types.X10ClassType;
import polyglot.types.Context;
import x10.types.X10ParsedClassType;
import x10.util.CollectionFactory;
import polyglot.types.TypeSystem;
import x10.visit.X10TypeChecker;
/**
* An <code>AmbTypeNode</code> is an ambiguous AST node composed of
* dot-separated list of identifiers that must resolve to a type.
*/
public class X10AmbTypeNode_c extends AmbTypeNode_c implements X10AmbTypeNode, AddFlags {
protected Prefix prefix;
protected Id name;
public X10AmbTypeNode_c(Position pos, Prefix qual, Id name) {
super(pos, qual, name);
assert(name != null); // qual may be null
this.prefix = qual;
this.name = name;
}
protected TypeNode disambiguateAnnotation(ContextVisitor tc) throws SemanticException {
Position pos = position();
TypeSystem ts = (TypeSystem) tc.typeSystem();
NodeFactory nf = (NodeFactory) tc.nodeFactory();
Context c = (Context) tc.context();
if (! c.inAnnotation())
return null;
SemanticException ex;
Prefix prefix = this.prefix;
// Look for a simply-named type.
try {
Disamb disamb = tc.nodeFactory().disamb();
Node n = disamb.disambiguate(this, tc, pos, prefix, name);
if (n instanceof TypeNode) {
TypeNode tn = (TypeNode) n;
Ref<Type> tref = (Ref<Type>) tn.typeRef();
Type t = tref.get();
if (t instanceof X10ParsedClassType) {
X10ParsedClassType ct = (X10ParsedClassType) t;
if (ct.flags().isInterface()) {
return postprocess((X10CanonicalTypeNode) tn, this, tc);
}
}
throw new SemanticException("Annotation type must be an interface.", position());
}
String typeName = (prefix == null ? name.toString() : prefix.toString() + "." + name.toString());
ex = new SemanticException("Could not find type \"" + typeName +"\".", pos);
Map<String, Object> map = CollectionFactory.newHashMap();
map.put(CodedErrorInfo.ERROR_CODE_KEY, CodedErrorInfo.ERROR_CODE_TYPE_NOT_FOUND);
map.put("TYPE", typeName);
ex.setAttributes(map);
}
catch (SemanticException e) {
ex = e;
}
throw ex;
}
public Node disambiguate(ContextVisitor ar) {
SemanticException ex;
Position pos = position();
ContextVisitor tc = ar;
TypeSystem ts = tc.typeSystem();
NodeFactory nf = (NodeFactory) tc.nodeFactory();
try {
TypeNode tn = disambiguateAnnotation(tc);
if (tn != null)
return tn;
}
catch (SemanticException e) {
LazyRef<Type> sym = (LazyRef<Type>) type;
X10ClassType ut = ts.createFakeClass(QName.make(fullName(this.prefix), name().id()), e);
ut.def().position(pos);
sym.update(ut);
Errors.issue(tc.job(), e, this);
return nf.CanonicalTypeNode(pos, sym);
}
Prefix prefix = this.prefix;
// First look for a typedef. FIXME: remove
try {
X10ParsedClassType typeDefContainer = null;
if (prefix instanceof PackageNode || prefix == null) {
// TODO: vj check isf this should be uncommented.
// PackageNode pn = (PackageNode) prefix;
// String dummyName = DUMMY_PACKAGE_CLASS_NAME;
// String fullName = (pn != null ? Types.get(pn.package_()).fullName() + "." : "") + dummyName;
// Named n = ts.systemResolver().find(fullName);
// if (n instanceof X10ParsedClassType) {
// typeDefContainer = (X10ParsedClassType) n;
// }
}
else if (prefix instanceof TypeNode) {
TypeNode tn = (TypeNode) prefix;
Type bt = tn.type();
if (Types.isConstrainedType(bt))
bt = Types.baseType(tn.type());
if (bt instanceof X10ParsedClassType) {
typeDefContainer = (X10ParsedClassType) bt;
}
}
else if (prefix instanceof Expr) {
throw new SemanticException("Non-static type members not implemented: " + prefix + " cannot be understood.", pos);
}
if (typeDefContainer != null) {
Context context = tc.context();
MacroType mt = ts.findTypeDef(typeDefContainer, name.id(), Collections.<Type>emptyList(), Collections.<Type>emptyList(), context);
LazyRef<Type> sym = (LazyRef<Type>) type;
sym.update(mt);
// Reset the resolver goal to one that can run when the ref is deserialized.
Goal resolver = tc.job().extensionInfo().scheduler().LookupGlobalType(sym);
resolver.update(Goal.Status.SUCCESS);
sym.setResolver(resolver);
return postprocess(nf.CanonicalTypeNode(pos, sym), this, ar);
}
}
catch (SemanticException e) {
}
// Otherwise, look for a simply-named type.
try {
Disamb disamb = ar.nodeFactory().disamb();
Node n = disamb.disambiguate(this, ar, pos, prefix, name);
if (n instanceof TypeNode) {
TypeNode tn = (TypeNode) n;
LazyRef<Type> sym = (LazyRef<Type>) type;
Type t2 = tn.type();
/* if (t2 instanceof X10ParsedClassType) {
X10ParsedClassType ct = (X10ParsedClassType) tn.type();
if (ct.x10Def().typeParameters().size() != 0) {
throw new SemanticException("Invalid type " + ct + "; incorrect number of type arguments.", position());
}
}*/
// Reset the resolver goal to one that can run when the ref is deserialized.
Goal resolver = tc.job().extensionInfo().scheduler().LookupGlobalType(sym);
resolver.update(Goal.Status.SUCCESS);
sym.setResolver(resolver);
return postprocess((X10CanonicalTypeNode) tn, this, ar);
}
String typeName = (prefix == null ? name.toString() : prefix.toString() + "." + name.toString());
ex = new SemanticException("Could not find type \"" + typeName +"\".", pos);
Map<String, Object> map = CollectionFactory.newHashMap();
map.put(CodedErrorInfo.ERROR_CODE_KEY, CodedErrorInfo.ERROR_CODE_TYPE_NOT_FOUND);
map.put("TYPE", typeName);
ex.setAttributes(map);
}
catch (SemanticException e) {
ex = e;
}
// Mark the type as an error, so we don't try looking it up again.
LazyRef<Type> sym = (LazyRef<Type>) type;
X10ClassType ut = ts.createFakeClass(QName.make(fullName(prefix), name().id()), ex);
ut.def().position(position());
sym.update(ut);
Errors.issue(tc.job(), ex, this);
return nf.CanonicalTypeNode(position(), sym);
}
public static QName fullName(Prefix prefix) {
if (prefix instanceof PackageNode) {
PackageNode pn = (PackageNode) prefix;
return Types.get(pn.package_()).fullName();
}
else if (prefix instanceof TypeNode) {
TypeNode tn = (TypeNode) prefix;
return tn.type().fullName();
}
return null;
}
static TypeNode postprocess(X10CanonicalTypeNode result, TypeNode n, ContextVisitor childtc) {
Flags f = ((X10AmbTypeNode_c) n).flags;
if (f != null) {
LazyRef<Type> sym = (LazyRef<Type>) result.typeRef();
Type t = Types.get(sym);
t = Types.processFlags(f, t);
sym.update(t);
}
return AmbDepTypeNode_c.postprocess(result, n, childtc);
}
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
if (prefix != null) {
print(prefix, w, tr);
w.write(".");
w.allowBreak(2, 3, "", 0);
}
tr.print(this, name, w);
}
public String toString() {
return (prefix == null
? name.toString()
: prefix.toString() + "." + name.toString()) + "{amb}";
}
Flags flags;
public void addFlags(Flags f) {
this.flags = f;
}
public Id name() {
return this.name;
}
public AmbTypeNode name(Id name) {
X10AmbTypeNode_c n = (X10AmbTypeNode_c) copy();
n.name = name;
return n;
}
public Prefix prefix() {
return this.prefix;
}
public AmbTypeNode prefix(Prefix prefix) {
X10AmbTypeNode_c n = (X10AmbTypeNode_c) copy();
n.prefix = prefix;
return n;
}
protected AmbTypeNode_c reconstruct(Prefix qual, Id name) {
if (qual != this.prefix || name != this.name) {
X10AmbTypeNode_c n = (X10AmbTypeNode_c) copy();
n.prefix = qual;
n.name = name;
return n;
}
return this;
}
public Node visitChildren(NodeVisitor v) {
Prefix prefix = (Prefix) visitChild(this.prefix, v);
Id name = (Id) visitChild(this.name, v);
return reconstruct(prefix, name);
}
}