/*
* 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.emitter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import polyglot.ast.Binary;
import polyglot.ast.Block;
import polyglot.ast.Block_c;
import polyglot.ast.Call;
import polyglot.ast.Cast;
import polyglot.ast.ClassMember;
import polyglot.ast.ConstructorCall;
import polyglot.ast.Expr;
import polyglot.ast.Field;
import polyglot.ast.Field_c;
import polyglot.ast.Formal;
import polyglot.ast.Id;
import polyglot.ast.Instanceof;
import polyglot.ast.Lit;
import polyglot.ast.Local;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.Node_c;
import polyglot.ast.Receiver;
import polyglot.ast.Stmt;
import polyglot.ast.TypeNode;
import polyglot.ast.Typed;
import polyglot.ast.Unary;
import polyglot.types.ClassType;
import polyglot.types.ContainerType;
import polyglot.types.Context;
import polyglot.types.Def;
import polyglot.types.Flags;
import polyglot.types.MethodDef;
import polyglot.types.Name;
import polyglot.types.NullType;
import polyglot.types.QName;
import polyglot.types.Ref;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.TypeSystem_c;
import polyglot.types.Types;
import polyglot.util.CodeWriter;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import polyglot.util.StringUtil;
import polyglot.visit.Translator;
import x10.X10CompilerOptions;
import x10.ast.ClosureCall;
import x10.ast.Closure_c;
import x10.ast.DepParameterExpr;
import x10.ast.OperatorNames;
import x10.ast.ParExpr_c;
import x10.ast.PropertyDecl;
import x10.ast.SettableAssign;
import x10.ast.TypeParamNode;
import x10.ast.X10Call;
import x10.ast.X10Call_c;
import x10.ast.X10CanonicalTypeNode;
import x10.ast.X10ClassDecl;
import x10.ast.X10ClassDecl_c;
import x10.ast.X10ConstructorDecl;
import x10.ast.X10MethodDecl_c;
import x10.ast.X10New_c;
import x10.ast.X10NodeFactory_c;
import x10.config.ConfigurationError;
import x10.config.OptionError;
import x10.constraint.XVar;
import x10.extension.X10Ext;
import x10.types.ConstrainedType;
import x10.types.FunctionType;
import x10.types.MacroType;
import x10.types.MethodInstance;
import x10.types.ParameterType;
import x10.types.X10ClassDef;
import x10.types.X10ClassType;
import x10.types.X10ConstructorInstance;
import x10.types.X10Def;
import x10.types.X10MethodDef;
import x10.types.X10ParsedClassType_c;
import x10.types.X10TypeEnv;
import x10.types.constants.ConstantValue;
import x10.types.constants.StringValue;
import x10.types.constraints.TypeConstraint;
import x10.util.AnnotationUtils;
import x10.util.CollectionFactory;
import x10.util.HierarchyUtils;
import x10.visit.ChangePositionVisitor;
import x10.visit.X10PrettyPrinterVisitor;
import x10c.types.BackingArrayType;
import x10c.visit.ClosureRemover;
import x10c.visit.StaticInitializer;
// static methods
import static x10.visit.X10PrettyPrinterVisitor.hasParams;
import static x10.visit.X10PrettyPrinterVisitor.isBoxedType;
import static x10.visit.X10PrettyPrinterVisitor.isIndexedMemoryChunk;
import static x10.visit.X10PrettyPrinterVisitor.isPrimitive;
import static x10.visit.X10PrettyPrinterVisitor.isPrimitiveGenericMethod;
import static x10.visit.X10PrettyPrinterVisitor.isSpecialType;
import static x10.visit.X10PrettyPrinterVisitor.isSpecialTypeForDispatcher;
import static x10.visit.X10PrettyPrinterVisitor.isString;
import static x10.visit.X10PrettyPrinterVisitor.needExplicitBoxing;
// constants
import static x10.visit.X10PrettyPrinterVisitor.BOX_PRIMITIVES;
import static x10.visit.X10PrettyPrinterVisitor.NO_QUALIFIER;
import static x10.visit.X10PrettyPrinterVisitor.NO_VARIANCE;
import static x10.visit.X10PrettyPrinterVisitor.PRINT_TYPE_PARAMS;
public class Emitter {
private static final String RETURN_PARAMETER_TYPE_SUFFIX = "$G";
private static final String RETURN_SPECIAL_TYPE_SUFFIX = "$O";
// XTENLANG-2463
private static final boolean mangleTypeVariable = true;
private static final String PARAMETER_TYPE_PREFIX = "$";
private static final String UNSIGNED_NUMERIC_TYPE_SUFFIX = "$u";
private static String FORMAL_MARKER(int i) {
return "__" + i;
}
public static final String NATIVE_ANNOTATION_BOXED_REP_SUFFIX = "$box";
public static final String NATIVE_ANNOTATION_RUNTIME_TYPE_SUFFIX = "$rtt";
// WIP XTENLANG-2680
// public static final boolean supportNativeMethodDecl = false;
public static final boolean supportNativeMethodDecl = true;
private static final String JAVA_KEYWORD_PREFIX = "kwd_";
private static final Set<String> JAVA_KEYWORDS = CollectionFactory.newHashSet(
Arrays.asList(new String[]{
"abstract", "default", "if", "private", "this",
"boolean", "do", "implements", "protected", "throw",
"break", "double", "import", "public", "throws",
"byte", "else", "instanceof", "return", "transient",
"case", "extends", "int", "short", "try",
"catch", "final", "interface", "static", "void",
"char", "finally", "long", "strictfp", "volatile",
"class", "float", "native", "super", "while",
"const", "for", "new", "switch",
"continue", "goto", "package", "synchronized",
"null", "true", "false",
// X10 implementation names
"serialVersionUID",
"x10", "java", // XTENLANG-2438
// X10 implementation names (rename is not needed since they include reserved character $)
// X10PrettyPrinterVisitor.GETRTT_NAME, X10PrettyPrinterVisitor.RTT_NAME, X10PrettyPrinterVisitor.GETPARAM_NAME,
}
)
);
CodeWriter w;
Translator tr;
public Emitter(CodeWriter w, Translator tr) {
this.w=w;
this.tr=tr;
}
private static final String[] NON_PRINTABLE = {
/* 000 */ "$NUL$",
/* 001 */ "$SOH$",
/* 002 */ "$STX$",
/* 003 */ "$ETX$",
/* 004 */ "$EOT$",
/* 005 */ "$ENQ$",
/* 006 */ "$ACK$",
/* 007 */ "$BEL$",
/* 008 */ "$BS$",
/* 009 */ "$HT$",
/* 010 */ "$LF$",
/* 011 */ "$VT$",
/* 012 */ "$FF$",
/* 013 */ "$CR$",
/* 014 */ "$SO$",
/* 015 */ "$SI$",
/* 016 */ "$DLE$",
/* 017 */ "$DC1$",
/* 018 */ "$DC2$",
/* 019 */ "$DC3$",
/* 020 */ "$DC4$",
/* 021 */ "$NAK$",
/* 022 */ "$SYN$",
/* 023 */ "$ETB$",
/* 024 */ "$CAN$",
/* 025 */ "$EM$",
/* 026 */ "$SUB$",
/* 027 */ "$ESC$",
/* 028 */ "$FS$",
/* 029 */ "$GS$",
/* 030 */ "$RS$",
/* 031 */ "$US$",
/* 032 */ "$SPACE$",
/* 033 */ "$EXCLAMATION$",
/* 034 */ "$QUOTE$",
/* 035 */ "$HASH$",
/* 036 */ null,
/* 037 */ "$PERCENT$",
/* 038 */ "$AMPERSAND$",
/* 039 */ "$APOSTROPHE$",
/* 040 */ "$LPAREN$",
/* 041 */ "$RPAREN$",
/* 042 */ "$STAR$",
/* 043 */ "$PLUS$",
/* 044 */ "$COMMA$",
/* 045 */ "$MINUS$",
/* 046 */ "$DOT$",
/* 047 */ "$SLASH$",
/* 048 */ "$ZERO$",
/* 049 */ "$ONE$",
/* 050 */ "$TWO$",
/* 051 */ "$THREE$",
/* 052 */ "$FOUR$",
/* 053 */ "$FIVE$",
/* 054 */ "$SIX$",
/* 055 */ "$SEVEN$",
/* 056 */ "$EIGHT$",
/* 057 */ "$NINE$",
/* 058 */ "$COLON$",
/* 059 */ "$SEMICOLON$",
/* 060 */ "$LT$",
/* 061 */ "$EQ$",
/* 062 */ "$GT$",
/* 063 */ "$QUESTION$",
/* 064 */ "$AT$",
/* 065 */ null,
/* 066 */ null,
/* 067 */ null,
/* 068 */ null,
/* 069 */ null,
/* 070 */ null,
/* 071 */ null,
/* 072 */ null,
/* 073 */ null,
/* 074 */ null,
/* 075 */ null,
/* 076 */ null,
/* 077 */ null,
/* 078 */ null,
/* 079 */ null,
/* 080 */ null,
/* 081 */ null,
/* 082 */ null,
/* 083 */ null,
/* 084 */ null,
/* 085 */ null,
/* 086 */ null,
/* 087 */ null,
/* 088 */ null,
/* 089 */ null,
/* 090 */ null,
/* 091 */ "$LBRACKET$",
/* 092 */ "$BACKSLASH$",
/* 093 */ "$RBRACKET$",
/* 094 */ "$CARET$",
/* 095 */ null,
/* 096 */ "$BACKQUOTE$",
/* 097 */ null,
/* 098 */ null,
/* 099 */ null,
/* 100 */ null,
/* 101 */ null,
/* 102 */ null,
/* 103 */ null,
/* 104 */ null,
/* 105 */ null,
/* 106 */ null,
/* 107 */ null,
/* 108 */ null,
/* 109 */ null,
/* 110 */ null,
/* 111 */ null,
/* 112 */ null,
/* 113 */ null,
/* 114 */ null,
/* 115 */ null,
/* 116 */ null,
/* 117 */ null,
/* 118 */ null,
/* 119 */ null,
/* 120 */ null,
/* 121 */ null,
/* 122 */ null,
/* 123 */ "$LBRACE$",
/* 124 */ "$BAR$",
/* 125 */ "$RBRACE$",
/* 126 */ "$TILDE$",
/* 127 */ "$DEL$",
};
private static String translateChar(char c) {
if (c > 127) {
StringBuilder sb = new StringBuilder("\\u");
sb.append(Integer.toHexString(c));
return sb.toString();
}
String s = NON_PRINTABLE[c];
if (s != null) {
return s;
}
return ""+c;
}
private static final Map<Name,Name> MANGLED_OPERATORS = CollectionFactory.newHashMap();
static {
Map<Name,Name> map = MANGLED_OPERATORS;
map.put(OperatorNames.AS, Name.make("$convert"));
map.put(OperatorNames.IMPLICIT_AS, Name.make("$implicit_convert"));
map.put(OperatorNames.SET, Name.make("$set"));
map.put(OperatorNames.APPLY, Name.make("$apply"));
map.put(OperatorNames.PLUS, Name.make("$plus"));
map.put(OperatorNames.MINUS, Name.make("$minus"));
map.put(OperatorNames.STAR, Name.make("$times"));
map.put(OperatorNames.SLASH, Name.make("$over"));
map.put(OperatorNames.PERCENT, Name.make("$percent"));
map.put(OperatorNames.LT, Name.make("$lt"));
map.put(OperatorNames.GT, Name.make("$gt"));
map.put(OperatorNames.LE, Name.make("$le"));
map.put(OperatorNames.GE, Name.make("$ge"));
map.put(OperatorNames.LEFT, Name.make("$left"));
map.put(OperatorNames.RIGHT, Name.make("$right"));
map.put(OperatorNames.RRIGHT, Name.make("$unsigned_right"));
map.put(OperatorNames.AMPERSAND, Name.make("$ampersand"));
map.put(OperatorNames.BAR, Name.make("$bar"));
map.put(OperatorNames.CARET, Name.make("$caret"));
map.put(OperatorNames.TILDE, Name.make("$tilde"));
map.put(OperatorNames.NTILDE, Name.make("$ntilde"));
map.put(OperatorNames.AND, Name.make("$and"));
map.put(OperatorNames.OR, Name.make("$or"));
map.put(OperatorNames.BANG, Name.make("$not"));
map.put(OperatorNames.EQ, Name.make("$equalsequals"));
map.put(OperatorNames.NE, Name.make("$ne"));
map.put(OperatorNames.RANGE, Name.make("$range"));
map.put(OperatorNames.ARROW, Name.make("$arrow"));
map.put(OperatorNames.LARROW, Name.make("$larrow"));
map.put(OperatorNames.FUNNEL, Name.make("$funnel"));
map.put(OperatorNames.LFUNNEL, Name.make("$lfunnel"));
map.put(OperatorNames.DIAMOND, Name.make("$diamond"));
map.put(OperatorNames.BOWTIE, Name.make("$bowtie"));
map.put(OperatorNames.STARSTAR, Name.make("$starstar"));
map.put(OperatorNames.inverse(OperatorNames.PLUS), Name.make("$inv_plus"));
map.put(OperatorNames.inverse(OperatorNames.MINUS), Name.make("$inv_minus"));
map.put(OperatorNames.inverse(OperatorNames.STAR), Name.make("$inv_times"));
map.put(OperatorNames.inverse(OperatorNames.SLASH), Name.make("$inv_over"));
map.put(OperatorNames.inverse(OperatorNames.PERCENT), Name.make("$inv_percent"));
map.put(OperatorNames.inverse(OperatorNames.LT), Name.make("$inv_lt"));
map.put(OperatorNames.inverse(OperatorNames.GT), Name.make("$inv_gt"));
map.put(OperatorNames.inverse(OperatorNames.LE), Name.make("$inv_le"));
map.put(OperatorNames.inverse(OperatorNames.GE), Name.make("$inv_ge"));
map.put(OperatorNames.inverse(OperatorNames.LEFT), Name.make("$inv_left"));
map.put(OperatorNames.inverse(OperatorNames.RIGHT), Name.make("$inv_right"));
map.put(OperatorNames.inverse(OperatorNames.RRIGHT), Name.make("$inv_unsigned_right"));
map.put(OperatorNames.inverse(OperatorNames.AMPERSAND), Name.make("$inv_ampersand"));
map.put(OperatorNames.inverse(OperatorNames.BAR), Name.make("$inv_bar"));
map.put(OperatorNames.inverse(OperatorNames.CARET), Name.make("$inv_caret"));
map.put(OperatorNames.inverse(OperatorNames.TILDE), Name.make("$inv_tilde"));
map.put(OperatorNames.inverse(OperatorNames.NTILDE), Name.make("$inv_ntilde"));
map.put(OperatorNames.inverse(OperatorNames.AND), Name.make("$inv_and"));
map.put(OperatorNames.inverse(OperatorNames.OR), Name.make("$inv_or"));
map.put(OperatorNames.inverse(OperatorNames.BANG), Name.make("$inv_not"));
map.put(OperatorNames.inverse(OperatorNames.EQ), Name.make("$inv_equalsequals"));
map.put(OperatorNames.inverse(OperatorNames.NE), Name.make("$inv_ne"));
map.put(OperatorNames.inverse(OperatorNames.RANGE), Name.make("$inv_range"));
map.put(OperatorNames.inverse(OperatorNames.ARROW), Name.make("$inv_arrow"));
map.put(OperatorNames.inverse(OperatorNames.LARROW), Name.make("$inv_larrow"));
map.put(OperatorNames.inverse(OperatorNames.FUNNEL), Name.make("$inv_funnel"));
map.put(OperatorNames.inverse(OperatorNames.LFUNNEL), Name.make("$inv_lfunnel"));
map.put(OperatorNames.inverse(OperatorNames.STARSTAR), Name.make("$inv_starstar"));
}
public static final String X10_JAVA_SERIALIZABLE_CLASS = "x10.serialization.X10JavaSerializable";
public static final String X10_JAVA_SERIALIZER_CLASS = "x10.serialization.X10JavaSerializer";
public static final String X10_JAVA_DESERIALIZER_CLASS = "x10.serialization.X10JavaDeserializer";
public static final String SERIALIZE_METHOD = "$_serialize";
public static final String DESERIALIZE_BODY_METHOD = "$_deserialize_body";
public static final String DESERIALIZER_METHOD = "$_deserializer";
private static Name mangleIdentifier(Name n) {
Name o = MANGLED_OPERATORS.get(n);
if (o != null)
return o;
String s = n.toString();
boolean replace = false;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (i == 0 ? !Character.isJavaIdentifierStart(c) : !Character.isJavaIdentifierPart(c)) {
replace = true;
sb.append(translateChar(c));
} else {
sb.append(c);
}
}
if (replace)
return Name.make(sb.toString());
return n;
}
public static String mangleIdentifier(String n) {
// Callers seem to assume that passing in a FQN here resulting in non-mangling.
if (!StringUtil.isNameShort(n))
return n;
return mangleIdentifier(Name.make(n)).toString();
}
public static QName mangleQName(QName name) {
String fullName = name.toString();
String qualifier = StringUtil.getPackageComponent(fullName);
String shortName = StringUtil.getShortNameComponent(fullName);
shortName = mangleIdentifier(shortName);
return QName.make(qualifier, shortName);
}
private static Name mangleAndFlattenQName(QName name) {
return Name.make(mangleIdentifier(name.toString().replace(".", "$")));
}
private static final String SPECIALTYPE_PREFIX = "$";
private static final String BYTE_SUFFIX = SPECIALTYPE_PREFIX + "B";
private static final String SHORT_SUFFIX = SPECIALTYPE_PREFIX + "S";
private static final String INT_SUFFIX = SPECIALTYPE_PREFIX + "I";
private static final String LONG_SUFFIX = SPECIALTYPE_PREFIX + "J";
private static final String FLOAT_SUFFIX = SPECIALTYPE_PREFIX + "F";
private static final String DOUBLE_SUFFIX = SPECIALTYPE_PREFIX + "D";
private static final String CHAR_SUFFIX = SPECIALTYPE_PREFIX + "C";
private static final String BOOLEAN_SUFFIX = SPECIALTYPE_PREFIX + "Z";
private static final String UBYTE_SUFFIX = SPECIALTYPE_PREFIX + "b";
private static final String USHORT_SUFFIX = SPECIALTYPE_PREFIX + "s";
private static final String UINT_SUFFIX = SPECIALTYPE_PREFIX + "i";
private static final String ULONG_SUFFIX = SPECIALTYPE_PREFIX + "j";
private static final String VOID_SUFFIX = SPECIALTYPE_PREFIX + "V";
public static final String specialTypeSuffixForDispatcher(Type type0) {
Type type = Types.baseType(type0);
assert isSpecialTypeForDispatcher(type);
String name = "";
if (type.isSignedNumeric()) {
if (type.isByte()) name = BYTE_SUFFIX;
else if (type.isShort()) name = SHORT_SUFFIX;
else if (type.isInt()) name = INT_SUFFIX;
else /*if (type.isLong())*/ name = LONG_SUFFIX;
} else if (type.isUnsignedNumeric()) {
if (type.isUByte()) name = UBYTE_SUFFIX;
else if (type.isUShort()) name = USHORT_SUFFIX;
else if (type.isUInt()) name = UINT_SUFFIX;
else /*if (type.isULong())*/ name = ULONG_SUFFIX;
} else if (type.isFloat()) {
return FLOAT_SUFFIX;
} else if (type.isDouble()) {
return DOUBLE_SUFFIX;
} else if (type.isChar()) {
return CHAR_SUFFIX;
} else if (type.isBoolean()) {
return BOOLEAN_SUFFIX;
} else if (type.isVoid()) {
return VOID_SUFFIX;
}
return name;
}
// N.B. we cannot use short name for type suffix since $b and $B become the same file on case-insensitive OSs.
public static final String specialTypeSuffixForType(Type type0) {
Type type = Types.baseType(type0);
assert isSpecialTypeForDispatcher(type);
return mangleAndFlattenQName(type0).toString();
}
private static final Name NULLTYPE_NAME = Name.make("$null"); // for NullType
public static Name mangleAndFlattenQName(Type type) {
if (type.isNull()) {
return NULLTYPE_NAME;
}
return mangleAndFlattenQName(type.fullName());
}
public static String mangleToJava(Name name) {
String str = mangleIdentifier(name).toString();
if (str.startsWith(JAVA_KEYWORD_PREFIX)) {
str = "_" + str;
}
if (JAVA_KEYWORDS.contains(str)) {
str = JAVA_KEYWORD_PREFIX + str;
}
return str;
}
private static String mangleParameterType(Name name) {
String mangledName = mangleToJava(name);
if (mangleTypeVariable) {
mangledName = PARAMETER_TYPE_PREFIX + mangledName;
}
return mangledName;
}
public static String mangleParameterType(ParameterType pt) {
return mangleParameterType(pt.name());
}
public static String mangleParameterType(TypeParamNode tpn) {
return mangleParameterType(tpn.name().id());
}
public void dumpRegex(String id, Map<String,Object> components, Translator tr, String regex) {
X10CompilerOptions opts = (X10CompilerOptions) tr.job().extensionInfo().getOptions();
int len = regex.length();
int pos = 0;
int start = 0;
while (pos < len) {
if (regex.charAt(pos) == '\n') {
w.write(regex.substring(start, pos));
w.newline(0);
start = pos + 1;
} else if (regex.charAt(pos) == '#') {
w.write(regex.substring(start, pos));
int endpos = pos + 1;
int idx = -1;
if (Character.isDigit(regex.charAt(endpos))) {
while (endpos < len && Character.isDigit(regex.charAt(endpos))) {
++endpos;
}
} else if (Character.isJavaIdentifierStart(regex.charAt(endpos))) {
while (endpos < len && Character.isJavaIdentifierPart(regex.charAt(endpos))) {
++endpos;
}
} else {
throw new InternalCompilerError("Template '" + id + "' uses ill-formed parameter #" + regex.substring(pos + 1));
}
String str = regex.substring(pos + 1, endpos);
Object component = components.get(str);
if (component == null) {
throw new InternalCompilerError("Template '" + id + "' uses undefined parameter #" + str);
}
pos = endpos - 1;
start = pos + 1;
if (component instanceof Expr && !isNoArgumentType((Expr) component)) {
component = new CastExpander(w, this, (Node) component).castTo(((Expr) component).type(), BOX_PRIMITIVES);
}
prettyPrint(component, tr);
} else if (regex.charAt(pos) == '`') {
w.write(regex.substring(start, pos));
int endpos = pos;
while (regex.charAt(++endpos) != '`') { }
String optionName = regex.substring(pos + 1, endpos);
Object optionValue = null;
try {
optionValue = opts.x10_config.get(optionName);
} catch (ConfigurationError e) {
throw new InternalCompilerError("There was a problem while processing the option `" + optionName + "` in template '" + id + "'", e);
} catch (OptionError e) {
throw new InternalCompilerError("Template '" + id + "' uses unrecognized option `" + optionName + "`", e);
}
w.write(optionValue.toString());
pos = endpos;
start = pos + 1;
}
pos++;
}
w.write(regex.substring(start));
}
/**
* Pretty-print a given object.
*
* @param o
* object to print
*/
public void prettyPrint(Object o, Translator tr) {
if (o instanceof Expander) {
((Expander) o).expand(tr);
} else if (o instanceof Node) {
((Node) o).del().translate(w, tr);
} else if (o instanceof Type) {
throw new InternalCompilerError("Should not attempt to pretty-print a type");
} else if (o != null) {
w.write(o.toString());
}
}
public static String getJavaImplForStmt(Stmt n, TypeSystem xts) {
if (n.ext() instanceof X10Ext) {
X10Ext ext = (X10Ext) n.ext();
Type java = xts.NativeType();
List<X10ClassType> as = ext.annotationMatching(java);
for (Type at : as) {
assertNumberOfInitializers(at, 2);
String lang = getPropertyInit(at, 0);
if (lang != null && lang.equals("java")) {
String lit = getPropertyInit(at, 1);
return lit;
}
}
}
return null;
}
public static String getJavaImplForDef(X10Def o) {
TypeSystem xts = o.typeSystem();
Type java = xts.NativeType();
List<Type> as = o.annotationsMatching(java);
for (Type at : as) {
assertNumberOfInitializers(at, 2);
String lang = getPropertyInit(at, 0);
if (lang != null && lang.equals("java")) {
String lit = getPropertyInit(at, 1);
return lit;
}
}
return null;
}
private static final HashMap<String,String> boxedPrimitives = new HashMap<String,String>();
static {
boxedPrimitives.put("x10.lang.Boolean", "x10.core.Boolean");
boxedPrimitives.put("x10.lang.Char", "x10.core.Char");
boxedPrimitives.put("x10.lang.Byte", "x10.core.Byte");
boxedPrimitives.put("x10.lang.Short", "x10.core.Short");
boxedPrimitives.put("x10.lang.Int", "x10.core.Int");
boxedPrimitives.put("x10.lang.Long", "x10.core.Long");
boxedPrimitives.put("x10.lang.Float", "x10.core.Float");
boxedPrimitives.put("x10.lang.Double", "x10.core.Double");
boxedPrimitives.put("x10.lang.UByte", "x10.core.UByte");
boxedPrimitives.put("x10.lang.UShort", "x10.core.UShort");
boxedPrimitives.put("x10.lang.UInt", "x10.core.UInt");
boxedPrimitives.put("x10.lang.ULong", "x10.core.ULong");
}
public static String getJavaRep(X10ClassDef def, boolean boxPrimitives) {
String pat = getJavaRep(def); // {int,int}
if (pat != null && boxPrimitives) {
String orig = def.fullName().toString(); // x10.lang.{Int,UInt}
String boxed = boxedPrimitives.get(orig); // x10.core.{Int,UInt}
if (boxed != null) {
pat = boxed;
}
}
return pat;
}
public static String getJavaRep(X10ClassDef def) {
return getJavaRepParam(def, 1);
}
public static String getJavaRTTRep(X10ClassDef def) {
return getJavaRepParam(def, 3);
}
private static String getJavaRepParam(X10ClassDef def, int i) {
Type rep = def.typeSystem().NativeRep();
List<Type> as = def.annotationsMatching(rep);
for (Type at : as) {
String lang = getPropertyInit(at, 0);
if (lang != null && lang.equals("java")) {
return getPropertyInit(at, i);
}
}
return null;
}
public static boolean isNativeRepedToJava(Type ct) {
Type bt = Types.baseType(ct);
if (bt.isClass()) {
X10ClassDef def = bt.toClass().x10Def();
String pat = getJavaRep(def);
if (pat != null && pat.startsWith("java.")) {
return true;
}
}
return false;
}
public static boolean isNativeRepedToJavaRecursive(Type type) {
String typeName = type.fullName().toString();
// N.B. currently following four class are such classes. but for safety, we exclude all Atomic classes.
// if (typeName.equals("x10.util.concurrent.AtomicInteger")) return true;
// if (typeName.equals("x10.util.concurrent.AtomicLong")) return true;
// if (typeName.equals("x10.util.concurrent.AtomicReference")) return true;
// if (typeName.equals("x10.util.concurrent.AtomicBoolean")) return true;
if (typeName.startsWith("x10.util.concurrent.Atomic")) return true;
return false;
// TODO check if NativeRep'ed target (i.e. pat) recursively extends or implements Java type in Java implementation level.
// Type bt = Types.baseType(type);
// if (bt.isClass()) {
// X10ClassDef def = bt.toClass().x10Def();
// String pat = getJavaRep(def);
// if (pat != null) {
// return true;
// }
// }
// return false;
}
// not used
// public static boolean isNativeReped(Type ct) {
// Type bt = Types.baseType(ct);
// if (bt.isClass()) {
// X10ClassDef def = bt.toClass().x10Def();
// String pat = getJavaRep(def);
// if (pat != null) {
// return true;
// }
// }
// return false;
// }
private static String getNativeClassJavaRepParam(X10ClassDef def, int i) {
List<Type> as = def.annotationsMatching(def.typeSystem().NativeClass());
for (Type at : as) {
String lang = getPropertyInit(at, 0);
if (lang != null && lang.equals("java")) {
return getPropertyInit(at, i);
}
}
return null;
}
public static boolean isNativeClassToJava(Type ct) {
Type bt = Types.baseType(ct);
if (bt.isClass()) {
X10ClassDef cd = bt.toClass().x10Def();
String pat = getNativeClassJavaRepParam(cd, 1);
if (pat != null && pat.startsWith("java.")) {
return true;
}
}
return false;
}
// not used
// public static boolean isJavaTypeRecursive(Type ct) {
// Type bt = Types.baseType(ct);
// if (bt.isClass()) {
// X10ClassType xct = bt.toClass();
// if (xct.isJavaType()) return true;
// Type superClass = xct.superClass();
// if (superClass != null && isJavaTypeRecursive(superClass)) return true;
// for (Type intf : xct.interfaces()) {
// if (isJavaTypeRecursive(intf)) return true;
// }
// }
// return false;
// }
// check if the specified method overrides or implements Java method (= a method whose container is a Java type)
public static boolean canOverrideOrImplementJavaMethod(MethodDef def) {
if (def.flags().isStatic()) return false;
// instance methods of Any (=java.lang.Object)
// N.B. these methods should be included in mi.implemented() but not for some reason, so added as special cases.
String methodName = def.name().toString();
List<Ref<? extends Type>> formalTypes = def.formalTypes();
int numFormals = formalTypes.size();
if (methodName.equals("toString") && numFormals == 0) return true;
if (methodName.equals("hashCode") && numFormals == 0) return true;
if (methodName.equals("equals") && numFormals == 1 && formalTypes.get(0).get().isAny()) return true;
Context context = def.typeSystem().emptyContext();
MethodInstance mi = def.asInstance();
for (MethodInstance overridden : mi.overrides(context)) {
X10ClassType type = overridden.container().toClass();
if (type.isJavaType()) return true;
if (isNativeClassToJava(type)) return true;
if (isNativeRepedToJava(type)) return true;
if (isNativeRepedToJavaRecursive(type)) return true;
}
for (MethodInstance implemented : mi.implemented(context)) {
X10ClassType type = implemented.container().toClass();
if (type.isJavaType()) return true;
if (isNativeClassToJava(type)) return true;
if (isNativeRepedToJava(type)) return true;
if (isNativeRepedToJavaRecursive(type)) return true;
}
return false;
}
private static String getPropertyInit(Type at, int index) {
at = Types.baseType(at);
if (at.isClass()) {
X10ClassType act = at.toClass();
if (index < act.propertyInitializers().size()) {
Expr e = act.propertyInitializer(index);
if (e != null && e.isConstant()) {
ConstantValue v = e.constantValue();
if (v instanceof StringValue) {
return ((StringValue) v).value();
}
}
}
}
return null;
}
private static void assertNumberOfInitializers(Type at, int len) {
at = Types.baseType(at);
if (at.isClass()) {
X10ClassType act = at.toClass();
assert len == act.propertyInitializers().size();
}
}
private boolean printRepType(Type type, int flags) {
boolean printTypeParams = (flags & PRINT_TYPE_PARAMS) != 0;
boolean boxPrimitives = (flags & BOX_PRIMITIVES) != 0;
// boolean inSuper = (flags & NO_VARIANCE) != 0;
if (type.isVoid()) {
w.write("void");
return true;
}
// If the type has a native representation, use that.
if (type.isClass()) {
X10ClassDef cd = type.toClass().x10Def();
String pat = getJavaRep(cd, boxPrimitives); // @NativeRep("java", JavaRep, n/a, JavaRTTRep)
if (pat != null) {
List<ParameterType> classTypeParams = cd.typeParameters();
// if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList();
Iterator<ParameterType> classTypeParamsIter = null;
if (classTypeParams != null) {
classTypeParamsIter = classTypeParams.iterator();
}
List<Type> classTypeArgs = type.toClass().typeArguments();
if (classTypeArgs == null) classTypeArgs = Collections.<Type>emptyList();
Map<String,Object> components = new HashMap<String,Object>();
int i = 0;
Object component;
String name;
component = new TypeExpander(this, type, flags);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
components.put("class", component);
for (Type at : classTypeArgs) {
if (classTypeParamsIter != null) {
name = classTypeParamsIter.next().name().toString();
} else {
name = null;
}
component = new TypeExpander(this, at, flags & ~BOX_PRIMITIVES);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name, component); }
component = new TypeExpander(this, at, flags | BOX_PRIMITIVES);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_BOXED_REP_SUFFIX, component); }
component = new RuntimeTypeExpander(this, at);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_RUNTIME_TYPE_SUFFIX, component); }
}
if (!printTypeParams) {
pat = pat.replaceAll("<.*>", "");
}
dumpRegex("NativeRep", components, tr, pat);
return true;
}
}
return false;
}
public void printBoxConversion(Type type) {
// treat unsigned types specially
if (needExplicitBoxing(type)) {
printType(type, BOX_PRIMITIVES);
w.write("." + X10PrettyPrinterVisitor.BOX_METHOD_NAME);
// it requires parentheses to be printed after
}
else {
// type == T comes here
// FIXME: maybe this is not needed at all? -- boxing of non-boxable types
w.write("(");
printType(type, BOX_PRIMITIVES);
w.write(")");
}
}
/**
* @param type - a type to print
* @return Returns true if an additional closing parenthesis needs to be printed after expression
*/
public boolean printUnboxConversion(Type type) {
if (needExplicitBoxing(type)) {
printType(type, BOX_PRIMITIVES);
w.write("." + X10PrettyPrinterVisitor.UNBOX_METHOD_NAME + "(");
return true;
}
else {
// FIXME: maybe this is not needed at all? -- unboxing of non-boxable types
w.write("(");
printType(type, BOX_PRIMITIVES);
w.write(")");
return false;
}
}
public static final QName X10_LANG_ARITHMETIC = QName.make("x10.lang.Arithmetic");
private static final String X10_CORE_ARITHMETIC = "x10.core.Arithmetic";
public static final QName X10_LANG_BITWISE = QName.make("x10.lang.Bitwise");
private static final String X10_CORE_BITWISE = "x10.core.Bitwise";
public static final QName X10_LANG_REDUCIBLE = QName.make("x10.lang.Reducible");
private static final String X10_CORE_REDUCIBLE = "x10.core.Reducible";
public static final QName X10_LANG_ITERATOR = QName.make("x10.lang.Iterator");
private static final String X10_CORE_ITERATOR = "x10.core.Iterator";
public static final QName X10_LANG_SEQUENCE = QName.make("x10.lang.Sequence");
private static final String X10_CORE_SEQUENCE = "x10.core.Sequence";
public void printType(Type type, int flags) {
boolean printTypeParams = (flags & PRINT_TYPE_PARAMS) != 0;
// boolean boxPrimitives = (flags & BOX_PRIMITIVES) != 0;
boolean inSuper = (flags & NO_VARIANCE) != 0;
boolean ignoreQual = (flags & NO_QUALIFIER) != 0;
type = Types.baseType(type);
if (type.isClass()) {
X10ClassType ct = type.toClass();
if (ct.isAnonymous()) {
if (ct.interfaces().size() > 0) {
printType(ct.interfaces().get(0), flags);
return;
} else if (ct.superClass() != null) {
printType(ct.superClass(), flags);
return;
} else {
assert false;
return;
}
}
}
if (printRepType(type, flags))
return;
if (type.isParameterType()) {
w.write(mangleParameterType((ParameterType) type));
return;
}
if (type instanceof FunctionType) {
FunctionType ct = (FunctionType) type;
List<Type> args = ct.argumentTypes();
Type ret = ct.returnType();
if (ret.isVoid()) {
w.write(X10PrettyPrinterVisitor.X10_VOIDFUN_CLASS_PREFIX);
} else {
w.write(X10PrettyPrinterVisitor.X10_FUN_CLASS_PREFIX);
}
w.write("_" + ct.typeParameters().size());
w.write("_" + args.size());
if (printTypeParams && args.size() + (ret.isVoid() ? 0 : 1) > 0) {
w.write("<");
String sep = "";
for (Type a : args) {
w.write(sep);
sep = ",";
printType(a, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
}
if (!ret.isVoid()) {
w.write(sep);
printType(ret, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
}
w.write(">");
}
return;
}
// Shouldn't get here.
if (type instanceof MacroType) {
MacroType mt = (MacroType) type;
printType(mt.definedType(), PRINT_TYPE_PARAMS);
return;
}
if (type instanceof BackingArrayType) {
Type base = ((BackingArrayType) type).base();
printType(base, 0);
w.write("[]");
return;
}
// print Arithmetic[Int] as Arithmetic.x10$lang$Int etc.
if (X10PrettyPrinterVisitor.exposeSpecialDispatcherThroughSpecialInterface && type.isClass()) {
X10ClassType ct = type.toClass();
QName fullName = ct.fullName();
List<Type> typeArguments = ct.typeArguments();
if (fullName.equals(X10_LANG_ARITHMETIC)) {
//assert typeArguments != null : "Suspicious Arithmetic without type parameter";
if (typeArguments != null && typeArguments.size() == 1 && isPrimitive(typeArguments.get(0))) {
w.write(X10_CORE_ARITHMETIC + "." + specialTypeSuffixForType(typeArguments.get(0)));
return;
}
}
else if (fullName.equals(X10_LANG_BITWISE)) {
//assert typeArguments != null : "Suspicious Bitwise without type parameter";
if (typeArguments != null && typeArguments.size() == 1 && isPrimitive(typeArguments.get(0))) {
w.write(X10_CORE_BITWISE + "." + specialTypeSuffixForType(typeArguments.get(0)));
return;
}
}
else if (fullName.equals(X10_LANG_REDUCIBLE)) {
//assert typeArguments != null : "Suspicious Reducible without type parameter";
if (typeArguments != null && typeArguments.size() == 1 && isPrimitive(typeArguments.get(0))) {
w.write(X10_CORE_REDUCIBLE + "." + specialTypeSuffixForType(typeArguments.get(0)));
return;
}
}
else if (fullName.equals(X10_LANG_ITERATOR)) {
//assert typeArguments != null : "Suspicious Iterator without type parameter";
if (typeArguments != null && typeArguments.size() == 1 && isPrimitive(typeArguments.get(0))) {
w.write(X10_CORE_ITERATOR + "." + specialTypeSuffixForType(typeArguments.get(0)));
return;
}
}
else if (fullName.equals(X10_LANG_SEQUENCE)) {
//assert typeArguments != null : "Suspicious Sequence without type parameter";
if (typeArguments != null && typeArguments.size() == 1 && isPrimitive(typeArguments.get(0))) {
w.write(X10_CORE_SEQUENCE + "." + specialTypeSuffixForType(typeArguments.get(0)));
return;
}
}
}
// Print the class name
if (ignoreQual) {
if (type.isClass()) {
w.write(mangleToJava(type.toClass().name()));
} else {
type.print(w);
}
} else if (type.isNull()) {
w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
} else {
w.write(mangleQName(type.fullName()).toString());
}
if (printTypeParams) {
if (type.isClass()) {
X10ClassType ct = type.toClass();
List<Type> typeArgs = ct.typeArguments();
if (typeArgs == null) typeArgs = new ArrayList<Type>(ct.x10Def().typeParameters());
String sep = "<";
for (int i = 0; i < typeArgs.size(); i++) {
w.write(sep);
sep = ", ";
Type a = typeArgs.get(i);
final boolean variance = false;
if (!inSuper && variance) {
ParameterType.Variance v = ct.x10Def().variances().get(i);
switch (v) {
case CONTRAVARIANT:
w.write("? super ");
break;
case COVARIANT:
w.write("? extends ");
break;
case INVARIANT:
break;
}
}
printType(a, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
}
if (typeArgs.size() > 0)
w.write(">");
}
}
}
// See comments in Native.x10
/**
* Annotation to mark methods and fields as having a particular native implementation.
* lang is the name of the language, typically "java" or "c++".
* code is the code to insert for a call to the method or an access to the field.
*
* For "java" annotations:
*
* Given a method with signature:
* def m[X, Y](x, y);
* and a call
* o.m[A, B](a, b);
* #0 = #this = o
* #1 = #X = A
* #2 = #X$box = boxed representation of A
* #3 = #X$rtt = run-time Type object for A
* #4 = #Y = B
* #5 = #Y$box = boxed representation of B
* #6 = #Y$rtt = run-time Type object for B
* #7 = #x = a
* #8 = #y = b
*
* For "c++" annotations:
*
* As for "java" except boxed and run-time representations of type vars should not be used.
*/
public void emitNativeAnnotation(String pat, Object receiver, List<ParameterType> typeParams, List<Type> typeArgs, List<String> params, List<? extends Object> args, List<ParameterType> classTypeParams, List<Type> classTypeArgs) {
// Object[] components = new Object[1 + typeArgs.size() * 3 + args.size() + classTypeArgs.size() * 3];
Map<String,Object> components = new HashMap<String,Object>();
int i = 0;
Object component;
String name;
if (receiver != null) {
component = receiver;
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
components.put("this", component);
} else {
i++;
}
Iterator<ParameterType> typeParamsIter = null;
if (typeParams != null) {
typeParamsIter = typeParams.iterator();
}
for (Type at : typeArgs) {
if (typeParamsIter != null) {
name = typeParamsIter.next().name().toString();
} else {
name = null;
}
component = new TypeExpander(this, at, PRINT_TYPE_PARAMS);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name, component); }
component = new TypeExpander(this, at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_BOXED_REP_SUFFIX, component); }
component = new RuntimeTypeExpander(this, at);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_RUNTIME_TYPE_SUFFIX, component); }
}
Iterator<String> paramsIter = null;
if (params != null) {
paramsIter = params.iterator();
}
for (Object e : args) {
if (paramsIter != null) {
name = paramsIter.next();
} else {
name = null;
}
component = e;
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name, component); }
}
Iterator<ParameterType> classTypeParamsIter = null;
if (classTypeParams != null) {
classTypeParamsIter = classTypeParams.iterator();
}
for (Type at : classTypeArgs) {
if (classTypeParamsIter != null) {
name = classTypeParamsIter.next().name().toString();
} else {
name = null;
}
component = new TypeExpander(this, at, PRINT_TYPE_PARAMS);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name, component); }
component = new TypeExpander(this, at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_BOXED_REP_SUFFIX, component); }
component = new RuntimeTypeExpander(this, at);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_RUNTIME_TYPE_SUFFIX, component); }
}
this.dumpRegex("Native", components, tr, pat);
}
public void generateMethodDecl(X10MethodDecl_c n, boolean boxPrimitives) {
Context c = tr.context();
boolean isInterface = c.currentClass().flags().isInterface();
Flags flags = n.flags().flags();
if (isInterface) {
flags = flags.clearPublic();
flags = flags.clearAbstract();
}
// XTENLANG-2680
Flags javaFlags = flags.retainJava(); // ensure that X10Flags are not printed out .. javac will not know what to do with them.
// TODO expand @Native annotation of interface method to the types that implement the interface and don't have its implementation.
boolean hasNativeAnnotation = supportNativeMethodDecl && getJavaImplForDef(n.methodDef()) != null && !isInterface/*for Comparable[T].compareTo(T)*/;
if (hasNativeAnnotation) {
// N.B. clear native as well since it has @Native annotation.
javaFlags = javaFlags.clearNative();
}
boolean isDispatcher = X10PrettyPrinterVisitor.useSelfDispatch && isInterface && isDispatcher(n);
// XTENLANG-2993
boolean isSpecialTypeForDispatcher = isSpecialTypeForDispatcher(n.returnType().type());
boolean needSpecialDispatcher = isDispatcher && (X10PrettyPrinterVisitor.generateSpecialDispatcher && isSpecialTypeForDispatcher);
// 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.
boolean canMangleMethodName = canMangleMethodName(n.methodDef());
boolean first = false;
int formalNum = 0;
boolean isFirst = false;
// XTENLANG-2993
// stop generating interface of dispatcher method returning j.l.Object if the return type is special type
if (X10PrettyPrinterVisitor.generateSpecialDispatcherNotUse || !needSpecialDispatcher) {
w.begin(0);
w.write(javaFlags.translate());
// print the method type parameters
printTypeParams(n, c, n.typeParameters());
// print the return type
if (isDispatcher) {
w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
} else {
printType(n.returnType().type(), X10PrettyPrinterVisitor.supportTypeConstraintsWithErasure ? 0 : PRINT_TYPE_PARAMS);
}
w.allowBreak(2, 2, " ", 1);
// decl
// print the method name
printMethodName(n.methodDef(), isInterface, isDispatcher, false, null);
// print formals
w.write("(");
w.allowBreak(2, 2, "", 0);
w.begin(0);
first = true;
// Add a formal parameter of type Type for each type parameters.
for (TypeParamNode p : n.typeParameters()) {
if (!first) {
w.write(",");
w.allowBreak(0, " ");
} else {
first = false;
}
w.write("final ");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
w.write(mangleParameterType(p));
}
formalNum = 1;
for (int i = 0; i < n.formals().size(); i++) {
boolean forceBoxing = false;
if (!canMangleMethodName) {
// for methods, for which we cannot mangle name, a different boxing rule applies:
// we force boxing of an argument if the method implements a method
// with a boxed (generic) argument type in corresponding position
for (MethodInstance supermeth : n.methodDef().asInstance().implemented(tr.context())) {
if (isBoxedType(supermeth.def().formalTypes().get(i).get())) {
forceBoxing = true;
break;
}
}
}
if (!first) {
w.write(",");
w.allowBreak(0, " ");
} else {
first = false;
}
Formal f = n.formals().get(i);
tr.print(n, f.flags(), w);
Type type = f.type().type();
if (isDispatcher && containsTypeParam(type)) {
// XTENLANG-2998
// Java backend erases type parameters of interface and merge multiple instantiations of the same generic interface (e.g. I[Int] and I[Float]) into a single Java generic interface (I).
if (type.isParameterType()) {
w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
} else {
printType(type, 0);
}
w.write(" ");
Name name = f.name().id();
if (name.toString().equals("")) {
name = Name.makeFresh("a");
}
tr.print(n, f.name().id(name), w);
w.write(",");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
Name name1 = Name.make("t" + formalNum++);
tr.print(n, f.name().id(name1), w);
}
else {
printType(
type,
(n.flags().flags().isStatic() ? PRINT_TYPE_PARAMS : 0) |
// 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.
(boxPrimitives || forceBoxing ? BOX_PRIMITIVES : 0)
);
w.write(" ");
Name name = f.name().id();
if (name.toString().equals("")) {
name = Name.makeFresh("a");
}
tr.print(n, f.name().id(name), w);
}
}
w.end();
w.write(")");
isFirst = true;
for (Ref<? extends Type> _throws : n.methodDef().throwTypes()) {
if (isFirst) {
w.write(" throws ");
isFirst = false;
} else {
w.write(", ");
}
printType(_throws.get(), 0);
}
w.end();
// XTENLANG-2680
// print @Native annotation as method body
if (hasNativeAnnotation) {
printNativeMethodDecl(n);
} else {
if (n.body() != null) {
tr.print(n, n.body(), w);
} else {
w.write(";");
}
}
// XTENLANG-2993
// stop generating interface of dispatcher method returning j.l.Object if the return type is special type
}
// XTENLANG-2993
// dispatcher method returing special type
if (needSpecialDispatcher) {
w.begin(0);
w.write(javaFlags.translate());
// print the method type parameters
printTypeParams(n, c, n.typeParameters());
// XTENLANG-2993
// // print the return type
// if (isDispatcher) {
// w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
// } else {
printType(n.returnType().type(), X10PrettyPrinterVisitor.supportTypeConstraintsWithErasure ? 0 : PRINT_TYPE_PARAMS);
// XTENLANG-2993
// }
w.allowBreak(2, 2, " ", 1);
// decl
// print the method name
// XTENLANG-2993
printMethodName(n.methodDef(), isInterface, isDispatcher, true, n.returnType().type());
// print formals
w.write("(");
w.allowBreak(2, 2, "", 0);
w.begin(0);
first = true;
// Add a formal parameter of type Type for each type parameters.
for (TypeParamNode p : n.typeParameters()) {
if (!first) {
w.write(",");
w.allowBreak(0, " ");
} else {
first = false;
}
w.write("final ");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
w.write(mangleParameterType(p));
}
formalNum = 1;
for (int i = 0; i < n.formals().size(); i++) {
boolean forceBoxing = false;
if (!canMangleMethodName) {
// for methods, for which we cannot mangle name, a different boxing rule applies:
// we force boxing of an argument if the method implements a method
// with a boxed (generic) argument type in corresponding position
for (MethodInstance supermeth : n.methodDef().asInstance().implemented(tr.context())) {
if (isBoxedType(supermeth.def().formalTypes().get(i).get())) {
forceBoxing = true;
break;
}
}
}
if (!first) {
w.write(",");
w.allowBreak(0, " ");
} else {
first = false;
}
Formal f = n.formals().get(i);
tr.print(n, f.flags(), w);
Type type = f.type().type();
if (isDispatcher && containsTypeParam(type)) {
// XTENLANG-2998
// Java backend erases type parameters of interface and merge multiple instantiations of the same generic interface (e.g. I[Int] and I[Float]) into a single Java generic interface (I).
if (type.isParameterType()) {
w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
} else {
printType(type, 0);
}
w.write(" ");
Name name = f.name().id();
if (name.toString().equals("")) {
name = Name.makeFresh("a");
}
tr.print(n, f.name().id(name), w);
w.write(",");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
Name name1 = Name.make("t" + formalNum++);
tr.print(n, f.name().id(name1), w);
}
else {
printType(
type,
(n.flags().flags().isStatic() ? PRINT_TYPE_PARAMS : 0) |
// 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.
(boxPrimitives || forceBoxing ? BOX_PRIMITIVES : 0)
);
w.write(" ");
Name name = f.name().id();
if (name.toString().equals("")) {
name = Name.makeFresh("a");
}
tr.print(n, f.name().id(name), w);
}
}
w.end();
w.write(")");
isFirst = true;
for (Ref<? extends Type> _throws : n.methodDef().throwTypes()) {
if (isFirst) {
w.write(" throws ");
isFirst = false;
} else {
w.write(", ");
}
printType(_throws.get(), 0);
}
w.end();
// XTENLANG-2680
// print @Native annotation as method body
if (hasNativeAnnotation) {
printNativeMethodDecl(n);
} else {
if (n.body() != null) {
tr.print(n, n.body(), w);
} else {
w.write(";");
}
}
}
}
// decl and call
private void printMethodName(MethodDef def, boolean isInterface, boolean isDispatcher, boolean useSpecialDispatcher, Type returnTypeForDispatcher) {
Type returnType = def.returnType().get();
printMethodName(def, isInterface, isDispatcher, useSpecialDispatcher, returnTypeForDispatcher, isSpecialType(returnType), tr.typeSystem().isParameterType(returnType));
}
public static final boolean canMangleMethodName(MethodDef def) {
// static methods are basically safe to be mangled since they don't implement or override Java methods.
if (def.flags().isStatic()) {
// N.B. following methods are executed with Java reflection during static initialization phase, therefore their names are important
String methodName = def.name().toString();
if (methodName.startsWith(StaticInitializer.initializerPrefix)) return false;/*intrinsic*/
return true;
}
// ContainerType containerType = def.container().get();
// if (isNativeClassToJava(containerType)) return false;
// if (isNativeRepedToJava(containerType)) return false; // included in canOverrideOrImplementJavaMethod(def)
// if (isNativeReped(containerType)) {
// // exclude classes that are @NativeRep'ed to non-java classes that extend java class
// // since some instance methods of the class may match its super class's java method (therefore cannot mangle)
// String containerName = containerType.fullName().toString();
// // N.B. currently following four class are such classes. but for safety, we exclude all Atomic classes.
//// if (containerName.equals("x10.util.concurrent.AtomicInteger")) return false;
//// if (containerName.equals("x10.util.concurrent.AtomicLong")) return false;
//// if (containerName.equals("x10.util.concurrent.AtomicReference")) return false;
//// if (containerName.equals("x10.util.concurrent.AtomicBoolean")) return false;
// if (containerName.startsWith("x10.util.concurrent.Atomic")) return false;
// // TODO looks like there is no reason to implement AtomicInteger as XRJ.
// // we may directly map it to j.u.c.a.AtomicInteger later and remove special handling here.
// }
// if (!def.flags().isStatic()) {
// String methodName = def.name().toString();
// // instance methods
// List<Ref<? extends Type>> formalTypes = def.formalTypes();
// int numFormals = formalTypes.size();
// //if (methodName.equals("compareTo") && numFormals == 1) return false;/*Comparable=j.l.Comparable*/
// List<ParameterType> typeParams = def.typeParameters();
// int numTypeParams = typeParams.size();
// if (methodName.equals("compareTo") && numFormals == 1 && numTypeParams == 1 && formalTypes.get(0).get().isComparable(typeParams.get(0))) return false;/*Comparable=j.l.Comparable*/
// }
// TODO want to check with the fact that x.l.Comparable is @NativeRep'ed to j.l.Comparable
// XTENLANG-2929
if (canOverrideOrImplementJavaMethod(def)) return false;/*CharSequence etc.*/
return true;
}
public void printMethodName(MethodDef def, boolean isInterface, boolean isDispatcher, boolean useSpecialDispatcher, Type returnTypeForDispatcher, boolean isSpecialReturnType, boolean isParamReturnType) {
// 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.
// WIP XTENLANG-2680 (ComparableTest.x10)
// enable it after enhancing canMangleMethodName with parameter list
if (X10PrettyPrinterVisitor.supportGenericOverloading && canMangleMethodName(def)) {
w.write(getMangledMethodName(def, !isInterface));
}
else {
w.write(mangleToJava(def.name()));
}
if (!isDispatcher) {
if (isSpecialReturnType) {
if (canMangleMethodName(def)) {
w.write(RETURN_SPECIAL_TYPE_SUFFIX);
}
}
// print $G
else if (isParamReturnType) {
w.write(RETURN_PARAMETER_TYPE_SUFFIX);
}
}
else {
// XTENLANG-2993
// isDispatcher
if (useSpecialDispatcher && isSpecialTypeForDispatcher(returnTypeForDispatcher)) {
if (canMangleMethodName(def)) {
w.write(specialTypeSuffixForDispatcher(returnTypeForDispatcher));
}
}
}
}
// not used
// public void printMethodName(MethodDef def, boolean isInterface, boolean isDispatcher, boolean isSpecialReturnType, boolean isParamReturnType) {
// // 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.
// // WIP XTENLANG-2680 (ComparableTest.x10)
// // enable it after enhancing canMangleMethodName with parameter list
// if (X10PrettyPrinterVisitor.supportGenericOverloading && canMangleMethodName(def)) {
// w.write(getMangledMethodName(def, !isInterface));
// }
// else {
// w.write(mangleToJava(def.name()));
// }
// if (!isDispatcher) {
// if (isSpecialReturnType) {
// if (canMangleMethodName(def)) {
// w.write(RETURN_SPECIAL_TYPE_SUFFIX);
// }
// }
// // print $G
// else if (isParamReturnType) {
// w.write(RETURN_PARAMETER_TYPE_SUFFIX);
// }
// }
// }
private void printMethodName(ClassType ct, MethodInstance mi) {
if (X10PrettyPrinterVisitor.supportGenericOverloading) {
w.write(getMangledMethodName(ct, mi, true));
} else {
w.write(mangleToJava(mi.name()));
}
if (isSpecialType(mi.returnType())) {
if (canMangleMethodName(mi.def())) {
w.write(RETURN_SPECIAL_TYPE_SUFFIX);
}
}
// print $G
else if (tr.typeSystem().isParameterType(mi.returnType())) {
w.write(RETURN_PARAMETER_TYPE_SUFFIX);
}
}
public void printApplyMethodName(MethodInstance mi, boolean newClosure) {
w.write(mangleToJava(ClosureCall.APPLY));
if (X10PrettyPrinterVisitor.useSelfDispatch && (!newClosure && !mi.returnType().isVoid() && mi.formalTypes().size() == 0)) {
w.write(RETURN_PARAMETER_TYPE_SUFFIX);
}
else if (!X10PrettyPrinterVisitor.useSelfDispatch && !(mi.returnType().isVoid() || (newClosure && !tr.typeSystem().isParameterType(mi.returnType())))) {
w.write(RETURN_PARAMETER_TYPE_SUFFIX);
}
}
public void printApplyMethodName(final Closure_c n, boolean isParamReturyType) {
w.write(mangleToJava(ClosureCall.APPLY));
if (!n.returnType().type().isVoid() && isParamReturyType && (!X10PrettyPrinterVisitor.useSelfDispatch || (X10PrettyPrinterVisitor.useSelfDispatch && n.formals().size() == 0))) {
w.write(RETURN_PARAMETER_TYPE_SUFFIX);
}
}
public static boolean isDispatcher(MethodInstance mi) {
for (Ref<? extends Type> ref: mi.def().formalTypes()) {
Type type = ref.get();
if (containsTypeParam(type)) {
return true;
}
}
return false;
}
public static boolean isDispatcher(X10MethodDecl_c n) {
for (int i = 0; i < n.formals().size(); i++) {
Type type = n.formals().get(i).type().type();
if (containsTypeParam(type)) {
return true;
}
}
return false;
}
private void printTypeParams(Node_c n, Context context, List<TypeParamNode> typeParameters, X10TypeEnv tenv, List<ParameterType> typeParams) {
int nTypeParameters = typeParameters.size();
// if (nTypeParameters <= 0) return;
assert nTypeParameters > 0;
w.write("<");
w.begin(0);
String sep = "";
for (int i = 0; i < nTypeParameters; ++i) {
w.write(sep);
sep = ", ";
TypeParamNode tp = typeParameters.get(i);
w.write(mangleParameterType(tp));
if (tenv == null) continue;
// print upperbounds
List<Type> upperBounds = new LinkedList<Type>(tenv.upperBounds(typeParams.get(i)));
if (upperBounds.isEmpty()) continue;
Type leastUpperBound = null;
Iterator<Type> it = upperBounds.iterator();
while (it.hasNext()) {
Type upperBound = Types.baseType(it.next());
if (upperBound.isParameterType()) {
it.remove();
}
if (upperBound.isClass()) {
if (upperBound.isAny()) {
it.remove();
}
else if (!upperBound.toClass().flags().isInterface()) {
if (leastUpperBound == null || upperBound.isSubtype(leastUpperBound, context)) {
leastUpperBound = upperBound;
}
it.remove();
}
}
}
if (leastUpperBound != null) {
upperBounds.add(0, leastUpperBound);
}
// FIXME need to check strategy for bounds of type parameter
if (upperBounds.size() > 0) {
w.write(" extends ");
List<Type> alreadyPrintedTypes = new ArrayList<Type>();
for (Type type : upperBounds) {
if (!alreadyPrinted(alreadyPrintedTypes, type)) {
if (alreadyPrintedTypes.size() != 0) w.write(" & ");
printType(type, BOX_PRIMITIVES);
alreadyPrintedTypes.add(type);
}
}
}
}
w.end();
w.write("> ");
}
public void printTypeParams(X10MethodDecl_c n, Context context, List<TypeParamNode> typeParameters) {
if (typeParameters.size() <= 0) return;
X10TypeEnv tenv = null;
MethodDef def = n.methodDef();
if (X10PrettyPrinterVisitor.supportUpperBounds) {
Ref<TypeConstraint> tc = def.typeGuard();
if (tc != null) {
Context c2 = context.pushBlock();
c2.setName(" MethodGuard for |" + def.name() + "| ");
c2.setTypeConstraintWithContextTerms(tc);
tenv = tr.typeSystem().env(c2);
}
}
printTypeParams(n, context, typeParameters, tenv, def.typeParameters());
}
public void printTypeParams(X10ClassDecl_c n, Context context, List<TypeParamNode> typeParameters) {
if (typeParameters.size() <= 0) return;
X10TypeEnv tenv = null;
X10ClassDef def = n.classDef();
if (X10PrettyPrinterVisitor.supportUpperBounds) {
Ref<TypeConstraint> tc = def.typeGuard();
if (tc != null) {
Context c2 = context.pushBlock();
c2.setName(" ClassGuard for |" + def.name() + "| ");
c2.setTypeConstraintWithContextTerms(tc);
tenv = tr.typeSystem().env(c2);
}
}
printTypeParams(n, context, typeParameters, tenv, def.typeParameters());
}
public void printMethodParams(List<? extends Type> methodTypeParams) {
if (methodTypeParams.size() > 0) {
w.write("<");
for (Iterator<? extends Type> i = methodTypeParams.iterator(); i.hasNext();) {
final Type at = i.next();
printType(at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
if (i.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
w.write(">");
w.write(" ");
}
}
public static boolean alreadyPrinted(List<Type> alreadyPrintedTypes, Type type) {
boolean alreadyPrinted = false;
if (type instanceof FunctionType) {
if (((FunctionType) type).returnType().isVoid()) {
for (Type apt : alreadyPrintedTypes) {
if (apt instanceof FunctionType && ((FunctionType) apt).returnType().isVoid()) {
if (((FunctionType) apt).typeArguments().size() == ((FunctionType) type).typeArguments().size()) {
alreadyPrinted = true;
break;
}
}
}
} else {
for (Type apt : alreadyPrintedTypes) {
if (apt instanceof FunctionType && !((FunctionType) apt).returnType().isVoid()) {
if (((FunctionType) apt).typeArguments().size() == ((FunctionType) type).typeArguments().size()) {
alreadyPrinted = true;
break;
}
}
}
}
}
else if (type.isClass()) {
X10ClassType ct = type.toClass();
if (ct.typeArguments() != null && ct.typeArguments().size() > 0) {
for (Type apt : alreadyPrintedTypes) {
if (apt.isClass() && !(apt instanceof FunctionType)) {
if (apt.toClass().name().toString().equals(type.toClass().name().toString())) {
alreadyPrinted = true;
break;
}
}
}
}
}
return alreadyPrinted;
}
public static String getMangledMethodSuffix(ClassType ct, List<Ref<? extends Type>> formalTypes, boolean printIncludingGeneric) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < formalTypes.size(); ++i) {
Type type = formalTypes.get(i).get();
buildMangledMethodName(ct, sb, i, type, printIncludingGeneric);
}
return sb.toString();
}
private static String getMangledMethodName(MethodDef md, boolean printIncludingGeneric) {
String methodName = mangleToJava(md.name());
ClassType ct = (ClassType) md.container().get();
List<Ref<? extends Type>> formalTypes = md.formalTypes();
String methodSuffix = getMangledMethodSuffix(ct, formalTypes, printIncludingGeneric);
return methodName + methodSuffix;
}
private static String getMangledMethodName(ClassType ct, MethodInstance mi, boolean printIncludingGeneric) {
StringBuilder sb = new StringBuilder(mangleToJava(mi.name()));
List<Type> formalTypes = mi.formalTypes();
for (int i = 0; i < formalTypes.size(); ++i) {
Type type = formalTypes.get(i);
buildMangledMethodName(ct, sb, i, type, printIncludingGeneric);
}
return sb.toString();
}
private static void buildMangledMethodName(ClassType ct, StringBuilder sb, int i, Type type, boolean printIncludingGeneric) {
Type t = Types.baseType(type);
if (t.isUnsignedNumeric()) {
sb.append(FORMAL_MARKER(i));
sb.append(UNSIGNED_NUMERIC_TYPE_SUFFIX);
}
else if (t.isClass() && (printIncludingGeneric || !containsTypeParam(t))) {
// def g(l:x10.util.Map[x10.lang.Int,x10.lang.Float]) {...}
// -> g__0$1x10$lang$Int$3x10$lang$Float$2(x10.util.Map l) {...} ("$1", "$2" and "$3" means "[", "]" and ",", respectively)
X10ClassType x10t = t.toClass();
List<Type> ts = x10t.typeArguments();
if (ts != null && ts.size() > 0) {
sb.append(FORMAL_MARKER(i));
sb.append("$1"); // "$1" means "["
String delim = null;
for (Type t1 : ts) {
if (delim != null) sb.append(delim);
delim = "$3"; // "$3" means ","
appendParameterizedType(sb, ct, Types.baseType(t1));
}
sb.append("$2"); // "$2" means "]"
}
}
else if (printIncludingGeneric && t.isParameterType()) {
// class I[T] { def foo(t:T) {...} }
// -> class I<T> { foo__0I$$T(T t) {...} } ("I$$T" means T of I)
sb.append(FORMAL_MARKER(i));
appendParameterType(ct, sb, (ParameterType) t);
}
}
private static void appendParameterizedType(StringBuilder sb, ClassType ct, Type t) {
if (t.isClass()) {
X10ClassType x10t = t.toClass();
sb.append(mangleAndFlattenQName(x10t));
if (x10t.typeArguments() != null && x10t.typeArguments().size() > 0) {
List<Type> ts = x10t.typeArguments();
if (ts.size() > 0) {
sb.append("$1"); // "$1" means "["
String delim = null;
for (Type t1 : ts) {
if (delim != null) sb.append(delim);
delim = "$3"; // "$3" means ","
appendParameterizedType(sb, ct, Types.baseType(t1));
}
sb.append("$2"); // "$2" means "]"
}
}
}
else if (t.isParameterType()) {
appendParameterType(ct, sb, (ParameterType) t);
}
else {
sb.append(mangleAndFlattenQName(t));
}
}
private static void appendParameterType(ClassType ct, StringBuilder sb, ParameterType t) {
// N.B. As of September 2011, type parameters are alpha-renamed so that each type parameter has a unique name at every location.
// Therefore the full name of the type which the type parameter belongs to is not necessarily needed.
sb.append(mangleAndFlattenQName(ct));
sb.append("$$");
sb.append(mangleIdentifier(t.name()));
}
public static boolean containsTypeParam(Type type) {
if (type.isParameterType()) {
return true;
}
else if (type.isClass()) {
List<Type> tas = type.toClass().typeArguments();
if (tas != null) {
for (Type type1 : tas) {
if (containsTypeParam(type1)) {
return true;
}
}
}
}
return false;
}
/*
* The word 'instantiated' means the instantiation of type parameter (e.g. T) with concrete type (e.g. Int).
*/
private void generateBridgeMethodsForGenerics(X10ClassDef cd) {
if (cd.flags().isInterface()) {
return;
}
X10ClassType ct = cd.asType();
for (MethodDef md : cd.methods()) {
List<MethodInstance> methods = getInstantiatedMethods(ct, md.asInstance());
for (MethodInstance mi : methods) {
printBridgeMethod(ct, md.asInstance(), mi.def(), false);
}
}
List<MethodInstance> inheriteds = new ArrayList<MethodInstance>();
List<MethodInstance> overrides = new ArrayList<MethodInstance>();
getInheritedMethods(ct, inheriteds, overrides);
for (MethodInstance mi : inheriteds) {
if (isInstantiated(mi.def().returnType().get(), mi.returnType())) {
printBridgeMethodForInheritedMethod(ct, mi);
continue;
}
for (int i = 0; i < mi.formalTypes().size(); ++ i) {
if (
isPrimitive(mi.formalTypes().get(i)) &&
isInstantiated(mi.def().formalTypes().get(i).get(), mi.formalTypes().get(i))
) {
printBridgeMethodForInheritedMethod(ct, mi);
break;
}
}
List<MethodInstance> implMethods = new ArrayList<MethodInstance>();
List<Type> interfaces = ct.interfaces();
getImplMethods(mi, implMethods, interfaces);
for (MethodInstance mi2 : implMethods) {
printBridgeMethod(ct, mi, mi2.def(), false);
}
}
}
/*
* 'inheriteds' will include all visible methods that are inherited from super classes to ct.
*/
private void getInheritedMethods(X10ClassType ct, List<MethodInstance> inheriteds, List<MethodInstance> overrides) {
ArrayList<MethodInstance> list = new ArrayList<MethodInstance>(ct.methods());
list.addAll(inheriteds);
for (MethodInstance mi : list) {
for (MethodInstance mi2 : mi.overrides(tr.context())) {
if (X10PrettyPrinterVisitor.supportGenericOverloading || (ct.superClass() != null && mi2.container().typeEquals(ct.superClass(), tr.context()))) {
overrides.add(mi2);
}
}
}
Type sup = ct.superClass();
if (sup != null && sup.isClass()) {
for (MethodInstance mi : sup.toClass().methods()) {
if (!mi.flags().isStatic() && !mi.flags().isPrivate()) {
boolean contains = false;
for (MethodInstance mi2 : overrides) {
if (mi2.isSameMethod(mi, tr.context())) {
contains = true;
break;
}
}
if (!contains) {
inheriteds.add(mi);
}
}
}
getInheritedMethods(sup.toClass(), inheriteds, overrides);
}
}
private void getImplMethods(MethodInstance mi, List<MethodInstance> implMethods, List<Type> interfaces) {
for (Type type : interfaces) {
if (type.isClass()) {
List<MethodInstance> imis = type.toClass().methods();
for (MethodInstance imi : imis) {
if (!(imi.name().equals(mi.name()) && imi.formalTypes().size() == mi.formalTypes().size())) continue;
if (containsInstantiatedMethod(implMethods, imi)) continue;
Type returnType = mi.returnType();
if (X10PrettyPrinterVisitor.supportGenericOverloading) {
if (
returnType.typeEquals(imi.returnType() , tr.context())
&& isInstantiated(imi.def().returnType().get(), returnType)
) {
boolean containsParam = false;
List<Ref<? extends Type>> types = imi.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (
mi.formalTypes().get(i).typeEquals(imi.formalTypes().get(i), tr.context())
&& containsTypeParam(imi.def().formalTypes().get(i).get())
) {
containsParam = true;
break;
}
}
if (!containsParam) {
implMethods.add(imi);
break;
}
}
} else {
if (
returnType.typeEquals(imi.returnType() , tr.context())
&& isInstantiated(imi.def().returnType().get(), returnType)
) {
implMethods.add(imi);
break;
}
List<Ref<? extends Type>> types = imi.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (
mi.formalTypes().get(i).typeEquals(imi.formalTypes().get(i), tr.context())
&& isPrimitive(mi.formalTypes().get(i))
&& isInstantiated(types.get(i).get(), mi.formalTypes().get(i))
) {
implMethods.add(imi);
break;
}
}
}
}
getImplMethods(mi, implMethods, type.toClass().interfaces());
}
}
}
private List<MethodInstance> getInstantiatedMethods(X10ClassType ct, MethodInstance mi) {
List<MethodInstance> methods = new ArrayList<MethodInstance>();
if (mi.flags().isPrivate()) return methods; // N.B. shortcut for (*1) is this needed?
for (MethodInstance impled : mi.implemented(tr.context())) {
// if (mi.flags().isPrivate()) continue; // N.B. (*1) is this needed?
if (mi.container().typeEquals(impled.container(), tr.context())) continue;
// Fix for XTENLANG-2940
// if (X10PrettyPrinterVisitor.supportGenericOverloading) {
if (false) {
boolean contains = false;
for (MethodInstance mi1 : methods) {
if (mi1.def().equals(impled.def())) {
contains = true;
break;
}
}
if (contains) continue;
}
else {
if (containsInstantiatedMethod(methods, impled)) continue;
}
Type ti = impled.container();
ti = Types.baseType(ti);
if (ti.isClass() && !ti.toClass().flags().isInterface()) {
if (
X10PrettyPrinterVisitor.supportGenericOverloading
|| (ti.typeEquals(ct.superClass(), tr.context()) || (ct.isMember() && ti.typeEquals(ct.container(), tr.context())))
) {
Type returnType = mi.returnType();
if (isInstantiated(impled.def().returnType().get(), returnType)) {
methods.add(impled);
continue;
}
else {
List<Ref<? extends Type>> types = impled.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (
(
X10PrettyPrinterVisitor.supportGenericOverloading
&& containsTypeParam(types.get(i).get())
)
|| (
!X10PrettyPrinterVisitor.supportGenericOverloading
&& isPrimitive(mi.formalTypes().get(i))
&& isInstantiated(types.get(i).get(), mi.formalTypes().get(i))
)
) {
methods.add(impled);
break;
}
}
}
}
}
else {
for (Type t : ct.interfaces()) {
if (existMethodInterface(t, ti, impled, mi)) {
methods.add(impled);
break;
}
}
}
}
return methods;
}
private static boolean isInstantiated(Type sup, Type t) {
return sup.isParameterType() && !t.isParameterType();
}
private boolean existMethodInterface(Type t, Type type, MethodInstance mi, MethodInstance mdi) {
if (t.typeEquals(type, tr.context())) {
Type returnType = mdi.returnType();
if (isInstantiated(mi.def().returnType().get(), returnType)) {
if (X10PrettyPrinterVisitor.supportGenericOverloading) {
boolean containsTypeParam = false;
List<Ref<? extends Type>> types = mi.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (containsTypeParam(types.get(i).get())) {
containsTypeParam = true;
break;
}
}
if (!containsTypeParam) return true;
} else {
return true;
}
}
if (!X10PrettyPrinterVisitor.supportGenericOverloading) {
List<Ref<? extends Type>> types = mi.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (containsTypeParam(types.get(i).get())) return false;
if (
isPrimitive(mdi.formalTypes().get(i))
&& isInstantiated(types.get(i).get(), mdi.formalTypes().get(i))
) {
return true;
}
}
}
}
t = Types.baseType(t);
if (t.isClass()) {
for (Type ti : t.toClass().interfaces()) {
if (existMethodInterface(ti, type, mi, mdi)) {
return true;
}
}
}
return false;
}
// old and potentially buggy code
// private boolean containsInstantiatedMethod(List<MethodInstance> methods, MethodInstance impled) {
// for (MethodInstance mi : methods) {
// if (
// !(
// (mi.def().returnType().get().isParameterType() && impled.def().returnType().get().isParameterType())
// || (!mi.def().returnType().get().isParameterType() && !impled.def().returnType().get().isParameterType())
// )
// ) {
// continue;
//// return false;
// }
// List<Ref<? extends Type>> types = mi.def().formalTypes();
// for (int i = 0;i < types.size(); ++i) {
// if (
// !(
// (types.get(i).get().isParameterType() && impled.def().formalTypes().get(i).get().isParameterType()))
// || (!types.get(i).get().isParameterType() && !impled.def().formalTypes().get(i).get().isParameterType())
// ) {
// continue;
//// return false;
// }
// }
// return true;
// }
// return false;
// }
// correct code
private static boolean containsInstantiatedMethod(List<MethodInstance> methods, MethodInstance impled) {
MethodDef impledDef = impled.def();
List<Ref<? extends Type>> implFormalTypes = impledDef.formalTypes();
methods: for (MethodInstance mi : methods) {
MethodDef miDef = mi.def();
Type miReturnType = miDef.returnType().get();
Type impledReturnType = impledDef.returnType().get();
if (
!(
(miReturnType.isParameterType() && impledReturnType.isParameterType())
|| (!miReturnType.isParameterType() && !impledReturnType.isParameterType())
)
) continue;
List<Ref<? extends Type>> miFormalTypes = miDef.formalTypes();
for (int i = 0; i < miFormalTypes.size(); ++i) {
Type miFormalType = miFormalTypes.get(i).get();
Type implFormalType = implFormalTypes.get(i).get();
if (
!(
(miFormalType.isParameterType() && implFormalType.isParameterType())
|| (!miFormalType.isParameterType() && !implFormalType.isParameterType())
)
) continue methods;
}
return true;
}
return false;
}
private void printBridgeMethod(ClassType ct, MethodInstance impl, MethodDef def, boolean isCovariantOverride) {
// bridge method should not be needed for unmangled method
if (!canMangleMethodName(def)) return;
w.write("// bridge for " + def);
w.newline();
Flags flags = impl.flags();
w.begin(0);
w.write(flags.clearAbstract().clearProtected().Public()
.clear(Flags.NATIVE)
.translateJava()
);
ContainerType st = def.container().get();
// XTENLANG-3144 type parameters should be of method instance rather than of method def
// if (def instanceof X10MethodDef) {
// List<ParameterType> tps = ((X10MethodDef) def).typeParameters();
// if (tps.size() > 0) {
// w.write("<");
// String delim = "";
// for (ParameterType pt : tps) {
// w.write(delim);
// delim = ",";
// w.write(mangleParameterType(pt));
// }
// w.write(">");
// w.write(" ");
// }
// }
List<Type> tps = impl.typeParameters();
if (tps.size() > 0) {
w.write("<");
String delim = "";
for (Type t : tps) {
w.write(delim);
delim = ",";
w.write(mangleParameterType((ParameterType) t));
}
w.write(">");
w.write(" ");
}
// e.g int m() overrides or implements T m()
boolean instantiateReturnType = isBoxedType(Types.baseType(def.returnType().get()));
int intflags = instantiateReturnType ? BOX_PRIMITIVES : 0;
if (!X10PrettyPrinterVisitor.supportGenericOverloading) intflags |= PRINT_TYPE_PARAMS;
printType(impl.returnType(), intflags);
boolean isInterface = st.isClass() && st.toClass().flags().isInterface();
w.allowBreak(2, 2, " ", 1);
// decl
// print the method name
printMethodName(def, isInterface, false, false, null);
// print the formals
w.write("(");
boolean first = true;
// XTENLANG-3144 type parameters should be of method instance rather than of method def (*)
// if (X10PrettyPrinterVisitor.supportGenericOverloading && def instanceof X10MethodDef && !isInterface) {
// X10MethodDef x10def = (X10MethodDef) def;
// for (ParameterType p : x10def.typeParameters()) {
// if (!first) {
// w.write(",");
// w.allowBreak(0, " ");
// }
// first = false;
// w.write("final ");
// w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
// w.write(" ");
// w.write(mangleParameterType(p));
// }
// }
if (X10PrettyPrinterVisitor.supportGenericOverloading && !isInterface) {
for (Type t : impl.typeParameters()) {
if (!first) {
w.write(",");
w.allowBreak(0, " ");
}
first = false;
w.write("final ");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
w.write(mangleParameterType((ParameterType) t));
}
}
for (int i = 0; i < def.formalTypes().size(); i++) {
Type f = impl.formalTypes().get(i);
if (!first || i != 0) {
w.write(",");
w.allowBreak(0, " ");
}
if (def.formalTypes().get(i).get().isParameterType()) {
printType(f, (X10PrettyPrinterVisitor.supportGenericOverloading ? 0 : PRINT_TYPE_PARAMS) | BOX_PRIMITIVES);
} else {
printType(f, X10PrettyPrinterVisitor.supportGenericOverloading ? 0 : PRINT_TYPE_PARAMS);
}
w.write(" ");
Name name = Name.make("a" + (i + 1));
w.write(name.toString());
}
w.end();
w.write(")");
boolean isFirst = true;
for (Type _throws : impl.throwTypes()) {
if (isFirst) {
w.write(" throws ");
isFirst = false;
} else {
w.write(", ");
}
printType(_throws, 0);
}
w.write("{");
if (!impl.returnType().isVoid()) {
w.write("return ");
}
boolean closeParen = false;
if (instantiateReturnType && !isBoxedType(impl.returnType())) {
printBoxConversion(impl.returnType());
w.write("(");
closeParen = true;
}
TypeSystem xts = tr.typeSystem();
boolean isInterface2 = false;
ContainerType st2 = impl.container();
Type bst = Types.baseType(st2);
if (st2.isClass()) {
if (xts.isInterfaceType(bst) || (xts.isFunctionType(bst) && bst.toClass().isAnonymous())) {
isInterface2 = true;
}
}
// call
printMethodName(impl.def(), isInterface2, false, false, null);
// print the argument list
w.write("(");
boolean first2 = true;
// XTENLANG-3144 type parameters should be of method instance rather than of method def (*)
// MethodInstance dmi = def.asInstance();
MethodInstance dmi = impl;
for (Iterator<Type> i = dmi.typeParameters().iterator(); i.hasNext(); ) {
final Type at = i.next();
first2 = false;
// TODO
new RuntimeTypeExpander(this, at).expand();
if (i.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
for (int i = 0; i < impl.formalTypes().size(); i++) {
Type f = impl.formalTypes().get(i);
if (!first2 || i != 0) {
w.write(",");
w.allowBreak(0, " ");
}
Name name = Name.make("a" + (i + 1));
boolean closeParenArg = false;
if (isPrimitive(f) && isBoxedType(def.formalTypes().get(i).get())) {
closeParenArg = printUnboxConversion(f);
}
w.write(name.toString());
if (closeParenArg) w.write(")");
}
w.write(")");
if (closeParen) {
w.write(")");
}
w.write(";");
w.write("}");
w.newline();
}
private void printBridgeMethodForInheritedMethod(ClassType ct, MethodInstance mi) {
MethodDef def = mi.def();
w.write("// bridge for " + def);
w.newline();
Flags flags = mi.flags();
w.begin(0);
w.write(flags.clearAbstract()
.clear(Flags.NATIVE)
.translateJava()
);
printType(mi.returnType(), PRINT_TYPE_PARAMS);
w.allowBreak(2, 2, " ", 1);
// print the method name
printMethodName(ct, mi);
w.write("(");
for (int i = 0; i < def.formalTypes().size(); i++) {
Type f = mi.formalTypes().get(i);
if (i != 0) {
w.write(",");
w.allowBreak(0, " ");
}
printType(f, (X10PrettyPrinterVisitor.supportGenericOverloading ? 0 : PRINT_TYPE_PARAMS));
w.write(" ");
Name name = Name.make("a" + (i + 1));
w.write(name.toString());
}
w.end();
w.write(")");
boolean isFirst = true;
for (Type _throws : mi.throwTypes()) {
if (isFirst) {
w.write(" throws ");
isFirst = false;
} else {
w.write(", ");
}
printType(_throws, 0);
}
w.write("{");
if (!mi.returnType().isVoid()) {
w.write("return ");
}
boolean closeParen = false;
if (!isBoxedType(mi.returnType()) && isBoxedType(mi.def().returnType().get())) {
// handle unboxing of the UInt values
closeParen = printUnboxConversion(mi.returnType());
}
w.write("super.");
// call
printMethodName(def, false, false, false, null);
// print the argument list
w.write("(");
for (int i = 0; i < mi.formalTypes().size(); i++) {
Type f = mi.formalTypes().get(i);
if (i != 0) {
w.write(",");
w.allowBreak(0, " ");
}
if (isPrimitive(f) && isInstantiated(def.formalTypes().get(i).get(), f)) {
printBoxConversion(f);
}
w.write("("); // required by printBoxConversion()
Name name = Name.make("a" + (i + 1));
w.write(name.toString());
w.write(")");
}
w.write(")");
if (closeParen) w.write(")");
w.write(";");
w.write("}");
w.newline();
}
private void generateBridgeMethodsForCovariantOverride(X10ClassDef cd) {
if (cd.flags().isInterface()) {
return;
}
X10ClassType ct = cd.asType();
for (MethodDef md : cd.methods()) {
List<MethodInstance> methods = getCovarientOverriddenMethods(ct, md.asInstance());
for (MethodInstance mi : methods) {
printBridgeMethod(ct, md.asInstance(), mi.def(), true);
}
}
List<MethodInstance> inheriteds = new ArrayList<MethodInstance>();
List<MethodInstance> overrides = new ArrayList<MethodInstance>();
getInheritedMethods(ct, inheriteds, overrides);
for (MethodInstance mi : inheriteds) {
// if (isCovariantOverride(mi.def().returnType().get(), mi.returnType())) {
// printBridgeMethodForInheritedMethod(ct, mi);
// continue;
// }
List<MethodInstance> implMethods = new ArrayList<MethodInstance>();
List<Type> interfaces = ct.interfaces();
getImplMethodsForCovariantOverride(mi, implMethods, interfaces);
for (MethodInstance mi2 : implMethods) {
printBridgeMethod(ct, mi, mi2.def(), true);
}
}
}
// Fix for XTENLANG-3035
// old and buggy code
// public void generateBridgeMethods(X10ClassDef cd) {
// generateBridgeMethodsForGenerics(cd);
// generateBridgeMethodsForCovariantOverride(cd);
// }
public void generateBridgeMethods(X10ClassDef cd) {
if (cd.flags().isInterface()) return;
List<MethodDef> methoddefs = cd.methods();
X10ClassType ct = cd.asType();
List<Type> interfaces = ct.interfaces();
List<MethodInstance> inheriteds = new ArrayList<MethodInstance>();
List<MethodInstance> overrides = new ArrayList<MethodInstance>();
getInheritedMethods(ct, inheriteds, overrides);
// first half
for (MethodDef md : methoddefs) {
MethodInstance impl = md.asInstance();
// generateBridgeMethodsForGenerics(cd);
List<MethodInstance> instantiatedMethods = getInstantiatedMethods(ct, impl);
for (MethodInstance instantiatedMethod : instantiatedMethods) {
printBridgeMethod(ct, impl, instantiatedMethod.def(), false);
}
// generateBridgeMethodsForCovariantOverride(cd);
List<MethodInstance> overriddenMethods = getCovarientOverriddenMethods(ct, impl);
alreadyGenerated: for (MethodInstance overriddenMethod : overriddenMethods) {
// N.B. skip already generated bridge method
if (!isString(impl.returnType())) {
MethodDef overriddenMethodDef = overriddenMethod.def();
for (MethodInstance instantiatedMethod : instantiatedMethods) {
if (hasSameSignature(overriddenMethodDef, instantiatedMethod.def())) continue alreadyGenerated;
}
}
printBridgeMethod(ct, impl, overriddenMethod.def(), true);
}
}
// second half
// generateBridgeMethodsForGenerics(cd);
for (MethodInstance mi : inheriteds) {
if (isInstantiated(mi.def().returnType().get(), mi.returnType())) {
printBridgeMethodForInheritedMethod(ct, mi);
continue;
}
for (int i = 0; i < mi.formalTypes().size(); ++i) {
if (isPrimitive(mi.formalTypes().get(i)) && isInstantiated(mi.def().formalTypes().get(i).get(), mi.formalTypes().get(i))) {
printBridgeMethodForInheritedMethod(ct, mi);
break;
}
}
List<MethodInstance> implMethods = new ArrayList<MethodInstance>();
getImplMethods(mi, implMethods, interfaces);
for (MethodInstance mi2 : implMethods) {
printBridgeMethod(ct, mi, mi2.def(), false);
}
}
// generateBridgeMethodsForCovariantOverride(cd);
for (MethodInstance mi : inheriteds) {
// if (isCovariantOverride(mi.def().returnType().get(), mi.returnType())) {
// printBridgeMethodForInheritedMethod(ct, mi);
// continue;
// }
List<MethodInstance> implMethods = new ArrayList<MethodInstance>();
getImplMethodsForCovariantOverride(mi, implMethods, interfaces);
for (MethodInstance mi2 : implMethods) {
printBridgeMethod(ct, mi, mi2.def(), true);
}
}
}
private List<MethodInstance> getCovarientOverriddenMethods(X10ClassType ct, MethodInstance mi) {
List<MethodInstance> methods = new ArrayList<MethodInstance>();
if (mi.flags().isPrivate()) return methods; // N.B. shortcut for (*1) is this needed?
for1:for (MethodInstance impled : mi.implemented(tr.context())) {
// if (mi.flags().isPrivate()) continue; // N.B. (*1) is this needed?
if (mi.container().typeEquals(impled.container(), tr.context())) continue;
if (X10PrettyPrinterVisitor.supportGenericOverloading) {
for2:for (MethodInstance mi1 : methods) {
if (mi1.def().equals(impled.def())) {
continue for1;
}
List<Ref<? extends Type>> types = impled.def().formalTypes();
List<Ref<? extends Type>> types2 = mi1.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (!types.get(i).get().typeEquals(types2.get(i).get(), tr.context())) {
continue for2;
}
}
continue for1;
}
}
else {
if (containsCovariantOverridingMethod(methods, impled)) continue;
}
Type ti = impled.container();
ti = Types.baseType(ti);
if (ti.isClass() && !ti.toClass().flags().isInterface()) {
if (
X10PrettyPrinterVisitor.supportGenericOverloading
|| (ti.typeEquals(ct.superClass(), tr.context()) || (ct.isMember() && ti.typeEquals(ct.container(), tr.context())))
) {
Type returnType = mi.returnType();
if (isCovariantOverride(impled.def().returnType().get(), returnType)) {
methods.add(impled);
continue;
}
}
}
else {
for (Type t : ct.interfaces()) {
if (existMethodInterfaceForCovariantOverride(t, ti, impled, mi)) {
methods.add(impled);
break;
}
}
}
}
return methods;
}
private boolean isCovariantOverride(Type sup, Type returnType) {
return !sup.typeSystem().isParameterType(sup) && !Types.baseType(sup).typeEquals(Types.baseType(returnType), tr.context()) && isSpecialType(Types.baseType(returnType));
}
private boolean containsCovariantOverridingMethod(List<MethodInstance> methods, MethodInstance impled) {
for (MethodInstance mi : methods) {
if (isCovariantOverride(impled.def().returnType().get(), mi.returnType())) {
return true;
}
}
return false;
}
private boolean existMethodInterfaceForCovariantOverride(Type t, Type type, MethodInstance mi, MethodInstance mdi) {
if (t.typeEquals(type, tr.context())) {
Type returnType = mdi.returnType();
if (isCovariantOverride(mi.def().returnType().get(), returnType)) {
return true;
}
}
t = Types.baseType(t);
if (t.isClass()) {
for (Type ti : t.toClass().interfaces()) {
if (existMethodInterfaceForCovariantOverride(ti, type, mi, mdi)) {
return true;
}
}
}
return false;
}
private void getImplMethodsForCovariantOverride(MethodInstance mi, List<MethodInstance> implMethods, List<Type> interfaces) {
for (Type type : interfaces) {
if (type.isClass()) {
List<MethodInstance> imis = type.toClass().methods();
for (MethodInstance imi : imis) {
if (!(imi.name().equals(mi.name()) && imi.formalTypes().size() == mi.formalTypes().size())) continue;
if (containsCovariantOverridingMethod(implMethods, imi)) continue;
Type returnType = mi.returnType();
if (X10PrettyPrinterVisitor.supportGenericOverloading) {
if (isCovariantOverride(imi.def().returnType().get(), returnType)) {
boolean containsParam = false;
List<Ref<? extends Type>> types = imi.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (
mi.formalTypes().get(i).typeEquals(imi.formalTypes().get(i), tr.context())
&& containsTypeParam(imi.def().formalTypes().get(i).get())
) {
containsParam = true;
break;
}
}
if (!containsParam) {
implMethods.add(imi);
break;
}
}
} else {
if (isCovariantOverride(imi.def().returnType().get(), returnType)) {
implMethods.add(imi);
break;
}
}
}
getImplMethodsForCovariantOverride(mi, implMethods, type.toClass().interfaces());
}
}
}
public void generateDispatchMethods(X10ClassDef cd) {
if (cd.flags().isInterface()) {
return;
}
X10ClassType ct = cd.asType();
List<MethodInstance> methods = ct.methods();
List<Type> interfaces = ct.interfaces();
List<Type> allInterfaces = new ArrayList<Type>();
getAllInterfaces(interfaces, allInterfaces);
Map<MethodInstance, List<MethodInstance>> dispatcherToMyMethods = CollectionFactory.newHashMap();
for (MethodInstance myMethod : methods) {
if (myMethod.flags().isStatic()) continue;
List<MethodInstance> implementeds = myMethod.implemented(tr.context());
List<MethodInstance> targets = new ArrayList<MethodInstance>();
for (MethodInstance implemented : implementeds) {
if (implemented.def().equals(myMethod.def())) continue;
// only interface
ContainerType st = implemented.def().container().get();
if (st.isClass()) {
if (!st.toClass().flags().isInterface()) {
continue;
}
// 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 (isNativeRepedToJava(st)) {
continue;
}
}
boolean containsTypeParam = false;
List<Ref<? extends Type>> formalTypes = implemented.def().formalTypes();
for (Ref<? extends Type> ref : formalTypes) {
Type type = ref.get();
if (containsTypeParam(type)) {
containsTypeParam = true;
break;
}
}
if (!containsTypeParam) continue;
// only implements by itself not super class's
boolean containsInterface = false;
for (Type type : allInterfaces) {
if (type.typeEquals(implemented.container(), tr.context())) {
containsInterface = true;
break;
}
}
if (!containsInterface) continue;
if (!containsSameSignature(targets, implemented)) {
targets.add(implemented);
}
}
add(dispatcherToMyMethods, myMethod, targets);
}
List<MethodInstance> inheriteds = new ArrayList<MethodInstance>();
List<MethodInstance> overrides = new ArrayList<MethodInstance>();
getInheritedMethods(ct, inheriteds, overrides);
for (MethodInstance mi : inheriteds) {
List<MethodInstance> implMethods = new ArrayList<MethodInstance>();
getImplMethodsForDispatch(mi, implMethods, interfaces);
add(dispatcherToMyMethods, mi, implMethods);
}
Set<Entry<MethodInstance, List<MethodInstance>>> entrySet = dispatcherToMyMethods.entrySet();
for (Entry<MethodInstance, List<MethodInstance>> entry : entrySet) {
printDispatchMethod(entry.getKey(), entry.getValue());
}
}
private static boolean hasSameSignature(MethodDef md, MethodDef td) {
if (!md.name().equals(td.name())) return false;
List<Ref<? extends Type>> mdFormalTypes = md.formalTypes();
List<Ref<? extends Type>> tdFormalTypes = td.formalTypes();
if (mdFormalTypes.size() != tdFormalTypes.size()) return false;
for (int i = 0; i < mdFormalTypes.size(); ++i) {
Type ft = mdFormalTypes.get(i).get();
Type tt = tdFormalTypes.get(i).get();
if (ft.isParameterType() && tt.isParameterType()) {}
else if (ft.isClass() && tt.isClass() && ft.toClass().name().toString().equals(tt.toClass().name().toString())) {}
else {
return false;
}
}
return true;
}
private static void add(Map<MethodInstance, List<MethodInstance>> dispatcherToMyMethods, MethodInstance myMethod, List<MethodInstance> targets) {
for (MethodInstance target : targets) {
boolean containsSameSignature = false;
Set<Entry<MethodInstance, List<MethodInstance>>> entrySet = dispatcherToMyMethods.entrySet();
for (Entry<MethodInstance, List<MethodInstance>> entry : entrySet) {
MethodDef md = entry.getKey().def();
MethodDef td = target.def();
List<Ref<? extends Type>> mdFormalTypes = md.formalTypes();
List<Ref<? extends Type>> tdFormalTypes = td.formalTypes();
if (md.name().equals(td.name()) && mdFormalTypes.size() == tdFormalTypes.size()) {
containsSameSignature = true;
for (int i = 0; i < mdFormalTypes.size(); ++i) {
Type ft = mdFormalTypes.get(i).get();
Type tt = tdFormalTypes.get(i).get();
if (ft.isParameterType() && tt.isParameterType()) {}
else if (ft.isClass() && tt.isClass() && ft.toClass().name().toString().equals(tt.toClass().name().toString())) {}
else {
containsSameSignature = false;
break;
}
}
if (containsSameSignature) {
entry.getValue().add(myMethod);
}
}
}
if (containsSameSignature) break;
ArrayList<MethodInstance> mis = new ArrayList<MethodInstance>();
mis.add(myMethod);
dispatcherToMyMethods.put(target, mis);
}
}
private void getImplMethodsForDispatch(MethodInstance mi, List<MethodInstance> implMethods, List<Type> interfaces) {
for (Type type : interfaces) {
if (type.isClass()) {
List<MethodInstance> imis = type.toClass().methods();
for (MethodInstance imi : imis) {
if (!(imi.name().equals(mi.name()) && imi.formalTypes().size() == mi.formalTypes().size())) continue;
if (containsSameSignature(implMethods, imi)) continue;
List<Ref<? extends Type>> types = imi.def().formalTypes();
for (int i = 0;i < types.size(); ++i) {
if (containsTypeParam(types.get(i).get()) ) {
implMethods.add(imi);
break;
}
}
}
getImplMethodsForDispatch(mi, implMethods, type.toClass().interfaces());
}
}
}
private static void getAllInterfaces(List<Type> interfaces, List<Type> allInterfaces) {
allInterfaces.addAll(interfaces);
for (Type type : interfaces) {
type = Types.baseType(type);
if (type.isClass()) {
List<Type> interfaces1 = type.toClass().interfaces();
getAllInterfaces(interfaces1, allInterfaces);
}
}
}
private boolean hasSameSignature(MethodInstance mi2, MethodInstance mi1) {
if (!mi2.name().equals(mi1.name())) return false;
List<Type> formalTypes1 = mi1.formalTypes();
List<Type> formalTypes2 = mi2.formalTypes();
if (formalTypes1.size() != formalTypes2.size()) return false;
// old and potentially buggy code
// for (int i = 0; i < formalTypes1.size(); ++i) {
// Type type1 = formalTypes1.get(i);
// Type type2 = formalTypes2.get(i);
// if (type1.typeEquals(type2, tr.context()) || (type1.isParameterType() && type2.isParameterType()))
// return true;
// }
// return false;
// correct code
for (int i = 0; i < formalTypes1.size(); ++i) {
Type type1 = formalTypes1.get(i);
Type type2 = formalTypes2.get(i);
if (!(type1.typeEquals(type2, tr.context()) || (type1.isParameterType() && type2.isParameterType())))
return false;
}
return true;
}
private boolean containsSameSignature(List<MethodInstance> targets, MethodInstance mi1) {
for (MethodInstance mi2 : targets) {
if (hasSameSignature(mi2, mi1)) return true;
}
return false;
}
private void printDispatchMethod(MethodInstance dispatch, List<MethodInstance> mis, boolean isSpecialTypeForDispatcher, Type returnTypeForDispatcher) {
MethodDef def = dispatch.def();
Flags flags = dispatch.flags();
X10MethodDef x10def = (X10MethodDef) def;
Name[] names = null;
boolean first = false;
w.write("// dispatcher for " + def);
w.newline();
w.begin(0);
w.write(flags.clearAbstract().clear(Flags.NATIVE).translateJava());
// print return type
// XTENLANG-2993
if (!isSpecialTypeForDispatcher) {
w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
} else {
printType(returnTypeForDispatcher, X10PrettyPrinterVisitor.supportTypeConstraintsWithErasure ? 0 : PRINT_TYPE_PARAMS);
}
w.write(" ");
// decl
// print method name
// XTENLANG-2993
printMethodName(def, true, true, isSpecialTypeForDispatcher, returnTypeForDispatcher);
w.write("(");
first = true;
for (ParameterType p : x10def.typeParameters()) {
if (!first) {
w.write(", ");
} else {
first = false;
}
w.write("final ");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
w.write(mangleParameterType(p));
}
names = new Name[def.formalTypes().size()];
for (int i = 0; i < def.formalTypes().size(); i++) {
Type f = dispatch.formalTypes().get(i);
if (!first || i != 0) {
w.write(", ");
}
Type type = def.formalTypes().get(i).get();
if (containsTypeParam(type)) {
w.write("final ");
if (type.isParameterType()) {
w.write(X10PrettyPrinterVisitor.JAVA_LANG_OBJECT);
} else {
printType(type, 0);
}
w.write(" ");
Name name = Name.make("a" + (i + 1));
w.write(name.toString());
w.write(", ");
w.write("final ");
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE);
w.write(" ");
Name name1 = Name.make("t" + (i + 1));
w.write(name1.toString());
names[i] = name1;
} else {
w.write("final ");
printType(f, 0);
w.write(" ");
Name name = Name.make("a" + (i + 1));
w.write(name.toString());
}
}
w.end();
w.write(")");
boolean isFirst = true;
for (Ref<? extends Type> _throws : def.throwTypes()) {
if (isFirst) {
w.write(" throws ");
isFirst = false;
} else {
w.write(", ");
}
printType(_throws.get(), 0);
}
w.write(" {");
w.newline();
for (MethodInstance mi : mis) {
if (mis.size() != 1) {
boolean first3 = true;
for (int i = 0; i < names.length; i++) {
Name name = names[i];
if (name == null) continue;
if (first3) {
w.write("if (");
first3 = false;
}
else {
w.write(" && ");
}
w.write(name.toString());
w.write(".equals(");
new RuntimeTypeExpander(this, mi.formalTypes().get(i)).expand();
w.write(")");
}
w.write(") {");
}
if (!mi.returnType().isVoid()) {
w.write("return ");
}
boolean needParen = false;
// XTENLANG-2993
if (!isSpecialTypeForDispatcher) {
// this dispatch methods returns Object, so box if the underlying type is not boxed
if (!isBoxedType(mi.returnType()) && !mi.returnType().isVoid()) {
printBoxConversion(mi.returnType());
w.write("(");
needParen = true;
}
}
// call
printMethodName(mi.def(), false, false, false, null);
// print the argument list
w.write("(");
boolean first2 = true;
MethodInstance x10mi = mi;
assert (x10mi.typeParameters().size() == x10def.typeParameters().size());
for (Type t : x10def.typeParameters()) {
if (!first2) {
w.write(", ");
}
first2 = false;
new RuntimeTypeExpander(this, t).expand();
}
for (int i = 0; i < mi.formalTypes().size(); i++) {
Type f = mi.formalTypes().get(i);
if (!first2 || i != 0) {
w.write(", ");
}
boolean closeParen = false;
if (isBoxedType(def.formalTypes().get(i).get())) {
Type bf = Types.baseType(f);
if (!isBoxedType(f)) {
closeParen = printUnboxConversion(f);
} else if (!isMethodParameter(bf, mi, tr.context())) {
// TODO:CAST
w.write("(");
// XTENLANG-3010 : for boxed type, boxing isn't needed anyway. stop boxing for printing "int[]" for "Java.array[Int]".
printType(f, 0);
w.write(")");
}
}
Name name = Name.make("a" + (i + 1));
w.write(name.toString());
if (closeParen)
w.write(")");
}
w.write(")");
if (needParen) {
w.write(")");
}
w.write(";");
// XTENLANG-2993
if (!isSpecialTypeForDispatcher) {
if (mi.returnType().isVoid()) {
w.write("return null;");
}
}
if (mis.size() != 1) {
w.write("}");
}
w.newline();
}
if (mis.size() != 1) {
w.write("throw new ");
new TypeExpander(this, tr.typeSystem().Error(), 0).expand();
w.write("(\"dispatch mechanism not completely implemented for contra-variant types.\");");
}
w.write("}");
w.newline();
}
// N.B. return type of dispatch is one of the return types which are merged into this dispatch method
private void printDispatchMethod(MethodInstance dispatch, List<MethodInstance> mis) {
printDispatchMethod(dispatch, mis, false, null);
// XTENLANG-2993
if (X10PrettyPrinterVisitor.generateSpecialDispatcher) {
Map<Type,List<MethodInstance>> specialTypeDispatchers = new HashMap<Type,List<MethodInstance>>();
for (MethodInstance mi : mis) {
Type type = Types.baseType(mi.returnType());
if (isSpecialTypeForDispatcher(type)) {
List<MethodInstance> specialTypeMethods = specialTypeDispatchers.get(type);
if (specialTypeMethods == null) {
specialTypeMethods = new ArrayList<MethodInstance>();
specialTypeDispatchers.put(type, specialTypeMethods);
}
specialTypeMethods.add(mi);
}
}
for (Map.Entry<Type, List<MethodInstance>> entry : specialTypeDispatchers.entrySet()) {
printDispatchMethod(dispatch, entry.getValue(), true, entry.getKey());
}
}
}
private static boolean isMethodParameter(Type bf, MethodInstance mi, Context context) {
if (bf.isParameterType()) {
Def def = ((ParameterType) bf).def().get();
if (def instanceof MethodDef) {
if (((MethodDef) def).container().get().typeEquals(mi.container(), context)) {
return true;
}
}
}
return false;
}
/**
* @param pos
* @param left
* TODO
* @param name
* @param right
* TODO
*/
public void generateStaticOrInstanceCall(Position pos, Expr left,
Name name, Expr... right) {
List<Expr> sargs = new ArrayList<Expr>();
List<Type> stypes = new ArrayList<Type>();
sargs.add(left);
stypes.add(left.type());
for (Expr e : right) {
sargs.add(e);
stypes.add(e.type());
}
List<Type> types = stypes.subList(1, stypes.size());
List<Expr> args = sargs.subList(1, sargs.size());
TypeSystem xts = tr.typeSystem();
NodeFactory nf = tr.nodeFactory();
try {
MethodInstance mi = xts.findMethod(left.type(), xts.MethodMatcher(
left.type(), name, types, tr.context()));
tr.print(null, nf.Call(pos, left, nf.Id(pos, name), args)
.methodInstance(mi).type(mi.returnType()), w);
} catch (SemanticException e) {
throw new InternalCompilerError(e.getMessage(), pos, e);
}
}
public void printFormal(Translator tr, Node n, Formal f, boolean mustBox) {
tr.print(n, f.flags(), w);
printType(f.type().type(), PRINT_TYPE_PARAMS | (mustBox ? BOX_PRIMITIVES : 0));
w.write(" ");
Name name = f.name().id();
if (name.toString().equals(""))
tr.print(n, f.name().id(Name.makeFresh("a")), w);
else {
tr.print(n, f.name(), w);
}
}
private boolean isNoArgumentType(Expr e) {
while (e instanceof ParExpr_c) {
e = ((ParExpr_c) e).expr();
if (e == null) {
return true;
}
}
Type exprTgtType = null;
if (e instanceof Field_c) {
exprTgtType = ((Field_c) e).target().type();
} else if (e instanceof Call) {
exprTgtType = ((Call) e).target().type();
}
if (exprTgtType != null) {
if (exprTgtType instanceof X10ParsedClassType_c) {
List<Type> typeArguments = ((X10ParsedClassType_c) exprTgtType).typeArguments();
if (typeArguments != null && !typeArguments.isEmpty()) {
return false;
}
}
}
return true;
}
private static Type actualType(Type type) {
if (type instanceof ConstrainedType) {
ConstrainedType ct = (ConstrainedType) type;
XVar selfVarBinding = ct.constraint().get().selfVarBinding();
if (selfVarBinding != null && selfVarBinding instanceof Typed) {
// x10.lang.Object{self=="abc"} -> x10.lang.String
Type actualType = ((Typed) selfVarBinding).type();
// N.B. stop infinite recursion with x10.lang.String{self=="abc"}
// actualType = actualType(actualType);
if (actualType instanceof ConstrainedType) {
actualType = ((ConstrainedType) actualType).baseType().get();
}
return actualType;
}
else {
return ct.baseType().get();
}
}
return type;
}
private ClassType Comparable_String_;
private ClassType Comparable_String() {
if (Comparable_String_ == null) {
TypeSystem_c xts = (TypeSystem_c) tr.typeSystem();
Comparable_String_ = xts.Comparable().typeArguments(Arrays.<Type> asList(xts.String()));
}
return Comparable_String_;
}
// TODO:CAST
public void coerce(Node parent, Expr e, Type expected) {
Type actual = e.type();
Type expectedBase = expected;
if (expectedBase instanceof ConstrainedType) {
expectedBase = ((ConstrainedType) expectedBase).baseType().get();
}
if (actual instanceof ConstrainedType) {
// XTENLANG-3085 if selfVarBinding is available, use its type
// actual = ((ConstrainedType) actual).baseType().get();
actual = actualType(actual);
}
CastExpander expander = new CastExpander(w, this, e);
if (actual.isNull() || e.isConstant() && !expectedBase.isParameterType() && !actual.isParameterType() && !isBoxedType(expectedBase)) {
prettyPrint(e, tr);
}
// for primitive
else if (needExplicitBoxing(actual)) {
if (actual.typeEquals(expectedBase, tr.context())) {
if (e instanceof X10Call && isBoxedType(Types.baseType(((X10Call) e).methodInstance().def().returnType().get()))) {
expander = expander.unboxTo(expectedBase);
expander.expand(tr);
}
else {
prettyPrint(e, tr);
}
} else {
if (isBoxedType(expectedBase)) {
// when expected type is T or Any, include an explicit boxing transformation
expander = expander.boxTo(actual).castTo(expectedBase);
expander.expand(tr);
}
else {
//cast to actual primitive to expected primitive to expected boxed primitive.
expander = expander.castTo(actual).castTo(expectedBase);
expander.expand(tr);
}
}
}
else {
if (actual.typeEquals(expected, tr.context()) && !(expected instanceof ConstrainedType) && !expectedBase.isParameterType() && !actual.isParameterType()) {
prettyPrint(e, tr);
}
else if (isString(actual)
&& !expectedBase.isAny() // Any is NativeRep'ed to j.l.Object
&& !expectedBase.isParameterType()
&& !expectedBase.typeEquals(Comparable_String(), tr.context()) // x.l.Comparable is NativeRep'ed to j.l.Comparable
&& !expectedBase.isString()
) {
expander = expander.boxTo(actual).castTo(expectedBase);
expander.expand(tr);
}
else {
//cast eagerly
if (isBoxedType(actual) && !isBoxedType(expectedBase))
expander = expander.unboxTo(expectedBase);
else {
// java primitive arrays do not use boxed types
boolean isJavaArray = tr.typeSystem().isJavaArray(expectedBase);
expander = expander.castTo(expectedBase, isJavaArray ? 0 : BOX_PRIMITIVES);
}
expander.expand(tr);
}
}
}
public boolean hasEffects(Receiver e) {
if (e instanceof TypeNode)
return false;
if (e instanceof Local)
return false;
if (e instanceof Lit)
return false;
if (e instanceof Field) {
Field f = (Field) e;
return hasEffects(f.target());
}
if (e instanceof Unary) {
Unary u = (Unary) e;
if (u.operator() == Unary.BIT_NOT || u.operator() == Unary.NOT
|| u.operator() == Unary.POS || u.operator() == Unary.NEG)
return hasEffects(u.expr());
}
if (e instanceof Binary) {
Binary b = (Binary) e;
return hasEffects(b.left()) || hasEffects(b.right());
}
if (e instanceof Cast) {
Cast c = (Cast) e;
return hasEffects(c.expr());
}
if (e instanceof Instanceof) {
Instanceof i = (Instanceof) e;
return hasEffects(i.expr());
}
return true;
}
public static String convertToString(Object[] a) {
StringBuffer s = new StringBuffer("[");
for (int i = 0; i < a.length; ++i) {
s.append(a[i].toString());
if (i + 1 < a.length) {
s.append(", ");
}
}
s.append("]");
return s.toString();
}
public static String convertToString(List<?> a) {
StringBuffer s = new StringBuffer("[");
final int size = a.size();
for (int i = 0; i < size; ++i) {
s.append(a.get(i).toString());
if (i + 1 < size) {
s.append(", ");
}
}
s.append("]");
return s.toString();
}
public void generateRTTInstance(X10ClassDef def) {
// for static inner classes that are compiled from closures
boolean isStaticFunType = def.name().toString().startsWith(ClosureRemover.STATIC_NESTED_CLASS_BASE_NAME);
boolean isVoidFun = false;
boolean isStruct = def.isStruct();
if (isStaticFunType) {
// Note: assume that the first interface in this X10ClassDef is a function type
Type type = def.interfaces().get(0).get();
assert type instanceof FunctionType;
isVoidFun = ((FunctionType) type).returnType().isVoid();
}
w.write("public static final x10.rtt.RuntimeType");
w.write("<");
printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
w.write("> " + X10PrettyPrinterVisitor.RTT_NAME + " = ");
if (isStaticFunType) {
if (isVoidFun) {
w.write("x10.rtt.StaticVoidFunType");
} else {
w.write("x10.rtt.StaticFunType");
}
} else {
if (isStruct) {
w.write("x10.rtt.NamedStructType");
} else {
w.write("x10.rtt.NamedType");
}
}
w.write(".<");
printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
w.write(">");
w.write(" make(");
w.newline();
if (!isStaticFunType) {
// Option for non-closures
w.write("\"" + def.asType() + "\", ");
}
w.write("/* base class */");
printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
w.write(".class");
if (def.variances().size() > 0) {
boolean allInvariants = true;
for (int i = 0; i < def.variances().size(); ++i) {
if (def.variances().get(i) != ParameterType.Variance.INVARIANT) {
allInvariants = false;
break;
}
}
if (allInvariants) {
// use cached one to avoid creating array of Variance repeatedly
w.write(", ");
w.newline();
w.write("/* variances */ x10.rtt.RuntimeType.INVARIANTS(" + def.variances().size() + ")");
}
else {
for (int i = 0; i < def.variances().size(); ++i) {
w.write(", ");
w.newline();
if (i == 0) w.write("/* variances */ new x10.rtt.RuntimeType.Variance[] {");
ParameterType.Variance v = def.variances().get(i);
switch (v) {
case INVARIANT:
w.write("x10.rtt.RuntimeType.Variance.INVARIANT");
break;
case COVARIANT:
w.write("x10.rtt.RuntimeType.Variance.COVARIANT");
break;
case CONTRAVARIANT:
w.write("x10.rtt.RuntimeType.Variance.CONTRAVARIANT");
break;
}
if (i == def.variances().size() - 1) w.write("}");
}
}
}
w.newline();
TypeSystem xts = tr.typeSystem();
if (def.interfaces().size() > 0 || def.superType() != null) {
w.write(", ");
w.write("/* parents */ new x10.rtt.Type[] {");
boolean needComma = false;
for (int i = 0 ; i < def.interfaces().size(); i ++) {
Type type = def.interfaces().get(i).get();
// we don't need to add Types.ANY as parents because everything is subtype of Any
if (xts.isAny(type)) continue;
if (needComma) {
w.write(", ");
} else {
needComma = true;
}
printRTT(def, type);
}
if (def.superType() != null) {
if (needComma) {
w.write(", ");
} else {
needComma = true;
}
printRTT(def, def.superType().get());
}
if (isStruct) {
if (needComma) {
w.write(", ");
} else {
needComma = true;
}
// Struct is not an X10 type, but it has RTT for runtime type checking such as instanceof
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPES + ".STRUCT");
}
w.write("}");
}
w.newline();
w.write(")");
w.write(";");
w.newline();
if (!def.flags().isInterface()) {
w.write("public x10.rtt.RuntimeType<?> " + X10PrettyPrinterVisitor.GETRTT_NAME + "() {");
w.write("return " + X10PrettyPrinterVisitor.RTT_NAME + ";");
w.write("}");
w.newline();
w.newline();
// To extend Any, the type requires getRTT even if it has no type params (e.g. VoidFun_0_0).
// if (!def.typeParameters().isEmpty()) {
w.write("public x10.rtt.Type<?> " + X10PrettyPrinterVisitor.GETPARAM_NAME + "(int i) {");
for (int i = 0; i < def.typeParameters().size(); i++) {
ParameterType pt = def.typeParameters().get(i);
w.write("if (i ==" + i + ")");
w.write("return ");
w.write(mangleParameterType(pt));
w.write(";");
}
w.write("return null;");
w.write("}");
// }
w.newline();
}
}
private void printRTT(final X10ClassDef def, Type type) {
type = Types.baseType(type);
if (type.isClass()) {
X10ClassType x10Type = type.toClass();
if (x10Type.isJavaType()) {
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPES + ".getRTT(");
printType(x10Type, 0);
w.write(".class)");
return;
}
X10ClassDef cd = x10Type.x10Def();
String pat = getJavaRTTRep(cd); // @NativeRep("java", JavaRep, n/a, JavaRTTRep)
if (pat != null) {
List<ParameterType> classTypeParams = cd.typeParameters();
// if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList();
Iterator<ParameterType> classTypeParamsIter = null;
if (classTypeParams != null) {
classTypeParamsIter = classTypeParams.iterator();
}
List<Type> classTypeArgs = x10Type.typeArguments();
if (classTypeArgs == null) classTypeArgs = Collections.<Type>emptyList();
HashMap<String,Object> components = new HashMap<String,Object>();
int i = 0;
Object component;
String name;
component = new TypeExpander(this, x10Type, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
components.put("class", component);
for (final Type at : classTypeArgs) {
if (classTypeParamsIter != null) {
name = classTypeParamsIter.next().name().toString();
} else {
name = null;
}
// XTENLANG-3010 : runtime type of Java.array[T] is defined as "Types.getRTT(#T[].class)"
component = new TypeExpander(this, at, PRINT_TYPE_PARAMS);
// Note: to avoid changing number based key, we only register this with name based key
// if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
// components.put(String.valueOf(i++), component);
if (name != null) { components.put(name, component); }
component = new TypeExpander(this, at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_BOXED_REP_SUFFIX, component); }
if (Types.baseType(at).typeEquals(def.asType(), tr.context())) {
component = "x10.rtt.UnresolvedType.THIS";
} else if (at.isParameterType()) {
component = "x10.rtt.UnresolvedType.PARAM(" + getIndex(def.typeParameters(), (ParameterType) Types.baseType(at)) + ")";
} else {
component = new Expander(this) {
public void expand(Translator tr) {
printRTT(def, at);
}
};
}
if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
components.put(String.valueOf(i++), component);
if (name != null) { components.put(name+NATIVE_ANNOTATION_RUNTIME_TYPE_SUFFIX, component); }
}
dumpRegex("NativeRep", components, tr, pat);
}
else if (x10Type.typeArguments() != null && x10Type.typeArguments().size() > 0) {
w.write("x10.rtt.ParameterizedType.make(");
if (x10Type instanceof FunctionType) {
FunctionType ft = (FunctionType) x10Type;
List<Type> args = ft.argumentTypes();
Type ret = ft.returnType();
if (ret.isVoid()) {
w.write(X10PrettyPrinterVisitor.X10_VOIDFUN_CLASS_PREFIX);
} else {
w.write(X10PrettyPrinterVisitor.X10_FUN_CLASS_PREFIX);
}
w.write("_" + ft.typeParameters().size());
w.write("_" + args.size());
w.write("." + X10PrettyPrinterVisitor.RTT_NAME);
}
else {
if (getJavaRep(cd) != null) {
w.write("new x10.rtt.RuntimeType(");
printType(x10Type, 0);
w.write(".class");
w.write(")");
}
else {
printType(x10Type, 0);
w.write("." + X10PrettyPrinterVisitor.RTT_NAME);
}
}
for (int i = 0; i < x10Type.typeArguments().size(); i++) {
w.write(", ");
Type ta = Types.baseType(x10Type.typeArguments().get(i));
if (ta.typeEquals(def.asType(), tr.context())) {
w.write("x10.rtt.UnresolvedType.THIS");
} else if (ta.isParameterType()) {
w.write("x10.rtt.UnresolvedType.PARAM(" + getIndex(def.typeParameters(), (ParameterType) ta) + ")");
} else {
printRTT(def, ta);
}
}
w.write(")");
} else {
new RuntimeTypeExpander(this, x10Type).expand();
}
}
else if (type instanceof NullType) {
new RuntimeTypeExpander(this, tr.typeSystem().Any()).expand();
}
}
private static int getIndex(List<ParameterType> pts, ParameterType t) {
for (int i = 0; i < pts.size(); i ++) {
if (pts.get(i).name().equals(t.name())) {
return i;
}
}
throw new InternalCompilerError(""); // TODO
}
// not used
private static boolean hasCustomSerializer(X10ClassDef def) {
for (MethodDef md: def.methods()) {
if ("serialize".equals(md.name().toString())) {
if (md.formalTypes().size() == 0) {
return true;
}
}
}
return false;
}
private static X10ConstructorDecl hasDefaultConstructor(X10ClassDecl n) {
for (ClassMember member : n.body().members()) {
if (member instanceof X10ConstructorDecl) {
X10ConstructorDecl ctor = (X10ConstructorDecl) member;
if (ctor.formals().size() == 0) {
return ctor;
}
}
}
return null;
}
// not used
// copy of X10ClassDecl_c.createDefaultConstructor
private static X10ConstructorDecl
createDefaultConstructor(X10ClassDef thisType, X10NodeFactory_c xnf, X10ClassDecl n) {
Position pos = Position.compilerGenerated(n.body().position());
Ref<? extends Type> superType = thisType.superType();
Stmt s1 = null;
if (superType != null) {
s1 = xnf.SuperCall(pos, Collections.<Expr>emptyList());
}
Stmt s2 = null;
List<TypeParamNode> typeFormals = Collections.<TypeParamNode>emptyList();
List<Formal> formals = Collections.<Formal>emptyList();
DepParameterExpr guard = null;
List<PropertyDecl> properties = n.properties();
if (! properties.isEmpty()) {
// build type parameters.
/*typeFormals = new ArrayList<TypeParamNode>(typeParameters.size());
List<TypeNode> typeActuals = new ArrayList<TypeNode>(typeParameters.size());
for (TypeParamNode tp : typeParameters) {
typeFormals.add(xnf.TypeParamNode(pos, tp.name()));
typeActuals.add(xnf.CanonicalTypeNode(pos, tp.type()));
}*/
formals = new ArrayList<Formal>(properties.size());
List<Expr> actuals = new ArrayList<Expr>(properties.size());
ChangePositionVisitor changePositionVisitor = new ChangePositionVisitor(pos);
for (PropertyDecl pd: properties) {
Id name = (Id) pd.name().position(pos);
TypeNode typeNode = (TypeNode) pd.type().copy();
Node newNode = typeNode.visit(changePositionVisitor);
formals.add(xnf.Formal(pos, xnf.FlagsNode(pos, Flags.FINAL), (TypeNode) newNode, name));
actuals.add(xnf.Local(pos, name));
}
guard = n.classInvariant();
s2 = xnf.AssignPropertyCall(pos, Collections.<TypeNode>emptyList(), actuals);
// TODO: add constraint on the return type
}
Block block = s2 == null ? (s1 == null ? xnf.Block(pos) : xnf.Block(pos, s1))
: (s1 == null ? xnf.Block(pos, s2) : xnf.Block(pos, s1, s2));
X10ClassType resultType = thisType.asType();
// for Generic classes
final List<ParameterType> typeParams = thisType.typeParameters();
resultType = resultType.typeArguments((List) typeParams);
X10CanonicalTypeNode returnType = (X10CanonicalTypeNode) xnf.CanonicalTypeNode(pos, resultType);
X10ConstructorDecl cd = xnf.X10ConstructorDecl(pos,
xnf.FlagsNode(pos, Flags.PUBLIC),
xnf.Id(pos, TypeSystem.CONSTRUCTOR_NAME),
returnType,
typeFormals,
formals,
guard,
null, // offerType
Collections.<TypeNode>emptyList(),
block);
return cd;
}
public void generateCustomSerializer(X10ClassDef def, X10ClassDecl_c n) {
X10CompilerOptions opts = (X10CompilerOptions) tr.job().extensionInfo().getOptions();
String fieldName = X10PrettyPrinterVisitor.SERIAL_DATA_FIELD_NAME;
w.write("// custom serializer");
w.newline();
w.write("private transient x10.io.SerialData " + fieldName + ";");
w.newline();
w.write("private Object writeReplace() { ");
if (!opts.x10_config.NO_TRACES && !opts.x10_config.OPTIMIZE) {
w.write("if (" + X10PrettyPrinterVisitor.X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { ");
w.write("java.lang.System.out.println(\"Serializer: serialize() of \" + this + \" calling\"); ");
w.write("} ");
}
w.write(fieldName + " = serialize(); ");
if (!opts.x10_config.NO_TRACES && !opts.x10_config.OPTIMIZE) {
w.write("if (" + X10PrettyPrinterVisitor.X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { ");
w.write("java.lang.System.out.println(\"Serializer: serialize() of \" + this + \" returned \" + " + fieldName + "); ");
w.write("} ");
}
w.write("return this; }");
w.newline();
w.write("private Object readResolve() { return ");
if (X10PrettyPrinterVisitor.generateFactoryMethod) {
printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
w.write(".");
w.write(X10PrettyPrinterVisitor.CREATION_METHOD_NAME);
} else {
assert X10PrettyPrinterVisitor.generateOnePhaseConstructor;
w.write("new ");
printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
}
w.write("(");
for (ParameterType type : def.typeParameters()) {
w.write(mangleParameterType(type) + ", ");
}
w.write(fieldName + "); }");
w.newline();
w.write("private void writeObject(java.io.ObjectOutputStream oos) throws java.io.IOException {");
w.newline();
for (ParameterType type : def.typeParameters()) {
w.write("oos.writeObject(" + mangleParameterType(type) + ");");
w.newline();
}
w.write("oos.writeObject(" + fieldName + "); }");
w.newline();
w.write("private void readObject(java.io.ObjectInputStream ois) throws java.io.IOException, java.lang.ClassNotFoundException {");
w.newline();
for (ParameterType type : def.typeParameters()) {
w.write(mangleParameterType(type) + " = (" + X10PrettyPrinterVisitor.X10_RTT_TYPE + ") ois.readObject();");
w.newline();
}
w.write(fieldName + " = (x10.io.SerialData) ois.readObject(); }");
w.newline();
/*
if (!hasCustomSerializer(def)) {
w.write("// default custom serializer");
w.newline();
// w.write("public x10.io.SerialData serialize() { return new x10.io.SerialData(null, super.serialize()); }");
w.write("public x10.io.SerialData serialize() { return super.serialize(); }");
w.newline();
}
*/
if (!def.hasDeserializationConstructor(tr.context())) {
w.write("// default deserialization constructor");
w.newline();
w.write("public " + def.name().toString() + "(");
for (ParameterType type : def.typeParameters()) {
w.write("final x10.rtt.Type " + mangleParameterType(type) + ", ");
}
w.write("final x10.io.SerialData a) { ");
// call super deserialization constructor
Ref<? extends Type> superType0Ref = def.superType();
if (superType0Ref != null) {
Type superType0 = superType0Ref.get();
X10ClassType superType;
if (superType0 instanceof ConstrainedType) {
superType = ((ConstrainedType) superType0).baseType().get().toClass();
} else {
superType = superType0.toClass();
}
w.write("super(");
if (superType.typeArguments() != null) {
for (Type type : superType.typeArguments()) {
// pass rtt of the type
// TODO mangle typa variable
new RuntimeTypeExpander(this, type).expand();
w.write(", ");
}
}
// w.write("a.superclassData); ");
w.write("a); ");
}
// initialize rtt
for (ParameterType type : def.typeParameters()) {
w.write("this." + mangleParameterType(type) + " = " + mangleParameterType(type) + "; ");
}
// copy the rest of default (standard) constructor to initialize properties and fields
X10ConstructorDecl ctor = hasDefaultConstructor(n);
// we must have default constructor to initialize properties
// assert ctor != null;
/*
if (ctor == null) {
ctor = createDefaultConstructor(def, (X10NodeFactory_c) tr.nodeFactory(), n);
// TODO apply FieldInitializerMover
}
*/
if (ctor != null) {
// initialize properties and call field initializer
Block_c body = (Block_c) ctor.body();
if (body.statements().size() > 0) {
if (body.statements().get(0) instanceof ConstructorCall) {
body = (Block_c) body.statements(body.statements().subList(1, body.statements().size()));
}
// X10PrettyPrinterVisitor.visit(Block_c body)
String s = getJavaImplForStmt(body, tr.typeSystem());
if (s != null) {
w.write(s);
} else {
body.translate(w, tr);
}
}
}
w.write("}");
w.newline();
}
//_deserialize_body method
w.write("public static ");
List<TypeParamNode> typeParameters = n.typeParameters();
if (typeParameters.size() > 0) {
printTypeParams(n, tr.context(), typeParameters);
}
w.write(X10_JAVA_SERIALIZABLE_CLASS + " " + DESERIALIZE_BODY_METHOD + "(");
printType(def.asType(), PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
w.writeln(" $_obj , " + X10_JAVA_DESERIALIZER_CLASS + " $deserializer) throws java.io.IOException {");
w.newline(4);
w.begin(0);
if (!opts.x10_config.NO_TRACES && !opts.x10_config.OPTIMIZE) {
w.write("if (" + X10PrettyPrinterVisitor.X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { ");
w.write("java.lang.System.out.println(\"X10JavaSerializable: " + DESERIALIZE_BODY_METHOD + "() of \" + " + mangleToJava(def.name()) + ".class + \" calling\"); ");
w.writeln("} ");
}
ArrayList<String> params = new ArrayList<String>();
w.writeln("x10.io.SerialData " + fieldName + " = (x10.io.SerialData) $deserializer.readRef();");
for (ParameterType at : def.typeParameters()) {
w.write(X10PrettyPrinterVisitor.X10_RTT_TYPE + " ");
printType(at, PRINT_TYPE_PARAMS | BOX_PRIMITIVES);
w.writeln(" = (" + X10PrettyPrinterVisitor.X10_RTT_TYPE + ") $deserializer.readRef();");
params.add(mangleParameterType(at));
}
// XTENLANG-2974
// N.B. we cannot reinstantiating $_obj since it may have already been serialized (and thus registered).
// w.write("$_obj = (");
// printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
// w.write(") ");
// if (X10PrettyPrinterVisitor.generateFactoryMethod) {
// printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
// w.write(".");
// w.write(X10PrettyPrinterVisitor.CREATION_METHOD_NAME);
// } else {
// assert X10PrettyPrinterVisitor.generateOnePhaseConstructor;
// w.write("new ");
// printType(def.asType(), BOX_PRIMITIVES | NO_QUALIFIER);
// }
// String paramNames = "";
// for (String param : params) {
// paramNames = paramNames + param + ", ";
// }
// w.writeln("(" + paramNames + fieldName + ");");
// set type objects to the fields of $_obj and initialize $_obj by calling $init(SerialData).
for (String param : params) {
w.writeln("$_obj." + param + " = " + param + ";");
}
w.writeln("$_obj." + X10PrettyPrinterVisitor.CONSTRUCTOR_METHOD_NAME(def) + "(" + fieldName + ");");
w.writeln("return $_obj;");
w.end();
w.newline();
w.writeln("}");
w.newline();
// _deserializer method
w.writeln("public static " + X10_JAVA_SERIALIZABLE_CLASS + " " + DESERIALIZER_METHOD + "(" + X10_JAVA_DESERIALIZER_CLASS + " $deserializer) throws java.io.IOException {");
w.newline(4);
w.begin(0);
w.write(mangleToJava(def.name()) + " $_obj = new " + mangleToJava(def.name()) + "(");
if (X10PrettyPrinterVisitor.supportConstructorSplitting
// XTENLANG-2830
/*&& !ConstructorSplitterVisitor.isUnsplittable(Types.baseType(def.asType()))*/
&& !def.flags().isInterface()) {
w.write("(" + X10PrettyPrinterVisitor.CONSTRUCTOR_FOR_ALLOCATION_DUMMY_PARAM_TYPE + ") null");
// N.B. in custom deserializer, initialize type params with null
for (ParameterType typeParam : def.typeParameters()) {
w.write(", (" + X10PrettyPrinterVisitor.X10_RTT_TYPE + ") null");
}
w.write(");");
w.newline();
} else {
for (int i = 0; i < def.typeParameters().size(); i++) {
w.write("null, ");
}
w.writeln("(x10.io.SerialData) null);");
}
w.writeln("$deserializer.record_reference($_obj);");
w.writeln("return " + DESERIALIZE_BODY_METHOD + "($_obj, $deserializer);");
w.end();
w.newline();
w.writeln("}");
w.newline();
// _serialize()
w.writeln("public void " + SERIALIZE_METHOD + "(" + X10_JAVA_SERIALIZER_CLASS + " $serializer) throws java.io.IOException {");
w.newline(4);
w.begin(0);
if (!opts.x10_config.NO_TRACES && !opts.x10_config.OPTIMIZE) {
w.write("if (" + X10PrettyPrinterVisitor.X10_RUNTIME_IMPL_JAVA_RUNTIME + ".TRACE_SER) { ");
w.write("java.lang.System.out.println(\" CustomSerialization : " + SERIALIZE_METHOD + " of \" + this + \" calling\"); ");
w.writeln("} ");
}
w.writeln(fieldName + " = serialize(); ");
w.writeln("$serializer.write(" + fieldName + ");");
for (ParameterType at : def.typeParameters()) {
w.writeln("$serializer.write(" + mangleParameterType(at) + ");");
}
w.end();
w.newline();
w.writeln("}");
w.newline();
// XTENLANG-2974 generate dummy $init(SerialData) for non-splittable type to simplify above _deserialize_body method.
if (!X10PrettyPrinterVisitor.isSplittable(def.asType())) {
w.writeln("// dummy 2nd-phase constructor for non-splittable type");
w.writeln("public void " + X10PrettyPrinterVisitor.CONSTRUCTOR_METHOD_NAME(def) + "(" + X10PrettyPrinterVisitor.SERIAL_DATA + " " + fieldName + ") {");
w.newline(4);
w.begin(0);
w.write("throw new ");
new TypeExpander(this, tr.typeSystem().Error(), 0).expand();
w.writeln("(\"dummy 2nd-phase constructor for non-splittable type should never be called.\");");
w.end();
w.newline();
w.writeln("}");
w.newline();
}
}
private ClassType Thread_;
private ClassType Thread() {
if (Thread_ == null)
Thread_ = tr.typeSystem().load("x10.lang.Thread");
return Thread_;
}
private boolean needToSerializeSuperClass(TypeNode superClassNode) {
if (superClassNode == null || !superClassNode.type().isClass()) return false;
Type superType = superClassNode.type();
if (superType.isAny() ||
superType.typeEquals(Thread(), tr.context())) return false;
return true;
}
public static boolean isRawJavaClass(Type type) {
return type.isClass() && type.toClass().isJavaType() || isNativeRepedToJava(type);
}
// Emits the code to serialize the super class
public void serializeSuperClass(TypeNode superClassNode) {
// Check whether need to serialize super class
if (needToSerializeSuperClass(superClassNode)) {
// If the super class is a pure java class we need to serialize it using reflection
if (isRawJavaClass(superClassNode.type())) {
w.write("$serializer.serializeClassUsingReflection(this, ");
printType(superClassNode.type(), BOX_PRIMITIVES);
w.writeln(".class);");
} else {
w.write("super." + SERIALIZE_METHOD + "($serializer);");
w.newline();
}
}
}
// Emits the code to deserialize the super class
public void deserializeSuperClass(TypeNode superClassNode) {
// Check whether we need to deserialize the super class
if (needToSerializeSuperClass(superClassNode)) {
// If the super class is a pure java class we need to deserialize it using reflection
if (isRawJavaClass(superClassNode.type())) {
w.write("$deserializer.deserializeClassUsingReflection(");
printType(superClassNode.type(), BOX_PRIMITIVES);
w.writeln(".class, $_obj, 0);");
} else {
printType(superClassNode.type(), BOX_PRIMITIVES);
w.writeln("." + DESERIALIZE_BODY_METHOD + "($_obj, $deserializer);");
}
}
}
public void generateZeroValueConstructor(X10ClassDef def, X10ClassDecl_c n) {
w.write("// zero value constructor");
w.newline();
w.write("public " + def.name().toString() + "(");
for (ParameterType type : def.typeParameters()) {
w.write("final x10.rtt.Type " + mangleParameterType(type) + ", ");
}
w.write("final " + X10PrettyPrinterVisitor.CONSTRUCTOR_FOR_ZERO_VALUE_DUMMY_PARAM_TYPE + " $dummy) { ");
/* struct does not have super type
// call super zero value constructor
Ref<? extends Type> superType0Ref = def.superType();
if (superType0Ref != null) {
Type superType0 = superType0Ref.get();
X10ClassType superType;
if (superType0 instanceof ConstrainedType) {
superType = ((ConstrainedType) superType0).baseType().get().toClass();
} else {
superType = superType0.toClass();
}
w.write("super(");
if (superType.typeArguments() != null) {
for (Type type : superType.typeArguments()) {
// pass rtt of the type
new RuntimeTypeExpander(this, type).expand();
w.write(", ");
}
}
w.write("$dummy); ");
}
*/
// initialize rtt
for (ParameterType type : def.typeParameters()) {
w.write("this." + mangleParameterType(type) + " = " + mangleParameterType(type) + "; ");
}
// initialize instance fields with zero value
TypeSystem xts = def.typeSystem();
for (polyglot.types.FieldDef field : def.fields()) {
if (field.flags().isStatic()) continue;
Type type = field.type().get();
if (type instanceof ConstrainedType) {
type = ((ConstrainedType) type).baseType().get();
}
String lhs = "this." + mangleToJava(field.name()) + " = ";
String zero = null;
if (xts.isStruct(type)) {
if (xts.isUByte(type)) {
zero = "(x10.core.UByte) " + X10PrettyPrinterVisitor.X10_RTT_TYPES + ".UBYTE_ZERO";
} else if (xts.isUShort(type)) {
zero = "(x10.core.UShort) " + X10PrettyPrinterVisitor.X10_RTT_TYPES + ".USHORT_ZERO";
} else if (xts.isUInt(type)) {
zero = "(x10.core.UInt) " + X10PrettyPrinterVisitor.X10_RTT_TYPES + ".UINT_ZERO";
} else if (xts.isULong(type)) {
zero = "(x10.core.ULong) " + X10PrettyPrinterVisitor.X10_RTT_TYPES + ".ULONG_ZERO";
} else if (xts.isByte(type)) {
zero = "(byte) 0";
} else if (xts.isShort(type)) {
zero = "(short) 0";
} else if (xts.isInt(type)) {
zero = "0";
} else if (xts.isLong(type)) {
zero = "0L";
} else if (xts.isFloat(type)) {
zero = "0.0F";
} else if (xts.isDouble(type)) {
zero = "0.0";
} else if (xts.isChar(type)) {
zero = "(char) 0";
} else if (xts.isBoolean(type)) {
zero = "false";
} else {
// user-defined struct type
// for struct a.b.S[T], "new a.b.S(T, (java.lang.System) null);"
w.write(lhs); lhs = "";
w.write("new ");
printType(type, PRINT_TYPE_PARAMS);
w.write("(");
X10ParsedClassType_c pcType = (X10ParsedClassType_c) type;
if (pcType.typeArguments() != null) {
for (Type typeArgument : pcType.typeArguments()) {
// pass rtt of the type
new RuntimeTypeExpander(this, typeArgument).expand();
w.write(", ");
}
}
w.write("$dummy); ");
}
} else if (xts.isParameterType(type)) {
// for type parameter T, "(T) x10.rtt.Types.zeroValue(T);"
ParameterType paramType = (ParameterType) type;
zero = "(" + mangleParameterType(paramType) + ") " + X10PrettyPrinterVisitor.X10_RTT_TYPES + ".zeroValue(" + mangleParameterType(paramType) + ")";
} else {
// reference (i.e. non-struct) type
zero = "null";
}
if (zero != null) w.write(lhs + zero + "; ");
}
w.write("}");
w.newline();
}
// N.B. these conditions are cut&pasted from printInlinedCode()
public boolean isInlinedCall(X10Call c) {
TypeSystem xts = tr.typeSystem();
if (!isMethodInlineTarget(xts, Types.baseType(c.target().type()))) return false;
MethodInstance mi = c.methodInstance();
if (mi.name() == SettableAssign.SET || mi.name() == ClosureCall.APPLY) return true;
return false;
}
public boolean printInlinedCode(X10Call_c c) {
TypeSystem xts = tr.typeSystem();
Type ttype = Types.baseType(c.target().type());
if (isMethodInlineTarget(xts, ttype)) {
Type ptype = ttype.toClass().typeArguments().get(0);
Name methodName = c.methodInstance().name();
// e.g. rail.set(a,i) -> ((Object[]) rail.value)[i] = a or ((int[]/* primitive array */)rail.value)[i] = a
if (methodName==SettableAssign.SET) {
w.write("(");
w.write("(");
printType(ptype, 0);
w.write("[]");
w.write(")");
c.print(c.target(), w, tr);
w.write(".value");
w.write(")");
w.write("[");
c.print(c.arguments().get(0), w, tr);
w.write("]");
w.write(" = ");
c.print(c.arguments().get(1), w, tr);
return true;
}
// e.g. rail.apply(i) -> ((String)((String[])rail.value)[i]) or ((int[])rail.value)[i]
if (methodName==ClosureCall.APPLY) {
w.write("(");
w.write("(");
printType(ptype, 0);
w.write("[]");
w.write(")");
c.print(c.target(), w, tr);
w.write(".value");
w.write(")");
w.write("[");
c.print(c.arguments().get(0), w, tr);
w.write("]");
return true;
}
}
return false;
}
public boolean isMethodInlineTarget(TypeSystem xts, Type ttype) {
ttype = Types.baseType(ttype);
if (!isIndexedMemoryChunk(ttype)) {
return false;
}
if (!hasParams(ttype)) {
return true;
}
List<Type> ta = ttype.toClass().typeArguments();
if (ta != null && !ta.isEmpty() && !xts.isParameterType(ta.get(0))) {
return true;
}
return false;
}
public boolean printNativeMethodCall(X10Call c) {
TypeSystem xts = tr.typeSystem();
MethodInstance mi = c.methodInstance();
String pat = getJavaImplForDef(mi.x10Def());
if (pat != null) {
Receiver target = c.target();
Type t = target.type();
boolean cast = xts.isParameterType(t) || hasParams(t);
CastExpander targetArg = new CastExpander(w, this, target);
if (cast) {
targetArg = targetArg.castTo(mi.container(), BOX_PRIMITIVES | PRINT_TYPE_PARAMS);
// in native methods of numerics (Int etc), the #this argument is expected to be unboxed
if (needExplicitBoxing(mi.container()))
targetArg = targetArg.unboxTo(mi.container());
}
List<ParameterType> classTypeParams = Collections.<ParameterType>emptyList();
List<Type> classTypeArguments = Collections.<Type>emptyList();
if (mi.container().isClass() && !mi.flags().isStatic()) {
X10ClassType ct = mi.container().toClass();
classTypeParams = ct.x10Def().typeParameters();
classTypeArguments = ct.typeArguments();
if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList();
if (classTypeArguments == null) classTypeArguments = Collections.<Type>emptyList();
}
List<String> params = new ArrayList<String>();
List<CastExpander> args = new ArrayList<CastExpander>();
List<Expr> arguments = c.arguments();
for (int i = 0; i < arguments.size(); ++ i) {
params.add(mi.def().formalNames().get(i).name().toString());
Type ft = mi.def().formalTypes().get(i).get();
Type at = arguments.get(i).type();
if (isPrimitive(at) && xts.isParameterType(ft) && !isPrimitiveGenericMethod(mi)) {
args.add(new CastExpander(w, this, arguments.get(i)).boxTo(at));
}
else if (isPrimitive(at)) {
args.add(new CastExpander(w, this, arguments.get(i)).castTo(at, 0));
}
else {
args.add(new CastExpander(w, this, arguments.get(i)));
}
}
emitNativeAnnotation(pat, targetArg, mi.x10Def().typeParameters(), mi.typeParameters(), params, args, classTypeParams, classTypeArguments);
return true;
}
return false;
}
public boolean printNativeNew(X10New_c c, X10ConstructorInstance mi) {
String pat = getJavaImplForDef(mi.x10Def());
if (pat != null) {
List<ParameterType> classTypeParams = Collections.<ParameterType>emptyList();
List<Type> classTypeArguments = Collections.<Type>emptyList();
if (mi.container().isClass() && !mi.flags().isStatic()) {
X10ClassType ct = mi.container().toClass();
classTypeParams = ct.x10Def().typeParameters();
classTypeArguments = ct.typeArguments();
if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList();
if (classTypeArguments == null) classTypeArguments = Collections.<Type>emptyList();
}
List<String> params = new ArrayList<String>();
List<CastExpander> args = new ArrayList<CastExpander>();
List<Expr> arguments = c.arguments();
for (int i = 0; i < arguments.size(); ++ i) {
params.add(mi.def().formalNames().get(i).name().toString());
Type ft = c.constructorInstance().def().formalTypes().get(i).get();
Type at = arguments.get(i).type();
if (isPrimitive(at) && ft.isParameterType()) {
args.add(new CastExpander(w, this, arguments.get(i)).castTo(at, BOX_PRIMITIVES));
}
else if (isPrimitive(at)) {
args.add(new CastExpander(w, this, arguments.get(i)).castTo(at, 0));
}
else {
args.add(new CastExpander(w, this, arguments.get(i)));
}
}
emitNativeAnnotation(pat, null, Collections.<ParameterType>emptyList(), Collections.<Type>emptyList(), params, args, classTypeParams, classTypeArguments);
return true;
}
return false;
}
// WIP XTENLANG-2680
// print @Native annotation as method body
public boolean printNativeMethodDecl(X10MethodDecl_c n) {
assert supportNativeMethodDecl;
TypeSystem xts = tr.typeSystem();
MethodInstance mi = n.methodDef().asInstance();
String pat = getJavaImplForDef(mi.x10Def());
assert pat != null;
if (pat != null) {
//// Receiver target = c.target();
//// Type t = target.type();
// Type t = mi.container();
// boolean cast = xts.isParameterType(t) || hasParams(t);
// CastExpander targetArg = new CastExpander(w, this, target);
// if (cast) {
// targetArg = targetArg.castTo(mi.container(), BOX_PRIMITIVES | PRINT_TYPE_PARAMS);
// }
String targetArg = null;
if (!mi.flags().isStatic()) {
targetArg = "this";
}
List<ParameterType> classTypeParams = Collections.<ParameterType>emptyList();
List<Type> classTypeArguments = Collections.<Type>emptyList();
if (mi.container().isClass() && !mi.flags().isStatic()) {
X10ClassType ct = mi.container().toClass();
classTypeParams = ct.x10Def().typeParameters();
classTypeArguments = ct.typeArguments();
if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList();
if (classTypeArguments == null) classTypeArguments = Collections.<Type>emptyList();
}
List<String> params = new ArrayList<String>();
// List<CastExpander> args = new ArrayList<CastExpander>();
List<String> args = new ArrayList<String>();
// List<Expr> arguments = c.arguments();
// for (int i = 0; i < arguments.size(); ++ i) {
for (int i = 0; i < mi.def().formalNames().size(); ++ i) {
params.add(mi.def().formalNames().get(i).name().toString());
/*
Type ft = mi.def().formalTypes().get(i).get();
Type at = arguments.get(i).type();
if (isPrimitive(at) && xts.isParameterType(ft)) {
args.add(new CastExpander(w, this, arguments.get(i)).castTo(at, BOX_PRIMITIVES));
}
else if (isPrimitive(at)) {
args.add(new CastExpander(w, this, arguments.get(i)).castTo(at, 0));
}
else {
args.add(new CastExpander(w, this, arguments.get(i)));
}
*/
args.add(mi.def().formalNames().get(i).name().toString());
}
w.write("{");
w.write("try {"); // XTENLANG-2686: handle Java exceptions inside @Native method
// always same?
if (!n.returnType().type().isVoid()) {
// if (!mi.returnType().isVoid()) {
w.write("return ");
}
emitNativeAnnotation(pat, targetArg, mi.x10Def().typeParameters(), mi.typeParameters(), params, args, classTypeParams, classTypeArguments);
w.write(";");
w.writeln("}"); // XTENLANG-2686
X10PrettyPrinterVisitor.catchAndThrowAsX10Exception(w); // XTENLANG-2686
w.write("}");
w.newline();
return true;
}
return false;
}
public boolean printMainMethod(X10MethodDecl_c n) {
if (HierarchyUtils.isMainMethod(n.methodDef(), tr.context())) {
/*Expander throwsClause = new Inline(er, "");
if (n.throwTypes().size() > 0) {
List<Expander> l = new ArrayList<Expander>();
for (TypeNode tn : n.throwTypes()) {
l.add(new TypeExpander(er, tn.type(), PRINT_TYPE_PARAMS));
}
throwsClause = new Join(er, "", "throws ", new Join(er, ", ", l));
}*/
Expander throwsClause = new Inline(this, "");
List<Ref<? extends Type>> throwsTypes = n.methodDef().throwTypes();
if (throwsTypes.size() > 0) {
List<Expander> l = new ArrayList<Expander>(throwsTypes.size());
for (Ref<? extends Type> _throws : throwsTypes) {
l.add(new TypeExpander(this, _throws.get(), 0));
}
throwsClause = new Join(this, "", "throws ", new Join(this, ", ", l));
}
// SYNOPSIS: #2.main(#0) #1 #0=args #1=body #2=mainclass #3=throws
String regex = "public static class " + X10PrettyPrinterVisitor.MAIN_CLASS + " extends " + X10PrettyPrinterVisitor.X10_RUNTIME_IMPL_JAVA_RUNTIME + " {\n" +
"private static final long serialVersionUID = 1L;\n" +
"public static void main(java.lang.String[] args) #throws {\n" +
"// start native runtime\n" +
"new " + X10PrettyPrinterVisitor.MAIN_CLASS + "().start(args);\n" +
"}\n" +
"\n" +
"// called by native runtime inside main x10 thread\n" +
"public void runtimeCallback(final x10.array.Array<java.lang.String> args) #throws {\n" +
"// call the original app-main method\n" +
"#mainclass.main(args);\n" +
"}\n" +
"}\n" +
"\n" +
"// the original app-main method\n" +
"public static void main(#args) #throws #body";
Map<String,Object> components = new HashMap<String,Object>();
Object component;
int i = 0;
component = n.formals().get(0);
// if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
// components.put(String.valueOf(i++), component);
components.put("args", component);
component = n.body();
// if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
// components.put(String.valueOf(i++), component);
components.put("body", component);
component = tr.context().currentClass().name();
// if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
// components.put(String.valueOf(i++), component);
components.put("mainclass", component);
component = throwsClause;
// if (X10PrettyPrinterVisitor.supportNumberedParameterForNative)
// components.put(String.valueOf(i++), component);
components.put("throws", component);
dumpRegex(X10PrettyPrinterVisitor.MAIN_CLASS, components, tr, regex);
return true;
}
return false;
}
}