/* * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.tools.comp; import org.visage.tools.code.VisageVarSymbol; import org.visage.tools.tree.*; import org.visage.tools.comp.VisageAbstractTranslation.ExpressionResult; import com.sun.tools.mjavac.code.Kinds; import com.sun.tools.mjavac.code.Symbol; import com.sun.tools.mjavac.code.Symbol.VarSymbol; import com.sun.tools.mjavac.code.Type; import com.sun.tools.mjavac.tree.JCTree.*; import com.sun.tools.mjavac.util.Context; import com.sun.tools.mjavac.util.List; import com.sun.tools.mjavac.util.Name; /** * Translate an inversion of bind expressions. * * @author Jim Laskey * @author Robert Field */ public class VisageTranslateInvBind extends VisageAbstractTranslation implements VisageVisitor { protected static final Context.Key<VisageTranslateInvBind> visageBoundInvTranslation = new Context.Key<VisageTranslateInvBind>(); // Symbol for the var whose bound expression we are translating. private VisageVarSymbol targetSymbol; // The outermost bound expression private VisageExpression boundExpression; public static VisageTranslateInvBind instance(Context context) { VisageTranslateInvBind instance = context.get(visageBoundInvTranslation); if (instance == null) { VisageToJava toJava = VisageToJava.instance(context); instance = new VisageTranslateInvBind(context, toJava); } return instance; } public VisageTranslateInvBind(Context context, VisageToJava toJava) { super(context, toJava); context.put(visageBoundInvTranslation, this); } ExpressionResult translate(VisageExpression expr, Type type, Symbol symbol) { this.targetSymbol = (VisageVarSymbol) symbol; this.boundExpression = expr; return translateToExpressionResult(expr, type); } private class BiBoundSequenceSelectTranslator extends BiBoundSelectTranslator { BiBoundSequenceSelectTranslator(VisageSelect tree) { super(tree); } @Override protected BoundSequenceResult doit() { addInterClassBindee((VisageVarSymbol) selectorSym, refSym); return new BoundSequenceResult( List.<JCStatement>nil(), null, bindees(), invalidators(), interClass(), makeGetElementBody(), makeSizeBody(), targetSymbol.type); } private JCExpression selector() { return refSym.isStatic() ? Getter(selectorSym) : concreteSelector(); } private JCExpression concreteSelector() { return translateToCheck(getToCheck()); } // ---- Stolen from BoundSequenceTranslator ---- //TODO: unify private Name activeFlagBit = defs.varFlagSEQUENCE_LIVE; VisageVarSymbol flagSymbol = (VisageVarSymbol)targetSymbol; JCExpression isSequenceActive() { return FlagTest(flagSymbol, activeFlagBit, activeFlagBit); } JCExpression isSequenceDormant() { return FlagTest(flagSymbol, activeFlagBit, null); } JCStatement setSequenceActive() { return FlagChangeStmt(flagSymbol, null, BITOR(id(defs.varFlagSEQUENCE_LIVE), id(defs.varFlagINIT_INITIALIZED_DEFAULT))); } protected JCExpression getReceiverForCallHack(Symbol sym) { if (sym.isStatic()) { return makeType(sym.owner.type, false); } return getReceiver(sym); } JCExpression CallSize(Symbol sym) { return CallSize(getReceiverForCallHack(sym), sym); } JCExpression CallSize(JCExpression rcvr, Symbol sym) { if (((VisageVarSymbol) sym).useAccessors()) return Call(rcvr, attributeSizeName(sym)); else return Call(defs.Sequences_size, Getter(rcvr, sym)); } JCExpression CallGetElement(Symbol sym, JCExpression pos) { return CallGetElement(getReceiverForCallHack(sym), sym, pos); } JCExpression CallGetElement(JCExpression rcvr, Symbol sym, JCExpression pos) { if (((VisageVarSymbol) sym).useAccessors()) return Call(rcvr, attributeGetElementName(sym), pos); else return Call(Getter(rcvr, sym), defs.get_SequenceMethodName, pos); } /** * size$ method */ JCStatement makeSizeBody() { JCVariableDecl vSize = TmpVar("size", syms.intType, CallSize(concreteSelector(), refSym)); return Block( vSize, If (isSequenceDormant(), Block( SetStmt(targetSymbol, m().NewClass(null, null, makeType(types.erasure(syms.visage_SequenceProxyType)), List.<JCExpression>of( TypeInfo(diagPos, refSym.type), selector(), Offset(getReceiver(selectorSym), refSym)), null) ), setSequenceActive(), CallStmt(defs.VisageBase_addDependent, selector(), Offset(selector(), refSym), getReceiverOrThis(selectorSym), DepNum(getReceiver(selectorSym), selectorSym, refSym) ), CallSeqInvalidateUndefined(targetSymbol), CallSeqTriggerInitial(targetSymbol, id(vSize)) ) ), Return (id(vSize)) ); } /** * elem$ method */ JCStatement makeGetElementBody() { return Block( If (isSequenceDormant(), Stmt(CallSize(targetSymbol)) ), Return (CallGetElement(concreteSelector(), refSym, posArg())) ); } } private class BiBoundSequenceIdentTranslator extends BoundIdentTranslator { private final VisageVarSymbol refSym; BiBoundSequenceIdentTranslator(VisageIdent tree) { super(tree); this.refSym = (VisageVarSymbol) tree.sym; } @Override protected BoundSequenceResult doit() { super.doit(); return new BoundSequenceResult( List.<JCStatement>nil(), null, bindees(), invalidators(), interClass(), makeGetElementBody(), makeSizeBody(), targetSymbol.type); } // ---- Stolen from BoundSequenceTranslator ---- //TODO: unify private Name activeFlagBit = defs.varFlagSEQUENCE_LIVE; VisageVarSymbol flagSymbol = (VisageVarSymbol)targetSymbol; JCExpression isSequenceActive() { return FlagTest(flagSymbol, activeFlagBit, activeFlagBit); } JCExpression isSequenceDormant() { return FlagTest(flagSymbol, activeFlagBit, null); } JCStatement setSequenceActive() { return FlagChangeStmt(flagSymbol, null, BITOR(id(defs.varFlagSEQUENCE_LIVE), id(defs.varFlagINIT_INITIALIZED_DEFAULT))); } protected JCExpression getReceiverForCallHack(Symbol sym) { if (sym.isStatic()) { return makeType(sym.owner.type, false); } return getReceiver(sym); } JCExpression CallSize(Symbol sym) { return CallSize(getReceiverForCallHack(sym), sym); } JCExpression CallSize(JCExpression rcvr, Symbol sym) { if (((VisageVarSymbol) sym).useAccessors()) return Call(rcvr, attributeSizeName(sym)); else return Call(defs.Sequences_size, Getter(rcvr, sym)); } JCExpression CallGetElement(Symbol sym, JCExpression pos) { return CallGetElement(getReceiverForCallHack(sym), sym, pos); } JCExpression CallGetElement(JCExpression rcvr, Symbol sym, JCExpression pos) { if (((VisageVarSymbol) sym).useAccessors()) return Call(rcvr, attributeGetElementName(sym), pos); else return Call(Getter(rcvr, sym), defs.get_SequenceMethodName, pos); } /** * size$ method */ JCStatement makeSizeBody() { JCVariableDecl vSize = TmpVar("size", syms.intType, CallSize(refSym)); return Block( vSize, If (isSequenceDormant(), Block( SetStmt(targetSymbol, m().NewClass(null, null, makeType(types.erasure(syms.visage_SequenceProxyType)), List.<JCExpression>of( TypeInfo(diagPos, refSym.type), getReceiverOrThis(refSym), Offset(refSym)), null) ), setSequenceActive(), CallSeqInvalidateUndefined(targetSymbol), CallSeqTriggerInitial(targetSymbol, id(vSize)) ) ), Return (id(vSize)) ); } /** * elem$ method */ JCStatement makeGetElementBody() { return Block( If (isSequenceDormant(), Stmt(CallSize(targetSymbol)) ), Return (CallGetElement(refSym, posArg())) ); } } private class BiBoundSelectTranslator extends BoundSelectTranslator { final Symbol selectorSym; BiBoundSelectTranslator(VisageSelect tree) { super(tree, targetSymbol); VisageExpression selectorExpr = tree.getExpression(); assert selectorExpr instanceof VisageIdent : "should be another var in the same instance."; VisageIdent selector = (VisageIdent) selectorExpr; selectorSym = selector.sym; } @Override protected ExpressionResult doit() { /* type tmp0 = inv expression(varNewValue$); seltype tmp1 = get$select(); if (tmp1 != null) tmp1.set$varSym(tmp0); varNewValue$ */ JCExpression receiver; if (!refSym.isStatic() && selectorSym.kind == Kinds.TYP && currentClass().sym.isSubClass(selectorSym, types)) { receiver = id(names._super); } else if (!(selectorSym instanceof VarSymbol)) { receiver = id(selectorSym); } else { JCVariableDecl selector = TmpVar(syms.visage_ObjectType, Getter(selectorSym)); addSetterPreface(selector); receiver = id(selector); } //note: we have to use the set$(int, VisageBase) version because //the set$xxx version is not always accessible from the //selector expression (if selector is XXX$Script class) addSetterPreface( If(NEnull(receiver), Block( CallStmt(receiver, defs.set_VisageObjectMethodName, Offset(receiver, refSym), id(defs.varNewValue_ArgName) ) ) ) ); return super.doit(); } } private class BiBoundIdentTranslator extends BoundIdentTranslator { BiBoundIdentTranslator(VisageIdent tree) { super(tree); } @Override protected ExpressionResult doit() { /* type tmp0 = inv expression(varNewValue$); set$varSym(tmp0); varNewValue$ */ addSetterPreface(SetterStmt(sym, id(defs.varNewValue_ArgName))); return super.doit(); } } /*********************************************************************** * * Utilities * */ protected String getSyntheticPrefix() { return "ibvisage$"; } /* *************************************************************************** * Visitor methods -- implemented (alphabetical order) ****************************************************************************/ private boolean isTargettedToSequence() { return types.isSequence(targetSymbol.type); } public void visitIdent(VisageIdent tree) { if (tree == boundExpression && isTargettedToSequence()) { result = new BiBoundSequenceIdentTranslator(tree).doit(); } else { result = new BiBoundIdentTranslator(tree).doit(); } } public void visitSelect(VisageSelect tree) { if (tree == boundExpression && isTargettedToSequence()) { result = new BiBoundSequenceSelectTranslator(tree).doit(); } else { result = new BiBoundSelectTranslator(tree).doit(); } } /*********************************************************************** * * Moot visitors (alphabetical order) * */ private void disallowedInInverseBind() { badVisitor("should not be processed as part of a binding with inverse"); } @Override public void visitBinary(VisageBinary tree) { disallowedInInverseBind(); } public void visitBlockExpression(VisageBlock tree) { disallowedInInverseBind(); } @Override public void visitClassDeclaration(VisageClassDeclaration tree) { disallowedInInverseBind(); } @Override public void visitForExpression(VisageForExpression tree) { disallowedInInverseBind(); } @Override public void visitForExpressionInClause(VisageForExpressionInClause tree) { disallowedInInverseBind(); } @Override public void visitFunctionDefinition(VisageFunctionDefinition tree) { disallowedInInverseBind(); } @Override public void visitFunctionInvocation(VisageFunctionInvocation tree) { disallowedInInverseBind(); } @Override public void visitFunctionValue(VisageFunctionValue tree) { disallowedInInverseBind(); } @Override public void visitIfExpression(VisageIfExpression tree) { disallowedInInverseBind(); } @Override public void visitIndexof(VisageIndexof tree) { disallowedInInverseBind(); } @Override public void visitInstanceOf(VisageInstanceOf tree) { disallowedInInverseBind(); } @Override public void visitInstanciate(VisageInstanciate tree) { disallowedInInverseBind(); } @Override public void visitInterpolateValue(VisageInterpolateValue tree) { disallowedInInverseBind(); } @Override public void visitLiteral(VisageLiteral tree) { disallowedInInverseBind(); } @Override public void visitParens(VisageParens tree) { disallowedInInverseBind(); } @Override public void visitSequenceExplicit(VisageSequenceExplicit tree) { disallowedInInverseBind(); } @Override public void visitSequenceIndexed(VisageSequenceIndexed tree) { disallowedInInverseBind(); } @Override public void visitSequenceRange(VisageSequenceRange tree) { disallowedInInverseBind(); } @Override public void visitSequenceSlice(VisageSequenceSlice tree) { disallowedInInverseBind(); } @Override public void visitStringExpression(VisageStringExpression tree) { disallowedInInverseBind(); } @Override public void visitTimeLiteral(VisageTimeLiteral tree) { disallowedInInverseBind(); } @Override public void visitLengthLiteral(VisageLengthLiteral tree) { disallowedInInverseBind(); } @Override public void visitAngleLiteral(VisageAngleLiteral tree) { disallowedInInverseBind(); } @Override public void visitColorLiteral(VisageColorLiteral tree) { disallowedInInverseBind(); } @Override public void visitTypeCast(VisageTypeCast tree) { disallowedInInverseBind(); } @Override public void visitUnary(VisageUnary tree) { disallowedInInverseBind(); } }