/* * 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.visit; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import polyglot.ast.Allocation_c; import polyglot.ast.Assert_c; import polyglot.ast.Assign; import polyglot.ast.Binary; import polyglot.ast.Block; import polyglot.ast.Block_c; import polyglot.ast.Branch_c; import polyglot.ast.CanonicalTypeNode; import polyglot.ast.CanonicalTypeNode_c; import polyglot.ast.Case_c; import polyglot.ast.Catch; import polyglot.ast.Catch_c; import polyglot.ast.Conditional_c; import polyglot.ast.ConstructorCall; import polyglot.ast.Empty_c; import polyglot.ast.Eval_c; import polyglot.ast.Expr; import polyglot.ast.FieldAssign_c; import polyglot.ast.FieldDecl_c; import polyglot.ast.Field_c; import polyglot.ast.FlagsNode_c; import polyglot.ast.Formal; import polyglot.ast.Formal_c; import polyglot.ast.Id_c; import polyglot.ast.If_c; import polyglot.ast.Import_c; import polyglot.ast.IntLit_c; import polyglot.ast.Labeled_c; import polyglot.ast.Lit; import polyglot.ast.Lit_c; import polyglot.ast.Local; import polyglot.ast.LocalAssign_c; import polyglot.ast.Local_c; import polyglot.ast.Loop_c; import polyglot.ast.New; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.Node_c; import polyglot.ast.PackageNode_c; import polyglot.ast.Receiver; import polyglot.ast.Return; import polyglot.ast.Return_c; import polyglot.ast.SourceFile; import polyglot.ast.Special; import polyglot.ast.Special_c; import polyglot.ast.Stmt; import polyglot.ast.StringLit_c; import polyglot.ast.SwitchBlock_c; import polyglot.ast.Switch_c; import polyglot.ast.Throw_c; import polyglot.ast.TopLevelDecl; import polyglot.ast.Try_c; import polyglot.ast.TypeNode; import polyglot.ast.Unary; import polyglot.ast.Unary_c; import polyglot.frontend.Source; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.ConstructorDef; import polyglot.types.ContainerType; import polyglot.types.Context; import polyglot.types.FieldDef; import polyglot.types.FieldInstance; import polyglot.types.Flags; import polyglot.types.JavaArrayType; import polyglot.types.JavaArrayType_c; import polyglot.types.LocalInstance; import polyglot.types.MethodDef; import polyglot.types.Name; import polyglot.types.Package; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.types.VarInstance; import polyglot.util.CodeWriter; import polyglot.util.ErrorInfo; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.util.StringUtil; import polyglot.visit.ContextVisitor; import polyglot.visit.InnerClassRemover; import polyglot.visit.NodeVisitor; import polyglot.visit.Translator; import x10.Configuration; import x10.ExtensionInfo; import x10.ast.AssignPropertyCall_c; import x10.ast.ClosureCall; import x10.ast.ClosureCall_c; import x10.ast.Closure_c; import x10.ast.HasZeroTest_c; import x10.ast.LocalTypeDef_c; import x10.ast.OperatorNames; import x10.ast.ParExpr; import x10.ast.ParExpr_c; import x10.ast.PropertyDecl; import x10.ast.SettableAssign; import x10.ast.SettableAssign_c; import x10.ast.StmtExpr_c; import x10.ast.StmtSeq_c; import x10.ast.SubtypeTest_c; import x10.ast.Tuple_c; import x10.ast.TypeDecl_c; import x10.ast.TypeParamNode; import x10.ast.TypeParamNode_c; import x10.ast.X10Binary_c; import x10.ast.X10Call; import x10.ast.X10Call_c; import x10.ast.X10CanonicalTypeNode; import x10.ast.X10Cast_c; import x10.ast.X10ClassBody_c; import x10.ast.X10ClassDecl_c; import x10.ast.X10ConstructorCall_c; import x10.ast.X10ConstructorDecl_c; import x10.ast.X10Initializer_c; import x10.ast.X10Instanceof_c; import x10.ast.X10LocalDecl_c; import x10.ast.X10MethodDecl_c; import x10.ast.X10New; import x10.ast.X10New_c; import x10.ast.X10ProcedureCall; import x10.ast.X10Special; import x10.ast.X10Unary_c; import x10.emitter.Emitter; import x10.emitter.Expander; import x10.emitter.Join; import x10.emitter.RuntimeTypeExpander; import x10.emitter.TryCatchExpander; import x10.emitter.TypeExpander; import x10.extension.X10Ext; import x10.types.ConstrainedType; import x10.types.FunctionType; import x10.types.MethodInstance; import x10.types.MethodInstance_c; import x10.types.ParameterType; import x10.types.ParameterType.Variance; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10ConstructorDef; import x10.types.X10ConstructorInstance; import x10.types.X10FieldInstance; import x10.types.X10MethodDef; import x10.types.X10ParsedClassType_c; import x10.types.X10TypeEnv; import x10.types.constraints.SubtypeConstraint; import x10.types.constraints.TypeConstraint; import x10.util.AnnotationUtils; import x10.util.CollectionFactory; import x10.util.HierarchyUtils; import x10c.ast.X10CBackingArrayAccessAssign_c; import x10c.ast.X10CBackingArrayAccess_c; import x10c.ast.X10CBackingArrayNewArray_c; import x10c.ast.X10CBackingArray_c; import x10c.types.X10CContext_c; import x10c.visit.ClosureRemover; import x10c.visit.InlineHelper; import x10cpp.visit.ASTQuery; /** * Visitor on the AST nodes that for some X10 nodes triggers the template based * dumping mechanism (and for all others just defaults to the normal pretty * printing). * * @author Christian Grothoff * @author Igor Peshansky (template classes) * @author Rajkishore Barik 26th Aug 2006 (added loop optimizations) * @author vj Refactored Emitter out. */ public class X10PrettyPrinterVisitor extends X10DelegatingVisitor { public static final String JAVA_LANG_OBJECT = "java.lang.Object"; public static final String JAVA_IO_SERIALIZABLE = "java.io.Serializable"; public static final String X10_CORE_REF = "x10.core.Ref"; public static final String X10_CORE_STRUCT = "x10.core.Struct"; public static final String X10_CORE_ANY = "x10.core.Any"; public static final String CONSTRUCTOR_FOR_ZERO_VALUE_DUMMY_PARAM_TYPE = "java.lang.System"; public static final String CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE = "java.lang.System[]"; public static final int PRINT_TYPE_PARAMS = 1; public static final int BOX_PRIMITIVES = 2; public static final int NO_VARIANCE = 4; public static final int NO_QUALIFIER = 8; public static final boolean useSelfDispatch = true; // XTENLANG-2993 public static final boolean generateSpecialDispatcher = true; public static final boolean generateSpecialDispatcherNotUse = false; // TODO to be removed public static final boolean supportGenericOverloading = true; public static final boolean supportConstructorSplitting = true; public static final boolean generateFactoryMethod = false; public static final boolean generateOnePhaseConstructor = true; // XTENLANG-3058 public static final boolean supportTypeConstraintsWithErasure = true; // XTENLANG-3090 (switched back to use java assertion) private static final boolean useJavaAssertion = true; // XTENLANG-3086 public static final boolean supportUpperBounds = false; // Support numbered parameters for @Native (e.g. @Native("java","#0.toString()")) for backward compatibility. public static final boolean supportNumberedParameterForNative = true; // Expose existing special dispatcher through special interfaces (e.g. Arithmetic, Bitwise) public static final boolean exposeSpecialDispatcherThroughSpecialInterface = false; // N.B. should be as short as file name length which is valid on all supported platforms (e.g. NAME_MAX on linux). public static final int longestTypeName = 255; // use hash code if type name becomes longer than some threshold. public static final String X10_FUN_PACKAGE = "x10.core.fun"; public static final String X10_FUN_CLASS_NAME_PREFIX = "Fun"; public static final String X10_VOIDFUN_CLASS_NAME_PREFIX = "VoidFun"; public static final String X10_FUN_CLASS_PREFIX = X10_FUN_PACKAGE+"."+X10_FUN_CLASS_NAME_PREFIX; public static final String X10_VOIDFUN_CLASS_PREFIX = X10_FUN_PACKAGE+"."+X10_VOIDFUN_CLASS_NAME_PREFIX; public static final String X10_RTT_TYPE = "x10.rtt.Type"; public static final String X10_RTT_TYPES = "x10.rtt.Types"; public static final String X10_RUNTIME_IMPL_JAVA_X10GENERATED = "x10.runtime.impl.java.X10Generated"; public static final String X10_RUNTIME_IMPL_JAVA_RUNTIME = "x10.runtime.impl.java.Runtime"; public static final String X10_RUNTIME_IMPL_JAVA_EVALUTILS = "x10.runtime.impl.java.EvalUtils"; public static final String X10_RUNTIME_IMPL_JAVA_ARRAYUTILS = "x10.runtime.impl.java.ArrayUtils"; public static final String X10_RUNTIME_IMPL_JAVA_THROWABLEUTILS = "x10.runtime.impl.java.ThrowableUtils"; public static final String ENSURE_X10_EXCEPTION = "ensureX10Exception"; public static final String JAVA_LANG_THROWABLE = "java.lang.Throwable"; public static final String JAVA_LANG_ERROR = "java.lang.Error"; public static final String MAIN_CLASS = "$Main"; public static final String RTT_NAME = "$RTT"; public static final String GETRTT_NAME = "$getRTT"; public static final String GETPARAM_NAME = "$getParam"; public static final String INITPARAMS_NAME = "$initParams"; public static final String CONSTRUCTOR_METHOD_NAME = "$init"; public static String CONSTRUCTOR_METHOD_NAME(ClassDef cd) { return InlineHelper.makeSuperBridgeName(cd, Name.make(CONSTRUCTOR_METHOD_NAME)).toString(); } public static final String CONSTRUCTOR_METHOD_NAME_FOR_REFLECTION = "$initForReflection"; public static final String CREATION_METHOD_NAME = "$make"; public static final String BOX_METHOD_NAME = "$box"; public static final String UNBOX_METHOD_NAME = "$unbox"; private static final QName ASYNC_CLOSURE = QName.make("x10.compiler.AsyncClosure"); private static final QName REMOTE_INVOCATION = QName.make("x10.compiler.RemoteInvocation"); private static int nextId_; final public CodeWriter w; final public Translator tr; final public Emitter er; final private Configuration config; public X10PrettyPrinterVisitor(CodeWriter w, Translator tr) { this.w = w; this.tr = tr; this.er = new Emitter(w, tr); this.config = ((ExtensionInfo) tr.job().extensionInfo()).getOptions().x10_config; } /* to provide a unique name for local variables introduce in the templates */ private static int getUniqueId_() { return nextId_++; } public static Name getId() { return Name.make("$var" + getUniqueId_()); } @Override public void visit(Node n) { // invoke appropriate visit method for Java backend's specific nodes if (n instanceof X10CBackingArray_c) { visit((X10CBackingArray_c) n); return; } if (n instanceof X10CBackingArrayAccess_c) { visit((X10CBackingArrayAccess_c) n); return; } if (n instanceof X10CBackingArrayAccessAssign_c) { visit((X10CBackingArrayAccessAssign_c) n); return; } if (n instanceof X10CBackingArrayNewArray_c) { visit((X10CBackingArrayNewArray_c) n); return; } if (n instanceof FlagsNode_c) { visit((FlagsNode_c) n); return; } if (n instanceof TypeParamNode_c) { visit((TypeParamNode_c) n); return; } if (n instanceof X10Initializer_c) { visit((X10Initializer_c) n); return; } tr.job().compiler().errorQueue() .enqueue(ErrorInfo.SEMANTIC_ERROR, "Unhandled node type: " + n.getClass(), n.position()); // Don't call through del; that would be recursive. n.translate(w, tr); } // /////////////////////////////////////// // handle Java backend's specific nodes // /////////////////////////////////////// public void visit(X10CBackingArray_c n) { // TODO:CAST w.write("("); w.write("("); JavaArrayType arrayType = (JavaArrayType) n.type(); er.printType(arrayType.base(), 0); w.write("[]"); w.write(")"); er.prettyPrint(n.container(), tr); w.write("."); w.write("value"); w.write(")"); } public void visit(X10CBackingArrayAccess_c n) { // TODO:CAST w.write("("); w.write("("); er.printType(n.type(), PRINT_TYPE_PARAMS); w.write(")"); er.prettyPrint(n.array(), tr); w.write("["); er.prettyPrint(n.index(), tr); w.write("]"); w.write(")"); } public void visit(X10CBackingArrayAccessAssign_c n) { er.prettyPrint(n.array(), tr); w.write("["); er.prettyPrint(n.index(), tr); w.write("]"); w.write(n.operator().toString()); boolean closeParen = false; if (isPrimitive(n.type()) && isBoxedType(n.right().type())) { closeParen = er.printUnboxConversion(n.type()); } er.prettyPrint(n.right(), tr); if (closeParen) w.write(")"); } public void visit(X10CBackingArrayNewArray_c n) { Type base = ((JavaArrayType) n.type()).base(); if (base.isParameterType()) { w.write("("); er.printType(n.type(), 0); w.write(")"); w.write(" "); // XTENLANG-3032 following code only works with non-primitives /* new RuntimeTypeExpander(er, base).expand(); w.write(".makeArray("); w.write(n.dims().get(0).toString()); w.write(")"); */ w.write("new java.lang.Object[" + n.dims().get(0) + "]"); return; } w.write("new "); er.printType(base, 0); for (Expr dim : n.dims()) { w.write("["); er.prettyPrint(dim, tr); w.write("]"); } for (int i = 0; i < n.additionalDims(); i++) w.write("[]"); } public void visit(FlagsNode_c n) { n.translate(w, tr); } public void visit(TypeParamNode_c n) { n.translate(w, tr); } public void visit(X10Initializer_c n) { w.write("static "); n.printBlock(n.body(), w, tr); } // /////////////////////////////////////// // handle X10 nodes // /////////////////////////////////////// @Override public void visit(Import_c c) { // don't generate any code at all--we should fully qualify all type // names } @Override public void visit(PackageNode_c n) { n.translate(w, tr); } @Override public void visit(X10ClassBody_c n) { n.translate(w, tr); } private ClassType X10JavaSerializable_; private ClassType X10JavaSerializable() { if (X10JavaSerializable_ == null) X10JavaSerializable_ = tr.typeSystem().load(Emitter.X10_JAVA_SERIALIZABLE_CLASS); return X10JavaSerializable_; } private boolean canCastToX10JavaSerializable(X10ClassDecl_c n, Type type, Context context) { type = Types.baseType(type); Type leastUpperBound = null; if (type.isParameterType()) { if (!supportUpperBounds) return true; X10ClassDef def = n.classDef(); Ref<TypeConstraint> tc = def.typeGuard(); if (tc == null) return true; // no upperbounds Context c2 = context.pushBlock(); c2.setName(" ClassGuard for |" + def.name() + "| "); c2.setTypeConstraintWithContextTerms(tc); X10TypeEnv tenv = tr.typeSystem().env(c2); List<Type> upperBounds = tenv.upperBounds(type); Iterator<Type> it = upperBounds.iterator(); while (it.hasNext()) { Type upperBound = Types.baseType(it.next()); if (upperBound.isParameterType()) { return canCastToX10JavaSerializable(n, upperBound, context); } if (upperBound.isClass()) { if (!upperBound.toClass().flags().isInterface()) { if (leastUpperBound == null || upperBound.isSubtype(leastUpperBound, context)) { leastUpperBound = upperBound; } } } } } else if (type.isClass() && !type.toClass().flags().isInterface()) { // FIXME uncomment the following requires X10JavaSerializable.class before compiling it. // leave it for now because of no immediate problem. // leastUpperBound = ftype; } return leastUpperBound == null || leastUpperBound.isSubtype(X10JavaSerializable(), context); } @Override public void visit(X10ClassDecl_c n) { X10CContext_c context = (X10CContext_c) tr.context(); // class name and source file name is different. this is the case when StringHelper is defined in String.x10. if (n.classDef().isTopLevel() && !n.classDef().sourceFile().name().equals(n.classDef().name().toString() + ".x10") && !context.containsGeneratedClasses(n.classDef())) { context.addGeneratedClasses(n.classDef()); // not include import SourceFile sf = tr.nodeFactory().SourceFile(n.position(), Collections.<TopLevelDecl> singletonList(n)); if (n.classDef().package_() != null) { sf = sf.package_(tr.nodeFactory().PackageNode(n.position(), n.classDef().package_())); } sf = sf.source(new Source(n.classDef().name().toString() + ".x10", n.position().path(), null)); tr.translate(sf); return; } TypeSystem xts = tr.typeSystem(); X10ClassDef def = n.classDef(); // Do not generate code if the class is represented natively. if (Emitter.getJavaRep(def) != null) { w.write(";"); w.newline(); return; } Flags flags = n.flags().flags(); w.begin(0); w.write("@"+X10_RUNTIME_IMPL_JAVA_X10GENERATED+" "); if (flags.isInterface()) { w.write(flags.clearInterface().clearAbstract().translateJava()); } else { w.write(flags.translateJava()); } if (flags.isInterface()) { w.write("interface "); } else { w.write("class "); } tr.print(n, n.name(), w); List<TypeParamNode> typeParameters = n.typeParameters(); if (typeParameters.size() > 0) { er.printTypeParams(n, context, typeParameters); } final TypeNode superClassNode = n.superClass(); if (!flags.isInterface()) { // [DC] all target classes use an extends clause now, even for roots (they extend x.c.Ref) w.write(" extends "); if (flags.isStruct()) { assert superClassNode == null : superClassNode; w.write(X10_CORE_STRUCT); } else { if (superClassNode == null) { // [DC] this is a root w.write(X10_CORE_REF); } else { Type superType = superClassNode.type(); er.printType(superType, PRINT_TYPE_PARAMS | BOX_PRIMITIVES | NO_VARIANCE); } } } // Filter out x10.lang.Any from the interfaces. List<TypeNode> interfaces = new ArrayList<TypeNode>(); for (TypeNode tn : n.interfaces()) { if (!xts.isAny(tn.type())) { interfaces.add(tn); } } // N.B. We cannot represent it with Type node since x10.core.Any is @NativeRep'ed to java.lang.Object instead of to x10.core.Any /* * Interfaces automatically extend Any if * (n.flags().flags().isInterface() && interfaces.isEmpty()) { * * X10TypeSystem ts = (X10TypeSystem) tr.typeSystem(); * interfaces.add(tr.nodeFactory().CanonicalTypeNode(n.position(), * ts.Any())); } */ if (!interfaces.isEmpty()) { if (flags.isInterface()) { w.write(" extends "); } else { w.write(" implements "); } List<Type> alreadyPrintedTypes = new ArrayList<Type>(); for (Iterator<TypeNode> i = interfaces.iterator(); i.hasNext();) { TypeNode tn = i.next(); if (!useSelfDispatch || (useSelfDispatch && !Emitter.alreadyPrinted(alreadyPrintedTypes, tn.type()))) { if (alreadyPrintedTypes.size() != 0) { w.write(", "); } alreadyPrintedTypes.add(tn.type()); boolean isJavaNative = Emitter.isNativeRepedToJava(tn.type()); er.printType(tn.type(), (useSelfDispatch && !isJavaNative ? 0 : PRINT_TYPE_PARAMS) | BOX_PRIMITIVES | NO_VARIANCE); } } if (!subtypeOfCustomSerializer(def)) { if (alreadyPrintedTypes.size() != 0) { w.write(", "); } w.write(Emitter.X10_JAVA_SERIALIZABLE_CLASS); } } else if (!def.flags().isInterface() && !(def.asType().toString().equals(CUSTOM_SERIALIZATION))) { w.write(" implements " + Emitter.X10_JAVA_SERIALIZABLE_CLASS); } else { // make all interfaces extend x10.core.Any // N.B. We cannot represent it with Type node since x10.core.Any is @NativeRep'ed to java.lang.Object instead of to x10.core.Any if (flags.isInterface() && !xts.isAny(def.asType())) { w.write(" extends " + X10_CORE_ANY); } } w.unifiedBreak(0); w.end(); w.write("{"); w.newline(4); w.begin(0); // print the serialVersionUID if (!flags.isInterface()) { // TODO compute serialVersionUID with the same logic as javac long serialVersionUID = 1L; w.write("private static final long serialVersionUID = " + serialVersionUID + "L;"); w.newline(); } // print the clone method boolean mutable_struct = false; try { if (def.isStruct() && !def.annotationsMatching(getType("x10.compiler.Mutable")).isEmpty()) { mutable_struct = true; } } catch (SemanticException e) { } if (mutable_struct) { w.write("public "); tr.print(n, n.name(), w); if (typeParameters.size() > 0) { er.printTypeParams(n, context, typeParameters); } w.write("clone() { try { return ("); tr.print(n, n.name(), w); if (typeParameters.size() > 0) { er.printTypeParams(n, context, typeParameters); } w.write(")super.clone(); } catch (java.lang.CloneNotSupportedException e) { e.printStackTrace() ; return null; } }"); w.newline(); } // XTENLANG-1102 er.generateRTTInstance(def); // print the custom serializer if (subtypeOfCustomSerializer(def)) { er.generateCustomSerializer(def, n); } else if (subtypeOfHadoopWritable(def)) { w.write("public static "); if (typeParameters.size() > 0) { er.printTypeParams(n, context, typeParameters); } w.write(Emitter.X10_JAVA_SERIALIZABLE_CLASS + " " + Emitter.DESERIALIZE_BODY_METHOD + "("); er.printType(def.asType(), PRINT_TYPE_PARAMS | BOX_PRIMITIVES); w.writeln(" $_obj , " + Emitter.X10_JAVA_DESERIALIZER_CLASS + " $deserializer) throws java.io.IOException { "); w.newline(4); w.begin(0); if (!config.NO_TRACES && !config.OPTIMIZE) { w.write("if (" + X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { "); w.write(X10_RUNTIME_IMPL_JAVA_RUNTIME + ".printTraceMessage(\"X10JavaSerializable for Hadoop Writable: " + Emitter.DESERIALIZE_BODY_METHOD + "() of \" + " + Emitter.mangleToJava(def.name()) + ".class + \" calling\"); "); w.writeln("} "); } //_deserialize_body method w.writeln("$_obj.readFields($deserializer.getInpForHadoop());"); w.writeln("$deserializer.record_reference($_obj);"); w.writeln("return $_obj;"); w.end(); w.newline(); w.writeln("}"); w.newline(); // _deserializer method w.writeln("public static " + Emitter.X10_JAVA_SERIALIZABLE_CLASS + " " + Emitter.DESERIALIZER_METHOD + "(" + Emitter.X10_JAVA_DESERIALIZER_CLASS + " $deserializer) throws java.io.IOException {"); w.newline(4); w.begin(0); w.write(Emitter.mangleToJava(def.name()) + " $_obj = (" + Emitter.mangleToJava(def.name()) + ") "); w.writeln("new " + Emitter.mangleToJava(def.name()) + "();"); w.writeln("return " + Emitter.DESERIALIZE_BODY_METHOD + "($_obj, $deserializer);"); w.end(); w.newline(); w.writeln("}"); w.newline(); // _serialize() w.writeln("public void " + Emitter.SERIALIZE_METHOD + "(" + Emitter.X10_JAVA_SERIALIZER_CLASS + " $serializer) throws java.io.IOException {"); w.newline(4); w.begin(0); w.writeln("this.write($serializer.getOutForHadoop());"); w.end(); w.newline(); w.writeln("}"); w.newline(); } else { if (!def.flags().isInterface()) { if (!config.NO_TRACES && !config.OPTIMIZE) { // override to trace serialization w.write("private void writeObject(java.io.ObjectOutputStream oos) throws java.io.IOException { "); w.write("if (" + X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { "); w.write("java.lang.System.out.println(\"Serializer: writeObject(ObjectOutputStream) of \" + this + \" calling\"); "); w.write("} "); w.write("oos.defaultWriteObject(); }"); w.newline(); } // Prints out custom serialization/deserialization code, the imeplementation resembles closely what the C++ backend does X10ClassType ct = def.asType(); ASTQuery query = new ASTQuery(tr); //_deserialize_body method w.write("public static "); // if (supportUpperBounds) if (typeParameters.size() > 0) { er.printTypeParams(n, context, typeParameters); } w.write(Emitter.X10_JAVA_SERIALIZABLE_CLASS + " " + Emitter.DESERIALIZE_BODY_METHOD + "("); er.printType(def.asType(), PRINT_TYPE_PARAMS | BOX_PRIMITIVES); w.writeln(" $_obj , " + Emitter.X10_JAVA_DESERIALIZER_CLASS + " $deserializer) throws java.io.IOException {"); w.newline(4); w.begin(0); if (!config.NO_TRACES && !config.OPTIMIZE) { w.write("if (" + X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { "); w.write(X10_RUNTIME_IMPL_JAVA_RUNTIME + ".printTraceMessage(\"X10JavaSerializable: " + Emitter.DESERIALIZE_BODY_METHOD + "() of \" + " + Emitter.mangleToJava(def.name()) + ".class + \" calling\"); "); w.writeln("} "); } er.deserializeSuperClass(superClassNode); List<ParameterType> parameterTypes = ct.x10Def().typeParameters(); // Deserialize type parameters for (Iterator<? extends Type> i = parameterTypes.iterator(); i.hasNext(); ) { final Type at = i.next(); w.write("$_obj."); er.printType(at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES); w.writeln(" = (" + X10_RTT_TYPE + ") $deserializer.readRef();"); } // Deserialize the public variables of this class , we do not serialize transient or static variables String str; QName fullName; for (int i = 0; i < ct.fields().size(); i++) { FieldInstance f = ct.fields().get(i); if (f instanceof X10FieldInstance && !query.ifdef(((X10FieldInstance) f).x10Def())) continue; if (f.flags().isStatic() || query.isSyntheticField(f.name().toString())) continue; if (f.flags().isTransient()) // don't serialize transient fields continue; if (f.type().isParameterType()) { w.write("$_obj." + Emitter.mangleToJava(f.name()) + " = "); if (supportUpperBounds) { w.write("("); er.printType(f.type(), BOX_PRIMITIVES); w.write(") "); } w.writeln("$deserializer.readRef();"); } else if ((str = needsCasting(f.type())) != null) { // Want these to be readInteger and so on..... These do not need a explicit case cause we are calling special methods w.writeln("$_obj." + Emitter.mangleToJava(f.name()) + " = $deserializer.read" + str + "();"); } else if (xts.isPrimitiveJavaArray(f.type())) { String type = f.type().toClass().typeArguments().get(0).toString(); String primitiveType = type.substring(type.lastIndexOf(".") + 1); w.write("$_obj." + Emitter.mangleToJava(f.name()) + " = "); w.writeln("$deserializer.read" + primitiveType + "Array();"); } else if (xts.isJavaArray(f.type())) { String type = f.type().toClass().typeArguments().get(0).toString(); w.write("$_obj." + Emitter.mangleToJava(f.name()) + " = "); w.write("("); er.printType(f.type(), BOX_PRIMITIVES); w.write(") "); w.writeln("$deserializer.readArrayUsingReflection(" + type + ".class);"); } else if (f.type().isArray() && f.type() instanceof JavaArrayType_c && ((JavaArrayType_c)f.type()).base().isParameterType()) { // This is to get the test case XTENLANG_2299 to compile. Hope its a generic fix w.write("$_obj." + Emitter.mangleToJava(f.name()) + " = "); // not needed because readRef takes type parameters // w.write("("); // er.printType(f.type(), BOX_PRIMITIVES); // w.write(") "); w.writeln("$deserializer.readRef();"); } else if (f.type().toClass() != null && f.type().toClass().isJavaType()) { // deserialize the variable using reflection and cast it back to the correct type w.write("$_obj." + Emitter.mangleToJava(f.name()) + " = "); w.write("("); er.printType(f.type(), BOX_PRIMITIVES); w.write(") "); w.writeln("$deserializer.readRefUsingReflection();"); } else { // deserialize the variable and cast it back to the correct type w.write("$_obj." + Emitter.mangleToJava(f.name()) + " = "); // not needed because readRef takes type parameters // w.write("("); // er.printType(f.type(), BOX_PRIMITIVES); // w.write(") "); w.writeln("$deserializer.readRef();"); } } w.writeln("return $_obj;"); w.end(); w.newline(); w.writeln("}"); w.newline(); // _deserializer method w.writeln("public static " + Emitter.X10_JAVA_SERIALIZABLE_CLASS + " " + Emitter.DESERIALIZER_METHOD + "(" + Emitter.X10_JAVA_DESERIALIZER_CLASS + " $deserializer) throws java.io.IOException {"); w.newline(4); w.begin(0); if (def.constructors().size() == 0 || def.flags().isAbstract()) { w.writeln("return null;"); } else { if (def.isStruct()) { //TODO Keith get rid of this if (!Emitter.mangleToJava(def.name()).equals("PlaceLocalHandle")) { w.write(Emitter.mangleToJava(def.name()) + " $_obj = new " + Emitter.mangleToJava(def.name()) + "((" + CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE + ") null"); // N.B. in custom deserializer, initialize type params with null for (ParameterType typeParam : def.typeParameters()) { w.write(", (" + X10_RTT_TYPE + ") null"); } w.write(");"); w.newline(); } else { w.writeln(Emitter.mangleToJava(def.name()) + " $_obj = new " + Emitter.mangleToJava(def.name()) + "(null, (" + CONSTRUCTOR_FOR_ZERO_VALUE_DUMMY_PARAM_TYPE + ") null);"); } } else { if (def.flags().isAbstract()) { w.write(Emitter.mangleToJava(def.name()) + " $_obj = (" + Emitter.mangleToJava(def.name()) + ") "); if (generateFactoryMethod) { w.write(Emitter.mangleToJava(def.name()) + "." + CREATION_METHOD_NAME); } else { assert generateOnePhaseConstructor; w.write("new " + Emitter.mangleToJava(def.name())); } w.writeln("();"); } else { w.write(Emitter.mangleToJava(def.name()) + " $_obj = new " + Emitter.mangleToJava(def.name()) + "("); if (supportConstructorSplitting // XTENLANG-2830 /*&& !ConstructorSplitterVisitor.isUnsplittable(Types.baseType(def.asType()))*/ && !def.flags().isInterface()) { w.write("(" + CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE + ") null"); // N.B. in custom deserializer, initialize type params with null for (ParameterType typeParam : def.typeParameters()) { w.write(", (" + X10_RTT_TYPE + ") null"); } w.write(");"); w.newline(); } else { w.writeln(");"); } } } w.writeln("$deserializer.record_reference($_obj);"); w.writeln("return " + Emitter.DESERIALIZE_BODY_METHOD + "($_obj, $deserializer);"); } w.end(); w.newline(); w.writeln("}"); w.newline(); // _serialize() w.writeln("public void " + Emitter.SERIALIZE_METHOD + "(" + Emitter.X10_JAVA_SERIALIZER_CLASS + " $serializer) throws java.io.IOException {"); w.newline(4); w.begin(0); // Serialize the super class first er.serializeSuperClass(superClassNode); // Serialize any type parameters for (Iterator<? extends Type> i = parameterTypes.iterator(); i.hasNext(); ) { final Type at = i.next(); w.write("$serializer.write((" + Emitter.X10_JAVA_SERIALIZABLE_CLASS + ") this."); er.printType(at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES); w.writeln(");"); } // Serialize the public variables of this class , we do not serialize transient or static variables for (int i = 0; i < ct.fields().size(); i++) { FieldInstance f = ct.fields().get(i); if (f instanceof X10FieldInstance && !query.ifdef(((X10FieldInstance) f).x10Def())) continue; if (f.flags().isStatic() || query.isSyntheticField(f.name().toString())) continue; if (f.flags().isTransient()) // don't serialize transient fields continue; String fieldName = Emitter.mangleToJava(f.name()); if (f.type().isArray()) { if (f.type() instanceof JavaArrayType_c && isPrimitive(((JavaArrayType_c)f.type()).base())) { // If this is an array and not a java primitive we need to cast it into an array w.writeln("$serializer.write(this." + fieldName + ");"); } else { w.writeln("if (" + fieldName + " instanceof " + Emitter.X10_JAVA_SERIALIZABLE_CLASS + " []) {"); w.writeln("$serializer.write((" + Emitter.X10_JAVA_SERIALIZABLE_CLASS + "[]) this." + fieldName + ");"); w.writeln("} else {"); w.writeln("$serializer.write(this." + fieldName + ");"); w.writeln("}"); } } else { if (isPrimitive(f.type()) || isString(f.type()) || xts.isPrimitiveJavaArray(f.type())) { w.writeln("$serializer.write(this." + fieldName + ");"); } else if (f.type().toClass() != null && f.type().toClass().isJavaType()) { w.writeln("$serializer.writeObjectUsingReflection(this." + fieldName + ");"); } else if (xts.isJavaArray(f.type())) { w.writeln("$serializer.writeArrayUsingReflection(this." + fieldName + ");"); } else { boolean canCastToX10JavaSerializable = canCastToX10JavaSerializable(n, f.type(), context); if (canCastToX10JavaSerializable) { w.writeln("if (" + fieldName + " instanceof " + Emitter.X10_JAVA_SERIALIZABLE_CLASS + ") {"); w.writeln("$serializer.write((" + Emitter.X10_JAVA_SERIALIZABLE_CLASS + ") this." + fieldName + ");"); w.writeln("} else {"); } w.writeln("$serializer.write(this." + fieldName + ");"); if (canCastToX10JavaSerializable) { w.writeln("}"); } } } } w.end(); w.newline(); w.writeln("}"); w.newline(); } } if (needZeroValueConstructor(def)) { er.generateZeroValueConstructor(def, n); } // print the constructor just for allocation if (supportConstructorSplitting // XTENLANG-2830 /*&& !ConstructorSplitterVisitor.isUnsplittable(Types.baseType(def.asType()))*/ && !def.flags().isInterface()) { w.write("// constructor just for allocation"); w.newline(); w.write("public " + Emitter.mangleToJava(def.name()) + "(final " + CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE + " $dummy"); List<String> params = new ArrayList<String>(); for (ParameterType p : def.typeParameters()) { String param = Emitter.mangleParameterType(p); w.write(", final " + X10_RTT_TYPE + " " + param); params.add(param); } w.write(") { "); w.newline(); // call super constructor if (flags.isStruct() || (superClassNode != null && Emitter.isNativeRepedToJava(superClassNode.type())) ) { // call default constructor instead of "constructor just for allocation" } else if (superClassNode != null && superClassNode.type().toClass().isJavaType()) { boolean hasDefaultConstructor = false; ConstructorDef ctorWithFewestParams = null; for (ConstructorDef ctor : superClassNode.type().toClass().def().constructors()) { List<Ref<? extends Type>> formalTypes = ctor.formalTypes(); if (formalTypes.size() == 0) { hasDefaultConstructor = true; break; } if (ctorWithFewestParams == null || ctor.formalTypes().size() < ctorWithFewestParams.formalTypes().size()) { ctorWithFewestParams = ctor; } } if (hasDefaultConstructor) { // call default constructor instead of "constructor just for allocation" } else { // XTENLANG-3070 // If super class does not have default constructor, call the constructor with the fewest parameters // with all the parameters null or zero. // FIXME This fixes post-compilation error but it may still cause runtime error. assert ctorWithFewestParams != null; w.write("super("); Iterator<Ref<? extends Type>> iter = ctorWithFewestParams.formalTypes().iterator(); while (iter.hasNext()) { Type formalType = iter.next().get(); if (formalType.isReference()) { w.write("("); er.printType(formalType, 0); w.write(") null"); } else if (formalType.isByte() || formalType.isShort()) { w.write("("); er.printType(formalType, 0); w.write(") 0"); } else if (formalType.isInt()) { w.write("0"); } else if (formalType.isLong()) { w.write("0L"); } else if (formalType.isFloat()) { w.write("0.0F"); } else if (formalType.isDouble()) { w.write("0.0"); } else if (formalType.isChar()) { w.write("'\\0'"); } else if (formalType.isBoolean()) { w.write("false"); } if (iter.hasNext()) { w.write(", "); } } w.write(");"); w.newline(); } } else { // call "constructor just for allocation" // [DC] if the class doesn't extend anything, don't bother calling super() if (def.superType() != null) { w.write("super($dummy"); printArgumentsForTypeParamsPreComma(def.superType().get().toClass().typeArguments(), false); w.write(");"); w.newline(); } } printInitParams(def.asType(), params); w.write("}"); w.newline(); } if (useSelfDispatch) { er.generateDispatchMethods(def); } er.generateBridgeMethods(def); // print the fields for the type params if (typeParameters.size() > 0) { w.newline(4); w.begin(0); if (!flags.isInterface()) { for (TypeParamNode tp : typeParameters) { w.write("private "); w.write(X10_RTT_TYPE); // w.write("<"); n.print(tp, w, tr); w.write(">"); // TODO w.write(" "); w.write(Emitter.mangleParameterType(tp)); w.write(";"); w.newline(); } w.write("// initializer of type parameters"); w.newline(); w.write("public static void "); w.write(INITPARAMS_NAME); w.write("(final "); tr.print(n, n.name(), w); /* w.write("<"); boolean first = true; for (TypeParamNode tp : typeParameters) { if (first) { first = false; } else { w.write(","); } w.write("?"); } w.write(">"); */ w.write(" $this"); for (TypeParamNode tp : typeParameters) { w.write(", final "); w.write(X10_RTT_TYPE); // w.write("<"); n.print(tp, w, tr); w.write(">"); // TODO w.write(" "); w.write(Emitter.mangleParameterType(tp)); } w.write(") {"); w.newline(); for (TypeParamNode tp : typeParameters) { w.write("$this."); w.write(Emitter.mangleParameterType(tp)); w.write(" = "); w.write(Emitter.mangleParameterType(tp)); w.write(";"); w.newline(); } w.write("}"); w.newline(); } w.end(); } // print the props if (!flags.isInterface()) { if (n.properties().size() > 0) { w.newline(4); w.begin(0); for (PropertyDecl pd : n.properties()) { n.print(pd, w, tr); w.newline(); } w.end(); } } setConstructorIds(def); // print the original body n.print(n.body(), w, tr); // print synthetic types for parameter mangling printExtraTypes(def); w.end(); w.newline(); w.write("}"); w.newline(0); } // used by custom serializer public static String needsCasting(Type type) { type = Types.baseType(type); if (isPrimitive(type)) { String name = type.name().toString(); if (type.isUnsignedNumeric()) { return name.substring(name.lastIndexOf(".") + 1 + 1); // x10.lang.UInt -> Int } else { return name.substring(name.lastIndexOf(".") + 1); // x10.lang.Int -> Int } } return null; } private static final String CUSTOM_SERIALIZATION = "x10.io.CustomSerialization"; public static final String SERIAL_DATA = "x10.io.SerialData"; public static final String SERIAL_DATA_FIELD_NAME = "$$serialdata"; private static boolean subtypeOfCustomSerializer(X10ClassDef def) { return subtypeOfInterface(def, CUSTOM_SERIALIZATION); } private static final String HADOOP_WRITABLE = "org.apache.hadoop.io.Writable"; private static boolean subtypeOfHadoopWritable(X10ClassDef def) { return subtypeOfInterface(def, HADOOP_WRITABLE); } private static boolean subtypeOfInterface(X10ClassDef def, String interfaceName) { for (Ref<? extends Type> ref : def.interfaces()) { if (interfaceName.equals(ref.get().toString())) { return true; } } Ref<? extends Type> ref = def.superType(); if (ref == null) return false; Type type = ref.get(); if (type instanceof ConstrainedType) { type = ((ConstrainedType) type).baseType().get(); } X10ClassDef superDef = ((X10ParsedClassType_c) type).def(); return subtypeOfInterface(superDef, interfaceName); } /* * (Definition of haszero by Yoav) Formally, the following types haszero: a * type that can be null (e.g., Any, closures, but not a struct or * Any{self!=null}) Primitive structs (Short,UShort,Byte,UByte, Int, Long, * ULong, UInt, Float, Double, Boolean, Char) user defined structs without a * constraint and without a class invariant where all fields haszero. */ private static boolean needZeroValueConstructor(X10ClassDef def) { if (def.flags().isInterface()) return false; if (!def.flags().isStruct()) return false; // Note: we don't need zero value constructor for primitive structs // because they are cached in x10.rtt.Types class. if (isPrimitive(def.asType())) return false; // TODO stop generating useless zero value constructor for user-defined // struct that does not have zero value // user-defined struct does not have zero value if it have a field of // type of either // 1) type parameter T that does not have haszero constraint // 2) any reference (i.e. non-struct) type that has {self != null} // consttaint // 3) any struct type (including primitive structs) that has any // constraint (e.g. Int{self != 0}) // 4) any user-defined struct that does not have zero value return true; } private static void setConstructorIds(X10ClassDef def) { List<ConstructorDef> cds = def.constructors(); int constructorId = 0; for (ConstructorDef cd : cds) { X10ConstructorDef xcd = (X10ConstructorDef) cd; List<Type> annotations = xcd.annotations(); List<Ref<? extends Type>> ats = new ArrayList<Ref<? extends Type>>(); for (Type type : annotations) { ats.add(Types.ref(type)); } boolean containsParamOrParameterized = false; List<Ref<? extends Type>> formalTypes = xcd.formalTypes(); for (Ref<? extends Type> ref : formalTypes) { Type t = ref.get(); Type bt = Types.baseType(t); if (bt.isParameterType() || hasParams(t) || bt.isUnsignedNumeric()) { containsParamOrParameterized = true; break; } } Type annotationType; if (containsParamOrParameterized) { annotationType = new ConstructorIdTypeForAnnotation(def).setIndex(constructorId++); } else { annotationType = new ConstructorIdTypeForAnnotation(def); } ats.add(Types.ref(annotationType)); xcd.setDefAnnotations(ats); } } private static boolean hasConstructorIdAnnotation(X10ConstructorDef condef) { List<Type> annotations = condef.annotations(); for (Type an : annotations) { if (an instanceof ConstructorIdTypeForAnnotation) { return true; } } return false; } // if it isn't set id or don't have an annotation, return -1 private static int getConstructorId(X10ConstructorDef condef) { if (!hasConstructorIdAnnotation(condef)) { ContainerType st = condef.container().get(); if (st.isClass()) { X10ClassDef def = st.toClass().def(); setConstructorIds(def); } } List<Type> annotations = condef.annotations(); for (Type an : annotations) { if (an instanceof ConstructorIdTypeForAnnotation) { return ((ConstructorIdTypeForAnnotation) an).getIndex(); } } return -1; } private Type getType(String name) throws SemanticException { return tr.typeSystem().systemResolver().findOne(QName.make(name)); } private boolean isMutableStruct(Type t) { TypeSystem ts = tr.typeSystem(); t = Types.baseType(ts.expandMacros(t)); if (t.isClass()) { X10ClassType ct = t.toClass(); try { if (ct.isX10Struct()) { X10ClassDef cd = ct.def(); if (!cd.annotationsMatching(getType("x10.compiler.Mutable")).isEmpty()) { return true; } } } catch (SemanticException e) { } } return false; } public static boolean isSplittable(Type type) { return supportConstructorSplitting && !type.name().toString().startsWith(ClosureRemover.STATIC_NESTED_CLASS_BASE_NAME) && !ConstructorSplitterVisitor.isUnsplittable(Types.baseType(type)); } @Override public void visit(X10ConstructorDecl_c n) { // Checks whether this is the constructor corresponding to CustomSerialization boolean isCustomSerializable = false; if (n.formals().size() == 1 && SERIAL_DATA.equals(n.formals().get(0).type().toString())) { isCustomSerializable = true; } printCreationMethodDecl(n); X10ClassType type = Types.get(n.constructorDef().container()).toClass(); if (isSplittable(type)) { printConstructorMethodDecl(n, isCustomSerializable); return; } w.begin(0); tr.print(n, tr.nodeFactory().FlagsNode(n.flags().position(), n.flags().flags().clearPrivate().clearProtected().Public()), w); tr.print(n, n.name(), w); List<String> params = printConstructorFormals(n, true); if (n.body() != null) { // if (typeAssignments.size() > 0) { w.write(" {"); w.begin(4); if (n.body().statements().size() > 0) { Stmt firstStmt = getFirstStatement(n); if (firstStmt instanceof X10ConstructorCall_c) { X10ConstructorCall_c cc = (X10ConstructorCall_c) firstStmt; // n.printSubStmt(cc, w, tr); printConstructorCallForJavaCtor(cc); w.allowBreak(0, " "); if (cc.kind() == ConstructorCall.THIS) params.clear(); } } printInitParams(type, params); if (n.body().statements().size() > 0) { Stmt firstStmt = getFirstStatement(n); if (firstStmt instanceof X10ConstructorCall_c) n.printSubStmt(n.body().statements(n.body().statements().subList(1, n.body().statements().size())), w, tr); // vj: the main body was not being written. Added next two // lines. else n.printSubStmt(n.body(), w, tr); } else n.printSubStmt(n.body(), w, tr); w.write("}"); w.end(); // } else { // n.printSubStmt(n.body(), w, tr); // } } else { w.write(";"); } } private void printCreationMethodDecl(X10ConstructorDecl_c n) { X10ClassType type = Types.get(n.constructorDef().container()).toClass(); if (type.flags().isAbstract()) { return; } List<ParameterType> typeParameters = type.x10Def().typeParameters(); boolean isSplittable = isSplittable(type); List<Formal> formals = n.formals(); if (generateFactoryMethod) { w.write("// creation method for java code (factory method)"); w.newline(); tr.print(n, tr.nodeFactory().FlagsNode(n.flags().position(), n.flags().flags().clearPrivate().clearProtected().Public().Static()), w); // TODO check without type bounds er.printMethodParams(typeParameters); // N.B. printing type parameters causes post compilation error for XTENLANG_423 and GenericInstanceof16 er.printType(type, 0); w.write(" "); w.write(CREATION_METHOD_NAME); printConstructorFormals(n, true); boolean isFirst = true; for (Ref<? extends Type> _throws : n.constructorDef().throwTypes()) { if (isFirst) { w.write(" throws "); isFirst = false; } else { w.write(", "); } er.printType(_throws.get(), 0); } w.write("{"); w.begin(4); w.write("return "); if (isSplittable) { printAllocationCall(type, typeParameters); w.write("."); w.write(CONSTRUCTOR_METHOD_NAME(type.def())); } else { w.write("new "); w.write(n.name().toString()); } w.write("("); if (!isSplittable) { printArgumentsForTypeParams(typeParameters, formals.size() == 0); } for (int i = 0; i < formals.size(); i++) { Formal formal = formals.get(i); if (i != 0) { w.write(","); } tr.print(n, formal.name(), w); } printExtraArgments((X10ConstructorInstance) n.constructorDef().asInstance()); w.write(")"); w.write(";"); w.end(); w.write("}"); w.newline(); } // N.B. we don't generate 1-phase constructor here, since it will be generated as a normal compilation result of X10 constructor. if (generateOnePhaseConstructor && isSplittable) { w.write("// creation method for java code (1-phase java constructor)"); w.newline(); tr.print(n, tr.nodeFactory().FlagsNode(n.flags().position(), n.flags().flags().clearPrivate().clearProtected().Public()), w); // N.B. printing type parameters causes post compilation error for XTENLANG_423 and GenericInstanceof16 er.printType(type, NO_QUALIFIER); printConstructorFormals(n, true); boolean isFirst = true; for (Ref<? extends Type> _throws : n.constructorDef().throwTypes()) { if (isFirst) { w.write(" throws "); isFirst = false; } else { w.write(", "); } er.printType(_throws.get(), 0); } w.write("{"); w.begin(4); if (isSplittable) { w.write("this"); w.write("((" + CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE + ") null"); printArgumentsForTypeParamsPreComma(typeParameters, false); w.write(")"); w.write(";"); w.newline(); w.write(CONSTRUCTOR_METHOD_NAME(type.toClass().def())); } else { w.write("this"); } w.write("("); if (!isSplittable) { printArgumentsForTypeParams(typeParameters, formals.size() == 0); } for (int i = 0; i < formals.size(); i++) { Formal formal = formals.get(i); if (i != 0) { w.write(","); } tr.print(n, formal.name(), w); } printExtraArgments((X10ConstructorInstance) n.constructorDef().asInstance()); w.write(")"); w.write(";"); w.end(); w.write("}"); w.newline(); } } private Stmt getFirstStatement(X10ConstructorDecl_c n) { Stmt firstStmt = n.body().statements().get(0); if (firstStmt instanceof Block) { List<Stmt> statements = ((Block) firstStmt).statements(); if (statements.size() == 1) { firstStmt = statements.get(0); } } return firstStmt; } private void printInitParams(Type type, List<String> params) { if (params.size() > 0) { er.printType(type, 0); w.write("."); w.write(INITPARAMS_NAME); w.write("(this"); for (String param : params) { w.write(", "); w.write(param); } w.writeln(");"); } } private void printConstructorMethodDecl(X10ConstructorDecl_c n, boolean isCustomSerializable) { w.newline(); w.writeln("// constructor for non-virtual call"); String methodName = null; Flags ctorFlags = n.flags().flags().clearPrivate().clearProtected().Public().Final(); tr.print(n, tr.nodeFactory().FlagsNode(n.flags().position(), ctorFlags), w); er.printType(n.constructorDef().container().get(), PRINT_TYPE_PARAMS | NO_VARIANCE); w.write(" "); String ctorName = CONSTRUCTOR_METHOD_NAME(n.constructorDef().container().get().toClass().def()); w.write(ctorName); List<String> params = printConstructorFormals(n, false); boolean isFirst = true; for (Ref<? extends Type> _throws : n.constructorDef().throwTypes()) { if (isFirst) { w.write(" throws "); isFirst = false; } else { w.write(", "); } er.printType(_throws.get(), 0); } Block body = n.body(); if (body != null) { body = (Block) body.visit(new NodeVisitor() { @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof Return) { NodeFactory nf = tr.nodeFactory(); return nf.Return(n.position(), nf.This(Position.COMPILER_GENERATED)); } return n; } }); // if (typeAssignments.size() > 0) { w.write(" {"); w.begin(4); // if (body.statements().size() > 0) { // if (body.statements().get(0) instanceof X10ConstructorCall_c) { // X10ConstructorCall_c cc = (X10ConstructorCall_c) // body.statements().get(0); // n.printSubStmt(cc, w, tr); // w.allowBreak(0, " "); // if (cc.kind() == ConstructorCall.THIS) typeAssignments.clear(); // } // } // If this is the custom serialization constructor we refractor it out into a new method and call it here if (isCustomSerializable) { // We cant use the same method name in all classes cause it creates and endless loop cause whn super.init is called it calls back to this method methodName = n.returnType().type().fullName().toString().replace(".", "$") + "$" + CONSTRUCTOR_METHOD_NAME_FOR_REFLECTION; w.writeln(methodName + "(" + n.formals().get(0).name() + ");"); } else { printConstructorBody(n, body); } w.newline(); if (body.reachable()) { w.writeln("return this;"); } w.write("}"); w.end(); // } else { // n.printSubStmt(body, w, tr); // } } else { w.write(";"); } w.newline(); // Refractored method that can be called by reflection if (isCustomSerializable) { w.begin(4); w.writeln("public void " + methodName + "(" + SERIAL_DATA + " " + n.formals().get(0).name() + ") {"); n.printSubStmt(body, w, tr); w.writeln("}"); w.end(); } } private void printConstructorBody(X10ConstructorDecl_c n, Block body) { if (body.statements().size() > 0) { if (body.statements().get(0) instanceof X10ConstructorCall_c) n.printSubStmt(body.statements(body.statements() /* .subList(1, body.statements().size()) */), w, tr); // vj: the main body was not being written. Added next // two lines. else n.printSubStmt(body, w, tr); } else n.printSubStmt(body, w, tr); } private List<String> printConstructorFormals(X10ConstructorDecl_c n, boolean forceParams) { w.write("("); w.begin(0); X10ConstructorDef ci = n.constructorDef(); X10ClassType ct = Types.get(ci.container()).toClass(); List<String> params = new ArrayList<String>(); if (forceParams) { for (Iterator<ParameterType> i = ct.x10Def().typeParameters().iterator(); i.hasNext();) { ParameterType p = i.next(); w.write("final "); w.write(X10_RTT_TYPE); w.write(" "); String name = Emitter.mangleParameterType(p); w.write(name); if (i.hasNext() || n.formals().size() > 0) { w.write(","); w.allowBreak(0, " "); } params.add(name); } } for (Iterator<Formal> i = n.formals().iterator(); i.hasNext();) { Formal f = i.next(); n.print(f, w, tr); if (i.hasNext()) { w.write(","); w.allowBreak(0, " "); } } printExtraFormals(n); w.end(); w.write(")"); /* * if (! n.throwTypes().isEmpty()) { w.allowBreak(6); * w.write("throws "); * * for (Iterator<TypeNode> i = n.throwTypes().iterator(); i.hasNext(); ) * { TypeNode tn = (TypeNode) i.next(); er.printType(tn.type(), * PRINT_TYPE_PARAMS); * * if (i.hasNext()) { w.write(","); w.allowBreak(4, " "); } } } */ return params; } private void printExtraFormals(X10ConstructorDecl_c n) { String dummy = "$dummy"; int cid = getConstructorId(n.constructorDef()); if (cid != -1) { String extraTypeName = getExtraTypeName(n.constructorDef()); w.write(", " + extraTypeName + " " + dummy); } } private static String getMangledMethodSuffix(X10ConstructorDef md) { ClassType ct = (ClassType) md.container().get(); List<Ref<? extends Type>> formalTypes = md.formalTypes(); String methodSuffix = Emitter.getMangledMethodSuffix(ct, formalTypes, true); assert methodSuffix.length() > 0; return methodSuffix; } private static String asTypeName(Type containerType, String methodSuffix) { X10ClassDef def = containerType.toClass().def(); String name = def.fullName().toString(); // x10.array.DistArray.LocalState Ref<? extends Package> pkg = def.package_(); if (pkg != null) { String packageName = pkg.toString(); // x10.array int packageNameLength = packageName.length(); if (packageNameLength > 0) packageNameLength += 1; // x10.array. name = name.substring(packageNameLength); // DistArray.LocalState } if (name.length() + 1/*$*/ + methodSuffix.length() + 6/*.class*/> longestTypeName) { // if method suffix is too long for file name, replace it with hash code representation of it to avoid post-compilation error. String typeName = "$_" + Integer.toHexString(methodSuffix.hashCode()); // System.out.println("asTypeName: " + name + ": " + methodSuffix + " -> " + typeName); return typeName; } else { return methodSuffix; } } private static String getExtraTypeName(X10ConstructorDef md) { assert getConstructorId(md) != -1; return asTypeName(md.container().get(), getMangledMethodSuffix(md)); } // should be called after setConstructorIds(def) private void printExtraTypes(X10ClassDef def) { HashSet<String> extraTypeNames = new HashSet<String>(); List<ConstructorDef> cds = def.constructors(); for (ConstructorDef cd : cds) { X10ConstructorDef xcd = (X10ConstructorDef) cd; int cid = getConstructorId(xcd); if (cid != -1) { String methodSuffix = getMangledMethodSuffix(xcd); String extraTypeName = asTypeName(cd.container().get(), methodSuffix); if (!extraTypeNames.contains(extraTypeName)) { extraTypeNames.add(extraTypeName); if (!extraTypeName.equals(methodSuffix)) { w.writeln("// synthetic type for parameter mangling for " + methodSuffix); } else { w.writeln("// synthetic type for parameter mangling"); } w.writeln("public static final class " + extraTypeName + " {}"); } } } } private void printConstructorParams(X10ConstructorDecl_c n) { w.write("("); w.begin(0); X10ConstructorDef ci = n.constructorDef(); X10ClassType ct = Types.get(ci.container()).toClass(); for (Iterator<Formal> i = n.formals().iterator(); i.hasNext();) { Formal f = i.next(); w.write(f.name().toString()); // TODO mangle? if (i.hasNext()) { w.write(","); } } printExtraParams(n); w.end(); w.write(")"); /* * if (! n.throwTypes().isEmpty()) { w.allowBreak(6); * w.write("throws "); * * for (Iterator<TypeNode> i = n.throwTypes().iterator(); i.hasNext(); ) * { TypeNode tn = (TypeNode) i.next(); er.printType(tn.type(), * PRINT_TYPE_PARAMS); * * if (i.hasNext()) { w.write(","); w.allowBreak(4, " "); } } } */ } private void printExtraParams(X10ConstructorDecl_c n) { String dummy = "$dummy"; int cid = getConstructorId(n.constructorDef()); if (cid != -1) { w.write(", " + dummy); } } // //////////////////////////////// // Expr // //////////////////////////////// @Override public void visit(Allocation_c n) { Type type = n.type(); printAllocationCall(type, type.toClass().typeArguments()); } private void printAllocationCall(Type type, List<? extends Type> typeParams) { w.write("new "); er.printType(type, PRINT_TYPE_PARAMS | NO_VARIANCE); w.write("((" + CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE + ") null"); printArgumentsForTypeParamsPreComma(typeParams, false); w.write(")"); } @Override public void visit(LocalAssign_c n) { Local l = n.local(); TypeSystem ts = tr.typeSystem(); if (n.operator() == Assign.ASSIGN || isPrimitive(l.type()) || l.type().isString()) { tr.print(n, l, w); w.write(" "); w.write(n.operator().toString()); w.write(" "); er.coerce(n, n.right(), l.type()); if (isMutableStruct(l.type())) { w.write(".clone()"); } } else { Binary.Operator op = n.operator().binaryOperator(); Name methodName = X10Binary_c.binaryMethodName(op); tr.print(n, l, w); w.write(" = "); tr.print(n, l, w); w.write("."); w.write(Emitter.mangleToJava(methodName)); w.write("("); tr.print(n, n.right(), w); w.write(")"); } } @Override public void visit(FieldAssign_c n) { Type t = n.fieldInstance().type(); TypeSystem ts = tr.typeSystem(); if (n.operator() == Assign.ASSIGN || isPrimitive(t) || t.isString()) { if (n.target() instanceof TypeNode) er.printType(n.target().type(), 0); else tr.print(n, n.target(), w); w.write("."); w.write(Emitter.mangleToJava(n.name().id())); w.write(" "); w.write(n.operator().toString()); w.write(" "); er.coerce(n, n.right(), n.fieldInstance().type()); if (isMutableStruct(n.fieldInstance().type())) { w.write(".clone()"); } } else if (n.target() instanceof TypeNode || n.target() instanceof Local || n.target() instanceof Lit) { // target has no side effects--evaluate it more than once Binary.Operator op = n.operator().binaryOperator(); Name methodName = X10Binary_c.binaryMethodName(op); if (n.target() instanceof TypeNode) er.printType(n.target().type(), 0); else tr.print(n, n.target(), w); w.write("."); w.write(Emitter.mangleToJava(n.name().id())); w.write(" "); w.write(" = "); tr.print(n, n.target(), w); w.write("."); w.write(Emitter.mangleToJava(n.name().id())); w.write("."); w.write(Emitter.mangleToJava(methodName)); w.write("("); tr.print(n, n.right(), w); w.write(")"); } else { // x.f += e // --> // new Object() { T eval(R target, T right) { return (target.f = // target.f.add(right)); } }.eval(x, e) Binary.Operator op = n.operator().binaryOperator(); Name methodName = X10Binary_c.binaryMethodName(op); w.write("new " + JAVA_IO_SERIALIZABLE + "() {"); w.allowBreak(0, " "); w.write("final "); er.printType(n.type(), PRINT_TYPE_PARAMS); w.write(" eval("); er.printType(n.target().type(), PRINT_TYPE_PARAMS); w.write(" target, "); er.printType(n.right().type(), PRINT_TYPE_PARAMS); w.write(" right) {"); w.allowBreak(0, " "); w.write("return (target."); w.write(Emitter.mangleToJava(n.name().id())); w.write(" = "); w.write("target."); w.write(Emitter.mangleToJava(n.name().id())); w.write("."); w.write(Emitter.mangleToJava(methodName)); w.write("(right));"); w.allowBreak(0, " "); w.write("} }.eval("); tr.print(n, n.target(), w); w.write(", "); tr.print(n, n.right(), w); w.write(")"); } } @Override public void visit(SettableAssign_c n) { SettableAssign_c a = n; Expr array = a.array(); List<Expr> index = a.index(); boolean effects = er.hasEffects(array); for (Expr e : index) { if (effects) break; if (er.hasEffects(e)) effects = true; } TypeSystem ts = tr.typeSystem(); Context context = tr.context(); Type t = n.leftType(); boolean nativeop = false; if (isPrimitive(t) || t.isString()) { nativeop = true; } MethodInstance mi = n.methodInstance(); boolean superUsesClassParameter = !mi.flags().isStatic(); // && // overridesMethodThatUsesClassParameter(mi); if (n.operator() == Assign.ASSIGN) { // Look for the appropriate set method on the array and emit native // code if there is an @Native annotation on it. String pat = Emitter.getJavaImplForDef(mi.x10Def()); if (pat != null) { List<String> params = new ArrayList<String>(index.size()); List<Expr> args = new ArrayList<Expr>(index.size() + 1); // args.add(array); args.add(n.right()); for (int i = 0; i < index.size(); ++i) { params.add(mi.def().formalNames().get(i).name().toString()); args.add(index.get(i)); } er.emitNativeAnnotation(pat, array, mi.x10Def().typeParameters(), mi.typeParameters(), params, args, Collections.<ParameterType>emptyList(), Collections.<Type> emptyList()); return; } else { // otherwise emit the hardwired code. tr.print(n, array, w); w.write(".set"); w.write("("); tr.print(n, n.right(), w); if (index.size() > 0) w.write(", "); new Join(er, ", ", index).expand(tr); w.write(")"); } } else if (!effects) { Binary.Operator op = n.operator().binaryOperator(); Name methodName = X10Binary_c.binaryMethodName(op); TypeSystem xts = ts; if (isPrimitive(t) && isIndexedMemoryChunk(array.type())) { w.write("("); w.write("("); er.printType(t, 0); w.write("[])"); tr.print(n, array, w); w.write(".value"); w.write(")"); w.write("["); new Join(er, ", ", index).expand(tr); w.write("]"); w.write(" "); w.write(op.toString()); w.write("="); w.write(" "); tr.print(n, n.right(), w); return; } tr.print(n, array, w); w.write(".set"); w.write("(("); tr.print(n, array, w); w.write(").$apply("); new Join(er, ", ", index).expand(tr); w.write(")"); if (nativeop) { w.write(" "); w.write(op.toString()); tr.print(n, n.right(), w); } else { w.write("."); w.write(Emitter.mangleToJava(methodName)); w.write("("); tr.print(n, n.right(), w); w.write(")"); } if (index.size() > 0) w.write(", "); new Join(er, ", ", index).expand(tr); w.write(")"); } else { // new Object() { T eval(R target, T right) { return (target.f = // target.f.add(right)); } }.eval(x, e) Binary.Operator op = n.operator().binaryOperator(); Name methodName = X10Binary_c.binaryMethodName(op); TypeSystem xts = ts; if (isPrimitive(t) && isIndexedMemoryChunk(array.type())) { w.write("("); w.write("("); er.printType(t, 0); w.write("[])"); tr.print(n, array, w); w.write(".value"); w.write(")"); w.write("["); new Join(er, ", ", index).expand(tr); w.write("]"); w.write(" "); w.write(op.toString()); w.write("="); w.write(" "); tr.print(n, n.right(), w); return; } w.write("new " + JAVA_IO_SERIALIZABLE + "() {"); w.allowBreak(0, " "); w.write("final "); er.printType(n.type(), PRINT_TYPE_PARAMS); w.write(" eval("); er.printType(array.type(), PRINT_TYPE_PARAMS); w.write(" array"); { int i = 0; for (Expr e : index) { w.write(", "); er.printType(e.type(), PRINT_TYPE_PARAMS); w.write(" "); w.write("i" + i); i++; } } w.write(", "); er.printType(n.right().type(), PRINT_TYPE_PARAMS); w.write(" right) {"); w.allowBreak(0, " "); if (!n.type().isVoid()) { w.write("return "); } w.write("array.set"); w.write("("); w.write(" array.$apply("); { int i = 0; for (Expr e : index) { if (i != 0) w.write(", "); w.write("i" + i); i++; } } w.write(")"); if (nativeop) { w.write(" "); w.write(op.toString()); w.write(" right"); } else { w.write("."); w.write(Emitter.mangleToJava(methodName)); w.write("(right)"); } if (index.size() > 0) w.write(", "); { int i = 0; for (Expr e : index) { if (i != 0) w.write(", "); w.write("i" + i); i++; } } w.write(");"); w.allowBreak(0, " "); w.write("} }.eval("); tr.print(n, array, w); if (index.size() > 0) w.write(", "); new Join(er, ", ", index).expand(); w.write(", "); tr.print(n, n.right(), w); w.write(")"); } } @Override public void visit(X10Binary_c n) { Expr left = n.left(); Type l = left.type(); Expr right = n.right(); Type r = right.type(); TypeSystem xts = tr.typeSystem(); Binary.Operator op = n.operator(); if (l.isNumeric() && r.isNumeric() || l.isBoolean() && r.isBoolean() || l.isChar() && r.isChar()) { prettyPrint(n); return; } if (op == Binary.EQ) { // SYNOPSIS: #0 == #1 // TODO generalize for reference type if (l.isNull() || r.isNull()) { // ((#0) == (#1)) w.write("(("); er.prettyPrint(left, tr); w.write(") == ("); er.prettyPrint(right, tr); w.write("))"); } else { // x10.rtt.Equality.equalsequals(#0,#1) w.write("x10.rtt.Equality.equalsequals("); if (needExplicitBoxing(l)) { er.printBoxConversion(l); } w.write("("); // required for printBoxConversion er.prettyPrint(left, tr); w.write(")"); w.write(","); if (needExplicitBoxing(r)) { er.printBoxConversion(r); } w.write("("); // required for printBoxConversion er.prettyPrint(right, tr); w.write("))"); } return; } if (op == Binary.NE) { // SYNOPSIS: #0 != #1 // TODO generalize for reference type if (l.isNull() || r.isNull()) { // ((#0) != (#1)) w.write("(("); er.prettyPrint(left, tr); w.write(") != ("); er.prettyPrint(right, tr); w.write("))"); } else { // (!x10.rtt.Equality.equalsequals(#0,#1)) w.write("(!x10.rtt.Equality.equalsequals("); if (needExplicitBoxing(l)) { er.printBoxConversion(l); } w.write("("); er.prettyPrint(left, tr); w.write(")"); w.write(","); if (needExplicitBoxing(r)) { er.printBoxConversion(r); } w.write("("); er.prettyPrint(right, tr); w.write(")))"); } return; } if (op == Binary.ADD && (l.isString() || r.isString())) { prettyPrint(n); return; } if (n.invert()) { Name methodName = X10Binary_c.invBinaryMethodName(op); if (methodName != null) { er.generateStaticOrInstanceCall(n.position(), right, methodName, left); return; } } else { Name methodName = X10Binary_c.binaryMethodName(op); if (methodName != null) { er.generateStaticOrInstanceCall(n.position(), left, methodName, right); return; } } throw new InternalCompilerError("No method to implement " + n, n.position()); } // This is an enhanced version of Binary_c#prettyPrint(CodeWriter, // PrettyPrinter) private void prettyPrint(X10Binary_c n) { Expr left = n.left(); Type l = left.type(); Expr right = n.right(); Type r = right.type(); Binary.Operator op = n.operator(); boolean asPrimitive = false; if (op == Binary.EQ || op == Binary.NE) { if (l.isNumeric() && r.isNumeric() || l.isBoolean() && r.isBoolean() || l.isChar() && r.isChar()) { asPrimitive = true; } } boolean needParenl = false; if (asPrimitive) { // TODO:CAST w.write("("); w.write("("); er.printType(l, 0); w.write(") "); } n.printSubExpr(left, true, w, tr); if (needParenl) w.write(")"); if (asPrimitive) w.write(")"); w.write(" "); w.write(op.toString()); w.allowBreak(n.type() == null || n.type().isJavaPrimitive() ? 2 : 0, " "); if (asPrimitive) { // TODO:CAST w.write("("); w.write("("); er.printType(r, 0); w.write(") "); } n.printSubExpr(right, false, w, tr); if (asPrimitive) w.write(")"); } private static boolean allMethodsFinal(X10ClassDef def) { return def.flags().isFinal() || def.isStruct(); } private static boolean doesNotHaveMethodBody(X10ClassDef def) { // for Comparable[T].compareTo(T) // TODO expand @Native annotation of interface method to the types that implement the interface and don't have its implementation. return def.flags().isInterface(); // return false; } private static boolean canBeNonVirtual(X10ClassDef def) { return allMethodsFinal(def) || doesNotHaveMethodBody(def); } // TODO consolidate isPrimitive(Type) and needExplicitBoxing(Type). // return all X10 types that are mapped to Java primitives and require explicit boxing public static boolean needExplicitBoxing(Type t) { return isPrimitive(t); } public static boolean isBoxedType(Type t) { // void is included here, because synthetic methods have no definition and are reported as having type (void) return !(isPrimitive(t) || t.isVoid()); } @Override public void visit(X10Call_c c) { if (er.printInlinedCode(c)) { return; } if (c.isConstant()) { Type t = Types.baseType(c.type()); if (isPrimitive(t) || t.isNull() || isString(t)) { er.prettyPrint(c.constantValue().toLit(tr.nodeFactory(), tr.typeSystem(), t, Position.COMPILER_GENERATED), tr); return; } } // XTENLANG-2680 invoke final methods as non-virtual call for optimization final MethodInstance mi = c.methodInstance(); final Receiver target = c.target(); final Type targetType = target.type(); final ContainerType containerType = mi.container(); assert containerType.isClass(); final X10ClassType containerClass = containerType.toClass(); // N.B. structs are implicitly final. all methods of final classes are final. invoke final methods as non-virtual call. boolean invokeNativeAsNonVirtual = !Emitter.supportNativeMethodDecl || mi.flags().isStatic() || mi.flags().isFinal() || canBeNonVirtual(containerClass.x10Def()) || (targetType.isClass() && canBeNonVirtual(targetType.toClass().x10Def())) ; if (invokeNativeAsNonVirtual && er.printNativeMethodCall(c)) { return; } // Check for properties accessed using method syntax. They may have // @Native annotations too. if (mi.flags().isProperty() && mi.formalTypes().size() == 0 && mi.typeParameters().size() == 0) { X10FieldInstance fi = (X10FieldInstance) containerType.fieldNamed(mi.name()); if (fi != null) { String pat2 = Emitter.getJavaImplForDef(fi.x10Def()); if (pat2 != null) { Map<String,Object> components = new HashMap<String,Object>(); int i = 0; Object component; component = target; if (supportNumberedParameterForNative) components.put(String.valueOf(i++), component); // TODO need check components.put(fi.x10Def().name().toString(), component); er.dumpRegex("Native", components, tr, pat2); return; } } } TypeSystem xts = tr.typeSystem(); // When the target class is a generics , print a cast operation // explicitly. if (target instanceof TypeNode) { er.printType(targetType, 0); } else { // add a check that verifies if the target of the call is in place // 'here' // This is not needed for: if (!(target instanceof Special || target instanceof New)) { if (xts.isParameterType(targetType)) { // TODO:CAST w.write("("); w.write("("); er.printType(containerType, PRINT_TYPE_PARAMS); // TODO // check w.write(")"); w.write(X10_RTT_TYPES); w.write(".conversion("); new RuntimeTypeExpander(er, Types.baseType(containerType)).expand(tr); w.write(","); er.prettyPrint(target, tr); w.write(")"); w.write(")"); } else if (useSelfDispatch && (mi.typeParameters().size() > 0 || hasParams(containerType))) { // TODO:CAST w.write("("); w.write("("); er.printType(containerType, PRINT_TYPE_PARAMS); w.write(")"); er.prettyPrint(target, tr); w.write(")"); } else { er.prettyPrint(target, tr); } } else { er.prettyPrint(target, tr); } } w.write("."); // print type parameters List<Type> methodTypeParams = mi.typeParameters(); if (methodTypeParams.size() > 0) { er.printMethodParams(methodTypeParams); } // print method name if (isMainMethod(mi) || mi.container().toClass().isJavaType()) { w.write(Emitter.mangleToJava(c.name().id())); } else { boolean invokeInterface = false; ContainerType st = mi.def().container().get(); Type bst = Types.baseType(st); if (bst.isClass()) { if (xts.isInterfaceType(bst) || (xts.isFunctionType(bst) && bst.toClass().isAnonymous())) { invokeInterface = true; } } boolean isDispatchMethod = false; if (useSelfDispatch) { Type tt = Types.baseType(containerType); if (tt.isClass() && tt.toClass().flags().isInterface()) { // XTENLANG-2723 (revert r21635) // // N.B. stop passing rtt to java raw class's methods // if (containsTypeParam(mi.def().formalTypes()) && !Emitter.isNativeRepedToJava(tt)) { if (containsTypeParam(mi.def().formalTypes())) { isDispatchMethod = true; } } else if (target instanceof ParExpr && ((ParExpr) target).expr() instanceof Closure_c) { if (mi.formalTypes().size() != 0) { isDispatchMethod = true; } } } boolean instantiatesReturnType = false; List<MethodInstance> list = mi.implemented(tr.context()); for (MethodInstance mj : list) { if (mj.container().typeEquals(containerType, tr.context()) && mj.def().returnType().get().isParameterType()) { instantiatesReturnType = true; break; } } MethodDef md = mi.def(); boolean isParamReturnType = md.returnType().get().isParameterType() || instantiatesReturnType; if (c.nonVirtual()) { Name name = InlineHelper.makeSuperBridgeName(mi.container().toClass().def(), mi.name()); List<MethodInstance> bridges = targetType.toClass().methodsNamed(name); assert (bridges.size()==1); md = bridges.get(0).def(); isParamReturnType = false; w.write("/"+"*"+"non-virtual"+"*"+"/"); } // call // XTENLANG-2993 // for X10PrettyPrinterVisitor.exposeSpecialDispatcherThroughSpecialInterface // Type returnTypeForDispatcher = md.returnType().get(); Type returnTypeForDispatcher = isPrimitive(mi.returnType()) && isPrimitiveGenericMethod(mi) ? mi.returnType() : md.returnType().get(); // for X10PrettyPrinterVisitor.exposeSpecialDispatcherThroughSpecialInterface // boolean isSpecialReturnType = isSpecialType(md.returnType().get()); boolean isSpecialReturnType = isPrimitive(mi.returnType()) && isPrimitiveGenericMethod(mi) ? true : isSpecialType(md.returnType().get()); er.printMethodName(md, invokeInterface, isDispatchMethod, generateSpecialDispatcher && !generateSpecialDispatcherNotUse, returnTypeForDispatcher, isSpecialReturnType, isParamReturnType); } // print the argument list w.write("("); w.begin(0); List<Type> typeParameters = mi.typeParameters(); int argumentSize = c.arguments().size(); printArgumentsForTypeParams(typeParameters, argumentSize == 0); boolean runAsync = false; if (Types.baseType(containerType).isRuntime()) { if (mi.signature().startsWith("runAsync")) { runAsync = true; } } List<Expr> exprs = c.arguments(); MethodDef def = c.methodInstance().def(); for (int i = 0; i < exprs.size(); ++i) { Expr e = exprs.get(i); Type defType = def.formalTypes().get(i).get(); if (runAsync && e instanceof Closure_c) { c.print(((Closure_c) e).methodContainer(mi), w, tr); } // else if (!er.isNoArgumentType(e)) { // new CastExpander(w, er, e).castTo(e.type(), // BOX_PRIMITIVES).expand(); // } else { if (isPrimitive(e.type())) { boolean forceBoxing = false; if (!Emitter.canMangleMethodName(def)) { // for methods with non-manglable names, we box argument // if any of the implemented methods has argument of generic type // in corresponding position for (MethodInstance supermeth : c.methodInstance().implemented(tr.context())) { if (isBoxedType(supermeth.def().formalTypes().get(i).get())) { forceBoxing = true; break; } } } // e.g) m((Integer) a) for m(T a) boolean closeParen = false; // unbalanced closing parenthesis needed? // N.B. @NativeRep'ed interface (e.g. Comparable) does not use dispatch method nor mangle method. primitives need to be boxed to allow instantiating type parameter. if (isBoxedType(defType) || forceBoxing) { // this can print something like '(int)' or 'UInt.$box' depending on the type // we require the parentheses to be printed below er.printBoxConversion(e.type()); // e.g) m((int) a) for m(int a) } else { // TODO:CAST w.write("("); er.printType(e.type(), 0); w.write(")"); if (e instanceof X10Call) { } else if (e instanceof ClosureCall) { ClosureCall cl = (ClosureCall) e; Expr expr = cl.target(); // if (expr instanceof ParExpr) { // expr = expr; // } if (!(expr instanceof Closure_c) && xts.isParameterType(cl.closureInstance().def().returnType().get())) { // TODO:CAST closeParen = er.printUnboxConversion(e.type()); w.write("("); er.printType(e.type(), BOX_PRIMITIVES); w.write(")"); } } } w.write("("); // it is important to add parentheses here, as some call may have been issued above c.print(e, w, tr); w.write(")"); if (closeParen) w.write(")"); if (isMutableStruct(e.type())) { w.write(".clone()"); } } // XTENLANG-1704 else { // TODO:CAST w.write("("); Type castType = mi.formalTypes().get(i); w.write("("); er.printType(castType, 0); w.write(")"); if (isString(e.type()) && !isString(castType)) { if (xts.isParameterType(castType)) { w.write(X10_RTT_TYPES); w.write(".conversion("); new RuntimeTypeExpander(er, Types.baseType(castType)).expand(tr); w.write(","); } } w.write("("); c.print(e, w, tr); w.write(")"); if (isMutableStruct(e.type())) { w.write(".clone()"); } w.write(")"); } } // if I is an interface and val i:I , t = type of the type of the // formal of method instance // i.m(a) => i.m(a,t) X10ClassType ct = null; if (useSelfDispatch && Types.baseType(targetType).isClass()) { ct = Types.baseType(targetType).toClass(); } else if (useSelfDispatch && xts.isParameterType(targetType)) { ct = Types.baseType(containerType).toClass(); } boolean passRTT = // // XTENLANG-2723 stop passing rtt to java raw class's methods (reverted in r21635) // ct != null && ((ct.flags().isInterface() || (xts.isFunctionType(ct) && ct.isAnonymous())) && Emitter.containsTypeParam(defType)) && !Emitter.isNativeRepedToJava(ct); ct != null && ((ct.flags().isInterface() || (xts.isFunctionType(ct) && ct.isAnonymous())) && Emitter.containsTypeParam(defType)); if (passRTT) { w.write(","); new RuntimeTypeExpander(er, c.methodInstance().formalTypes().get(i)).expand(); } if (i != exprs.size() - 1) { w.write(","); w.allowBreak(0, " "); } } w.end(); w.write(")"); } private void printArgumentsForTypeParams(List<? extends Type> typeParameters, boolean isLast) { for (Iterator<? extends Type> i = typeParameters.iterator(); i.hasNext();) { final Type at = i.next(); new RuntimeTypeExpander(er, at).expand(tr); if (i.hasNext() || !isLast) { w.write(", "); // w.allowBreak(0, " "); } } } private void printArgumentsForTypeParamsPreComma(List<? extends Type> typeParameters, boolean isFirst) { if (typeParameters == null) return; for (Type at : typeParameters) { if (isFirst) { isFirst = false; } else { w.write(", "); } new RuntimeTypeExpander(er, at).expand(tr); } } private boolean isMainMethod(MethodInstance mi) { return HierarchyUtils.isMainMethod(mi, tr.context()); } @Override public void visit(X10Cast_c c) { TypeNode tn = c.castType(); assert tn instanceof CanonicalTypeNode; Expr expr = c.expr(); Type exprType = expr.type(); switch (c.conversionType()) { case CHECKED: case PRIMITIVE: case SUBTYPE: case UNCHECKED: if (tn instanceof X10CanonicalTypeNode) { X10CanonicalTypeNode castTN = (X10CanonicalTypeNode) tn; Type castType = Types.baseType(castTN.type()); Expander castTE = new TypeExpander(er, castType, PRINT_TYPE_PARAMS); Expander castRE = new RuntimeTypeExpander(er, castType); Expander exprRE = new RuntimeTypeExpander(er, exprType); TypeSystem xts = exprType.typeSystem(); // Note: constraint checking should be desugared when compiling // without NO_CHECKS flag // e.g. any as Int (any:Any), t as Int (t:T) if (isBoxedType(exprType) && xts.isStruct(castType)) { // N.B. castType.isUnsignedNumeric() must be before isPrimitive(castType) // since Int and UInt are @NativeRep'ed to the same Java primive int. if (castType.isUnsignedNumeric()) { w.write(X10_RTT_TYPES + ".as" + castType.name().toString()); w.write("("); c.printSubExpr(expr, w, tr); w.write(","); exprRE.expand(); w.write(")"); } else if (isPrimitive(castType)) { w.write(X10_RTT_TYPES + ".as"); er.printType(castType, NO_QUALIFIER); w.write("("); c.printSubExpr(expr, w, tr); w.write(","); exprRE.expand(); w.write(")"); } else { w.write("("); w.write("("); er.printType(castType, 0); w.write(")"); w.write(X10_RTT_TYPES + ".asStruct("); castRE.expand(); w.write(","); c.printSubExpr(expr, w, tr); w.write(")"); w.write(")"); } } else if (isPrimitive(castType)) { w.begin(0); // for the case the method is a dispatch method and that // returns Object. // e.g. (Boolean) m(a) if (castType.typeEquals(Types.baseType(exprType), tr.context())) { boolean closeParen = false; if (expr instanceof X10Call) { X10Call call = (X10Call)expr; MethodInstance mi = call.methodInstance(); if (!isPrimitiveGenericMethod(mi) && ((isBoxedType(mi.def().returnType().get()) && !er.isInlinedCall(call)) || Emitter.isDispatcher(mi)) ) closeParen = er.printUnboxConversion(castType); } else if (expr instanceof ClosureCall) { ClosureCall call = (ClosureCall)expr; if (isBoxedType(call.closureInstance().def().returnType().get())) closeParen = er.printUnboxConversion(castType); } c.printSubExpr(expr, w, tr); if (closeParen) w.write(")"); } else { w.write("("); // put "(Type) expr" in parentheses. w.write("("); castTE.expand(tr); w.write(")"); // e.g. d as Int (d:Double) -> (int)(double)(Double) d if (isPrimitive(exprType)) { w.write(" "); w.write("("); er.printType(exprType, 0); w.write(")"); w.write(" "); if (!(expr instanceof Unary || expr instanceof Lit) && (expr instanceof X10Call)) { w.write("("); er.printType(exprType, BOX_PRIMITIVES); w.write(")"); } } w.allowBreak(2, " "); // HACK: (java.lang.Integer) -1 // doesn't parse correctly, but // (java.lang.Integer) (-1) // does boolean needParan = expr instanceof Unary || expr instanceof Lit || expr instanceof Conditional_c; if (needParan) w.write("("); c.printSubExpr(expr, w, tr); if (needParan) w.write(")"); w.write(")"); } w.end(); } else if (exprType.isSubtype(castType, tr.context())) { w.begin(0); w.write("("); // put "(Type) expr" in parentheses. w.write("("); castTE.expand(tr); w.write(")"); if (castType.isClass()) { X10ClassType ct = castType.toClass(); if (ct.hasParams()) { boolean castToRawType = false; for (Variance variance : ct.x10Def().variances()) { if (variance != Variance.INVARIANT) { castToRawType = true; break; } } if (castToRawType) { // cast to raw type // e.g. for covariant class C[+T]{} and // C[Object] v = new C[String](), // it generates class C<T>{} and C<Object> v = // (C<Object>) (C) (new C<String>()). w.write("("); er.printType(castType, 0); w.write(")"); } } } w.allowBreak(2, " "); boolean closeParen = false; // provide extra closing parenthesis if (isString(exprType) && !isString(castType)) { if (xts.isParameterType(castType)) { w.write(X10_RTT_TYPES); w.write(".conversion("); castRE.expand(); w.write(","); } else { // box only if converting to function type if (xts.isFunctionType(castType)) { er.printBoxConversion(exprType); } w.write("("); } closeParen = true; } else if (needExplicitBoxing(exprType) && isBoxedType(castType)) { er.printBoxConversion(exprType); w.write("("); closeParen = true; } boolean needParen = expr instanceof Unary || expr instanceof Lit || expr instanceof Conditional_c; if (needParen) w.write("("); c.printSubExpr(expr, w, tr); if (needParen) w.write(")"); if (closeParen) w.write(")"); w.write(")"); w.end(); } else { // SYNOPSIS: (#0) #1 // -> Types.<#0>cast(#1,#2) #0=type #1=expr #2=runtime type // -> Types.<#0>castConversion(#1,#2) #0=type #1=expr #2=runtime type w.write(X10_RTT_TYPES + ".<"); er.prettyPrint(castTE, tr); boolean convert = xts.isParameterType(exprType) || !xts.isAny(Types.baseType(exprType)) && xts.isParameterType(castType) || isString(castType); w.write("> cast" + (convert ? "Conversion" : "") + "("); boolean closeParen = false; if (needExplicitBoxing(exprType) && isBoxedType(castType)) { er.printBoxConversion(exprType); w.write("("); closeParen = true; } er.prettyPrint(expr, tr); if (closeParen) w.write(")"); w.write(","); er.prettyPrint(castRE, tr); w.write(")"); } } else { throw new InternalCompilerError("Ambiguous TypeNode survived type-checking.", tn.position()); } break; case BOXING: er.printBoxConversion(c.type()); w.write("("); er.prettyPrint(c.expr(), tr); w.write(")"); break; case UNBOXING: boolean closeParen; closeParen = er.printUnboxConversion(c.type()); er.prettyPrint(c.expr(), tr); if (closeParen) w.write(")"); break; case UNKNOWN_IMPLICIT_CONVERSION: throw new InternalCompilerError("Unknown implicit conversion type after type-checking.", c.position()); case UNKNOWN_CONVERSION: throw new InternalCompilerError("Unknown conversion type after type-checking.", c.position()); } } @Override public void visit(Conditional_c n) { n.translate(w, tr); } /* * Field access -- this includes only access of fields for read; * see visit(FieldAssign_c) for write access. */ @Override public void visit(Field_c n) { Receiver target = n.target(); Type targetType = target.type(); TypeSystem xts = targetType.typeSystem(); X10FieldInstance fi = (X10FieldInstance) n.fieldInstance(); // print native field access String pat = Emitter.getJavaImplForDef(fi.x10Def()); if (pat != null) { Map<String,Object> components = new HashMap<String,Object>(); int i = 0; Object component; component = target; if (supportNumberedParameterForNative) components.put(String.valueOf(i++), component); components.put("this", component); // TODO is this needed? // components.put(fi.x10Def().name().toString(), component); er.dumpRegex("Native", components, tr, pat); return; } if (target instanceof TypeNode) { TypeNode tn = (TypeNode) target; if (targetType.isParameterType()) { // Rewrite to the class declaring the field. FieldDef fd = fi.def(); targetType = Types.get(fd.container()); target = tn.typeRef(fd.container()); n = (Field_c) n.target(target); } } // static access if (target instanceof TypeNode) { er.printType(targetType, 0); w.write("."); w.write(Emitter.mangleToJava(n.name().id())); } else { assert target instanceof Expr; boolean closeParen = false; Type fieldType = n.fieldInstance().def().type().get(); if (xts.isStruct(target.type()) && !isBoxedType(n.type()) && isBoxedType(fieldType)) { closeParen = er.printUnboxConversion(n.type()); } w.begin(0); if (!n.isTargetImplicit()) { if (!(target instanceof Special || target instanceof New) && (xts.isParameterType(targetType) || hasParams(fi.container()))) { // TODO:CAST w.write("("); w.write("("); er.printType(fi.container(), PRINT_TYPE_PARAMS); w.write(")"); n.printSubExpr((Expr) target, w, tr); w.write(")"); } else { n.printSubExpr((Expr) target, w, tr); } w.write("."); w.allowBreak(2, 3, "", 0); } tr.print(n, n.name(), w); if (closeParen) w.write(")"); w.end(); } } @Override public void visit(X10Instanceof_c c) { // Note: constraint checking should be desugared when compiling without // NO_CHECKS flag Type t = c.compareType().type(); // XTENLANG-1102 if (t.isClass()) { X10ClassType ct = t.toClass(); X10ClassDef cd = ct.x10Def(); String pat = Emitter.getJavaRTTRep(cd); if (t instanceof FunctionType) { FunctionType ft = (FunctionType) t; List<Type> args = ft.argumentTypes(); Type ret = ft.returnType(); if (ret.isVoid()) { w.write(X10_VOIDFUN_CLASS_PREFIX); } else { w.write(X10_FUN_CLASS_PREFIX); } w.write("_" + ft.typeParameters().size()); w.write("_" + args.size()); w.write("." + RTT_NAME); } else if (pat == null && !ct.isJavaType() && Emitter.getJavaRep(cd) == null && ct.isGloballyAccessible() && cd.typeParameters().size() != 0) { String rttString = RuntimeTypeExpander.getRTT(Emitter.mangleQName(cd.fullName()).toString(), RuntimeTypeExpander.hasConflictingField(ct, tr)); w.write(rttString); } else { new RuntimeTypeExpander(er, t).expand(tr); } } else { new RuntimeTypeExpander(er, t).expand(tr); } w.write("."); w.write("isInstance("); Type exprType = Types.baseType(c.expr().type()); boolean needParen = false; if (needExplicitBoxing(exprType)) { er.printBoxConversion(exprType); w.write("("); needParen = true; } tr.print(c, c.expr(), w); if (needParen) { w.write(")"); } if (t.isClass()) { X10ClassType ct = t.toClass(); X10ClassDef cd = ct.x10Def(); String pat = Emitter.getJavaRTTRep(cd); if (pat == null && Emitter.getJavaRep(cd) == null && ct.typeArguments() != null) { for (int i = 0; i < ct.typeArguments().size(); i++) { w.write(", "); new RuntimeTypeExpander(er, ct.typeArguments().get(i)).expand(tr); } } } w.write(")"); } @Override public void visit(Lit_c n) { n.translate(w, tr); } @Override public void visit(IntLit_c n) { String val = null; switch (n.kind()) { case BYTE: case UBYTE: val = "((byte) " + Byte.toString((byte) n.value()) + ")"; break; case SHORT: case USHORT: val = "((short) " + Short.toString((short) n.value()) + ")"; break; case INT: case UINT: val = Integer.toString((int) n.value()); break; case LONG: case ULONG: val = Long.toString(n.value()) + "L"; break; // default: // Int, Short, Byte // if (n.value() >= 0x80000000L) // val = "0x" + Long.toHexString(n.value()); // else // val = Long.toString((int) n.value()); } if (!n.type().isLongOrLess()) { assert (Types.baseType(n.type()).isAny()); w.write("("); er.printBoxConversion(n.constantValue().getLitType(tr.typeSystem())); w.write("("); } w.write(val); if (!n.type().isLongOrLess()) { w.write("))"); } } @Override public void visit(StringLit_c n) { w.write("\""); w.write(StringUtil.escape(n.value())); w.write("\""); // N.B. removed it since now we pass captured environment explicitly, // therefore the workaround is no longer needed. // w.write(".toString()"); // workaround for XTENLANG-2006. } @Override public void visit(Local_c n) { n.translate(w, tr); } @Override public void visit(X10New_c c) { Type type = c.objectType().type(); X10ConstructorInstance mi = c.constructorInstance(); if (er.printNativeNew(c, mi)) return; if (isSplittable(type) && !type.fullName().toString().startsWith("java.")) { printAllocationCall(type, mi.container().toClass().typeArguments()); w.write("."); w.write(CONSTRUCTOR_METHOD_NAME(type.toClass().def())); printConstructorArgumentList(c, c, c.constructorInstance(), null, false); return; } if (c.qualifier() != null) { tr.print(c, c.qualifier(), w); w.write("."); } w.write("new "); if (c.qualifier() == null) { er.printType(type, PRINT_TYPE_PARAMS | NO_VARIANCE); } else { er.printType(type, PRINT_TYPE_PARAMS | NO_VARIANCE | NO_QUALIFIER); } printConstructorArgumentList(c, c, mi, type, true); if (c.body() != null) { w.write("{"); tr.print(c, c.body(), w); w.write("}"); } } private void printExtraArgments(X10ConstructorInstance mi) { ConstructorDef md = mi.def(); if (md instanceof X10ConstructorDef) { int cid = getConstructorId((X10ConstructorDef) md); if (cid != -1) { String extraTypeName = getExtraTypeName((X10ConstructorDef) md); w.write(", ("); // print as qualified name er.printType(md.container().get(), 0); w.write("."); w.write(extraTypeName + ") null"); } } } @Override public void visit(Special_c n) { Context c = tr.context(); /* * The InnerClassRemover will have replaced the */ if (c.inAnonObjectScope() && n.kind() == Special.THIS && c.inStaticContext()) { w.write(InnerClassRemover.OUTER_FIELD_NAME.toString()); return; } if ((((X10Translator) tr).inInnerClass() || c.inAnonObjectScope()) && n.qualifier() == null && n.kind() != X10Special.SELF && n.kind() != Special.SUPER) { er.printType(n.type(), 0); w.write("."); } else if (n.qualifier() != null && n.kind() != X10Special.SELF && n.kind() != Special.SUPER) { er.printType(n.qualifier().type(), 0); w.write("."); } w.write(n.kind().toString()); } @Override public void visit(ParExpr_c n) { n.translate(w, tr); } public void visit(SubtypeTest_c n) { TypeNode sub = n.subtype(); TypeNode sup = n.supertype(); w.write("(("); new RuntimeTypeExpander(er, sub.type()).expand(tr); w.write(")"); if (n.equals()) { w.write(".equals("); } else { w.write(".isAssignableTo("); } new RuntimeTypeExpander(er, sup.type()).expand(tr); w.write("))"); } @Override public void visit(HasZeroTest_c n) { TypeNode sub = n.parameter(); w.write("(("); new RuntimeTypeExpander(er, sub.type()).expand(tr); w.write(").hasZero())"); } @Override public void visit(Tuple_c c) { Type t = Types.getParameterType(c.type(), 0); w.write(X10_RUNTIME_IMPL_JAVA_ARRAYUTILS + ".<"); er.printType(t, PRINT_TYPE_PARAMS | BOX_PRIMITIVES); w.write("> "); w.write("makeArrayFromJavaArray("); new RuntimeTypeExpander(er, t).expand(); w.write(", "); if (t.isParameterType()) { new RuntimeTypeExpander(er, t).expand(); w.write(".makeArray("); new Join(er, ", ", c.arguments()).expand(); w.write(")"); } else { w.write("new "); er.printType(t, 0); w.write("[] {"); new Join(er, ", ", c.arguments()).expand(); w.write("}"); } w.write(")"); } @Override public void visit(Unary_c n) { n.translate(w, tr); } @Override public void visit(X10Unary_c n) { Expr left = n.expr(); Type l = left.type(); Unary.Operator op = n.operator(); if (op == Unary.POST_DEC || op == Unary.POST_INC || op == Unary.PRE_DEC || op == Unary.PRE_INC) { Expr expr = left; Type t = left.type(); Expr target = null; List<Expr> args = null; List<TypeNode> typeArgs = null; MethodInstance mi = null; // Handle a(i)++ and a.apply(i)++ if (expr instanceof ClosureCall) { ClosureCall e = (ClosureCall) expr; target = e.target(); args = e.arguments(); typeArgs = Collections.<TypeNode> emptyList(); // e.typeArgs(); mi = e.closureInstance(); } else if (expr instanceof X10Call) { X10Call e = (X10Call) expr; if (e.target() instanceof Expr && e.name().id() == ClosureCall.APPLY) { target = (Expr) e.target(); args = e.arguments(); typeArgs = e.typeArguments(); mi = e.methodInstance(); } } if (mi != null) { // MethodInstance setter = null; List<Type> setArgTypes = new ArrayList<Type>(); List<Type> setTypeArgs = new ArrayList<Type>(); for (Expr e : args) { setArgTypes.add(e.type()); } setArgTypes.add(expr.type()); for (TypeNode tn : typeArgs) { setTypeArgs.add(tn.type()); } // try { // setter = ts.findMethod(target.type(), ts.MethodMatcher(t, // SettableAssign.SET, setTypeArgs, setArgTypes, tr.context())); // } // catch (SemanticException e) { // } // TODO: handle type args // TODO: handle setter method w.write("new " + JAVA_IO_SERIALIZABLE + "() {"); w.allowBreak(0, " "); w.write("final "); er.printType(t, PRINT_TYPE_PARAMS); w.write(" eval("); er.printType(target.type(), PRINT_TYPE_PARAMS); w.write(" target"); { int i = 0; for (Expr e : args) { w.write(", "); er.printType(e.type(), PRINT_TYPE_PARAMS); w.write(" a" + (i + 1)); i++; } } w.write(") {"); w.allowBreak(0, " "); er.printType(left.type(), PRINT_TYPE_PARAMS); w.write(" old = "); String pat = Emitter.getJavaImplForDef(mi.x10Def()); if (pat != null) { Map<String,Object> components = new HashMap<String,Object>(); int j = 0; Object component; component = "target"; if (supportNumberedParameterForNative) components.put(String.valueOf(j++), component); components.put("target", component); { int i = 0; for (Expr e : args) { component = "a" + (i + 1); if (supportNumberedParameterForNative) components.put(String.valueOf(j++), component); // TODO need check components.put(mi.def().formalNames().get(i).name().toString(), component); i++; } } er.dumpRegex("Native", components, tr, pat); } else { w.write("target.$apply("); { int i = 0; for (Expr e : args) { if (i > 0) w.write(", "); w.write("a" + (i + 1)); i++; } } w.write(")"); } w.write(";"); w.allowBreak(0, " "); er.printType(left.type(), PRINT_TYPE_PARAMS); w.write(" neu = ("); er.printType(left.type(), PRINT_TYPE_PARAMS); w.write(") old"); w.write((op == Unary.POST_INC || op == Unary.PRE_INC ? "+" : "-") + "1"); w.write(";"); w.allowBreak(0, " "); w.write("target.set(neu"); { int i = 0; for (Expr e : args) { w.write(", "); w.write("a" + (i + 1)); i++; } } w.write(");"); w.allowBreak(0, " "); w.write("return "); w.write((op == Unary.PRE_DEC || op == Unary.PRE_INC ? "neu" : "old")); w.write(";"); w.allowBreak(0, " "); w.write("}"); w.allowBreak(0, " "); w.write("}.eval("); tr.print(n, target, w); w.write(", "); new Join(er, ", ", args).expand(tr); w.write(")"); return; } } if (l.isNumeric() || l.isBoolean()) { visit((Unary_c) n); return; } Name methodName = X10Unary_c.unaryMethodName(op); if (methodName != null) er.generateStaticOrInstanceCall(n.position(), left, methodName); else throw new InternalCompilerError("No method to implement " + n, n.position()); return; } @Override public void visit(final Closure_c n) { // System.out.println(this + ": " + n.position() + ": " + n + // " captures "+n.closureDef().capturedEnvironment()); Translator tr2 = ((X10Translator) tr).inInnerClass(true); tr2 = tr2.context(n.enterScope(tr2.context())); List<Expander> typeArgs = new ArrayList<Expander>(); for (final Formal f : n.formals()) { TypeExpander ft = new TypeExpander(er, f.type().type(), PRINT_TYPE_PARAMS | BOX_PRIMITIVES); typeArgs.add(ft); // must box formals } boolean runAsync = false; MethodInstance_c mi = (MethodInstance_c) n.methodContainer(); if (mi != null && mi.container().isClass() && mi.container().toClass().fullName().toString().equals("x10.lang.Runtime") && mi.signature().startsWith("runAsync")) { runAsync = true; } TypeExpander ret = new TypeExpander(er, n.returnType().type(), PRINT_TYPE_PARAMS | BOX_PRIMITIVES); if (!n.returnType().type().isVoid()) { typeArgs.add(ret); w.write("new " + X10_FUN_CLASS_PREFIX + "_0_" + n.formals().size()); } else { w.write("new " + X10_VOIDFUN_CLASS_PREFIX + "_0_" + n.formals().size()); } if (typeArgs.size() > 0) { w.write("<"); new Join(er, ", ", typeArgs).expand(tr2); w.write(">"); } w.write("() {"); List<Formal> formals = n.formals(); // bridge boolean bridge = needBridge(n); if (bridge) { w.write("public final "); if (useSelfDispatch && n.returnType().type().isVoid() && n.formals().size() != 0) { w.write(JAVA_LANG_OBJECT); } else { ret.expand(tr2); } w.write(" "); er.printApplyMethodName(n, true); // print the formals w.write("("); for (int i = 0; i < formals.size(); ++i) { if (i != 0) w.write(","); er.printFormal(tr2, n, formals.get(i), true); if (useSelfDispatch) { w.write(", "); w.write(X10_RTT_TYPE); w.write(" "); w.write("t" + (i + 1)); } } w.write(") { "); if (!n.returnType().type().isVoid()) { w.write("return "); } er.printApplyMethodName(n, n.returnType().type().isParameterType()); w.write("("); String delim = ""; for (Formal f : formals) { w.write(delim); delim = ","; if (isPrimitive(f.type().type())) { // TODO:CAST w.write("("); er.printType(f.type().type(), 0); w.write(")"); } w.write(f.name().toString()); } w.write(");"); if (useSelfDispatch && n.returnType().type().isVoid() && n.formals().size() != 0) { w.write("return null;"); } w.write("}"); w.newline(); } w.write("public final "); if (useSelfDispatch && !bridge && n.returnType().type().isVoid() && n.formals().size() != 0) { w.write(JAVA_LANG_OBJECT); } else { er.printType(n.returnType().type(), PRINT_TYPE_PARAMS); } w.write(" "); er.printApplyMethodName(n, n.returnType().type().isParameterType()); w.write("("); for (int i = 0; i < formals.size(); i++) { if (i != 0) w.write(", "); er.printFormal(tr2, n, formals.get(i), false); if (useSelfDispatch && !bridge) { w.write(", "); w.write(X10_RTT_TYPE); w.write(" "); w.write("t" + (i + 1)); } } w.write(")"); // print the closure body w.write(" { "); List<Stmt> statements = n.body().statements(); // boolean throwException = false; // boolean throwThrowable = false; // for (Stmt stmt : statements) { // final List<Type> throwables = getThrowables(stmt); // if (throwables == null) { // continue; // } // for (Type type : throwables) { // if (type != null) { // if (type.isSubtype(tr.typeSystem().Exception(), tr.context()) && // !type.isSubtype(tr.typeSystem().RuntimeException(), tr.context())) { // throwException = true; // } else if (!type.isSubtype(tr.typeSystem().Exception(), tr.context()) // && !type.isSubtype(tr.typeSystem().Error(), tr.context())) { // throwThrowable = true; // } // } // } // } // TODO remove wrapping with UnknownJavaThrowable // TryCatchExpander tryCatchExpander = new TryCatchExpander(w, er, n.body(), null); // if (runAsync) { // tryCatchExpander.addCatchBlock(X10_IMPL_UNKNOWN_JAVA_THROWABLE, "ex", new Expander(er) { // public void expand(Translator tr) { // w.write("x10.lang.Runtime.pushException(ex);"); // } // }); // } // if (throwThrowable) { // tryCatchExpander.addCatchBlock("java.lang.RuntimeException", "ex", // new Expander(er) { // public void expand(Translator tr) { // w.write("throw ex;"); // } // }); // tryCatchExpander.addCatchBlock("java.lang.Error", "er", new // Expander(er) { // public void expand(Translator tr) { // w.write("throw er;"); // } // }); // if (runAsync) { // tryCatchExpander.addCatchBlock("java.lang.Throwable", "t", new // Expander(er) { // public void expand(Translator tr) { // w.write("x10.lang.Runtime.pushException(new " + X10_IMPL_UNKNOWN_JAVA_THROWABLE + "(t));"); // } // }); // } else { // tryCatchExpander.addCatchBlock("java.lang.Throwable", "t", new // Expander(er) { // public void expand(Translator tr) { // w.write("throw new " + X10_IMPL_UNKNOWN_JAVA_THROWABLE + "(t);"); // } // }); // } // tryCatchExpander.expand(tr2); // } // else // if (throwException) { // tryCatchExpander.addCatchBlock("java.lang.RuntimeException", "ex", // new Expander(er) { // public void expand(Translator tr) { // w.write("throw ex;"); // } // }); // // if (runAsync) { // tryCatchExpander.addCatchBlock("java.lang.Exception", "ex", new // Expander(er) { // public void expand(Translator tr) { // w.write("x10.lang.Runtime.pushException(new " + X10_IMPL_UNKNOWN_JAVA_THROWABLE + "(ex));"); // } // }); // } else { // tryCatchExpander.addCatchBlock("java.lang.Exception", "ex", new // Expander(er) { // public void expand(Translator tr) { // w.write("throw new " + X10_IMPL_UNKNOWN_JAVA_THROWABLE + "(ex);"); // } // }); // } // tryCatchExpander.expand(tr2); // } else // // TODO remove wrapping with UnknownJavaThrowable // if (runAsync) // tryCatchExpander.expand(tr2); // else er.prettyPrint(n.body(), tr2); if (useSelfDispatch && !bridge && n.returnType().type().isVoid() && n.formals().size() != 0) { w.write("return null;"); } w.write("}"); w.newline(); Type type = n.type(); type = Types.baseType(type); if (type.isClass()) { X10ClassType ct = type.toClass(); X10ClassDef def = ct.x10Def(); // XTENLANG-1102 Set<ClassDef> visited = CollectionFactory.newHashSet(); visited = CollectionFactory.newHashSet(); visited.add(def); if (!def.flags().isInterface()) { List<Type> types = new ArrayList<Type>(); LinkedList<Type> worklist = new LinkedList<Type>(); for (Type t : def.asType().interfaces()) { Type it = Types.baseType(t); worklist.add(it); } while (!worklist.isEmpty()) { Type it = worklist.removeFirst(); if (it.isClass()) { X10ClassType ct2 = it.toClass(); X10ClassDef idef = ct2.x10Def(); if (visited.contains(idef)) continue; visited.add(idef); for (Type t : ct2.interfaces()) { Type it2 = Types.baseType(t); worklist.add(it2); } if (ct2.typeArguments() != null) types.addAll(ct2.typeArguments()); } } // To extend Any, the type requires getRTT even if it has no type params (e.g. VoidFun_0_0). // if (types.size() > 0) { w.write("public x10.rtt.RuntimeType<?> " + GETRTT_NAME + "() { return " + RTT_NAME + "; }"); w.write("public x10.rtt.Type<?> " + GETPARAM_NAME + "(int i) {"); for (int i = 0; i < types.size(); i++) { w.write("if (i ==" + i + ")"); Type t = types.get(i); w.write(" return "); new RuntimeTypeExpander(er, t).expand(); w.write(";"); } w.write("return null;"); w.newline(); w.write("}"); w.newline(); // } } } w.write("}"); } private boolean needBridge(final Closure_c n) { return containsPrimitive(n) || !n.returnType().type().isVoid() && !n.returnType().type().isParameterType(); } // private boolean throwException(List<Stmt> statements) { // for (Stmt stmt : statements) { // final List<Type> exceptions = getThrowables(stmt); // if (exceptions == null) { // continue; // } // for (Type type : exceptions) { // if (type != null) { // if (type.isSubtype(tr.typeSystem().Exception(), tr.context()) && // !type.isSubtype(tr.typeSystem().RuntimeException(), tr.context())) { // return true; // } else if (!type.isSubtype(tr.typeSystem().Exception(), tr.context()) && // !type.isSubtype(tr.typeSystem().Error(), tr.context())) { // return true; // } // } // } // } // return false; // } // private static List<Type> getThrowables(Stmt stmt) { // final List<Type> throwables = new ArrayList<Type>(); // stmt.visit( // new NodeVisitor() { // @Override // public Node leave(Node old, Node n, NodeVisitor v) { // /* if (n instanceof X10Call_c) { // List<Type> throwTypes = ((X10Call_c) n).methodInstance().throwTypes(); // if (throwTypes != null) throwables.addAll(throwTypes); // } // if (n instanceof Throw) { // throwables.add(((Throw) n).expr().type()); // } // if (n instanceof X10New_c) { // List<Type> throwTypes = ((X10New_c) n).procedureInstance().throwTypes(); // if (throwTypes != null) throwables.addAll(throwTypes); // } // */ // return n; // } // }); // return throwables; // } private boolean containsPrimitive(Closure_c n) { Type t = n.returnType().type(); if (isPrimitive(t)) { return true; } for (Formal f : n.formals()) { Type type = f.type().type(); if (isPrimitive(type)) { return true; } } return false; } @Override public void visit(ClosureCall_c c) { Expr target = c.target(); Type targetType = target.type(); boolean base = false; TypeSystem xts = targetType.typeSystem(); MethodInstance mi = c.closureInstance(); Expr expr = target; if (target instanceof ParExpr) { expr = ((ParExpr) target).expr(); } boolean newClosure = expr instanceof Closure_c; if (!newClosure) { // TODO:CAST w.write("("); w.write("("); er.printType(mi.container(), PRINT_TYPE_PARAMS); w.write(")"); if (xts.isParameterType(targetType)) { w.write(X10_RTT_TYPES); w.write(".conversion("); new RuntimeTypeExpander(er, Types.baseType(mi.container())).expand(tr); w.write(","); c.printSubExpr(target, w, tr); w.write(")"); } else { c.printSubExpr(target, w, tr); } w.write(")"); } else { c.printSubExpr(target, w, tr); } w.write("."); er.printApplyMethodName(mi, newClosure); // print the argument list w.write("("); w.begin(0); for (Iterator<Type> i = mi.typeParameters().iterator(); i.hasNext();) { final Type at = i.next(); new RuntimeTypeExpander(er, at).expand(tr); if (i.hasNext() || c.arguments().size() > 0) { w.write(","); w.allowBreak(0, " "); } } List<Expr> l = c.arguments(); for (int i = 0; i < l.size(); i++) { Expr e = l.get(i); Type castType = mi.formalTypes().get(i); Type defType = mi.def().formalTypes().get(i).get(); boolean closeParen = false; if (isString(e.type()) && !isString(castType)) { w.write("("); er.printType(castType, 0); w.write(")"); if (xts.isParameterType(castType)) { w.write(X10_RTT_TYPES); w.write(".conversion("); new RuntimeTypeExpander(er, Types.baseType(castType)).expand(tr); w.write(","); closeParen = true; } } if (!isBoxedType(e.type()) /*&& isBoxedType(defType)*/) { // primitives need to be boxed er.printBoxConversion(e.type()); w.write("("); closeParen = true; } c.print(e, w, tr); if (isMutableStruct(e.type())) { w.write(".clone()"); } if (closeParen) { w.write(")"); } if (useSelfDispatch && (!newClosure || !needBridge((Closure_c) expr))) { w.write(","); new RuntimeTypeExpander(er, mi.formalTypes().get(i)).expand(); } if (i != l.size() - 1) { w.write(","); w.allowBreak(0, " "); } } w.end(); w.write(")"); } @Override public void visit(StmtExpr_c n) { final Context c = tr.context(); final ArrayList<LocalInstance> capturedVars = new ArrayList<LocalInstance>(); // This visitor (a) finds all captured local variables, // (b) adds a qualifier to every "this", and // (c) rewrites fields and calls to use an explicit "this" target. n = (StmtExpr_c) n.visit(new ContextVisitor(tr.job(), tr.typeSystem(), tr.nodeFactory()) { public Node leaveCall(Node n) { if (n instanceof Local) { Local l = (Local) n; assert (l.name() != null) : l.position().toString(); VarInstance<?> found = c.findVariableSilent(l.name().id()); if (found != null) { VarInstance<?> local = context().findVariableSilent(l.name().id()); if (found.def() == local.def()) { assert (found.def() == l.localInstance().def()) : l.toString(); capturedVars.add(l.localInstance()); } } } if (n instanceof Field_c) { Field_c f = (Field_c) n; return f.target(f.target()).targetImplicit(false); } if (n instanceof X10Call_c) { X10Call_c l = (X10Call_c) n; return l.target(l.target()).targetImplicit(false); } if (n instanceof Special_c) { NodeFactory nf = nodeFactory(); Special_c s = (Special_c) n; if (s.qualifier() == null) { return s.qualifier(nf.CanonicalTypeNode(n.position(), s.type())); } } return n; } }.context(c.pushBlock())); /* * N.B. this is workaround for front-end bug that generates non-final variable access * in the body of statement expression when constructor splitting is enabled. */ if (supportConstructorSplitting && config.OPTIMIZE && config.SPLIT_CONSTRUCTORS) { w.write("(new " + JAVA_IO_SERIALIZABLE + "() { "); er.printType(n.type(), PRINT_TYPE_PARAMS); w.write(" eval("); String delim = null; for (LocalInstance li : capturedVars) { if (!li.flags().isFinal()) { if (delim == null) { delim = ","; } else { w.write(","); } w.write("final "); er.printType(li.type(), PRINT_TYPE_PARAMS); w.write(" "); w.write(Emitter.mangleToJava(li.name())); // System.err.println("Bad statement expression: " + n + // " at " // + n.position()); // DEBUG // n.dump(System.err); // DEBUG // throw new // InternalCompilerError("Statement expression uses non-final variable " // + li + "(at " // + li.position() + ") from the outer scope", // n.position()); } } w.write(") {"); w.newline(4); w.begin(0); Translator tr = this.tr.context(c.pushBlock()); List<Stmt> statements = n.statements(); for (Stmt stmt : statements) { tr.print(n, stmt, w); w.newline(); } w.write("return "); tr.print(n, n.result(), w); w.write(";"); w.end(); w.newline(); w.write("} }.eval("); delim = null; for (LocalInstance li : capturedVars) { if (!li.flags().isFinal()) { if (delim == null) { delim = ","; } else { w.write(","); } w.write(Emitter.mangleToJava(li.name())); } } w.write("))"); return; } for (LocalInstance li : capturedVars) { if (!li.flags().isFinal()) { System.err.println("Bad statement expression: " + n + " at " + n.position()); // DEBUG n.dump(System.err); // DEBUG throw new InternalCompilerError("Statement expression uses non-final variable " + li + "(at " + li.position() + ") from the outer scope", n.position()); } } w.write("(new " + JAVA_IO_SERIALIZABLE + "() { "); er.printType(n.type(), PRINT_TYPE_PARAMS); w.write(" eval() {"); w.newline(4); w.begin(0); Translator tr = this.tr.context(c.pushBlock()); List<Stmt> statements = n.statements(); for (Stmt stmt : statements) { tr.print(n, stmt, w); w.newline(); } w.write("return "); tr.print(n, n.result(), w); w.write(";"); w.end(); w.newline(); w.write("} }.eval())"); } // //////////////////////////////// // end of Expr // //////////////////////////////// @Override public void visit(FieldDecl_c n) { Flags flags; if (!n.flags().flags().isStatic()) { flags = n.flags().flags().clearFinal(); } else { flags = n.flags().flags(); } flags = flags.retainJava(); // ensure that X10Flags are not printed out // .. javac will not know what to do with // them. FieldDecl_c javaNode = (FieldDecl_c) n.flags(n.flags().flags(flags)); // same with FiledDecl_c#prettyPrint(CodeWriter w, PrettyPrinter tr) FieldDef fieldDef = javaNode.fieldDef(); boolean isInterface = fieldDef != null && fieldDef.container() != null && fieldDef.container().get().toClass().flags().isInterface(); Flags f = javaNode.flags().flags(); if (isInterface) { f = f.clearPublic(); f = f.clearStatic(); f = f.clearFinal(); } w.write(f.translateJava()); er.printType(javaNode.type().type(), PRINT_TYPE_PARAMS); // tr.print(javaNode, javaNode.type(), w); w.write(" "); tr.print(javaNode, javaNode.name(), w); if (javaNode.init() != null) { w.write(" = "); // X10 unique er.coerce(javaNode, javaNode.init(), javaNode.type().type()); } w.write(";"); } @Override public void visit(Formal_c f) { if (f.name().id().toString().equals("")) f = (Formal_c) f.name(f.name().id(Name.makeFresh("a"))); f.translate(w, tr); } @Override public void visit(X10MethodDecl_c n) { // should be able to assert n.name() is not typeName here, once we stop generating such decls somewhere in the frontend... if (er.printMainMethod(n)) { return; } er.generateMethodDecl(n, false); } // //////////////////////////////// // Stmt // //////////////////////////////// public static void catchAndThrowAsX10Exception(CodeWriter w) { String TEMPORARY_EXCEPTION_VARIABLE_NAME = Name.makeFresh("exc$").toString(); w.writeln("catch (" + JAVA_LANG_THROWABLE + " " + TEMPORARY_EXCEPTION_VARIABLE_NAME + ") {"); w.writeln("throw " + X10_RUNTIME_IMPL_JAVA_THROWABLEUTILS + "." + ENSURE_X10_EXCEPTION + "(" + TEMPORARY_EXCEPTION_VARIABLE_NAME + ");"); w.writeln("}"); } @Override public void visit(Block_c n) { String s = Emitter.getJavaImplForStmt(n, tr.typeSystem()); if (s != null) { w.write("try {"); // XTENLANG-2686: handle Java exceptions inside @Native block w.write(s); w.write("}"); // XTENLANG-2686 catchAndThrowAsX10Exception(w); // XTENLANG-2686 } else { n.translate(w, tr); } } @Override public void visit(StmtSeq_c n) { n.translate(w, tr); } @Override public void visit(SwitchBlock_c n) { n.translate(w, tr); } @Override public void visit(Assert_c n) { if (!tr.job().extensionInfo().getOptions().assertions) return; if (useJavaAssertion) { n.translate(w, tr); } else { Expr cond = ((Assert_c) n).cond(); Expr errorMessage = ((Assert_c) n).errorMessage(); w.write("if (!" + X10_RUNTIME_IMPL_JAVA_RUNTIME + ".DISABLE_ASSERTIONS && "); w.write("!("); tr.print(n, cond, w); w.write(")"); w.write(") {"); w.write("throw new x10.lang.AssertionError("); if (errorMessage != null) { w.write("java.lang.String.valueOf("); tr.print(n, errorMessage, w); w.write(")"); } w.write(");"); w.write("}"); } } @Override public void visit(AssignPropertyCall_c n) { // TODO: initialize properties in the Java constructor List<X10FieldInstance> definedProperties = n.properties(); List<Expr> arguments = n.arguments(); int aSize = arguments.size(); assert (definedProperties.size() == aSize); for (int i = 0; i < aSize; i++) { Expr arg = arguments.get(i); X10FieldInstance fi = definedProperties.get(i); w.write("this."); w.write(Emitter.mangleToJava(fi.name())); w.write(" = "); er.coerce(n, arg, fi.type()); w.write(";"); w.newline(); } } @Override public void visit(Branch_c n) { n.translate(w, tr); } @Override public void visit(Case_c n) { n.translate(w, tr); } @Override public void visit(Catch_c n) { w.write("catch ("); n.printBlock(n.formal(), w, tr); w.write(")"); n.printSubStmt(n.body(), w, tr); } @Override public void visit(X10ConstructorCall_c c) { ContainerType ct = c.constructorInstance().container(); if (isSplittable(ct) || ct.name().toString().startsWith(ClosureRemover.STATIC_NESTED_CLASS_BASE_NAME) // is this needed? ) { TypeSystem ts = tr.typeSystem(); Expr target = c.target(); if (target == null || target instanceof Special) { if (c.kind() == ConstructorCall.SUPER) { if (Emitter.isNativeRepedToJava(ct) || Emitter.isNativeClassToJava(ct)) { return; } w.write("/*super.*/"); } else { w.write("/*this.*/"); } } else { if (c.kind() == ConstructorCall.SUPER) { target.translate(w, tr); w.write("."); // invoke constructor for non-virtual call directly String ctorName = CONSTRUCTOR_METHOD_NAME(ct.toClass().def()); w.write(ctorName); printConstructorArgumentList(c, c, c.constructorInstance(), null, false); w.write(";"); return; } target.translate(w, tr); w.write("."); } w.write(CONSTRUCTOR_METHOD_NAME(ct.toClass().def())); printConstructorArgumentList(c, c, c.constructorInstance(), null, false); w.write(";"); return; } printConstructorCallForJavaCtor(c); } private void printConstructorCallForJavaCtor(X10ConstructorCall_c c) { if (c.qualifier() != null) { tr.print(c, c.qualifier(), w); w.write("."); } w.write(c.kind() == ConstructorCall.THIS ? "this" : "super"); printConstructorArgumentList(c, c, c.constructorInstance(), null, true); w.write(";"); } private void printConstructorArgumentList(Node_c c, X10ProcedureCall p, X10ConstructorInstance mi, Type type, boolean forceParams) { w.write("("); w.begin(0); if (forceParams) { X10ClassType ct = mi.container().toClass(); List<Type> ta = ct.typeArguments(); boolean isJavaNative = type != null ? Emitter.isNativeRepedToJava(type) : false; if (ta != null && ta.size() > 0 && !isJavaNative) { printArgumentsForTypeParams(ta, p.arguments().size() == 0); } } List<Expr> l = p.arguments(); for (int i = 0; i < l.size(); i++) { Expr e = l.get(i); if (i < mi.formalTypes().size()) { // FIXME This is a workaround Type castType = mi.formalTypes().get(i); Type defType = mi.def().formalTypes().get(i).get(); TypeSystem xts = tr.typeSystem(); if (isString(e.type()) && !isString(castType)) { w.write("("); er.printType(castType, 0); w.write(")"); if (xts.isParameterType(castType)) { w.write(X10_RTT_TYPES); w.write(".conversion("); new RuntimeTypeExpander(er, Types.baseType(castType)).expand(tr); w.write(","); } else { w.write("("); } c.print(e, w, tr); w.write(")"); } else if (useSelfDispatch && !castType.typeEquals(e.type(), tr.context())) { w.write("("); if (needExplicitBoxing(e.type()) && isBoxedType(defType)) { er.printBoxConversion(e.type()); } else { // TODO:CAST w.write("("); // XTENLANG-2895 use erasure to implement co/contra-variance of function type er.printType(castType, xts.isFunctionType(castType) ? 0 : PRINT_TYPE_PARAMS); w.write(")"); } w.write("("); // printBoxConvesion assumes parentheses around expression c.print(e, w, tr); w.write(")"); w.write(")"); } else { if (needExplicitBoxing(castType) && defType.isParameterType()) { er.printBoxConversion(castType); w.write("("); c.print(e, w, tr); w.write(")"); } else { c.print(e, w, tr); } } } else { c.print(e, w, tr); } if (isMutableStruct(e.type())) { w.write(".clone()"); } if (i != l.size() - 1) { w.write(","); w.allowBreak(0, " "); } } printExtraArgments(mi); w.end(); w.write(")"); } @Override public void visit(Empty_c n) { n.translate(w, tr); } @Override public void visit(Eval_c n) { boolean semi = tr.appendSemicolon(true); Expr expr = n.expr(); // XTENLANG-2000 if (expr instanceof X10Call) { // support for back-end method inlining if (er.isMethodInlineTarget(tr.typeSystem(), ((X10Call) expr).target().type()) && ((X10Call) expr).methodInstance().name() == ClosureCall.APPLY) { w.write(X10_RUNTIME_IMPL_JAVA_EVALUTILS + ".eval("); n.print(expr, w, tr); w.write(")"); } else if (er.isMethodInlineTarget(tr.typeSystem(), ((X10Call) expr).target().type()) && ((X10Call) expr).methodInstance().name() == SettableAssign.SET) { n.print(expr, w, tr); } // support for @Native else if (!expr.type().isVoid() && Emitter.getJavaImplForDef(((X10Call) expr).methodInstance().x10Def()) != null) { w.write(X10_RUNTIME_IMPL_JAVA_EVALUTILS + ".eval("); n.print(expr, w, tr); w.write(")"); } else { n.print(expr, w, tr); } } // when expr is StatementExpression(Assignment || // [Pre/Post][De/In]crementExpression || MethodInvocation || // ClassInstanceCreationExpression) else if (expr instanceof ClosureCall || expr instanceof Assign || expr instanceof Unary || expr instanceof X10New) { n.print(expr, w, tr); } // not a legal java statement else { w.write(X10_RUNTIME_IMPL_JAVA_EVALUTILS + ".eval("); n.print(expr, w, tr); w.write(")"); } if (semi) { w.write(";"); } tr.appendSemicolon(semi); } @Override public void visit(If_c n) { n.translate(w, tr); } @Override public void visit(Labeled_c n) { Stmt statement = n.statement(); if (statement instanceof Block_c) { w.write(n.labelNode() + ": "); w.write("{"); Block_c block = (Block_c) statement; for (Stmt s : block.statements()) { tr.print(n, s, w); } w.write("}"); } else { w.write(n.labelNode() + ": "); tr.print(n, statement, w); } } @Override public void visit(X10LocalDecl_c n) { // same with FieldDecl_c#prettyPrint(CodeWriter w, PrettyPrinter tr) boolean printSemi = tr.appendSemicolon(true); boolean printType = tr.printType(true); tr.print(n, n.flags(), w); if (printType) { if (supportTypeConstraintsWithErasure) { er.printType(n.type().type(), 0); } else tr.print(n, n.type(), w); w.write(" "); } tr.print(n, n.name(), w); if (n.init() != null) { w.write(" ="); w.allowBreak(2, " "); // X10 unique er.coerce(n, n.init(), n.type().type()); if (isMutableStruct(n.type().type())) { w.write(".clone()"); } } // assign default value for access vars in at or async else if (!n.flags().flags().isFinal()) { Type type = Types.baseType(n.type().type()); TypeSystem xts = tr.typeSystem(); w.write(" ="); w.allowBreak(2, " "); if (xts.isBoolean(type)) { w.write(" false"); } else if (!xts.isParameterType(type) && (xts.isChar(type) || xts.isNumeric(type))) { w.write(" 0"); } else { w.write(" null"); } } if (printSemi) { w.write(";"); } tr.printType(printType); tr.appendSemicolon(printSemi); } @Override public void visit(LocalTypeDef_c n) { n.translate(w, tr); } @Override public void visit(Loop_c n) { n.translate(w, tr); } @Override public void visit(Return_c n) { n.translate(w, tr); } @Override public void visit(Switch_c n) { n.translate(w, tr); } @Override public void visit(Throw_c n) { n.translate(w, tr); } @Override public void visit(Try_c c) { TryCatchExpander expander = new TryCatchExpander(w, er, c.tryBlock(), c.finallyBlock()); final List<Catch> catchBlocks = c.catchBlocks(); boolean isConstrainedThrowableCaught = false; // XTENLANG-2384 for (int i = 0; i < catchBlocks.size(); ++i) { Type type = catchBlocks.get(i).catchType(); if (type instanceof ConstrainedType) // XTENLANG-2384: Check if there is a constained type in catchBlocks isConstrainedThrowableCaught = true; } // XTENLANG-2384: If there is a constrained type, generate if sequence instead of catch sequence if (isConstrainedThrowableCaught) { final String temp = "$ex"; int convRequired = 0; expander.addCatchBlock(JAVA_LANG_THROWABLE, temp, new Expander(er) { public void expand(Translator tr) { w.newline(); for (int i = 0; i < catchBlocks.size(); ++i) { Catch cb = catchBlocks.get(i); Type type = cb.catchType(); w.write("if (" + temp + " instanceof "); er.printType(type, 0); if (type instanceof ConstrainedType) { ConstrainedType ctype = (ConstrainedType)type; //w.write(" && true/* Constraint condition check */"); // TODO: add constraint check here } w.write(")"); w.newline(); cb.body().translate(w, tr); w.write("else "); w.newline(); } // should not come here w.write("{ "+ temp + ".printStackTrace(); assert false; }"); w.newline(); } }); } else { // XTENLANG-2384: Normal case, no constrained type in catchBlocks final String temp = "$ex"; for (int i = 0; i < catchBlocks.size(); ++i) { Catch catchBlock = catchBlocks.get(i); expander.addCatchBlock(catchBlock); } } expander.expand(tr); } // //////////////////////////////// // end of Stmt // //////////////////////////////// @Override public void visit(CanonicalTypeNode_c n) { Type t = n.type(); if (t != null) er.printType(t, PRINT_TYPE_PARAMS); else // WARNING: it's important to delegate to the appropriate visit() // here! visit((Node) n); } @Override public void visit(TypeDecl_c n) { // Do not write anything. return; } @Override public void visit(Id_c n) { w.write(Emitter.mangleToJava(n.id())); } public static boolean isString(Type type) { return Types.baseType(type).isString(); } public static boolean isIndexedMemoryChunk(Type type) { return Types.baseType(type).isIndexedMemoryChunk(); } // TODO consolidate isPrimitive(Type) and needExplicitBoxing(Type). public static boolean isPrimitive(Type t) { return t.isBoolean() || t.isChar() || t.isNumeric(); } public static boolean isSpecialType(Type type) { return isPrimitive(Types.baseType(type)); } /** * Returns true if the method does not satisfy the boxing rules. * The currently existing example is Java array access methods, which are declared as generic methods, * but are implemented without boxing using @Native snippets. * @param mi - MethodInstance * @return true if method should be treated specially wrt argument and return value boxing. */ public static boolean isPrimitiveGenericMethod(MethodInstance mi) { QName fullName = mi.container().fullName(); if (fullName.toString().equals("x10.interop.Java.array")) return true; if (exposeSpecialDispatcherThroughSpecialInterface) { Name name = mi.name(); List<LocalInstance> formalNames = mi.formalNames(); if (fullName.equals(Emitter.X10_LANG_ARITHMETIC)) { // dispatch method ($G->$I etc.) if (formalNames != null && formalNames.size() == 1 && (OperatorNames.PLUS.equals(name) || OperatorNames.MINUS.equals(name) || OperatorNames.STAR.equals(name) || OperatorNames.SLASH.equals(name))) return true; } else if (fullName.equals(Emitter.X10_LANG_BITWISE)) { // dispatch method ($G->$I etc.) if (formalNames != null && formalNames.size() == 1 && (OperatorNames.AMPERSAND.equals(name) || OperatorNames.BAR.equals(name) || OperatorNames.CARET.equals(name))) return true; } else if (fullName.equals(Emitter.X10_LANG_REDUCIBLE)) { // dispatch method ($G->$I etc.) if (formalNames != null && formalNames.size() == 2 && (OperatorNames.APPLY.equals(name))) return true; } else if (fullName.equals(Emitter.X10_LANG_ITERATOR)) { // special return type ($G->$O) if ((formalNames == null || formalNames.size() == 0) && ("next".equals(name.toString()))) return true; } else if (fullName.equals(Emitter.X10_LANG_SEQUENCE)) { // special return type ($G->$O) if (formalNames != null && formalNames.size() == 1 && (OperatorNames.APPLY.equals(name))) return true; } } return false; } public static boolean isSpecialTypeForDispatcher(Type type) { // XTENLANG-2993 return isSpecialType(type) || type.isVoid(); } public static boolean hasParams(Type t) { Type bt = Types.baseType(t); TypeSystem ts = bt.typeSystem(); return (bt.isClass() && !ts.isJavaArray(bt) && bt.toClass().hasParams()); } public static boolean containsTypeParam(List<Ref<? extends Type>> list) { for (Ref<? extends Type> ref : list) { if (Emitter.containsTypeParam(ref.get())) { return true; } } return false; } private final static class ConstructorIdTypeForAnnotation extends X10ParsedClassType_c { private static final long serialVersionUID = 1L; private int i = -1; private ConstructorIdTypeForAnnotation(X10ClassDef def) { super(def); } private ConstructorIdTypeForAnnotation setIndex(int i) { assert i > -1; this.i = i; return this; } private int getIndex() { return i; } } } // end of X10PrettyPrinterVisitor