/* * Copyright (c) 2019, Juraj Papp * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package theleo.jstruct.plugin.ecj; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import jdk.nashorn.internal.ir.debug.ASTWriter; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTMatcher; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTRequestor; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.BooleanLiteral; import org.eclipse.jdt.core.dom.CastExpression; import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NumberLiteral; import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.ParenthesizedExpression; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.TypeLiteral; import org.eclipse.jdt.core.dom.WildcardType; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving; import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IRegion; import theleo.jstruct.plugin.Log; import theleo.jstruct.plugin.ecj.StructCache.Entry; import theleo.jstruct.plugin.ecj.StructCache.FieldType; import theleo.jstruct.plugin.ecj.StructCache.TypeSymbol; import theleo.jstruct.plugin.ecj.Translator.MethodFrame; import static theleo.jstruct.plugin.ecj.Translator.R1X; import static theleo.jstruct.plugin.ecj.Translator.STRUCT_TYPE_VAR; import theleo.jstruct.plugin.ecj.Translator.StringCache.MethodType; import theleo.jstruct.plugin.ecj.Translator.StringCache.OpSymbol; import theleo.jstruct.plugin.ecj.Translator.TmpTranslator; import static theleo.jstruct.plugin.ecj.Translator.err; /** * * @author Juraj Papp */ public class BaseTranslator extends ASTVisitor { public static final String STRUCT_DATA = "$structdata$"; public static final String[] MEM0 = {"theleo", "jstruct", "hidden", "Mem0"}; public static final String[] MEM0_B = {"theleo", "jstruct", "hidden", "Mem0", "B"}; public static final String TYPEBIND_PROP = "theleo.jstruct.CUSTOM_TYPEBIND"; public static final String TYPEBIND_METHOD_TMP = "theleo.jstruct.METHOD_TMP"; public static final String IS_REPLACE = "theleo.jstruct.IS_REPLACE"; public static enum TypebindMethodTmp { Array, Array_Ptr, Ptr, Ref, StackVar } public CompilationUnit cu; public Document doc; public String sourceFileName; public AST ast; TmpTranslator tmpTranslator; public BaseTranslator(CompilationUnit cu, Document doc, String sourceFileName) { this.cu = cu; this.doc = doc; this.sourceFileName = sourceFileName; this.ast = cu.getAST(); } public ASTNode copySubtreeIfHasParent(Object o) { ASTNode n = (ASTNode)o; if(n.getParent() == null) return n; return copySubtree(n); } public ASTNode copySubtree(Object o) { ASTNode n = (ASTNode)o; MethodTmp m = null; if(tmpTranslator != null) { m = getMethodTmp(n); if(m != null) { n.setProperty(TYPEBIND_METHOD_TMP, null); } n = tmpTranslator.translate(n); } ASTNode copy = ASTNode.copySubtree(ast, n); Object t = n.getProperty(TYPEBIND_PROP); if(t != null) copy.setProperty(TYPEBIND_PROP, t); if(m != null) copy.setProperty(TYPEBIND_METHOD_TMP, m); // Object t2 = n.getProperty(TYPEBIND_METHOD_TMP); // if(t2 != null) copy.setProperty(TYPEBIND_METHOD_TMP, t2); return copy; } public void replace(ASTNode old, ASTNode neww) { // if(!copyStack.isEmpty()) { // if(copyStack.get(copyStack.size()-1) == old) { // copyStack.set(copyStack.size()-1, neww); // Log.err("COPY STACK REPLACE"); // Object oldProp = old.getProperty(TYPEBIND_PROP); // if(oldProp != null && neww.getProperty(TYPEBIND_PROP) == null) { // Log.err(" copy old prop"); // neww.setProperty(TYPEBIND_PROP, oldProp); // } // Object oldProp2 = old.getProperty(TYPEBIND_METHOD_TMP); // if(oldProp2 != null && neww.getProperty(TYPEBIND_METHOD_TMP) == null) { // Log.err(" copy old prop2"); // neww.setProperty(TYPEBIND_METHOD_TMP, oldProp2); // } // return; // } // } old.setProperty(IS_REPLACE, neww); ASTNode parent = old.getParent(); StructuralPropertyDescriptor desc = old.getLocationInParent(); if(desc instanceof ChildListPropertyDescriptor) { ChildListPropertyDescriptor ch = (ChildListPropertyDescriptor)desc; List<ASTNode> list = (List)parent.getStructuralProperty(ch); int index = list.indexOf(old); list.set(index, neww); } else { if(parent instanceof QualifiedName && QualifiedName.QUALIFIER_PROPERTY.getId().equals(desc.getId()) && !(neww instanceof SimpleName)) { if(!(neww instanceof Expression))throw new IllegalArgumentException(); //QualifiedName has to be changed to FieldAccess // throw new IllegalArgumentException("qual name expression"); FieldAccess fa = ast.newFieldAccess(); fa.setExpression((Expression)neww); fa.setName((SimpleName)copySubtreeIfHasParent(((QualifiedName)parent).getName())); // for(Map.Entry ee : (Set<Map.Entry>)parent.properties().entrySet()) { // Log.err("ee " + ee.getKey()); // } if(parent.getProperty(TYPEBIND_PROP) == null) fa.setProperty(TYPEBIND_PROP, parent.getProperty(TYPEBIND_PROP)); replace(parent, fa); return; } parent.setStructuralProperty(desc, neww); } } // ArrayList<ASTNode> copyStack = new ArrayList<>(); public ASTNode copyArg(Object o) { return copy((ASTNode)o); } public ASTNode copy(ASTNode node) { // copyStack.add(node); node.accept(this); // ASTNode n = copyStack.remove(copyStack.size()-1); ASTNode n = getReplace(node); if(n != node) { err("Different"); if(n.getProperty(TYPEBIND_PROP) == null) throw new CompilerError("Differnet null type: " + node); return n; //throw new CompilerError("different"); } return copySubtree(node); } public ASTNode translate(ASTNode node) { // copyStack.add(node); node.accept(this); // ASTNode n = copyStack.remove(copyStack.size()-1); ASTNode n = getReplace(node); if(n != node) { err("Different"); if(n.getProperty(TYPEBIND_PROP) == null) throw new CompilerError("Differnet null type"); return n; //throw new CompilerError("different"); } return node; } public SimpleName name(String name) { SimpleName n = ast.newSimpleName(name); n.setProperty(TYPEBIND_PROP, FieldType.OBJECT); return n; } public Name name(String... name) { Name n = ast.newName(name); n.setProperty(TYPEBIND_PROP, FieldType.OBJECT); return n; } public SimpleType typeQualified(String quadlifiedName) { SimpleType n = ast.newSimpleType(ast.newName(quadlifiedName)); n.setProperty(TYPEBIND_PROP, FieldType.OBJECT); return n; } public SimpleType type(String... name) { return ast.newSimpleType(name(name)); } public SimpleType type(Object typeprop, String... name) { SimpleType t = ast.newSimpleType(name(name)); t.setProperty(TYPEBIND_PROP, typeprop); return t; } public Entry entry(ITypeBinding type) { return StructCache.get(type); } public Entry entry(TypeDeclaration name) { Object o = name.getProperty(TYPEBIND_PROP); if(o instanceof StructCache.FieldType) return null; Entry e = (Entry)o; if(e != null) return e; return StructCache.get(name); } public Entry entry(Name name) { Object o = name.getProperty(TYPEBIND_PROP); if(o instanceof StructCache.FieldType) return null; Entry e = (Entry)o; if(e != null) return e; return StructCache.get(name); } public Entry entry(Type name) { Object o = name.getProperty(TYPEBIND_PROP); if(o instanceof StructCache.FieldType) return null; Entry e = (Entry)o; if(e != null) return e; return StructCache.get(name); } public StructCache.Entry entry(Expression name) { if(name instanceof Name) return entry((Name)name); Object o = name.getProperty(TYPEBIND_PROP); if(o instanceof StructCache.FieldType) return null; Entry e = (Entry)o; if(e != null) return e; return StructCache.get(name); } public Entry typeLiteral(Object o) { TypeLiteral typeLit = (TypeLiteral)o; Type type = typeLit.getType(); return entry(type); } public Expression returnBool(boolean val) { BooleanLiteral num = ast.newBooleanLiteral(val); num.setProperty(TYPEBIND_PROP, StructCache.FieldType.BOOLEAN); return num; } public Expression returnLong(long val) { NumberLiteral num = ast.newNumberLiteral(""+val); num.setProperty(TYPEBIND_PROP, StructCache.FieldType.LONG); return num; } public Expression returnInt(int val) { NumberLiteral num = ast.newNumberLiteral(""+val); num.setProperty(TYPEBIND_PROP, StructCache.FieldType.INT); return num; } public Expression returnString(String val) { StringLiteral str = ast.newStringLiteral(); str.setLiteralValue(val); str.setProperty(TYPEBIND_PROP, StructCache.FieldType.OBJECT); return str; } public ParenthesizedExpression wrap(Expression e) { ParenthesizedExpression p = ast.newParenthesizedExpression(); p.setExpression(e); Object o = e.getProperty(TYPEBIND_PROP); if(o != null) p.setProperty(TYPEBIND_PROP, o); return p; } public Type newType(ITypeBinding typeBinding) { if( typeBinding == null ) throw new NullPointerException("typeBinding is null"); if( typeBinding.isPrimitive() ) { return ast.newPrimitiveType( PrimitiveType.toCode(typeBinding.getName())); } if( typeBinding.isCapture() ) { ITypeBinding wildCard = typeBinding.getWildcard(); WildcardType capType = ast.newWildcardType(); ITypeBinding bound = wildCard.getBound(); if( bound != null ) { capType.setBound(newType(bound),wildCard.isUpperbound()); } return capType; } if(typeBinding.isWildcardType()) { WildcardType capType = ast.newWildcardType(); ITypeBinding bound = typeBinding.getBound(); if( bound != null ) { capType.setBound(newType(bound),typeBinding.isUpperbound()); } return capType; } if( typeBinding.isArray() ) { Type elType = newType(typeBinding.getElementType()); return ast.newArrayType(elType, typeBinding.getDimensions()); } if( typeBinding.isParameterizedType() ) { ParameterizedType type = ast.newParameterizedType( newType(typeBinding.getErasure())); List<Type> newTypeArgs = type.typeArguments(); for( ITypeBinding typeArg : typeBinding.getTypeArguments() ) { newTypeArgs.add(newType(typeArg)); } return type; } String qualName = typeBinding.getQualifiedName().trim(); if(qualName == null || "".equals(qualName) ) { throw new IllegalArgumentException("No name for type binding."); } return ast.newSimpleType(ast.newName(qualName)); } public MethodTmp getMethodTmp(ASTNode n) { Object o = n.getProperty(TYPEBIND_METHOD_TMP); if(o != null) return (MethodTmp)o; return null; } public MethodInvocation methodTmpStackVar(ASTNode StackExpression, Expression AddressIdentifier, Entry TypeBind) { MethodInvocation m = ast.newMethodInvocation(); m.setExpression(name(MEM0)); m.setName(name("tmpstack")); List args = m.arguments(); args.add((Expression)copySubtreeIfHasParent(StackExpression)); args.add((Expression)copySubtreeIfHasParent(AddressIdentifier)); args.add(returnInt(0)); m.setProperty(TYPEBIND_PROP, TypeBind); m.setProperty(TYPEBIND_METHOD_TMP, new MethodTmp(TypebindMethodTmp.StackVar, TypeBind)); return m; } public MethodInvocation methodTmpRef(ASTNode StackExpression, Expression AddressIdentifier, Entry TypeBind, StructCache.FieldEntry f, String varData, String var) { MethodInvocation m = ast.newMethodInvocation(); m.setExpression(name(MEM0)); m.setName(name("tmpref")); List args = m.arguments(); args.add((Expression)copySubtreeIfHasParent(StackExpression)); args.add((Expression)copySubtreeIfHasParent(AddressIdentifier)); args.add(returnInt(0)); m.setProperty(TYPEBIND_PROP, TypeBind); m.setProperty(TYPEBIND_METHOD_TMP, new MethodTmp(TypebindMethodTmp.Ref, TypeBind, f, varData, var)); return m; } public MethodInvocation methodTmpArrayIndex(ASTNode ArrayExpression, SimpleName ArrayIdentifier, Entry TypeBind, List dims) { if(dims.size() < 1) throw new IllegalArgumentException(); MethodInvocation m = ast.newMethodInvocation(); m.setExpression(name(MEM0)); m.setName(name("tmparr")); List args = m.arguments(); if(dims.size() == 1) { args.add((Expression)copySubtreeIfHasParent(ArrayExpression)); } else { FieldAccess fa = ast.newFieldAccess(); fa.setExpression((Expression)copySubtreeIfHasParent(ArrayExpression)); fa.setName(name("r")); args.add(fa); } args.add((Expression)copySubtreeIfHasParent(ArrayIdentifier)); args.add(returnInt(0)); if(dims.size() == 1) args.add(copySubtreeIfHasParent(dims.get(0))); else { MethodInvocation idx2 = ast.newMethodInvocation(); idx2.setExpression((Expression)copySubtreeIfHasParent(ArrayIdentifier)); idx2.setName(name(getIndexMethodName(dims.size()))); idx2.setProperty(TYPEBIND_PROP, FieldType.LONG); for(int i = 0; i < dims.size(); i++) { idx2.arguments().add(copySubtreeIfHasParent(dims.get(i))); } for(int i = 0; i < dims.size(); i++) { ASTNode arg3 = (ASTNode)dims.get(i); MethodTmp tmp3 = getMethodTmp(arg3); if(tmp3 != null) { replaceMethodTmp(arg3, (MethodInvocation)arg3, tmp3, MethodType.get, null, Assignment.Operator.ASSIGN); } } args.add(idx2); } m.setProperty(TYPEBIND_PROP, TypeBind); m.setProperty(TYPEBIND_METHOD_TMP, new MethodTmp(TypebindMethodTmp.Array, TypeBind)); return m; } public class MethodTmp { public TypebindMethodTmp type; public int offset = 0; public Entry e; public StructCache.FieldEntry f; public String varData, var; // public boolean isLocalVar; public MethodTmp(Entry e) { this.type = TypebindMethodTmp.Ptr; this.e = e; } public MethodTmp(StructCache.FieldEntry f) { // this.type = f.isReference()?TypebindMethodTmp.Ref:TypebindMethodTmp.Ptr; this.type = TypebindMethodTmp.Ptr; this.f = f; this.offset = f.offset; } private MethodTmp(TypebindMethodTmp type) { this.type = type; } private MethodTmp(TypebindMethodTmp type, Entry e) { this.type = type; this.e = e; } private MethodTmp(TypebindMethodTmp type, Entry e, StructCache.FieldEntry f, String varData, String var) { this.type = type; this.e = e; this.f = f; this.varData = varData; this.var = var; } public Entry getEntryResult() { if(f == null) return e; if(f.isStruct()) return f.structType; if(f.isReference()) return f.structType; return null; } public Expression getArrayReference(MethodInvocation mi) { return (Expression)copySubtree(mi.arguments().get(0)); } public Expression getLongAddress(MethodInvocation mi) { Expression indexExpr = getLongAddressBase(mi); NumberLiteral lit = (NumberLiteral)mi.arguments().get(2); if(offset != Integer.parseInt(lit.getToken())) throw new IllegalArgumentException("offset != " + lit); Expression args; if(offset == 0) args = indexExpr; else { InfixExpression add = ast.newInfixExpression(); add.setOperator(InfixExpression.Operator.PLUS); add.setLeftOperand(indexExpr); add.setRightOperand(returnInt(offset)); args = add; } return args; } public Expression getLongAddressBase(MethodInvocation mi) { Expression indexExpr = null; if(null != type) switch (type) { case StackVar: case Ptr: case Ref: indexExpr = (Expression)copySubtreeIfHasParent(mi.arguments().get(1)); break; case Array: case Array_Ptr: MethodInvocation mIndex = ast.newMethodInvocation(); mIndex.setExpression((Expression)copySubtree(mi.arguments().get(1))); mIndex.setName(name(getIndexMethodName(mi))); fillIndexMethodArgs(mi, mIndex.arguments()); indexExpr = mIndex; // indexExpr = getLongAddressWithIdx(mIndex); break; default: throw new IllegalArgumentException(); } return indexExpr; } public void fillIndexMethodArgs(MethodInvocation mi, List store) { for(int i = 3; i < mi.arguments().size(); i++) { ASTNode arg3 = (ASTNode)mi.arguments().get(i); MethodTmp tmp3 = getMethodTmp(arg3); if(tmp3 != null) { replaceMethodTmp(arg3, (MethodInvocation)arg3, tmp3, MethodType.get, null, Assignment.Operator.ASSIGN); } store.add(copySubtree(mi.arguments().get(i))); } } public Expression getLongAddressOffset(MethodInvocation mi) { return returnInt(offset); } public Expression addLongAddressOffset(Expression e) { Expression args; if(offset == 0) args = e; else { InfixExpression add = ast.newInfixExpression(); add.setOperator(InfixExpression.Operator.PLUS); add.setLeftOperand(e); add.setRightOperand(returnInt(offset)); args = add; } return args; } // public Expression getLongAddressWithIdx(MethodInvocation mi) { // return mi; //// ////// mi.arguments().add(ast.newNumberLiteral(""+e.structSize)); ////// return mi; //// Expression ret = mi; //// //// //test no index checking //// ret = wrap((Expression)copySubtreeIfHasParent(mi.arguments().get(0))); //// //// if(e.structSize != 1) { //// InfixExpression mult = ast.newInfixExpression(); //// mult.setOperator(InfixExpression.Operator.TIMES); //// mult.setLeftOperand((Expression)copySubtreeIfHasParent(ret)); //// mult.setRightOperand(ast.newNumberLiteral(""+e.structSize)); //// return wrap(mult); //// } //// else return ret; // } } public static final String INDEX_METHOD = "idx"; // public static final String INDEX_METHOD = "idxCheckOnly"; public String getIndexMethodName(MethodInvocation mi) { int dims = mi.arguments().size()-3; return getIndexMethodName(dims); } public String getIndexMethodName(int dims) { if(dims < 1) throw new IllegalArgumentException(); else if(dims == 1) { return INDEX_METHOD; } else if(dims < 5) { return INDEX_METHOD+dims; } else return INDEX_METHOD+'N'; } public void replaceMethodCallArguments(List list) { for(int i = 0; i < list.size(); i++) { Expression expr = (Expression)list.get(i); Entry e = entry(expr); if(e != null) { MethodTmp tmp = getMethodTmp(expr); Expression trimmed = trimWrap(expr); if(trimmed instanceof SimpleName) { SimpleName n = name(((SimpleName)trimmed).getIdentifier()+STRUCT_DATA); n.setProperty(TYPEBIND_PROP, e); list.add(i,n); i++; } else if(tmp != null) { MethodInvocation mi = (MethodInvocation)expr; list.set(i, tmp.getArrayReference(mi)); list.add(i+1, tmp.getLongAddress(mi)); mi.setProperty(TYPEBIND_PROP, FieldType.INT); i++; } else throw new IllegalArgumentException(); } } } public Expression methodB(String methodName, Type castType, Object... args) { MethodInvocation p = ast.newMethodInvocation(); p.setExpression(name(MEM0_B)); // p.setName(name(Translator.StringCache.getString( // type, // t, // opsymbol))); p.setName(name(methodName)); for(Object arg : args) p.arguments().add(arg); if(castType != null) { CastExpression cast = ast.newCastExpression(); cast.setType(castType); cast.setExpression(p); cast.setProperty(TYPEBIND_PROP, FieldType.OBJECT); return cast; } return p; } public void replaceMethodTmp(ASTNode node, MethodInvocation mi, MethodTmp tmp, MethodType type, ASTNode putValue, Assignment.Operator op) { OpSymbol opsymbol = null; // String metName = "put"; if(op != null && op != Assignment.Operator.ASSIGN) { if(type == MethodType.get) throw new CompilerError("Used operator for get " + node); switch(op.toString()) { case "+=": opsymbol = OpSymbol.Add; break; case "-=": opsymbol = OpSymbol.Sub; break; case "*=": opsymbol = OpSymbol.Mul; break; case "/=": opsymbol = OpSymbol.Div; break; case "&=": opsymbol = OpSymbol.And; break; case "|=": opsymbol = OpSymbol.Or; break; case "^=": opsymbol = OpSymbol.Xor; break; case "%=": opsymbol = OpSymbol.Mod; break; case "<<=": opsymbol = OpSymbol.LL; break; case ">>=": opsymbol = OpSymbol.RR; break; case ">>>=": opsymbol = OpSymbol.RRR; break; default: throw new CompilerError("Unknown operator " + op.toString()); } } MethodInvocation p = ast.newMethodInvocation(); p.setExpression(name(MEM0_B)); MethodInvocation miL = mi; switch(tmp.type) { case Array: if(type == MethodType.get) { throw CompilerError.get(getErrorLine(node), CompilerError.STRUCT_CONVERT_TO_OBJECT); } else { Expression right = (Expression)putValue; MethodTmp tmpL = tmp; Entry eL = tmpL.getEntryResult(); Entry eR = entry(right); if(eL != null && eR != null) { if(eL == eR) { if(right instanceof SimpleName) { SimpleName s = (SimpleName)right; p.setExpression(name(MEM0)); p.setName(name("copy")); List args = p.arguments(); args.add(name(s.getIdentifier()+STRUCT_DATA)); args.add(name(s.getIdentifier())); args.add(tmpL.getArrayReference(miL)); args.add(tmpL.getLongAddress(miL)); args.add(newEntryType(eR)); args.add(returnLong(1)); replace(node, p); return; } else { MethodTmp tmpR = getMethodTmp(putValue); if(tmpR != null) { MethodInvocation mRight = (MethodInvocation)putValue; p.setExpression(name(MEM0)); p.setName(name("copy")); List args = p.arguments(); args.add(tmpR.getArrayReference(mRight)); args.add(tmpR.getLongAddress(mRight)); args.add(tmpL.getArrayReference(miL)); args.add(tmpL.getLongAddress(miL)); args.add(newEntryType(eR)); args.add(returnLong(1)); replace(node, p); } else throw new IllegalArgumentException(); } } else { throw CompilerError.get(getErrorLine(node), CompilerError.STRUCT_COPY_TYPE_MISMATCH, eR.qualifiedName, eL.qualifiedName); } } else throw CompilerError.get(getErrorLine(node), CompilerError.UNCATEGORIZED_ERROR); } return; // throw new IllegalArgumentException("node " + node + ", " + mi + ", " + type); // break; case Array_Ptr: case Ptr: case Ref: case StackVar: // boolean isLocalVar = tmp.isLocalVar; FieldType ftype = tmp.f.type; TypeSymbol t = tmp.f.type.symbol; if(t == null) { // if(tmp.f.isReference() && tmp.f.isSibling) // t = TypeSymbol.LONG; // else throw new IllegalArgumentException(); if(tmp.f.isReference()) { if(type == MethodType.get) { throw CompilerError.get(getErrorLine(node), CompilerError.STRUCT_CONVERT_TO_OBJECT); } else { p.setName(name("pR")); if(tmp.type == TypebindMethodTmp.Ref) { p.arguments().add(getRefArg(miL, 3)); if(tmp.f.isSibling) { p.arguments().add(getRefArg(miL, 4)); } else { p.arguments().add(getRefArg(miL, 4)); p.arguments().add(getRefArg(miL, 5)); p.arguments().add(returnInt(tmp.f.refData.objOffset)); } } else { p.arguments().add(tmp.getArrayReference(mi)); if(tmp.f.isSibling) { p.arguments().add(tmp.getLongAddress(mi)); } else { p.arguments().add(tmp.getLongAddressBase(mi)); p.arguments().add(tmp.getLongAddressOffset(mi)); p.arguments().add(returnInt(tmp.f.refData.objOffset)); } } if(putValue instanceof SimpleName) { SimpleName s = (SimpleName)putValue; p.arguments().add(name(s.getIdentifier()+STRUCT_DATA)); p.arguments().add(name(s.getIdentifier())); } else { MethodTmp tmpR = getMethodTmp(putValue); if(tmpR != null) { MethodInvocation miR = (MethodInvocation)putValue; p.arguments().add(tmpR.getArrayReference(miR)); p.arguments().add(tmpR.getLongAddress(miR)); } else throw new IllegalArgumentException(); } replace(node, p); return; } } else if(tmp.f.isStruct()) { if(type == MethodType.get) { throw new IllegalArgumentException(); } Expression right = (Expression)putValue; MethodTmp tmpL = tmp; Entry eL = tmpL.getEntryResult(); Entry eR = entry(right); if(eL != null && eR != null) { if(eL == eR) { if(right instanceof SimpleName) { SimpleName s = (SimpleName)right; p.setExpression(name(MEM0)); p.setName(name("copy")); List args = p.arguments(); args.add(name(s.getIdentifier()+STRUCT_DATA)); args.add(name(s.getIdentifier())); args.add(tmpL.getArrayReference(miL)); args.add(tmpL.getLongAddress(miL)); args.add(newEntryType(eR)); args.add(returnLong(1)); replace(node, p); return; } else { MethodTmp tmpR = getMethodTmp(putValue); if(tmpR != null) { MethodInvocation mRight = (MethodInvocation)putValue; p.setExpression(name(MEM0)); p.setName(name("copy")); List args = p.arguments(); args.add(tmpR.getArrayReference(mRight)); args.add(tmpR.getLongAddress(mRight)); args.add(tmpL.getArrayReference(miL)); args.add(tmpL.getLongAddress(miL)); args.add(newEntryType(eR)); args.add(returnLong(1)); replace(node, p); return; } else throw new IllegalArgumentException(); } } else { CompilerError.exec(CompilerError.STRUCT_COPY_TYPE_MISMATCH, eR.qualifiedName, eL.qualifiedName); } } else throw new IllegalArgumentException(); } else throw new IllegalArgumentException(); } p.setName(name(Translator.StringCache.getString( type, t, opsymbol))); p.arguments().add(tmp.getArrayReference(mi)); p.arguments().add(tmp.getLongAddress(mi)); /* if(tmp.type == TypebindMethodTmp.Ptr) { Object arg0 = mi.arguments().get(0); // if(arg0 instanceof SimpleName) { // SimpleName s = (SimpleName)arg0; // p.arguments().add(name(s.getIdentifier())); // indexExpr = (Expression)copySubtreeIfHasParent(mi.arguments().get(1)); // } // else { // p.arguments().add(copySubtreeIfHasParent(arg0)); // indexExpr = (Expression)copySubtreeIfHasParent(mi.arguments().get(1)); // } // p.arguments().add(copySubtreeIfHasParent(arg0)); indexExpr = (Expression)copySubtreeIfHasParent(mi.arguments().get(1)); // throw new IllegalArgumentException("not yet implemented"); } else { // if(isLocalVar) { Log.err(" base --- " + mi); p.arguments().add((Expression)copySubtree(mi.arguments().get(0))); MethodInvocation mIndex = ast.newMethodInvocation(); mIndex.setExpression((Expression)copySubtree(mi.arguments().get(1))); mIndex.setName(name("idx")); mIndex.arguments().add(copySubtree(mi.arguments().get(3))); indexExpr = mIndex; // } // else { //// indexExpr = null; // throw new IllegalArgumentException("not yet implemented"); // } } */ if(ftype == StructCache.FieldType.OBJECT || ftype == StructCache.FieldType.REFERENCE) p.arguments().add(returnInt(tmp.f.objOffset)); if(type == MethodType.put) { if(ftype.primCast && (op != null || (trimWrap((Expression)putValue)) instanceof NumberLiteral)) { CastExpression cast = ast.newCastExpression(); cast.setType(newType(tmp.f.typeb)); cast.setExpression((Expression)copySubtree(putValue)); cast.setProperty(TYPEBIND_PROP, ftype); p.arguments().add(cast); } else p.arguments().add(copySubtree(putValue)); } if(ftype == StructCache.FieldType.OBJECT) { CastExpression cast = ast.newCastExpression(); cast.setType(newType(tmp.f.typeb)); cast.setExpression(p); cast.setProperty(TYPEBIND_PROP, ftype); replace(node, wrap(cast)); } else replace(node, p); break; } } public FieldAccess newEntryType(Entry e) { FieldAccess structType = ast.newFieldAccess(); structType.setExpression(ast.newName(e.qualifiedName)); structType.setName(name(STRUCT_TYPE_VAR)); return structType; } public boolean isReplace(ASTNode n) { return n.getProperty(IS_REPLACE) != null;} public ASTNode getReplace(ASTNode n) { ASTNode r = n; while(r.getProperty(IS_REPLACE) != null) r = (ASTNode)r.getProperty(IS_REPLACE); return r; } public Expression addOffset(Expression e, int offset) { if(offset == 0) return e; InfixExpression add = ast.newInfixExpression(); add.setOperator(InfixExpression.Operator.PLUS); add.setLeftOperand(e); add.setRightOperand(returnInt(offset)); return add; } public Expression getArg(MethodInvocation mi, int arg) { return (Expression)copySubtreeIfHasParent(mi.arguments().get(arg)); } public Expression getRefArg(MethodInvocation mi, int arg) { return (Expression)copySubtreeIfHasParent(mi.arguments().get(arg)); } public Expression trimWrap(Expression expr) { Expression e = expr; while(e instanceof ParenthesizedExpression) { e = ((ParenthesizedExpression)e).getExpression(); } return e; } public String getErrorLine(ASTNode node) { int pos = getStartPos(node); if(pos < 0) return null; int line = cu.getLineNumber(pos); try { IRegion r = doc.getLineInformationOfOffset(pos); // int len = doc.getLineLength(line); // for(int i = 190; i < 210; i++) { // IRegion r = doc.getLineInformation(i); // Log.err("Line " + i + ": " + r); // Log.err(" OFF " + r.getOffset() + ", len " + r.getLength()); // Log.err("xx " + doc.get().substring(r.getOffset(), r.getOffset()+r.getLength())); // // } // Log.err("DOC " + doc.get()); // // Log.err("len fgg " + doc.getLineInformation(line).toString()); String text = doc.get(r.getOffset(), r.getLength()); return sourceFileName + ":" + line + ": " + text; } catch (Exception ex) { return "Line " + line + ": "; } } public int getStartPos(ASTNode node) { int n = node.getStartPosition(); while(n == -1) { node = node.getParent(); if(node == null) return n; n = node.getStartPosition(); } return n; } // public ASTNode getNodeWithPos(ASTNode node) { // int n = node.getStartPosition(); // while(n == -1) { // node = node.getParent(); // if(node == null) return null; // n = node.getStartPosition(); // } // return node; // } }