/* * 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.plugin; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import polyglot.ast.ArrayInit; import polyglot.ast.Assign; import polyglot.ast.Binary; import polyglot.ast.Call; import polyglot.ast.Expr; import polyglot.ast.Field; import polyglot.ast.Local; import polyglot.ast.LocalDecl; import polyglot.ast.New; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.ProcedureCall; import polyglot.ast.Unary; import x10.ExtensionInfo; import x10.ExtensionInfo.X10Scheduler; import x10.ast.ParExpr; import x10.ast.X10Cast; import x10.ast.X10Instanceof; import x10.ast.X10NodeFactory; import x10.types.X10ClassType; import x10.types.X10ConstructorInstance; import x10.types.X10Context; import x10.types.X10FieldInstance; import x10.types.X10LocalInstance; import x10.types.X10MethodInstance; import x10.types.X10Type; import x10.types.X10TypeSystem; import polyglot.frontend.Goal; import polyglot.frontend.Job; import polyglot.frontend.Scheduler; import polyglot.types.ArrayType; import polyglot.types.ProcedureInstance; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; public abstract class SimpleTypeAnnotationPlugin implements CompilerPlugin { public SimpleTypeAnnotationPlugin() { super(); System.out.println("Registering " + this.getClass().getName()); } public static class CheckerGoal extends VisitorGoal { public static Goal create(Scheduler scheduler, Job job, NodeVisitor v) { return scheduler.internGoal(new CheckerGoal(job, v)); } Goal precheckGoal; private CheckerGoal(Job job, NodeVisitor v) { super(job, v); } public Collection prerequisiteGoals(Scheduler scheduler) { X10Scheduler x10Sched = (X10Scheduler) scheduler; List<Goal> l = new ArrayList<Goal>(); l.add(x10Sched.TypeChecked(job)); l.add(x10Sched.ConstantsChecked(job)); l.add(x10Sched.PropagateAnnotations(job)); l.addAll(super.prerequisiteGoals(scheduler)); return l; } public int hashCode() { return super.hashCode() + v.hashCode(); } public boolean equals(Object o) { return super.equals(o) && v.equals(((VisitorGoal) o).visitor()); } } public static class CasterGoal extends VisitorGoal { public static Goal create(Scheduler scheduler, Job job, NodeVisitor v, Goal checkGoal) { return scheduler.internGoal(new CasterGoal(job, v, checkGoal)); } Goal checkGoal; private CasterGoal(Job job, NodeVisitor v, Goal checkGoal) { super(job, v); this.checkGoal = checkGoal; } public Collection prerequisiteGoals(Scheduler scheduler) { X10Scheduler x10Sched = (X10Scheduler) scheduler; List<Goal> l = new ArrayList<Goal>(); l.add(checkGoal); l.addAll(super.prerequisiteGoals(scheduler)); return l; } public int hashCode() { return super.hashCode() + v.hashCode(); } public boolean equals(Object o) { return super.equals(o) && v.equals(((VisitorGoal) o).visitor()); } } public class CheckVisitor extends ContextVisitor { public CheckVisitor(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); } @Override public NodeVisitor begin() { // System.out.println("Running " + plugin().getClass().getName()); return super.begin(); } public Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { X10Context context = (X10Context) this.context; X10TypeSystem ts = (X10TypeSystem) this.ts; X10NodeFactory nf = (X10NodeFactory) this.nf; if (n instanceof LocalDecl) { LocalDecl ld = (LocalDecl) n; X10Type type = (X10Type) ld.type().type(); if (ld.init() != null) { Expr newInit = checkImplicitCoercion(type, ld.init(), context, ts, nf); return ld.init(newInit); } if (ld.init() instanceof ArrayInit && type instanceof ArrayType) { ArrayInit init = (ArrayInit) ld.init(); List<Expr> newElements = new ArrayList<Expr>(init.elements().size()); for (Iterator i = init.elements().iterator(); i.hasNext(); ) { Expr e = (Expr) i.next(); Expr newE = checkImplicitCoercion((X10Type) ((ArrayType) type).base(), e, context, ts, nf); newElements.add(newE); } return ld.init(init.elements(newElements)); } } if (n instanceof Assign) { Assign a = (Assign) n; Expr newRight = checkImplicitCoercion((X10Type) a.left().type(), a.right(), context, ts, nf); return annotationCast(a.right(newRight), context, ts, nf); } if (n instanceof ProcedureCall) { ProcedureCall c = (ProcedureCall) n; List<Expr> newActuals = new ArrayList<Expr>(c.arguments().size()); ProcedureInstance pi = c.procedureInstance(); for (int i = 0; i < c.arguments().size(); i++) { Expr e = (Expr) c.arguments().get(i); Type t = (Type) pi.formalTypes().get(i); Expr newE = checkImplicitCoercion((X10Type) t, e, context, ts, nf); newActuals.add(newE); } c = (ProcedureCall) c.arguments(newActuals); if (c instanceof Call) { return annotationCast(checkCall((Call) c, context, ts, nf), context, ts, nf); } if (c instanceof New) { return annotationCast(checkNew((New) c, context, ts, nf), context, ts, nf); } if (c instanceof Expr) { return annotationCast((Expr) c, context, ts, nf); } return c; } if (n instanceof ParExpr) { ParExpr p = (ParExpr) n; return annotationCast(p.type(p.expr().type()), context, ts, nf); } if (n instanceof Field) { Field f = (Field) n; return annotationCast(checkField(f, context, ts, nf), context, ts, nf); } if (n instanceof Local) { Local l = (Local) n; return annotationCast(checkLocal(l, context, ts, nf), context, ts, nf); } if (n instanceof X10Cast) { X10Cast c = (X10Cast) n; Expr e = checkCast((X10Type) c.castType().type(), c.expr(), context, ts, nf); return annotationCast(c.expr(e), context, ts, nf); } if (n instanceof Unary) { Unary b = (Unary) n; return annotationCast(b.type(unaryPromote(b, ts, nf)), context, ts, nf); } if (n instanceof Binary) { Binary b = (Binary) n; return annotationCast(b.type(binaryPromote(b, ts, nf)), context, ts, nf); } if (n instanceof Expr) { Expr e = (Expr) n; return annotationCast(e, context, ts, nf); } return n; } public SimpleTypeAnnotationPlugin plugin() { return SimpleTypeAnnotationPlugin.this; } public int hashCode() { return super.hashCode() + plugin().hashCode(); } public boolean equals(Object o) { return super.equals(o) && plugin() == ((CheckVisitor) o).plugin(); } } public Expr checkField(Field f, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { X10FieldInstance fi = (X10FieldInstance) f.fieldInstance(); List<X10ClassType> memberAnnotations = ((X10FieldInstance) fi.orig()).annotations(); X10Type type = (X10Type) fi.orig().type(); List<X10ClassType> typeAnnotations = type.defAnnotations(); return propagate(f, type, memberAnnotations, typeAnnotations); } public Expr checkLocal(Local l, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { X10LocalInstance li = (X10LocalInstance) l.localInstance(); List<X10ClassType> memberAnnotations = ((X10LocalInstance) li.orig()).annotations(); X10Type type = (X10Type) li.orig().type(); List<X10ClassType> typeAnnotations = type.defAnnotations(); return propagate(l, type, memberAnnotations, typeAnnotations); } public Expr checkCall(Call c, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { X10MethodInstance mi = (X10MethodInstance) c.methodInstance(); List<X10ClassType> memberAnnotations = ((X10MethodInstance) mi.orig()).annotations(); X10Type type = (X10Type) mi.orig().returnType(); List<X10ClassType> typeAnnotations = type.defAnnotations(); return propagate(c, type, memberAnnotations, typeAnnotations); } public Expr checkNew(New n, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { X10ConstructorInstance ci = (X10ConstructorInstance) n.constructorInstance(); List<X10ClassType> memberAnnotations = ((X10ConstructorInstance) ci.orig()).annotations(); X10Type type = (X10Type) ci.orig().container(); List<X10ClassType> typeAnnotations = type.defAnnotations(); return propagate(n, type, memberAnnotations, typeAnnotations); } public Expr propagate(Expr e, X10Type declType, List<X10ClassType> memberAnnotations, List<X10ClassType> typeAnnotations) { X10Type t = (X10Type) e.type(); t = (X10Type) t.annotations(typeAnnotations); return e.type(t); } public X10Type binaryPromote(Binary b, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return (X10Type) b.type(); } public X10Type unaryPromote(Unary u, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return (X10Type) u.type(); } public Expr checkCast(X10Type castType, Expr e, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { X10Type etype = (X10Type) e.type(); if (ts.isCastValid(etype, castType) && checkCastCoercion(castType, etype, context, ts, nf)) return e; throw new SemanticException("Cannot cast " + e + "(" + etype + ") to " + castType + ".", e.position()); } public boolean checkCastCoercion(X10Type toType, X10Type fromType, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return true; } public Expr checkImplicitCoercion(X10Type toType, Expr e, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { X10Type etype = (X10Type) e.type(); if (ts.isImplicitCastValid(etype, toType) && checkImplicitCoercion(toType, etype, context, ts, nf)) return e; if (e.isConstant() && ts.numericConversionValid(toType, e.constantValue()) && checkNumericCoercion(toType, e, context, ts, nf)) return e; throw new SemanticException("Cannot coerce " + e + " (" + etype + ") to " + toType + ".", e.position()); } public boolean checkNumericCoercion(X10Type toType, Expr e, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return true; } public boolean checkImplicitCoercion(X10Type toType, X10Type fromType, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return true; } public class CastRewriteVisitor extends ContextVisitor { public CastRewriteVisitor(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); } public Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { if (n instanceof X10Cast) { return rewriteCast((X10Cast) n, (X10Context) context, (X10TypeSystem) ts, (X10NodeFactory) nf); } if (n instanceof X10Instanceof) { return rewriteInstanceof((X10Instanceof) n, (X10Context) context, (X10TypeSystem) ts, (X10NodeFactory) nf); } return n; } public SimpleTypeAnnotationPlugin plugin() { return SimpleTypeAnnotationPlugin.this; } public int hashCode() { return super.hashCode() + plugin().hashCode(); } public boolean equals(Object o) { return super.equals(o) && plugin() == ((CheckVisitor) o).plugin(); } } protected Expr rewriteCast(X10Cast n, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return n; } protected Expr rewriteInstanceof(X10Instanceof e, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return e; } protected CheckVisitor checkVisitor(ExtensionInfo extInfo, Job job) { return new CheckVisitor(job, extInfo.typeSystem(), extInfo.nodeFactory()); } protected CastRewriteVisitor castRewriteVisitor(ExtensionInfo extInfo, Job job) { return new CastRewriteVisitor(job, extInfo.typeSystem(), extInfo.nodeFactory()); } public Goal register(ExtensionInfo extInfo, Job job) { Goal check = CheckerGoal.create(extInfo.scheduler(), job, checkVisitor(extInfo, job)); Goal cast = CasterGoal.create(extInfo.scheduler(), job, castRewriteVisitor(extInfo, job), check); X10Scheduler x10Sched = (X10Scheduler) extInfo.scheduler(); x10Sched.addDependencyAndEnqueue(x10Sched.X10Boxed(job), cast, true); return cast; } protected Expr annotationCast(Expr e, X10Context context, X10TypeSystem ts, X10NodeFactory nf) throws SemanticException { return e; } }