/* * Copyright 2008-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.api.VisageBindStatus; import org.visage.tools.code.VisageFlags; import org.visage.tools.tree.*; import org.visage.tools.code.VisageTypes; import org.visage.tools.code.VisageSymtab; import org.visage.tools.code.VisageVarSymbol; import org.visage.tools.tree.VisageExpression; import com.sun.tools.mjavac.code.Flags; import com.sun.tools.mjavac.code.Kinds; import com.sun.tools.mjavac.code.Scope; import com.sun.tools.mjavac.code.Symbol; import com.sun.tools.mjavac.code.Symbol.MethodSymbol; import com.sun.tools.mjavac.code.Symbol.TypeSymbol; import com.sun.tools.mjavac.code.Symbol.VarSymbol; import com.sun.tools.mjavac.code.Type; import com.sun.tools.mjavac.code.TypeTags; import com.sun.tools.mjavac.util.Context; import com.sun.tools.mjavac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.mjavac.util.List; import com.sun.tools.mjavac.util.ListBuffer; import com.sun.tools.mjavac.util.Name; import java.util.Map; import java.util.HashMap; /** * Normalize tree before translation. This includes adding explicit type conversions * (e.g. for autoboxing, sequence conversions, etc.) and rewriting unary/assignop operations * as binary operations. * * @author Maurizio Cimadamore */ public class VisageLower implements VisageVisitor { protected static final Context.Key<VisageLower> convertTypesKey = new Context.Key<VisageLower>(); private VisagePreTranslationSupport preTrans; private VisageTypes types; private VisageResolve rs; private VisageSymtab syms; private VisageTreeMaker m; private VisageDefs defs; private Type pt; private LowerMode mode; private Map<VisageForExpressionInClause, VisageForExpressionInClause> forClauseMap; //TODO this should be refactord into a common translation support private int synthNameCount = 0; private VisageEnv<VisageAttrContext> env; private VisageTree enclFunc; private VisageTree result; private Name.Table names; private Symbol currentClass; private int varCount; enum LowerMode { EXPRESSION, STATEMENT, DECLARATION; } public static VisageLower instance(Context context) { VisageLower instance = context.get(convertTypesKey); if (instance == null) instance = new VisageLower(context); return instance; } VisageLower(Context context) { context.put(convertTypesKey, this); preTrans = VisagePreTranslationSupport.instance(context); types = VisageTypes.instance(context); syms = (VisageSymtab)VisageSymtab.instance(context); m = VisageTreeMaker.instance(context); rs = VisageResolve.instance(context); names = Name.Table.instance(context); defs = VisageDefs.instance(context); forClauseMap = new HashMap<VisageForExpressionInClause, VisageForExpressionInClause>(); } public VisageTree lower(VisageEnv<VisageAttrContext> attrEnv) { this.env = attrEnv; attrEnv.toplevel = lowerDecl(attrEnv.toplevel); //System.out.println(result); return result; } @SuppressWarnings("unchecked") <T extends VisageTree> T lower(T tree, Type pt, LowerMode mode) { Type prevPt = this.pt; LowerMode prevMode = this.mode; try { this.pt = pt; this.mode = mode; if (tree != null) { tree.accept(this); return (T)(mode == LowerMode.EXPRESSION ? convertTree((VisageExpression)result, this.pt) : result); } else return null; } finally { this.pt = prevPt; this.mode = prevMode; } } public <T extends VisageTree> T lowerExpr(T tree) { return lower(tree, Type.noType, LowerMode.EXPRESSION); } public <T extends VisageTree> T lowerExpr(T tree, Type pt) { return lower(tree, pt, LowerMode.EXPRESSION); } public <T extends VisageTree> T lowerStmt(T tree) { return lower(tree, Type.noType, LowerMode.STATEMENT); } public <T extends VisageTree> T lowerDecl(T tree) { return lower(tree, Type.noType, LowerMode.DECLARATION); } <T extends VisageTree> List<T> lower(List<T> trees, LowerMode mode) { ListBuffer<T> buf = ListBuffer.lb(); for (T tree : trees) { buf.append(lower(tree, Type.noType, mode)); } return buf.toList(); } public <T extends VisageExpression> List<T> lowerExprs(List<? extends T> trees, List<Type> pts) { ListBuffer<T> buf = ListBuffer.lb(); for (T tree : trees) { buf.append(lowerExpr(tree, pts.head)); pts = pts.tail; } return buf.toList(); } public <T extends VisageTree> List<T> lowerExprs(List<T> trees) { return lower(trees, LowerMode.EXPRESSION); } public <T extends VisageTree> List<T> lowerDecls(List<T> trees) { return lower(trees, LowerMode.DECLARATION); } public <T extends VisageTree> List<T> lowerStats(List<T> trees) { return lower(trees, LowerMode.STATEMENT); } VisageExpression convertTree(VisageExpression tree, Type type) { if (type == Type.noType) return tree; return tree = needSequenceConversion(tree, type) ? toSequence(tree, type) : preTrans.makeCastIfNeeded(tree, type); } private boolean needSequenceConversion(VisageExpression tree, Type type) { return (types.isSequence(type) && ((!types.isSequence(tree.type) && tree.type != syms.unreachableType && !types.isArray(tree.type)) || isNull(tree))); } private boolean isNull(VisageTree tree) { return (tree.getVisageTag() == VisageTag.LITERAL && ((VisageLiteral)tree).value == null); } private VisageExpression toSequence(VisageExpression tree, Type type) { VisageExpression seqExpr = null; if (isNull(tree)) { seqExpr = m.at(tree.pos).EmptySequence().setType(type); } else if (types.isSameType(tree.type, syms.objectType) && types.isSubtypeUnchecked(syms.visage_SequenceTypeErasure, type)) { //synthetic call MethodSymbol msym = (MethodSymbol)rs.findIdentInType(env, syms.visage_SequencesType, defs.Sequences_convertObjectToSequence.methodName, Kinds.MTH); VisageExpression sequencesType = m.at(tree.pos).Type(syms.visage_SequencesType).setType(syms.visage_SequencesType); VisageTreeInfo.setSymbol(sequencesType, syms.visage_SequencesType.tsym); VisageIdent convertMeth = m.at(tree.pos).Ident(defs.Sequences_convertObjectToSequence.methodName); convertMeth.sym = msym; convertMeth.type = msym.type; seqExpr = m.at(tree.pos).Apply(List.<VisageExpression>nil(), convertMeth, List.of(tree)).setType(msym.type.getReturnType()); } else { seqExpr = m.at(tree.pos).ExplicitSequence(List.of(preTrans.makeCastIfNeeded(tree, types.elementType(type)))); seqExpr.type = type; } return seqExpr; } private Name tempName(String label) { return names.fromString("$" + label + "$" + varCount++); } private VisageVar makeVar(DiagnosticPosition diagPos, String name, VisageExpression init, Type type) { return makeVar(diagPos, 0L, name, VisageBindStatus.UNBOUND, init, type); } private VisageVar makeVar(DiagnosticPosition diagPos, long flags, String name, VisageBindStatus bindStatus, VisageExpression init, Type type) { VisageVarSymbol vsym = new VisageVarSymbol(types, names, flags, tempName(name), types.normalize(type), preTrans.makeDummyMethodSymbol(currentClass)); return makeVar(diagPos, vsym, bindStatus, init); } private VisageVar makeVar(DiagnosticPosition diagPos, VisageVarSymbol vSym, VisageBindStatus bindStatus, VisageExpression init) { VisageModifiers mod = m.at(diagPos).Modifiers(vSym.flags()); VisageType visageType = preTrans.makeTypeTree(vSym.type); VisageVar v = m.at(diagPos).Var(vSym.name, visageType, mod, init, bindStatus, null, null); v.sym = vSym; v.type = vSym.type; return v; } public void visitAssign(VisageAssign tree) { if (tree.lhs.getVisageTag() == VisageTag.SEQUENCE_INDEXED && types.isSequence(((VisageSequenceIndexed)tree.lhs).getSequence().type) && (types.isSequence(tree.rhs.type) || types.isSameType(tree.rhs.type, syms.objectType))) { result = lowerSequenceIndexedAssign(tree.pos(), (VisageSequenceIndexed)tree.lhs, tree.rhs); } else { VisageExpression lhs = lowerExpr(tree.lhs); VisageExpression rhs = lowerExpr(tree.rhs, tree.lhs.type); result = m.at(tree.pos).Assign(lhs, rhs).setType(tree.type); } } VisageExpression lowerSequenceIndexedAssign(DiagnosticPosition pos, VisageSequenceIndexed indexed, VisageExpression val) { Type resType = indexed.getSequence().type; VisageVar indexVar = makeVar(pos, defs.posNamePrefix(), indexed.getIndex(), indexed.getIndex().type); VisageIdent indexRef = m.at(pos).Ident(indexVar); VisageExpression lhs = m.SequenceSlice(indexed.getSequence(), indexRef, indexRef, VisageSequenceSlice.END_INCLUSIVE); lhs.setType(resType); VisageExpression assign = m.Assign(lhs, val).setType(resType); return lowerExpr(m.Block(0L, List.<VisageExpression>of(indexVar), assign).setType(resType)); } public void visitAssignop(VisageAssignOp tree) { result = visitNumericAssignop(tree, types.isSameType(tree.lhs.type, syms.visage_DurationType) || types.isSameType(tree.lhs.type, syms.visage_LengthType) || types.isSameType(tree.lhs.type, syms.visage_AngleType) || types.isSameType(tree.lhs.type, syms.visage_ColorType)); } //where private VisageExpression visitNumericAssignop(VisageAssignOp tree, boolean isSpecialLiteralOperation) { VisageTag opTag = tree.getNormalOperatorVisageTag(); ListBuffer<VisageExpression> stats = ListBuffer.lb(); //if the assignop operand is an indexed expression of the kind a.x[i] //then we need to cache the index value (not to recompute it twice). VisageExpression lhs = tree.lhs; VisageIdent index = null; if (tree.lhs.getVisageTag() == VisageTag.SEQUENCE_INDEXED) { VisageSequenceIndexed indexed = (VisageSequenceIndexed)tree.lhs; VisageVar varDef = makeVar(tree.pos(), defs.indexNamePrefix(), indexed.getIndex(), indexed.getIndex().type); index = m.at(tree.pos).Ident(varDef.sym); index.sym = varDef.sym; index.type = varDef.type; stats.append(varDef); lhs = indexed.getSequence(); } //if the assignop operand is a select of the kind a.x //then we need to cache the selected part (a), so that //it won't be recomputed twice. // // var $expr$ = a; VisageIdent selector = null; if (lhs.getVisageTag() == VisageTag.SELECT) { VisageExpression selected = ((VisageSelect)lhs).selected; // But, if this select is ClassName.foo, then we don't want // to create "var $expr = a;" Symbol sym = VisageTreeInfo.symbolFor(selected); if (sym == null || sym.kind != Kinds.TYP) { VisageVar varDef = makeVar(tree.pos(), defs.exprNamePrefix(), selected, selected.type); selector = m.at(tree.pos).Ident(varDef.sym); selector.sym = varDef.sym; selector.type = varDef.type; stats.append(varDef); } } VisageExpression varRef = lhs; //create a reference to the cached var. The translated expression //depends on whether the operand is a select or not: // //(SELECT) $expr$.x; //(IDENT) x; if (selector != null) { VisageVarSymbol vsym = (VisageVarSymbol)VisageTreeInfo.symbol(lhs); varRef = m.at(tree.pos).Select(selector, vsym, false); ((VisageSelect)varRef).sym = vsym; } if (index != null) { varRef = m.at(tree.pos).SequenceIndexed(varRef, index).setType(tree.lhs.type); } //Generate the binary expression this assignop translates to VisageExpression op = null; if (isSpecialLiteralOperation) { //special literal assignop (duration, length, angle, or color) // //(SELECT) $expr$.x = $expr$.x.[add/sub/mul/div](lhs); //(IDENT) x = x.[add/sub/mul/div](lhs); VisageSelect meth = (VisageSelect)m.at(tree.pos).Select(varRef, tree.operator.name, false); meth.setType(tree.operator.type); meth.sym = tree.operator; op = m.at(tree.pos).Apply(List.<VisageExpression>nil(), meth, List.of(tree.rhs)); op.setType(tree.type); } else { //numeric assignop // //(SELECT) $expr$.x = $expr$.x [+|-|*|/] lhs; //(IDENT) x = $expr$.x [+|-|*|/] lhs; op = m.at(tree.pos).Binary(opTag, varRef, tree.rhs); ((VisageBinary)op).operator = tree.operator; op.setType(tree.operator.type.asMethodType().getReturnType()); } VisageExpression assignOpStat = (VisageExpression)m.at(tree.pos).Assign(varRef, op).setType(op.type); VisageExpression res = stats.nonEmpty() ? m.at(tree.pos).Block(0L, stats.toList(), assignOpStat).setType(op.type) : assignOpStat; return lowerExpr(res, Type.noType); } public void visitBinary(VisageBinary tree) { boolean isSpecialLiteralBinaryExpr = tree.operator == null; boolean isEqualExpr = (tree.getVisageTag() == VisageTag.EQ || tree.getVisageTag() == VisageTag.NE); boolean isSequenceOp = types.isSequence(tree.lhs.type) || types.isSequence(tree.rhs.type); boolean isBoxedOp = (tree.lhs.type.isPrimitive() && !tree.rhs.type.isPrimitive()) || (tree.rhs.type.isPrimitive() && !tree.lhs.type.isPrimitive()); Type lhsType = tree.lhs.type; Type rhsType = tree.rhs.type; if (!isSpecialLiteralBinaryExpr) { lhsType = isSequenceOp && isEqualExpr ? types.sequenceType(tree.operator.type.getParameterTypes().head) : tree.operator.type.getParameterTypes().head; rhsType = isSequenceOp && isEqualExpr ? types.sequenceType(tree.operator.type.getParameterTypes().tail.head) : tree.operator.type.getParameterTypes().tail.head; } VisageExpression lhs = isEqualExpr && isBoxedOp && !isSequenceOp ? lowerExpr(tree.lhs) : lowerExpr(tree.lhs, lhsType); VisageExpression rhs = isEqualExpr && isBoxedOp && !isSequenceOp ? lowerExpr(tree.rhs) : lowerExpr(tree.rhs, rhsType); VisageBinary res = m.at(tree.pos).Binary(tree.getVisageTag(), lhs, rhs); res.operator = tree.operator; result = res.setType(tree.type); } public void visitForExpressionInClause(VisageForExpressionInClause that) { VisageExpression whereExpr = lowerExpr(that.getWhereExpression()); Type typeToCheck = that.seqExpr.type; if (that.seqExpr.type.tag == TypeTags.BOT || types.isSameType(that.seqExpr.type, syms.visage_EmptySequenceType)) { typeToCheck = types.sequenceType(that.var.type); } else if (that.isBound() && types.isArray(that.seqExpr.type)) { // Bound-for is implemented only over sequences, convert the nativearray to a sequence typeToCheck = types.sequenceType(types.elemtype(that.seqExpr.type)); } else if (!types.isSequence(that.seqExpr.type) && !types.isArray(that.seqExpr.type) && types.asSuper(that.seqExpr.type, syms.iterableType.tsym) == null) { typeToCheck = types.sequenceType(that.seqExpr.type); } VisageExpression seqExpr = lowerExpr(that.seqExpr, typeToCheck); VisageForExpressionInClause res = m.at(that.pos).InClause(that.getVar(), seqExpr, whereExpr); res.setIndexUsed(that.getIndexUsed()); res.indexVarSym = that.indexVarSym; forClauseMap.put(that, res); result = res.setType(that.type); } public void visitFunctionDefinition(VisageFunctionDefinition tree) { VisageTree prevFunc = enclFunc; try { enclFunc = tree; VisageBlock body = (VisageBlock)lowerExpr(tree.getBodyExpression(), tree.type != null ? tree.type.getReturnType() : Type.noType); VisageFunctionDefinition res = m.at(tree.pos).FunctionDefinition(tree.mods, tree.name, tree.getVisageReturnType(), tree.getParams(), body); res.operation.definition = res; res.sym = tree.sym; result = res.setType(tree.type); } finally { enclFunc = prevFunc; } } public void visitFunctionInvocation(VisageFunctionInvocation tree) { VisageExpression meth = lowerFunctionName(tree.meth); List<Type> paramTypes = tree.meth.type.getParameterTypes(); Symbol sym = VisageTreeInfo.symbolFor(tree.meth); List<VisageExpression> args = List.nil(); boolean pointer_Make = types.isSyntheticPointerFunction(sym); boolean builtins_Func = types.isSyntheticBuiltinsFunction(sym); if (pointer_Make || builtins_Func) { VisageExpression varExpr = lowerExpr(tree.args.head); ListBuffer<VisageExpression> syntheticArgs = ListBuffer.lb(); syntheticArgs.append(m.at(tree.pos).VarRef(varExpr, VisageVarRef.RefKind.INST).setType(syms.visage_ObjectType)); if (varExpr.getVisageTag() == VisageTag.IDENT && ((VisageIdent)varExpr).getName().equals(names._this)) { syntheticArgs.append(m.at(tree.pos).LiteralInteger("-1", 10).setType(syms.intType)); } else { syntheticArgs.append(m.at(tree.pos).VarRef(varExpr, VisageVarRef.RefKind.VARNUM).setType(syms.intType)); } Symbol msym = builtins_Func ? preTrans.makeSyntheticBuiltinsMethod(sym.name) : preTrans.makeSyntheticPointerMake(); VisageTreeInfo.setSymbol(meth, msym); meth.type = msym.type; args = syntheticArgs.toList(); } else if (sym instanceof MethodSymbol && ((MethodSymbol)sym).isVarArgs()) { List<VisageExpression> actuals = tree.args; while (paramTypes.tail.nonEmpty()) { args = args.append(lowerExpr(actuals.head, paramTypes.head)); actuals = actuals.tail; paramTypes = paramTypes.tail; } Type varargType = paramTypes.head; if (actuals.size() == 1 && (types.isSequence(actuals.head.type) || types.isArray(actuals.head.type))) { args = args.append(lowerExpr(actuals.head, varargType)); } else if (actuals.size() > 0) { while (actuals.nonEmpty()) { args = args.append(lowerExpr(actuals.head, types.elemtype(varargType))); actuals = actuals.tail; } } } else { args = lowerExprs(tree.args, paramTypes); } result = m.Apply(tree.typeargs, meth, args); result.type = tree.type; } //where private VisageExpression lowerFunctionName(VisageExpression meth) { Symbol msym = VisageTreeInfo.symbolFor(meth); if (meth.getVisageTag() == VisageTag.IDENT) { return m.at(meth.pos()).Ident(msym).setType(meth.type); } else if (meth.getVisageTag() == VisageTag.SELECT) { return lowerSelect((VisageSelect)meth); } else { return lowerExpr(meth); } } public void visitFunctionValue(VisageFunctionValue tree) { VisageTree prevFunc = enclFunc; try { enclFunc = tree; tree.bodyExpression = (VisageBlock)lowerExpr(tree.bodyExpression, tree.type.getReturnType()); result = tree; } finally { enclFunc = prevFunc; } } public void visitIfExpression(VisageIfExpression tree) { if (tree.type.tag != TypeTags.VOID && (tree.truepart.type == syms.unreachableType || (tree.falsepart != null && tree.falsepart.type == syms.unreachableType))) { result = lowerUnreachableIfExpression(tree); } else { boolean thenPartSeq = types.isSequence(tree.truepart.type); boolean elsePartSeq = tree.falsepart != null ? types.isSequence(tree.falsepart.type) : thenPartSeq; boolean nonSeqExpected = thenPartSeq != elsePartSeq && !types.isSequence(pt); VisageExpression cond = lowerExpr(tree.cond, syms.booleanType); VisageExpression truePart = lowerExpr(tree.truepart, !nonSeqExpected || thenPartSeq ? tree.type : types.elementTypeOrType(tree.type)); VisageExpression falsePart = lowerExpr(tree.falsepart, !nonSeqExpected || elsePartSeq ? tree.type : types.elementTypeOrType(tree.type)); result = m.at(tree.pos).Conditional(cond, truePart, falsePart); result.setType(nonSeqExpected ? syms.objectType : tree.type); } } public VisageTree lowerUnreachableIfExpression(VisageIfExpression tree) { boolean inverted = tree.truepart.type == syms.unreachableType; Type treeType = tree.type.tag == TypeTags.BOT ? types.isSequence(tree.type) ? types.sequenceType(syms.objectType) : syms.objectType : tree.type; VisageExpression truePart = lowerExpr(tree.truepart, treeType); VisageExpression falsePart = lowerExpr(tree.falsepart, treeType); VisageVar varDef = makeVar(tree.pos(), defs.resNamePrefix(), null, treeType); VisageIdent varRef = m.at(tree.pos).Ident(varDef.sym); varRef.sym = varDef.sym; varRef.type = varDef.type; VisageExpression assign = m.at(tree.pos).Assign(varRef, inverted ? falsePart : truePart).setType(syms.voidType); //we need void here! VisageExpression ifExpr = m.at(tree.pos).Conditional(tree.cond, inverted ? truePart : assign, inverted ? assign : falsePart).setType(syms.voidType); //we need void here! return m.at(tree.pos()).Block(0L, List.of(varDef, ifExpr), varRef).setType(varRef.type); } public void visitIndexof(VisageIndexof that) { VisageIndexof res = m.at(that.pos).Indexof(that.fname); res.clause = that.clause; result = res.setType(that.type); } public void visitInstanceOf(VisageInstanceOf tree) { VisageExpression expr = lowerExpr(tree.getExpression()); result = m.at(tree.pos).TypeTest(expr, tree.clazz).setType(tree.type); } public void visitInterpolateValue(VisageInterpolateValue that) { VisageExpression pointerType = m.at(that.pos).Type(syms.visage_PointerType).setType(syms.visage_PointerType); Symbol pointerMakeSym = rs.resolveQualifiedMethod(that.pos(), env, syms.visage_PointerType, defs.Pointer_make.methodName, rs.newMethTemplate(List.of(syms.objectType), List.<Type>nil())); pointerMakeSym.flags_field |= VisageFlags.FUNC_POINTER_MAKE; VisageSelect pointerMake = (VisageSelect)m.at(that.pos).Select(pointerType, pointerMakeSym, false); pointerMake.sym = pointerMakeSym; VisageExpression pointerCall = m.at(that.pos).Apply(List.<VisageExpression>nil(), pointerMake, List.of(that.attribute)).setType(pointerMakeSym.type.getReturnType()); ListBuffer<VisageTree> parts = ListBuffer.lb(); parts.append(makeObjectLiteralPart(that.pos(), syms.visage_KeyValueType, defs.value_InterpolateMethodName, that.funcValue)); parts.append(makeObjectLiteralPart(that.pos(), syms.visage_KeyValueType, defs.target_InterpolateMethodName, pointerCall)); if (that.interpolation != null) { parts.append(makeObjectLiteralPart(that.pos(), syms.visage_KeyValueType, defs.interpolate_InterpolateMethodName, that.interpolation)); } VisageExpression res = m.at(that.pos).ObjectLiteral(m.at(that.pos).Type(syms.visage_KeyValueType), parts.toList()).setType(syms.visage_KeyValueType); result = lowerExpr(res); } //where private VisageObjectLiteralPart makeObjectLiteralPart(DiagnosticPosition pos, Type site, Name varName, VisageExpression value) { VisageObjectLiteralPart part = m.at(pos).ObjectLiteralPart(varName, value, VisageBindStatus.UNBOUND); part.setType(value.type); part.sym = rs.findIdentInType(env, site, varName, Kinds.VAR); return part; } public void visitKeyFrameLiteral(VisageKeyFrameLiteral that) { ListBuffer<VisageTree> parts = ListBuffer.lb(); VisageExpression keyValues = m.at(that.pos).ExplicitSequence(that.values).setType(types.sequenceType(syms.visage_KeyValueType)); parts.append(makeObjectLiteralPart(that.pos(), syms.visage_KeyFrameType, defs.time_KeyFrameMethodName, that.start)); parts.append(makeObjectLiteralPart(that.pos(), syms.visage_KeyFrameType, defs.values_KeyFrameMethodName, keyValues)); VisageExpression res = m.at(that.pos).ObjectLiteral(m.at(that.pos).Type(syms.visage_KeyValueType), parts.toList()).setType(syms.visage_KeyFrameType); result = lowerExpr(res); } public void visitLiteral(VisageLiteral tree) { result = tree; } public void visitObjectLiteralPart(VisageObjectLiteralPart tree) { VisageExpression expr = lowerExpr(tree.getExpression(), tree.sym.type); VisageObjectLiteralPart res = m.at(tree.pos).ObjectLiteralPart(tree.name, expr, tree.getExplicitBindStatus()); res.markBound(tree.getBindStatus()); res.sym = tree.sym; result = res.setType(tree.type); } public void visitOverrideClassVar(VisageOverrideClassVar tree) { VisageExpression init = lowerExpr(tree.getInitializer(), tree.getId().sym.type); VisageOnReplace onReplace = lowerDecl(tree.getOnReplace()); VisageOnReplace onInvalidate = lowerDecl(tree.getOnInvalidate()); VisageOverrideClassVar res = m.at(tree.pos).OverrideClassVar(tree.name, tree.getVisageType(), tree.mods, tree.getId(), init, tree.getBindStatus(), onReplace, onInvalidate); res.sym = tree.sym; result = res.setType(tree.type); } public void visitReturn(VisageReturn tree) { Type typeToCheck = enclFunc.type != null ? enclFunc.type.getReturnType() : syms.objectType; //nedded because run function has null type VisageExpression retExpr = lowerExpr(tree.getExpression(), typeToCheck); result = m.at(tree.pos).Return(retExpr).setType(tree.type); } public void visitSequenceDelete(VisageSequenceDelete that) { VisageExpression seq = lowerExpr(that.getSequence()); VisageExpression el = that.getElement(); if (that.getElement() != null) { Type typeToCheck = types.isArrayOrSequenceType(that.getElement().type) ? that.getSequence().type : types.elementType(that.getSequence().type); el = lowerExpr(that.getElement(), typeToCheck); } result = m.at(that.pos).SequenceDelete(seq, el).setType(that.type); } public void visitSequenceEmpty(VisageSequenceEmpty that) { result = that; } public void visitSequenceExplicit(VisageSequenceExplicit that) { ListBuffer<VisageExpression> buf = ListBuffer.lb(); for (VisageExpression item : that.getItems()) { Type typeToCheck = types.isSameType(item.type, syms.objectType) || types.isArrayOrSequenceType(item.type) ? that.type : types.elementType(that.type); flatten(lowerExpr(item, typeToCheck), buf); } result = buf.length() == 1 && types.isSequence(buf.toList().head.type) ? buf.toList().head : m.at(that.pos).ExplicitSequence(buf.toList()).setType(that.type); } //where private void flatten(VisageExpression item, ListBuffer<VisageExpression> items) { if (item.getVisageTag() == VisageTag.SEQUENCE_EXPLICIT) { VisageSequenceExplicit nestedSeq = (VisageSequenceExplicit)item; for (VisageExpression nestedItem : nestedSeq.getItems()) { flatten(nestedItem, items); } } else { items.append(item); } } public void visitSequenceIndexed(VisageSequenceIndexed that) { VisageExpression index = lowerExpr(that.getIndex(), syms.intType); VisageExpression seq = lowerExpr(that.getSequence()); result = m.at(that.pos).SequenceIndexed(seq, index).setType(that.type); } public void visitSequenceInsert(VisageSequenceInsert that) { VisageExpression seq = lowerExpr(that.getSequence()); Type typeToCheck = types.isArrayOrSequenceType(that.getElement().type) || types.isSameType(syms.objectType, that.getElement().type) ? that.getSequence().type : types.elementType(that.getSequence().type); VisageExpression el = lowerExpr(that.getElement(), typeToCheck); VisageExpression pos = lowerExpr(that.getPosition(), syms.intType); result = m.at(that.pos).SequenceInsert(seq, el, pos, that.shouldInsertAfter()).setType(that.type); } public void visitSequenceRange(VisageSequenceRange that) { VisageExpression lower = lowerExpr(that.getLower(), types.elementType(that.type)); VisageExpression upper = lowerExpr(that.getUpper(), types.elementType(that.type)); VisageExpression step = lowerExpr(that.getStepOrNull(), types.elementType(that.type)); VisageSequenceRange res = m.at(that.pos).RangeSequence(lower, upper, step, that.isExclusive()); result = res.setType(that.type); } public void visitSequenceSlice(VisageSequenceSlice that) { VisageExpression seq = lowerExpr(that.getSequence()); VisageExpression start = lowerExpr(that.getFirstIndex(), syms.intType); VisageExpression end = lowerExpr(that.getLastIndex(), syms.intType); result = m.at(that.pos).SequenceSlice(seq, start, end, that.getEndKind()).setType(that.type); } public void visitStringExpression(VisageStringExpression tree) { List<VisageExpression> parts = lowerExprs(tree.parts); result = m.at(tree.pos).StringExpression(parts, tree.translationKey).setType(tree.type); } public void visitUnary(VisageUnary tree) { if (tree.getVisageTag().isIncDec()) { result = lowerNumericUnary(tree); } else { VisageExpression arg = tree.getVisageTag() == VisageTag.REVERSE ? lowerExpr(tree.getExpression(), tree.type) : tree.getOperator() != null ? lowerExpr(tree.getExpression(), tree.getOperator().type.getParameterTypes().head) : lowerExpr(tree.getExpression()); VisageUnary res = m.at(tree.pos).Unary(tree.getVisageTag(), arg); res.operator = tree.operator; res.type = tree.type; result = res; } } private VisageExpression lowerNumericUnary(VisageUnary tree) { boolean postFix = isPostfix(tree.getVisageTag()); VisageTag opTag = unaryToBinaryOpTag(tree.getVisageTag()); Type opType = types.unboxedTypeOrType(tree.getExpression().type); if (types.isSameType(opType, syms.charType)) { opType = syms.intType; } ListBuffer<VisageExpression> stats = ListBuffer.lb(); //if the unary operand is an indexed expression of the kind a.x[i] //then we need to cache the index value (not to recumpute it twice). VisageExpression expr = tree.getExpression(); VisageIdent index = null; if (tree.getExpression().getVisageTag() == VisageTag.SEQUENCE_INDEXED) { VisageSequenceIndexed indexed = (VisageSequenceIndexed)tree.getExpression(); VisageVar varDef = makeVar(tree.pos(), defs.indexNamePrefix(), indexed.getIndex(), indexed.getIndex().type); index = m.at(tree.pos).Ident(varDef.sym); index.sym = varDef.sym; index.type = varDef.type; stats.append(varDef); expr = indexed.getSequence(); } //if the unary operand is a select of the kind a.x //then we need to cache the selected part (a), so that //it won't be recomputed twice. // // var $expr$ = a; VisageIdent selector = null; if (expr.getVisageTag() == VisageTag.SELECT) { VisageExpression selected = ((VisageSelect)expr).selected; Symbol sym = VisageTreeInfo.symbolFor(selected); // But, if this select is ClassName.foo, then we don't want // to create "var $expr = a;" if (sym == null || sym.kind != Kinds.TYP) { VisageVar varDef = makeVar(tree.pos(), defs.exprNamePrefix(), selected, selected.type); selector = m.at(tree.pos).Ident(varDef.sym); selector.sym = varDef.sym; selector.type = varDef.type; stats.append(varDef); } } VisageExpression varRef = expr; if (selector != null) { VisageVarSymbol vsym = (VisageVarSymbol)VisageTreeInfo.symbol(expr); varRef = m.at(tree.pos).Select(selector, vsym, false); ((VisageSelect)varRef).sym = vsym; } if (index != null) { varRef = m.at(tree.pos).SequenceIndexed(varRef, index).setType(tree.getExpression().type); } //cache the old value of the unary operand. The translated expression //depends on whether the operand is a select or not: // //(SELECT) var $oldVal$ = $expr$.x; //(IDENT) var $oldVal$ = x; VisageExpression oldVal = varRef; boolean needOldValue = postFix && ( pt != Type.noType || mode == LowerMode.EXPRESSION); if (needOldValue) { VisageVar oldValDef = makeVar(tree.pos(), defs.oldValueNamePrefix(), varRef, varRef.type); stats.append(oldValDef); oldVal = m.at(tree.pos).Ident(oldValDef.sym); ((VisageIdent)oldVal).sym = oldValDef.sym; } //Generate the binary expression this unary translates to // //(SELECT) $expr$.x = $oldVal [+/-] 1; //(IDENT) x = $oldVal [+/-] 1; VisageBinary binary = (VisageBinary)m.at(tree.pos).Binary(opTag, oldVal, m.at(tree.pos).Literal(opType.tag, 1).setType(opType)); binary.operator = rs.resolveBinaryOperator(tree.pos(), opTag, env, opType, opType); binary.setType(binary.operator.type.asMethodType().getReturnType()); VisageExpression incDecStat = (VisageExpression)m.at(tree.pos).Assign(varRef, binary).setType(opType); //If this is a postfix unary expression, the old value is returned VisageExpression blockValue = incDecStat; if (needOldValue) { stats.append(incDecStat); blockValue = oldVal; } VisageExpression res = stats.nonEmpty() ? m.at(tree.pos).Block(0L, stats.toList(), blockValue).setType(opType) : blockValue; return lowerExpr(res, Type.noType); } //where private VisageTag unaryToBinaryOpTag(VisageTag tag) { switch (tag) { case POSTINC: case PREINC: return VisageTag.PLUS; case POSTDEC: case PREDEC: return VisageTag.MINUS; default: throw new AssertionError("Unexpecetd unary operator tag: " + tag); } } //where private boolean isPostfix(VisageTag tag) { switch (tag) { case POSTINC: case POSTDEC: return true; case PREINC: case PREDEC: return false; default: throw new AssertionError("Unexpected unary operator tag: " + tag); } } public void visitVar(VisageVar tree) { VisageExpression init = lowerExpr(tree.getInitializer(), tree.type); VisageOnReplace onReplace = lowerDecl(tree.getOnReplace()); VisageOnReplace onInvalidate = lowerDecl(tree.getOnInvalidate()); VisageVar res = m.at(tree.pos).Var(tree.name, tree.getVisageType(), tree.mods, init, tree.getBindStatus(), onReplace, onInvalidate); res.sym = tree.sym; result = res.setType(tree.type); VisageVarInit vsi = tree.getVarInit(); if (vsi != null) { // update the var in the var-init vsi.resetVar(res); } } public void visitVarInit(VisageVarInit tree) { result = tree; } public void visitVarRef(VisageVarRef tree) { result = tree; } public void visitBlockExpression(VisageBlock tree) { List<VisageExpression> stats = tree.stats; VisageExpression value = tree.value; if (value != null) { if (VisageTreeInfo.skipParens(value).getVisageTag() == VisageTag.VAR_DEF) { VisageVar varDef = (VisageVar)VisageTreeInfo.skipParens(value); VisageIdent varRef = m.at(tree.value.pos).Ident(varDef.sym); varRef.sym = varDef.sym; varRef.type = varDef.type; value = varRef; stats = stats.append(varDef); } else if (value.type == syms.voidType && !tree.isVoidValueAllowed) { stats = stats.append(value); value = makeDefaultValue(tree.type); } } List<VisageExpression> loweredStats = lowerBlockStatements(stats); VisageExpression loweredValue = value != null ? lowerExpr(value, pt) : null; if (value != null && pt == syms.voidType) { List<VisageExpression> mergedLoweredValue = mergeLoweredBlockStatements( new ListBuffer<VisageExpression>(), loweredValue, value).toList(); while (mergedLoweredValue.tail.nonEmpty()) { loweredStats = loweredStats.append(mergedLoweredValue.head); mergedLoweredValue = mergedLoweredValue.tail; } loweredValue = mergedLoweredValue.head; } VisageBlock res = m.at(tree.pos).Block(tree.flags, loweredStats, loweredValue); res.endpos = tree.endpos; result = res; result.type = value != null ? loweredValue != null ? loweredValue.type : syms.voidType : tree.type; } private List<VisageExpression> lowerBlockStatements(List<VisageExpression> stats) { ListBuffer<VisageExpression> loweredStats = ListBuffer.lb(); for (VisageExpression stat : stats) { mergeLoweredBlockStatements(loweredStats, lowerStmt(stat), stat); } return loweredStats.toList(); } private ListBuffer<VisageExpression> mergeLoweredBlockStatements(ListBuffer<VisageExpression> loweredStats, VisageExpression loweredStat, VisageExpression stat) { loweredStats.append(loweredStat); return loweredStats; } //where private VisageExpression makeDefaultValue(Type t) { switch (t.tag) { case TypeTags.BYTE: return m.Literal(TypeTags.BYTE, 0).setType(syms.byteType); case TypeTags.SHORT: return m.Literal(TypeTags.SHORT, 0).setType(syms.shortType); case TypeTags.INT: return m.Literal(TypeTags.INT, 0).setType(syms.intType); case TypeTags.FLOAT: return m.Literal(TypeTags.FLOAT, 0).setType(syms.floatType); case TypeTags.DOUBLE: return m.Literal(TypeTags.DOUBLE, 0).setType(syms.doubleType); case TypeTags.BOOLEAN: return m.Literal(TypeTags.BOOLEAN, 0).setType(syms.booleanType); case TypeTags.CLASS: { if (types.isSequence(t)) { return m.EmptySequence().setType(syms.visage_EmptySequenceType); } else if (types.isSameType(t, syms.visage_StringType)) { return m.Literal("").setType(syms.visage_StringType); } else if (types.isSameType(t, syms.visage_DurationType)) { Name zeroName = names.fromString("ZERO"); VisageSelect res = (VisageSelect)m.Select( preTrans.makeTypeTree(syms.visage_DurationType), zeroName, false).setType(syms.visage_DurationType); res.sym = rs.findIdentInType(env, syms.visage_DurationType, zeroName, Kinds.VAR); return res; } else if (types.isSameType(t, syms.visage_LengthType)) { Name zeroName = names.fromString("ZERO"); VisageSelect res = (VisageSelect)m.Select( preTrans.makeTypeTree(syms.visage_LengthType), zeroName, false).setType(syms.visage_LengthType); res.sym = rs.findIdentInType(env, syms.visage_LengthType, zeroName, Kinds.VAR); return res; } else if (types.isSameType(t, syms.visage_AngleType)) { Name zeroName = names.fromString("ZERO"); VisageSelect res = (VisageSelect)m.Select( preTrans.makeTypeTree(syms.visage_AngleType), zeroName, false).setType(syms.visage_AngleType); res.sym = rs.findIdentInType(env, syms.visage_AngleType, zeroName, Kinds.VAR); return res; } else if (types.isSameType(t, syms.visage_ColorType)) { Name blackName = names.fromString("BLACK"); VisageSelect res = (VisageSelect)m.Select( preTrans.makeTypeTree(syms.visage_ColorType), blackName, false).setType(syms.visage_ColorType); res.sym = rs.findIdentInType(env, syms.visage_ColorType, blackName, Kinds.VAR); return res; } } default: return m.Literal(TypeTags.BOT, null).setType(syms.botType); } } public void visitBreak(VisageBreak tree) { result = tree; } public void visitCatch(VisageCatch tree) { VisageBlock body = lowerExpr(tree.body); result = m.at(tree.pos).Catch(tree.param, body).setType(tree.type); } public void visitClassDeclaration(VisageClassDeclaration tree) { Symbol prevClass = currentClass; try { currentClass = tree.sym; List<VisageTree> cdefs = lowerDecls(tree.getMembers()); tree.setMembers(cdefs); result = tree; } finally { currentClass = prevClass; } } public void visitContinue(VisageContinue tree) { result = tree; } public void visitErroneous(VisageErroneous tree) { result = tree; } public void visitForExpression(VisageForExpression tree) { result = lowerForExpression(tree); patchForLoop(result, tree.getForExpressionInClauses()); for (VisageForExpressionInClause clause : tree.getForExpressionInClauses()) { forClauseMap.remove(clause); } } public VisageExpression lowerForExpression(VisageForExpression tree) { VisageForExpressionInClause clause = lowerDecl(tree.getForExpressionInClauses().head); VisageExpression body = tree.getBodyExpression(); if (tree.getForExpressionInClauses().size() > 1) { // for (INCLAUSE(1), INCLAUSE(2), ... INCLAUSE(n)) BODY // (n>1) is lowered to: // for (INCLAUSE(1) Lower(for (INCLAUSE(2) (... for (INCLAUSE(n)) ... )) BODY VisageForExpression nestedFor = (VisageForExpression)m.ForExpression(tree.getForExpressionInClauses().tail, tree.bodyExpr).setType(tree.type); body = lowerForExpression(nestedFor); } else { //single clause for expression - standard lowering Type typeToCheck = types.isSameType(tree.getBodyExpression().type, syms.objectType) || types.isSequence(tree.getBodyExpression().type) ? tree.type : types.elementType(tree.type); body = lowerExpr(tree.bodyExpr, typeToCheck); } // Standard form is that the body is a block-expression if(!(body instanceof VisageBlock)) { body = m.Block(0L, List.<VisageExpression>nil(), body).setType(body.type); } VisageForExpression res = m.at(tree.pos).ForExpression(List.of(clause), body); return (VisageForExpression)res.setType(tree.type); } private void patchForLoop(VisageTree forExpr, final List<VisageForExpressionInClause> clausesToPatch) { class ForLoopPatcher extends VisageTreeScanner { Name targetLabel; boolean inWhile = false; private Name newLabelName() { return names.fromString(VisageDefs.synthForLabelPrefix + forClauseMap.size() + "$" + synthNameCount++); } @Override public void visitWhileLoop(VisageWhileLoop tree) { boolean prevInWhile = inWhile; try { inWhile = true; super.visitWhileLoop(tree); } finally { inWhile = prevInWhile; } } @Override public void visitBreak(VisageBreak tree) { tree.label = (tree.label == null && !inWhile) ? targetLabel : tree.label; } @Override public void visitContinue(VisageContinue tree) { tree.label = (tree.label == null && !inWhile) ? targetLabel : tree.label; } @Override public void visitIndexof(VisageIndexof tree) { tree.clause = clausesToPatch.contains(tree.clause) ? forClauseMap.get(tree.clause) : tree.clause; } @Override public void visitForExpressionInClause(VisageForExpressionInClause tree) { tree.label = tree.label == null ? newLabelName() : tree.label; if (targetLabel == null) { targetLabel = tree.label; } super.visitForExpressionInClause(tree); } } new ForLoopPatcher().scan(forExpr); } public void visitIdent(VisageIdent tree) { if (tree.sym.kind == Kinds.MTH) { result = toFunctionValue(tree, false); } else { result = tree; } } VisageExpression toFunctionValue(VisageExpression tree, boolean isSelect) { boolean needsReceiverVar = isSelect; if (isSelect) { VisageSelect qualId = (VisageSelect)tree; Symbol selectedSym = VisageTreeInfo.symbolFor(qualId.selected); if (selectedSym != null && selectedSym.kind == Kinds.TYP) { needsReceiverVar = false; } } MethodSymbol msym = (MethodSymbol)VisageTreeInfo.symbolFor(tree); Type mtype = msym.type; ListBuffer<VisageVar> params = ListBuffer.lb(); ListBuffer<VisageExpression> args = ListBuffer.lb(); MethodSymbol lambdaSym = new MethodSymbol(Flags.SYNTHETIC, defs.lambda_MethodName, mtype, currentClass); int count = 0; for (Type t : mtype.getParameterTypes()) { Name paramName = tempName("x"+count); VisageVarSymbol paramSym = new VisageVarSymbol(types, names, Flags.PARAMETER, paramName, t, lambdaSym); VisageVar param = m.at(tree.pos).Param(paramName, preTrans.makeTypeTree(t)); param.sym = paramSym; param.type = t; params.append(param); VisageIdent arg = m.at(tree.pos).Ident(param); arg.type = param.type; arg.sym = param.sym; args.append(arg); count++; } Type returnType = mtype.getReturnType(); VisageVar receiverVar = null; VisageExpression meth = tree.setType(mtype); if (needsReceiverVar) { VisageSelect qualId= (VisageSelect)tree; receiverVar = makeVar(tree.pos(), "rec", qualId.selected, qualId.selected.type); VisageIdent receiverVarRef = (VisageIdent)m.at(tree.pos).Ident(receiverVar.sym).setType(receiverVar.type); meth = m.at(tree.pos).Select(receiverVarRef, msym, false).setType(mtype); } VisageExpression call = m.at(tree.pos).Apply(List.<VisageExpression>nil(), meth, args.toList()).setType(returnType); VisageBlock body = (VisageBlock)m.at(tree.pos).Block(0, List.<VisageExpression>nil(), call).setType(returnType); VisageFunctionValue funcValue = m.at(tree.pos).FunctionValue(preTrans.makeTypeTree(returnType), params.toList(), body); funcValue.type = syms.makeFunctionType((Type.MethodType)mtype); funcValue.definition = new VisageFunctionDefinition( m.at(tree.pos).Modifiers(lambdaSym.flags_field), lambdaSym.name, funcValue); funcValue.definition.pos = tree.pos; funcValue.definition.sym = lambdaSym; funcValue.definition.type = lambdaSym.type; if (needsReceiverVar) { VisageBinary eqNull = (VisageBinary)m.at(tree.pos).Binary( VisageTag.EQ, m.at(tree.pos).Ident(receiverVar.sym).setType(receiverVar.type), m.at(tree.pos).Literal(TypeTags.BOT, null).setType(syms.botType)); eqNull.operator = rs.resolveBinaryOperator(tree.pos(), VisageTag.EQ, env, syms.objectType, syms.objectType); eqNull.setType(syms.booleanType); VisageExpression blockValue = m.at(tree.pos()).Conditional( eqNull, m.at(tree.pos).Literal(TypeTags.BOT, null).setType(syms.botType), funcValue).setType(funcValue.type); return m.at(tree.pos).Block(0, List.<VisageExpression>of(receiverVar), blockValue).setType(funcValue.type); } else { return funcValue; } } public void visitImport(VisageImport tree) { result = tree; } public void visitInitDefinition(VisageInitDefinition tree) { VisageBlock body = lowerExpr(tree.body); VisageInitDefinition res = m.at(tree.pos).InitDefinition(body); res.sym = tree.sym; result = res.setType(tree.type); } /* * Determine if the expression uses any names that could clash with names in the class */ private boolean hasNameConflicts(final TypeSymbol csym, final VisageExpression expr) { class NameClashScanner extends VisageTreeScanner { boolean clashFound = false; //TODO: utterly naive -- add visibility testing void checkForClash(Name name) { Scope.Entry e = csym.members().lookup(name); if (e.scope != null) { clashFound = true; } } @Override public void visitIdent(VisageIdent tree) { checkForClash(tree.getName()); } } NameClashScanner ncs = new NameClashScanner(); ncs.scan(expr); boolean clashFound = ncs.clashFound; // if (clashFound) System.err.println("Name clash found: " + csym + ", expr: " + expr); return clashFound; } public void visitInstanciate(VisageInstanciate tree) { ListBuffer<VisageExpression> locals = ListBuffer.lb(); if (tree.getLocalvars().nonEmpty()) { //ObjLit { // local var 1; // local var 2; // ... // local var n; //} // //is equivalent to: // //{ // // local var 1; // local var 2; // ... // local var n; // // ObjLit { // ... // } //} for (VisageVar var : tree.getLocalvars()) { locals.append(lowerDecl(var)); } } ListBuffer<VisageTree> newOverrides = ListBuffer.<VisageTree>lb(); ListBuffer<VisageObjectLiteralPart> unboundParts = ListBuffer.<VisageObjectLiteralPart>lb(); // Determine if there is a mutable non-explicitly bound initializer in a bound object literal, // since this could cause the instance to be re-created so binds then need to be external so // that they can be re-used (thus, won't, for example, create new objects) boolean holdBindsOutsideSubclass = false; if (tree.isBound()) { for (VisageObjectLiteralPart part : tree.getParts()) { if (!part.isExplicitlyBound() && !preTrans.isImmutable(part.getExpression())) { // A bound object literal with non-explicitly bound initializer // requires continuity of binds holdBindsOutsideSubclass = true; break; } } } for (VisageObjectLiteralPart part : tree.getParts()) { if (part.isExplicitlyBound()) { m.at(part.pos()); // create at part position // id for the override VisageIdent id = m.Ident(part.name); id.sym = part.sym; id.type = part.sym.type; VisageExpression partExpr = part.getExpression(); VisageExpression initExpr; // Determine if bound object literal initializer should be scoped to object literal level. if ((holdBindsOutsideSubclass && preTrans.hasSideEffectsInBind(partExpr)) || hasNameConflicts(tree.type.tsym, partExpr)) { // Shread the expression outside the class, so that the context is correct // The variable should be marked as script private as it shouldn't // be accessible from outside. VisageVar shred = makeVar( part.pos(), Flags.SYNTHETIC | VisageFlags.SCRIPT_PRIVATE, part.name + "$ol", part.getBindStatus(), lowerExpr(partExpr, part.sym.type), part.sym.type); VisageIdent sid = m.Ident(shred.name); sid.sym = shred.sym; sid.type = part.sym.type; locals.append(shred); initExpr = sid; } else { initExpr = partExpr; // lowered with class } // Turn the part into an override var VisageOverrideClassVar ocv = m.OverrideClassVar( part.name, preTrans.makeTypeTree(part.type), m.Modifiers(part.sym.flags_field), id, initExpr, part.getBindStatus(), null, null); ocv.sym = (VisageVarSymbol) part.sym; ocv.type = part.sym.type; newOverrides.append(ocv); } else { unboundParts.append(lowerExpr(part)); } } // Lower the class. If there are new overrides, fold them into the class first VisageClassDeclaration cdecl = tree.getClassBody(); VisageClassDeclaration lowCdecl; if (newOverrides.nonEmpty()) { cdecl.setMembers(cdecl.getMembers().appendList(newOverrides)); lowCdecl = lowerDecl(cdecl); preTrans.liftTypes(cdecl, cdecl.type, preTrans.makeDummyMethodSymbol(cdecl.sym)); } else { lowCdecl = lowerDecl(cdecl); } // Construct the new instanciate VisageInstanciate res = m.at(tree.pos).Instanciate(tree.getVisageKind(), tree.getIdentifier(), lowCdecl, lowerExprs(tree.getArgs()), unboundParts.toList(), List.<VisageVar>nil()); res.sym = tree.sym; res.constructor = tree.constructor; res.varDefinedByThis = tree.varDefinedByThis; res.type = tree.type; // If there are locals wrap the whole thing in a block-expression if (locals.nonEmpty()) { result = m.Block(0L, locals.toList(), res).setType(tree.type); } else { result = res; } } public void visitInvalidate(VisageInvalidate tree) { VisageExpression expr = lowerExpr(tree.getVariable()); result = m.at(tree.pos).Invalidate(expr).setType(tree.type); } public void visitModifiers(VisageModifiers tree) { result = tree; } public void visitOnReplace(VisageOnReplace tree) { VisageBlock body = lowerExpr(tree.getBody()); VisageOnReplace res = tree.getTriggerKind() == VisageOnReplace.Kind.ONREPLACE ? m.at(tree.pos).OnReplace(tree.getOldValue(), tree.getFirstIndex(), tree.getLastIndex(), tree.getNewElements(), body) : m.at(tree.pos).OnInvalidate(body); result = res.setType(tree.type); } public void visitParens(VisageParens tree) { VisageExpression expr = lowerExpr(tree.expr); result = m.at(tree.pos).Parens(expr).setType(tree.type); } public void visitPostInitDefinition(VisagePostInitDefinition tree) { VisageBlock body = lowerExpr(tree.body); VisagePostInitDefinition res = m.at(tree.pos).PostInitDefinition(body); res.sym = tree.sym; result = res.setType(tree.type); } public void visitScript(VisageScript tree) { varCount = 0; tree.defs = lowerDecls(tree.defs); result = tree; } public void visitSelect(VisageSelect tree) { result = (tree.sym.kind == Kinds.MTH) ? toFunctionValue(tree, true) : lowerSelect(tree); } private VisageExpression lowerSelect(VisageSelect tree) { VisageExpression res = null; if (tree.sym.isStatic() && VisageTreeInfo.symbolFor(tree.selected) != null && VisageTreeInfo.symbolFor(tree.selected).kind == Kinds.TYP) { res = m.at(tree.pos()).Ident(tree.sym); } else { VisageExpression selected = lowerExpr(tree.selected); res = (VisageSelect)m.Select(selected, tree.sym, tree.nullCheck); } return res.setType(tree.type); } public void visitSkip(VisageSkip tree) { result = tree; } public void visitThrow(VisageThrow tree) { VisageExpression expr = lowerExpr(tree.getExpression()); result = m.at(tree.pos).Throw(expr).setType(tree.type); } public void visitTimeLiteral(VisageTimeLiteral tree) { result = tree; } public void visitLengthLiteral(VisageLengthLiteral tree) { result = tree; } public void visitAngleLiteral(VisageAngleLiteral tree) { result = tree; } public void visitColorLiteral(VisageColorLiteral tree) { result = tree; } public void visitTry(VisageTry tree) { VisageBlock body = lowerExpr(tree.getBlock()); List<VisageCatch> catches = lowerDecls(tree.catchers); VisageBlock finallyBlock = lowerExpr(tree.getFinallyBlock()); result = m.at(tree.pos).Try(body, catches, finallyBlock).setType(tree.type); } public void visitTypeAny(VisageTypeAny tree) { result = tree; } public void visitTypeArray(VisageTypeArray tree) { result = tree; } public void visitTypeCast(VisageTypeCast tree) { VisageExpression expr = lowerExpr(tree.getExpression(), tree.clazz.type); result = m.at(tree.pos).TypeCast(tree.clazz, expr).setType(tree.type); } public void visitTypeClass(VisageTypeClass tree) { result = tree; } public void visitTypeFunctional(VisageTypeFunctional tree) { result = tree; } public void visitTypeUnknown(VisageTypeUnknown tree) { result = tree; } public void visitWhileLoop(VisageWhileLoop tree) { VisageExpression cond = lowerExpr(tree.getCondition(), syms.booleanType); VisageExpression body = lowerExpr(tree.getBody()); // Standard form is that the body is a block-expression if(!(body instanceof VisageBlock)) { body = m.Block(0L, List.<VisageExpression>nil(), body); } body.setType(syms.voidType); result = m.at(tree.pos).WhileLoop(cond, body).setType(syms.voidType); } }