/* * 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 2010. */ package x10.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import polyglot.ast.Allocation; import polyglot.ast.Assign; import polyglot.ast.Assign.Operator; import polyglot.ast.Binary; import polyglot.ast.Block; import polyglot.ast.BooleanLit; import polyglot.ast.Branch; import polyglot.ast.CanonicalTypeNode; import polyglot.ast.Catch; import polyglot.ast.ConstructorCall; import polyglot.ast.Expr; import polyglot.ast.Field; import polyglot.ast.FieldAssign; import polyglot.ast.FlagsNode; import polyglot.ast.FloatLit; import polyglot.ast.For; import polyglot.ast.ForInit; import polyglot.ast.ForUpdate; import polyglot.ast.Formal; import polyglot.ast.Id; import polyglot.ast.If; import polyglot.ast.IntLit; import polyglot.ast.Labeled; import polyglot.ast.Local; import polyglot.ast.LocalDecl; import polyglot.ast.New; import polyglot.ast.NodeFactory; import polyglot.ast.Special; import polyglot.ast.Stmt; import polyglot.ast.StringLit; import polyglot.ast.Term; import polyglot.ast.Try; import polyglot.ast.TypeNode; import polyglot.ast.Unary; import polyglot.types.ClassType; import polyglot.types.Context; import polyglot.types.Flags; import polyglot.types.LocalDef; import polyglot.types.LocalInstance; import polyglot.types.Name; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.visit.ContextVisitor; import x10.ast.SettableAssign; import x10.ast.StmtExpr; import x10.ast.StmtSeq; import x10.ast.Tuple; import x10.ast.X10Call; import x10.ast.X10Cast; import x10.ast.X10Formal; import x10.ast.X10NodeFactory_c; import x10.constraint.XTerm; import x10.types.MethodInstance; import x10.types.X10FieldInstance; import x10.types.X10LocalDef; import x10.types.checker.Converter; import x10.types.constants.ConstantValue; import x10.types.constraints.CConstraint; import x10.visit.ConstantPropagator; import x10.visit.Desugarer; /** * Helper methods for manufacturing AST Nodes on the fly. * * TODO: merge this class into x10.util.Synthesizer * * @author Bowen Alpern * */ public class AltSynthesizer { private static final Name ITERATOR = Name.make("iterator"); private static final Name HASNEXT = Name.make("hasNext"); private static final Name REGION = Name.make("region"); private static final Name DIST = Name.make("dist"); private static final Name NEXT = Name.make("next"); private static final Name MAKE = Name.make("make"); private static final Name RANK = Name.make("rank"); private static final Name MIN = Name.make("min"); private static final Name MAX = Name.make("max"); private static final Name SET = SettableAssign.SET; private final TypeSystem ts; private final NodeFactory nf; private final Synthesizer synth; public AltSynthesizer(TypeSystem ts, NodeFactory nf) { this.ts = ts; this.nf = nf; synth = new Synthesizer(nf, ts); } /** * Create a new Name for a temporary variable. * * @return the newly created name */ public Name createTemporaryName() { return Name.makeFresh("t"); } /** * @param pos * @return */ public Id createLabel(Position pos) { Id label = nf.Id(pos, Name.makeFresh("L")); return label; } // helper methods that create subclasses of Expr /** * Create a statement expression -- a block of statements with a result value. * * @param pos the Position of the statement expression in source code * @param stmts the statements to proceed evaluation of expr * @param expr the result of the statement expression * @return a synthesized statement expression comprising stmts and expr */ public StmtExpr createStmtExpr(Position pos, List<Stmt> stmts, Expr expr) { if (null == expr) return (StmtExpr) nf.StmtExpr(pos, stmts, null).type(ts.Void()); return (StmtExpr) nf.StmtExpr(pos, stmts, expr).type(expr.type()); } // literals /** * @param pos * @param value * @return */ public Expr createLiteral(Position pos, Object value) { if (value == null) return nf.NullLit(pos).type(ts.Null()); if (value instanceof Integer) return nf.IntLit(pos, IntLit.INT, (long) (int) (Integer) value).type(ts.Int()); if (value instanceof Long) return nf.IntLit(pos, IntLit.LONG, (long) (Long) value).type(ts.Long()); if (value instanceof Float) return nf.FloatLit(pos, FloatLit.FLOAT, (double) (float) (Float) value).type(ts.Float()); if (value instanceof Double) return nf.FloatLit(pos, FloatLit.DOUBLE, (double) (Double) value).type(ts.Double()); if (value instanceof Character) return nf.CharLit(pos, (char) (Character) value).type(ts.Char()); if (value instanceof Boolean) return nf.BooleanLit(pos, (boolean) (Boolean) value).type(ts.Boolean()); if (value instanceof String) // return nf.StringLit(pos, (String) value).type(ts.String()); return null; // strings have reference semantics if (value instanceof Object[]) { Object[] a = (Object[]) value; List<Expr> args = new ArrayList<Expr>(a.length); for (Object ai : a) { Expr ei = createLiteral(pos, ai); if (ei == null) return null; args.add(ei); } return nf.Tuple(pos, args).type(ts.arrayOf(ts.Any())); } return null; } /** * @param pos * @param type * @return */ private Expr createNull(Position pos, Type type) { return nf.NullLit(pos).type(type); } /** * Create the boolean literal "false". * * @param pos the Position of the literal in source code * @return the synthesized boolean literal */ public BooleanLit createFalse(Position pos) { return (BooleanLit) nf.BooleanLit(pos, false).type(ts.Boolean()); } /** * Create the boolean literal "true". * * @param pos the Position of the literal in source code * @return the synthesized boolean literal */ public BooleanLit createTrue(Position pos) { return (BooleanLit) nf.BooleanLit(pos, true).type(ts.Boolean()); } /** * Create an IntLit node representing a given integer literal. * * @param val the int value to be represented * @return an IntLit node representing the literal integer val */ public IntLit createIntLit(int val) { IntLit lit = nf.IntLit(Position.COMPILER_GENERATED, IntLit.INT, val); return (IntLit) lit.type(ts.Int()); } /** * Create an IntLit node representing a given long literal. * * @param val the long value to be represented * @return an IntLit node representing the literal long val */ public IntLit createLongLit(long val) { IntLit lit = nf.IntLit(Position.COMPILER_GENERATED, IntLit.LONG, val); return (IntLit) lit.type(ts.Long()); } /** * Create a StringLit node representing a given String literal. * * @param string the String value to be represented * @return a StringLit node representing the literal String string */ public StringLit createStringLit(String string) { return (StringLit) nf.StringLit(Position.COMPILER_GENERATED, string).type(ts.String()); } // formals, locals, and field references /** * @param pos * @param type * @return */ public Formal createFormal(Position pos, Type type) { return createFormal(pos, Flags.FINAL, type, Name.makeFresh("formal")); } /** * @param pos * @param name * @param type * @return */ private Formal createFormal(Position pos, Flags flags, Type type, Name name) { FlagsNode fn = nf.FlagsNode(pos, flags); CanonicalTypeNode tn = nf.CanonicalTypeNode(pos, type); Id id = nf.Id(pos, name); X10LocalDef ld = ts.localDef(pos, flags, Types.ref(type), name); return nf.Formal(pos, fn, tn, id).localDef(ld); } /** * @param pos * @param f * @return */ public Local createLocal(Position pos, Formal f) { return synth.createLocal(pos, f.localDef().asInstance()); } /** * Create a local variable reference copied from another * * @param pos the Position of the new local variable reference in source code. * @param local the local variable reference to copy * @return a synthesized local variable reference */ public Local createLocal(Position pos, Local local) { return synth.createLocal(pos, local.localInstance()); } /** * Create a local variable reference. * * @param pos the Position of the reference in the source code * @param decl the declaration of the local variable * @return the synthesized Local variable reference */ public Local createLocal(Position pos, LocalDecl decl) { return synth.createLocal(pos, decl.localDef().asInstance()); } /** * Create a local variable reference. * * @param pos the Position of the reference in the source code * @param li a type system object representing this local variable * @return the synthesized Local variable reference * TODO: moved into synthesizer and eliminate */ public Local createLocal(Position pos, LocalInstance li) { return synth.createLocal(pos, li); } /** * Create a reference to a field of an object or struct. * If the receiver has a self constraint, propagate the constraint appropriately. * * @param pos the Position of the reference * @param receiver the object or struct containing the field * @param name the Name of the field * @return the synthesized Field expression: (container . name), or null if no such field */ public Field createFieldRef(Position pos, Expr receiver, Name name) { final Type type = receiver.type(); X10FieldInstance fi = Types.getProperty(type, name); if (null == fi) { fi = (X10FieldInstance) type.toClass().fieldNamed(name); } if (null == fi) return null; return createFieldRef(pos, receiver, fi); } /** * Create a reference to a field of an object or struct. * If the receiver has a self constraint, propagate the constraint appropriately. * * @param pos the Position of the reference in the source code * @param receiver the object or struct containing the field * @param fi a type system object representing this field * @return the synthesized Field expression */ public Field createFieldRef(Position pos, Expr receiver, X10FieldInstance fi) { Field f = nf.Field(pos, receiver, nf.Id(pos, fi.name())).fieldInstance(fi); Type type = fi.rightType(); // propagate self binding (if any) CConstraint c = Types.realX(receiver.type()); XTerm term = Types.selfVarBinding(c); // the RHS of {self==x} in c if (term != null) { type = addSelfConstraint(type, ts.xtypeTranslator().translate(term, fi)); assert (null != type); } return (Field) f.type(type); } // unary expressions /** * Create a unary expression. * * @param pos the Position of the unary expression in the source code * @param op the unary operation of the expression * @param expr the argument to the unary operator * @param visitor a ContextVisitor needed for desugaring * @return a synthesized unary expression equivalent to applying op to expr */ public Expr createUnary(Position pos, polyglot.ast.Unary.Operator op, Expr expr, ContextVisitor visitor) { Unary unary = (Unary) nf.Unary(pos, op, expr).type(expr.type()); return Desugarer.desugarUnary(unary, visitor); } /** * @param pos * @param expr * @param visitor a ContextVisitor needed for desugaring * @return */ public Expr createIsNull(Position pos, Expr expr, ContextVisitor visitor) { return createBinary(pos, createNull(pos, expr.type()), Binary.EQ, expr, visitor).type(ts.Boolean()); } /** * @param pos * @param expr, * @param visitor a ContextVisitor needed for desugaring * @return */ public Expr createNotNull(Position pos, Expr expr, ContextVisitor visitor) { return createBinary(pos, createNull(pos, expr.type()), Binary.NE, expr, visitor).type(ts.Boolean()); } /** * Create the boolean negation of a given (boolean) expression. * * @param expr the boolean expression to be negated * @param visitor a ContextVisitor needed for desugaring * @return a synthesized expression which is the boolean negation of expr */ public Expr createNot(Expr expr, ContextVisitor visitor) { return createNot(expr.position(), expr, visitor); } /** * Create the boolean negation of a given (boolean) expression. * * @param pos the Position of the negated expression in the source code * @param expr the boolean expression to be negated * @param visitor a ContextVisitor needed for desugaring * @return a synthesized expression that negates expr */ public Expr createNot(Position pos, Expr expr, ContextVisitor visitor) { assert (expr.type().isBoolean()); return createUnary(pos, Unary.NOT, expr, visitor); } // binary expressions /** * Create a binary expression. * * @param pos the Position of the expression in the source code * @param left the first operand * @param op the operator * @param right the second operand * @param visitor a ContextVisitor needed for desugaring * @return the synthesized Binary expression: (left op right) */ public Expr createBinary(Position pos, Expr left, Binary.Operator op, Expr right, ContextVisitor visitor) { Binary binary = (Binary) nf.Binary(pos, left, op, right).type(left.type()); return Desugarer.desugarBinary(binary, visitor); } /** * Create an assignment expression. * * @param pos the Position of the assignment in the source code * @param target the lval being assigned to * @param op the assignment operator * @param source the right-hand-side of the assignment * @param visitor the ContextVisitor needed for desugaring * @return the synthesized Assign expression: (target op source) */ public Assign createAssign(Position pos, Expr target, Operator op, Expr source, ContextVisitor visitor) { try { Assign assign = synth.makeAssign(pos, target, op, source, visitor.context()); return (Assign) Desugarer.desugarAssign(assign, visitor); } catch (SemanticException e) { throw new InternalCompilerError("Attempting to synthesize an Assign that cannot be typed", pos, e); } } /** * @param pos * @param prop * @param init * @param visitor * @return */ public FieldAssign createFieldAssign(Position pos, X10FieldInstance fi, Expr init, ContextVisitor visitor) { Expr target = createThis(pos, fi.container()); return createFieldAssign(pos, target, fi, init, visitor); } /** * @param pos * @param prop * @param init * @param visitor * @return */ public FieldAssign createFieldAssign(Position pos, Expr target, X10FieldInstance fi, Expr init, ContextVisitor visitor) { Type lbt = Types.baseType(fi.rightType()); Type rbt = Types.baseType(init.type()); if (!ts.typeEquals(rbt, lbt, visitor.context())){ init = createCoercion(pos, init, lbt, visitor); } Id id = nf.Id(pos, fi.name()); FieldAssign fa = nf.FieldAssign(pos, target, id, Assign.ASSIGN, init); fa = fa.fieldInstance(fi); fa = fa.targetImplicit(false); fa = (FieldAssign) fa.type(lbt); return fa; } /** * @param pos * @param expr * @param type * @return */ public Expr createInstanceof(Position pos, Expr expr, ClassType type) { return nf.Instanceof(pos, expr, nf.CanonicalTypeNode(pos, type)).type(ts.Boolean()); } /** * @param pos * @param expr * @param type * @param visitor a ContextVisitor needed for desugaring * @return */ public Expr createNotInstanceof(Position pos, Expr expr, ClassType type, ContextVisitor visitor) { return createNot(pos, createInstanceof(pos, expr, type), visitor).type(ts.Boolean()); } /** * @param pos * @param expr * @param tn * @return */ public Expr createUncheckedCast(Position pos, Expr expr, Type type) { return nf.X10Cast(pos, nf.CanonicalTypeNode(pos, type), expr, Converter.ConversionType.UNCHECKED).type(type); } /** * @param pos * @param expr * @param type * @param context * @return */ public Expr createUncheckedCast(Position pos, Expr expr, Type type, Context context) { if (ts.typeDeepBaseEquals(expr.type(), type, context)) return expr; return nf.X10Cast(pos, nf.CanonicalTypeNode(pos, type), expr, Converter.ConversionType.UNCHECKED).type(type); } /** * Create a coercion (implicit conversion) expression. * * @param pos the Position of the cast in the source code * @param expr the Expr being cast * @param toType the resultant type * @return the synthesized Cast expression: (expr as toType), or null if the conversion is invalid */ public X10Cast createCoercion(Position pos, Expr expr, Type toType, ContextVisitor visitor) { X10Cast cast; // FIXME: Have to typeCheck, because the typechecker has already desugared this to a conversion chain cast = nf.X10Cast(pos, nf.CanonicalTypeNode(pos, toType), expr, Converter.ConversionType.UNKNOWN_IMPLICIT_CONVERSION); cast = (X10Cast) cast.typeCheck(visitor); return cast; } // method calls /** * Create a Call to a static method. * * @param pos the Position of the call in the source code * @param container the class that defines the static method * @param name the name of the static method * @param args the arguments to the static method * @return the synthesized Call to the method of the given type with the required name taking the prescribed arguments, * or null if no such method */ public X10Call createStaticCall(Position pos, Type container, Name name, Expr... args) { Context context = container.typeSystem().emptyContext(); MethodInstance mi = createMethodInstance(container, name, context, args); if (null == mi) return null; return createStaticCall(pos, mi, args); } /** * Create a Call to a generic static method. * * @param pos the Position of the call in the source code * @param container the class of the generic static method * @param name the name of the generic static method * @param typeArgs the type arguments to the generic static method * @param args the arguments to the generic static method * @return the synthesized Call to the method of the given type * with the required name taking the prescribed type arguments and arguments, * or null if no such method */ public X10Call createStaticCall(Position pos, Type container, Name name, List<Type> typeArgs, Expr... args) { Context context = container.typeSystem().emptyContext(); MethodInstance mi = createMethodInstance(container, name, context, typeArgs, args); if (null == mi) return null; return createStaticCall(pos, mi, args); } /** * Create a Call to a static method. * The name and type of method (and any generic type arguments) are contained in the method instance. * * @param pos the Position of the call in the source code * @param mi a type system object representing the static method being called * @param args the arguments to the call to the static method * @return the synthesized Call to the specified method taking the prescribed arguments */ public X10Call createStaticCall(Position pos, MethodInstance mi, Expr... args) { List<Type> typeParams = mi.typeParameters(); List<TypeNode> typeParamNodes = new ArrayList<TypeNode>(); for (Type t : typeParams) { typeParamNodes.add(nf.CanonicalTypeNode(pos, t)); } return (X10Call) nf.X10Call( pos, nf.CanonicalTypeNode(pos, mi.container()), nf.Id(pos, mi.name()), typeParamNodes, Arrays.asList(args) ).methodInstance(mi).type(mi.returnType()); } /** * Create a Call to an instance method. * * @param pos the Position of the call in the source code * @param receiver the object on which the instance method is being called * @param name the Name of the instance method * @param args the arguments to the instance method * @return the synthesized Call to a method on the specified receiver with the required name and prescribed arguments, * or null if no such method */ public X10Call createInstanceCall(Position pos, Expr receiver, Name name, Context context, Expr... args) { MethodInstance mi = createMethodInstance(receiver, name, context, args); if (null == mi) return null; return createInstanceCall(pos, receiver, mi, args); } /** * Create a Call to a generic instance method. * * @param pos the Position of the call in the source code * @param receiver the object on which the generic instance method is being called * @param name the Name of the generic instance method * @param typeArgs the type arguments to the generic instance method * @param args the arguments to the generic instance method * @return the synthesized Call to the method on the specified receiver * with the required name taking the prescribed type arguments and arguments, * or null if no such method */ public X10Call createInstanceCall(Position pos, Expr receiver, Name name, Context context, List<Type> typeArgs, Expr... args) { MethodInstance mi = createMethodInstance(receiver, name, context, typeArgs, args); if (null == mi) return null; return createInstanceCall(pos, receiver, mi, args); } /** * Create a Call to an instance method. * The Name and any type arguments to the instance method are encoded in the method instance. * * @param pos the Position of the call in the source code * @param receiver the object on which the instance method is being called * @param mi a type system object representing the instance method being called * @param args the arguments to the instance method * @return the synthesized Call to the specified method on the given receiver taking the prescribed arguments, * or null if no such method */ public X10Call createInstanceCall(Position pos, Expr receiver, MethodInstance mi, Expr... args) { List<Type> typeParams = mi.typeParameters(); List<TypeNode> typeParamNodes = new ArrayList<TypeNode>(); for (Type t : typeParams) { typeParamNodes.add(nf.CanonicalTypeNode(pos, t)); } return (X10Call) nf.X10Call( pos, receiver, nf.Id(pos, mi.name()), typeParamNodes, Arrays.asList(args) ).methodInstance(mi).type(mi.returnType()); } // methods for creating Stmts /** * Create a labeled statement. * * @param pos the Position of the statement in the source program * @param label the label for the statement * @param stmt the statement to label * @return the synthesized labeled statement */ public Labeled createLabeledStmt(Position pos, Name label, Stmt stmt) { return createLabeledStmt(pos, nf.Id(pos, label), stmt); } /** * Create a labeled statement. * * @param pos the Position of the statement in the source program * @param id the label for the statement * @param stmt the statement to label * @return the synthesized labeled statement */ public Labeled createLabeledStmt(Position pos, Id id, Stmt stmt) { return nf.Labeled(pos, id, stmt); } /** * Turn a single statement into a statement sequence. * * @param stmt the statement to be encapsulated * @return a synthesized statement sequence comprising stmt */ public StmtSeq createStmtSeq(Stmt stmt) { return createStmtSeq(stmt.position(), Collections.singletonList(stmt)); } /** * Turn a list of statements into a statement sequence. * * @param pos the Position of the statement sequence in source code * @param stmts a list of statements * @return a synthesized statement sequence comprising stmts */ public StmtSeq createStmtSeq(Position pos, List<Stmt> stmts) { return nf.StmtSeq(pos, stmts); } /** * Create a block of statements from a list. * * @param pos the Position of the block in the source code * @param stmts the Stmt's to be included in the block * @return the synthesized Block */ public Block createBlock(Position pos, List<Stmt> stmts) { return nf.Block(pos, stmts); } /** * Create a block of statements from individual terms (statements and/or expressions). * If a term is already a Stmt, it is used as is. * If it is an Expr, the Stmt is its evaluation. * Otherwise an InvalidArgumentException is thrown. * * @param pos the Position of the block in the source code * @param terms the sequence of terms to become statements of the block * @return the synthesized Block of terms turned to statements * @throws IllegalArgumentException if one of the terms is not a Stmt or an Expr */ public Block createBlock(Position pos, Term... terms) { return createBlock(pos, convertToStmtList(terms)); } /** * Create a break statement. * * @param pos the Position of the break statement in source code * @return the synthesized break statement */ public Branch createBreak(Position pos) { return nf.Break(pos); } /** * @param pos * @param label * @return */ public Branch createBreak(Position pos, String label) { return nf.Break(pos, nf.Id(pos, label)); } /** * @param pos * @return */ public Stmt createContinue(Position pos) { return nf.Continue(pos); } /** * @param pos * @param lit * @return */ public Branch createContinue(Position pos, String label) { return nf.Continue(pos, nf.Id(pos, label)); } /** * @param pos * @return */ public Stmt createReturn(Position pos) { return nf.Return(pos); } /** * @param pos * @param expr * @param type * @return */ public Stmt createReturn(Position pos, Expr expr) { return nf.Return(pos, expr); } /** * Create an evaluation statement for a given expression. * * @param expr the expression to be evaluated * @return a synthesized statement that evaluates expr */ public Stmt createEval(Expr expr) { return nf.Eval(expr.position(), expr); } /** * Create an assignment statement. * * @param pos the Position of the assignment in source code * @param target the left-hand side of the assignment * @param op the assignment operator * @param source the right-hand side of the assignment * @param visitor a ContextVistor needed for desugaring * @return the synthesized assignment statement */ public Stmt createAssignment(Position pos, Expr target, Operator op, Expr source, ContextVisitor visitor) { return createEval(createAssign(pos, target, op, source, visitor)); } /** * Create a conditional statements. * * @param pos the Position of the conditional statement in source code. * @param cond the boolean expression to be tested * @param thenStmt the statement to execute if cond is true * @param elseStmt the statement to execute if cond is false * @return the synthesized conditional statement */ public If createIf(Position pos, Expr cond, Stmt thenStmt, Stmt elseStmt) { if (null == elseStmt) return nf.If(pos, cond, thenStmt); return nf.If(pos, cond, thenStmt, elseStmt); } /** * Create a traditional C-style 'for' loop. * This form assumes that the update part of the for header is empty. * * @param pos the Position of the loop in the source program * @param init the declaration that initializes the iterate * @param cond the condition governing whether the body should continue to be executed * @param body the body of the loop to be executed repeatedly * @return the synthesized 'for' loop */ public For createStandardFor(Position pos, LocalDecl init, Expr cond, Stmt body) { return nf.For( pos, Collections.<ForInit>singletonList(init), cond, Collections.<ForUpdate>emptyList(), body ); } /** * Create a traditional C-style 'for' loop. * * @param pos the Position of the loop in the source program * @param init the declaration that initializes the iterate * @param cond the condition governing whether the body should continue to be executed * @param update the statement to increment the iterate after each execution of the body * @param body the body of the loop to be executed repeatedly * @return the synthesized for-loop */ public For createStandardFor(Position pos, LocalDecl init, Expr cond, Expr update, Stmt body) { return nf.For( pos, Collections.<ForInit>singletonList(init), cond, Collections.<ForUpdate>singletonList(nf.Eval(pos, update)), body ); } /** * @param pos * @param b * @param c * @return */ public Try createTry(Position pos, Block b, Catch c) { return createTry(pos, b, Collections.<Catch>singletonList(c), null); } /** * @param pos * @param b * @param catches * @param f * @return */ private Try createTry(Position pos, Block b, List<Catch> catches, Block f) { return nf.Try(pos, b, catches, f); } /** * @param pos * @param f * @param body * @return */ public Catch createCatch(Position pos, Formal f, Block body) { return nf.Catch(pos, f, body); } /** * @param pos * @param expr * @param f * @return */ public Stmt createThrow(Position pos, Expr expr) { return nf.Throw(pos, expr); } /** * Create a declaration for an uninitialized local variable from scratch. * (A local variable definition is created as a side-effect and may be retrieved from the result.) * * @param pos the Position of the declaration * @param flags the Flags ("static", "public", "var") for the declared local variable * @param name the Name of the declared local variable * @param type the Type of the declared local variable * @return the LocalDecl representing the declaration of the local variable */ public LocalDecl createLocalDecl(Position pos, Flags flags, Name name, Type type) { LocalDef def = ts.localDef(pos, flags, Types.ref(type), name); return createLocalDecl(pos, def); } /** * Create a declaration for a local variable from scratch. * (A local variable definition is created as a side-effect and may be retrieved from the result.) * * @param pos the Position of the declaration * @param flags the Flags ("static", "public", "var") for the declared local variable * @param name the Name of the declared local variable * @param type the Type of the declared local variable * @param init an Expr representing the initial value of the declared local variable * @return the LocalDecl representing the declaration of the local variable */ public LocalDecl createLocalDecl(Position pos, Flags flags, Name name, Type type, Expr init) { LocalDef def = ts.localDef(pos, flags, Types.ref(type), name); return createLocalDecl(pos, def, init); } /** * Create a declaration for a local variable from scratch using the type of the initializer. * * @param pos the Position of the declaration * @param flags the Flags ("static", "public", "var") for the declared local variable * @param name the Name of the declared local variable * @param init an Expr representing the initial value of the declared local variable * @return the LocalDecl representing the declaration of the local variable */ public LocalDecl createLocalDecl(Position pos, Flags flags, Name name, Expr init) { if (null == init || null == init.type() || init.type().isVoid()) { throw new InternalCompilerError("trying to create a LocalDecl " +name+ " but init is null or has null or void type, init=" +init, pos); } return createLocalDecl(pos, flags, name, init.type(), init); } /** * Create a declaration for an uninitialized local variable from a local type definition. * * @param pos the Position of the declaration * @param def the definition of the declared local variable * @return the LocalDecl representing the declaration of the local variable */ public LocalDecl createLocalDecl(Position pos, LocalDef def) { return nf.LocalDecl( pos, nf.FlagsNode(pos, def.flags()), nf.CanonicalTypeNode(pos, def.type().get()), nf.Id(pos, def.name()) ).localDef(def); } /** * Create a declaration for a local variable from a local type definition. * * @param pos the Position of the declaration * @param def the definition of the declared local variable * @param init the Expr representing the initial value of the declared local variable * @return the LocalDecl representing the declaration of the local variable */ public LocalDecl createLocalDecl(Position pos, LocalDef def, Expr init) { return nf.LocalDecl( pos.markCompilerGenerated(), nf.FlagsNode(pos, def.flags()), nf.CanonicalTypeNode(pos, def.type()), nf.Id(pos, def.name()), init ).localDef(def); } /** * Create a declaration of a local variable from a formal parameter. * The formal parameter is transformed into the local variable. * * @param formal the parameter to be transformed * @param init an expression representing the initial value of new local variable * @return the declaration for a local variable with the same behavior as formal */ public LocalDecl createLocalDecl(X10Formal formal, Expr init) { return nf.LocalDecl( formal.position(), formal.flags(), formal.type().typeRef(formal.localDef().type()), // adjust ref formal.name(), init ).localDef(formal.localDef()); } // Helper methods for dealing with properties and constraints /** * Obtain the constant value of a property of an expression, if that value is known at compile time. * * @param expr the Expr whose property is to be extracted * @param name the Name of the property to extract * @return the value of the named property of expr if it is a compile-time constant, or null if none * TODO: move into ASTQuery */ public Object getPropertyConstantValue(Expr expr, Name name) { X10FieldInstance propertyFI = Types.getProperty(expr.type(), name); if (null == propertyFI) return null; Expr propertyExpr = createFieldRef(expr.position(), expr, propertyFI); if (null == propertyExpr) return null; return ConstantValue.toJavaObject(ConstantPropagator.constantValue(propertyExpr)); } /** * Add a self constraint to the type that binds self to a given value. * * @param type the Type to be constrained * @param value the value of self for this type * @return the type with the additional constraint {self==value}, or null if the proposed * binding is inconsistent */ public static Type addSelfConstraint(Type type, XTerm value) { return Types.addSelfBinding(type, value); } // helper methods that return method instances /** * Create a type system object representing a specified Generic instance method. * * @param receiver the receiver of the (instance) method call * @param name the Name of the method to be called * @param typeArgs the type arguments to the method * @param args the arguments to the method * @return the synthesized method instance for this method call * @throws InternalCompilerError if the required method instance cannot be created * TODO: move to a type system helper class */ public MethodInstance createMethodInstance(Expr receiver, Name name, Context context, List<Type> typeArgs, Expr... args) { return createMethodInstance(receiver.type(), name, context, typeArgs, args); } /** * Create a type system object representing a specified Generic method (either static or instance). * * @param container the type (static method) or receiver (instance method) of the method call * @param name the Name of the method to be called * @param context the Context in which the method is to be found * @param typeArgs the type arguments to the method * @param args the arguments to the method * @return the synthesized method instance for this method call * @throws InternalCompilerError if the required method instance cannot be created * TODO: move to a type system helper class */ public MethodInstance createMethodInstance(Type container, Name name, Context context, List<Type> typeArgs, Expr... args) { List<Type> argTypes = getExprTypes(args); return createMethodInstance(container, name, context, typeArgs, argTypes); } /** * Create a type system object representing a specified Generic method (either static or instance). * * @param container the type (static method) or receiver (instance method) of the method call * @param name the Name of the method to be called * @param context the Context in which the method is to be found * @param typeArgs the type arguments to the method * @param argTypes the types of the arguments to the method * @return the synthesized method instance for this method call * @throws InternalCompilerError if the required method instance cannot be created * TODO: move to a type system helper class */ public MethodInstance createMethodInstance(Type container, Name name, Context context, List<Type> typeArgs, List<Type> argTypes) { try { return ts.findMethod(container, ts.MethodMatcher(container, name, typeArgs, argTypes, context)); } catch (SemanticException e) { throw new InternalCompilerError("Unable to find required method instance", container.position(), e); } } /** * Create a type system object representing a specified instance method. * * @param receiver the receiver of the (instance) method call * @param name the Name of the method to be called * @param context the Context in which the method is to be found * @param args the arguments to the method * @return the synthesized method instance for this method call * @throws InternalCompilerError if the required method instance cannot be created * TODO: move to a type system helper class */ public MethodInstance createMethodInstance(Expr receiver, Name name, Context context, Expr... args) { return createMethodInstance(receiver.type(), name, context, args); } /** * Create a type system object representing a specified method (either static or instance). * * @param container the type (static method) or receiver (instance method) of the method call * @param name the Name of the method to be called * @param context the Context in which the method is to be found * @param args the arguments to the method * @return the synthesized method instance for this method call * @throws InternalCompilerError if the required method instance cannot be created * TODO: move to a type system helper class */ public MethodInstance createMethodInstance(Type container, Name name, Context context, Expr... args) { List<Type> argTypes = getExprTypes(args); return createMethodInstance(container, name, context, argTypes); } /** * Create a type system object representing a specified method (either static or instance). * * @param container the type (static method) or receiver (instance method) of the method call * @param name the Name of the method to be called * @param context the Context in which the method is to be found * @param argTypes the types of the arguments to the method * @return the synthesized method instance for this method call * @throws InternalCompilerError if the required method instance cannot be created * TODO: move to a type system helper class */ public MethodInstance createMethodInstance(Type container, Name name, Context context, List<Type> argTypes) { try { return ts.findMethod(container, ts.MethodMatcher(container, name, argTypes, context) ); } catch (SemanticException e) { throw new InternalCompilerError("Unable to find required method instance", container.position(), e); } } // constructor splitter synthesize methods /** * @param n * @param pos * @return */ public ConstructorCall createConstructorCall(Expr target, New n) { Position pos = n.position(); // DEBUG List<TypeNode> types = n.typeArguments(); // DEBUG ConstructorCall cc = nf.X10ThisCall(n.position(), n.typeArguments(), n.arguments()); cc = cc.target(target); cc = cc.constructorInstance(n.constructorInstance()); return cc; } /** * @param pos * @param type * @return * TODO: move to Synthesizer */ public Special createThis(Position pos, Type type) { return (Special) nf.This(pos).type(type); } /** * Create an artificial Allocation node. * * @param pos the Position of the allocation * @param type the Type of the object (or struct) being allocated * @param typeArgs * @return a synthesized Allocation node. * TODO: move to Synthesizer */ public Allocation createAllocation(Position pos, TypeNode objType, List<TypeNode> typeArgs) { return (Allocation) ((Allocation) ((X10NodeFactory_c) nf).Allocation(pos, objType, typeArgs).type(objType.type())); } // local helper methods /** * Convert individual terms (statements and/or expressions) to a list of statements. * If a term is already a Stmt, it is used as is. * If it is an Expr, the Stmt is its evaluation. * Otherwise an InvalidArgumentException is thrown. * * @param terms the sequence of terms * @return the newly constructed list of statements * @throws IllegalArgumentException if one of the terms is not a Stmt or an Expr */ public List<Stmt> convertToStmtList(Term... terms) { List<Stmt> stmts = new ArrayList<Stmt> (terms.length); for (Term term : terms) { if (term instanceof Expr) { term = nf.Eval(term.position(), (Expr) term); } else if (!(term instanceof Stmt)) { throw new IllegalArgumentException("Invalid argument type: "+term.getClass()); } stmts.add((Stmt) term); } return stmts; } /** * Find the Types for a sequence of expressions. * * @param args the sequence of expressions to be typed * @return a List of the Types of the args */ private static List<Type> getExprTypes(Expr... args) { List<Type> argTypes = new ArrayList<Type> (args.length); for (Expr a : args) { argTypes.add(a.type()); } return argTypes; } public Expr createTuple(Position pos, int numElems, Expr initForAllElems) { List<Expr> tupleVals = new ArrayList<Expr>(numElems); for (int i=0; i<numElems; i++) { tupleVals.add(initForAllElems); } Type elemType = ts.Array(initForAllElems.type()); return nf.Tuple(pos, tupleVals).type(elemType); } }