/* * 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.api.VisageBindStatus; import org.visage.tools.code.VisageFlags; import org.visage.tools.code.VisageSymtab; import org.visage.tools.code.VisageTypes; import org.visage.tools.code.VisageVarSymbol; import org.visage.tools.tree.*; import org.visage.tools.tree.VisageExpression; import com.sun.tools.mjavac.code.Flags; import com.sun.tools.mjavac.code.Symbol; import com.sun.tools.mjavac.code.Symbol.MethodSymbol; 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.ListBuffer; import com.sun.tools.mjavac.util.Name; /** * Fill in the synthetic definitions needed in a bound function * and bound object literal. * * @author A. Sundararajan * @author Robert Field */ public class VisageBoundFiller extends VisageTreeScanner { private final VisagePreTranslationSupport preTrans; private final VisageTreeMaker visagemake; private final VisageDefs defs; private final VisageSymtab syms; protected final VisageTypes types; private final Name.Table names; protected static final Context.Key<VisageBoundFiller> boundFuncFill = new Context.Key<VisageBoundFiller>(); public static VisageBoundFiller instance(Context context) { VisageBoundFiller instance = context.get(boundFuncFill); if (instance == null) { instance = new VisageBoundFiller(context); } return instance; } private VisageBoundFiller(Context context) { context.put(boundFuncFill, this); preTrans = VisagePreTranslationSupport.instance(context); visagemake = VisageTreeMaker.instance(context); defs = VisageDefs.instance(context); syms = (VisageSymtab)VisageSymtab.instance(context); types = VisageTypes.instance(context); names = Name.Table.instance(context); } public void fill(VisageEnv<VisageAttrContext> attrEnv) { scan(attrEnv.tree); } /** * Add variables needed when a bound for-expression body is converted into a class: * * var $indexof$x : Integer = $index$; * var x : T; * def result = bind block_value; */ @Override public void visitForExpression(VisageForExpression tree) { if (tree.isBound()) { VisageBlock body = (VisageBlock) tree.getBodyExpression(); assert tree.getInClauses().size() == 1 : "lower is supposed to flatten to exactly one in-clause"; VisageForExpressionInClause clause = tree.getForExpressionInClauses().get(0); MethodSymbol dummyOwner = preTrans.makeDummyMethodSymbol(clause.var.sym.owner); VisageVar idxv = createIndexVar(clause, dummyOwner); VisageVar iv = createInductionVar(clause, idxv.sym, dummyOwner); VisageVar rv = createResultVar(clause, body, dummyOwner, tree.type); body.stats = body.stats.prepend(iv).prepend(idxv).append(rv); body.value = preTrans.defaultValue(body.type); // just fill the spot scan(clause); scan(body); } else { super.visitForExpression(tree); } } /** * Create the '$indexof$x' variable */ private VisageVar createIndexVar(VisageForExpressionInClause clause, Symbol owner) { // Create the method parameter // $index$ Name indexParamName = names.fromString(defs.dollarIndexNamePrefix()); Name indexName = VisageTranslationSupport.indexVarName(clause.getVar().getName(), names); VisageVarSymbol indexParamSym = new VisageVarSymbol(types, names,Flags.FINAL | Flags.PARAMETER, indexParamName, syms.intType, owner); // Create the index var // var $indexof$x = $index$ VisageVar indexVar = preTrans.LocalVar(clause.pos(), syms.intType, indexName, visagemake.Ident(indexParamSym), owner); // Stash the created variable so it can be used when we visit a // VisageIndexof, where we convert that to a VisageIdent referencing the indexDecl. clause.indexVarSym = indexVar.sym; return indexVar; } /** * Create the induction var in the body * var x */ private VisageVar createInductionVar(VisageForExpressionInClause clause, VisageVarSymbol boundIndexVarSym, Symbol owner) { VisageVar param = clause.getVar(); VisageVar inductionVar = preTrans.LocalVar(param.pos(), param.type, param.name, null, owner); clause.inductionVarSym = inductionVar.sym = param.sym; return inductionVar; } /** * Create the bound result: * def result = bind block_value; */ private VisageVar createResultVar(VisageForExpressionInClause clause, VisageBlock body, Symbol owner, Type seqType) { VisageExpression value = body.value; Type valtype = value.type; if (clause.getWhereExpression() != null) { // There is a where-clause, convert to an if-expression VisageExpression nada; if (types.isSequence(valtype)) { nada = visagemake.EmptySequence(); } else { // For now, at least, if there is a where clause, we need to be // able to return null, so box the type nada = visagemake.Literal(TypeTags.BOT, null); valtype = types.boxedElementType(seqType); value = preTrans.makeCastIfNeeded(value, valtype); value.type = valtype; } nada.type = valtype; value = visagemake.Conditional(clause.getWhereExpression(), value, nada); value.type = valtype; clause.setWhereExpr(null); } body.type = valtype; VisageVar param = clause.getVar(); Name resName = resultVarName(param.name); VisageVar resultVar = preTrans.BoundLocalVar(clause.pos(), valtype, resName, value, owner); resultVar.sym.flags_field |= VisageFlags.VARUSE_BIND_ACCESS; clause.boundResultVarSym = resultVar.sym; return resultVar; } public Name resultVarName(Name name) { return names.fromString(defs.resultDollarNamePrefix() + name.toString()); } @Override public void visitIndexof(VisageIndexof tree) { // Convert super.visitIndexof(tree); } @Override public void visitFunctionDefinition(VisageFunctionDefinition tree) { if (tree.isBound()) { // Fill out the bound function support vars before // local inflation boundFunctionFiller(tree); } super.visitFunctionDefinition(tree); } private void boundFunctionFiller(VisageFunctionDefinition tree) { /* * For bound functions, make a synthetic bound variable with * initialization expression to be the return expression and return * the Pointer of the synthetic variable as the result. */ VisageBlock blk = tree.getBodyExpression(); if (blk != null) { VisageExpression returnExpr = (blk.value instanceof VisageReturn) ? ((VisageReturn) blk.value).getExpression() : blk.value; if (returnExpr != null) { visagemake.at(blk.value.pos); ListBuffer<VisageExpression> stmts = ListBuffer.lb(); /* * Generate a local variable for each parameter. We will later * transform each param as VisageObject+varNum pair during translation. * These locals will be converted into instance variables of the * local context class. */ for (VisageVar visageVar : tree.getParams()) { VisageVar localVar = visagemake.Var( visageVar.name, visageVar.getVisageType(), visagemake.Modifiers(visageVar.mods.flags & ~Flags.PARAMETER), preTrans.defaultValue(visageVar.type), VisageBindStatus.UNIDIBIND, null, null); localVar.type = visageVar.type; localVar.sym = visageVar.sym; stmts.append(localVar); } stmts.appendList(blk.stats); // is return expression a variable declaration? boolean returnExprIsVar = (returnExpr.getVisageTag() == VisageTag.VAR_DEF); if (returnExprIsVar) { stmts.append(returnExpr); } VisageVar returnVar = visagemake.Var( defs.boundFunctionResultName, visagemake.TypeUnknown(), visagemake.Modifiers(0), returnExprIsVar ? visagemake.Ident((VisageVar) returnExpr) : returnExpr, VisageBindStatus.UNIDIBIND, null, null); returnVar.type = tree.sym.type.getReturnType(); returnVar.sym = new VisageVarSymbol(types, names,0L, defs.boundFunctionResultName, returnVar.type, tree.sym); returnVar.sym.flags_field |= VisageFlags.VARUSE_BIND_ACCESS; returnVar.markBound(VisageBindStatus.UNIDIBIND); stmts.append(returnVar); // find the symbol of Pointer.make(Object) method. // The select expression Pointer.make VisageSelect select = visagemake.Select(visagemake.Type(syms.visage_PointerType), defs.make_PointerMethodName, false); select.sym = preTrans.makeSyntheticPointerMake(); select.type = select.sym.type; // args for Pointer.make(Object) VisageIdent ident = visagemake.Ident(returnVar); ident.type = returnVar.type; ident.sym = returnVar.sym; ListBuffer<VisageExpression> pointerMakeArgs = ListBuffer.lb(); pointerMakeArgs.append(visagemake.VarRef(ident, VisageVarRef.RefKind.INST).setType(syms.visage_ObjectType)); pointerMakeArgs.append(visagemake.VarRef(ident, VisageVarRef.RefKind.VARNUM).setType(syms.intType)); // call Pointer.make($$bound$result$) VisageFunctionInvocation apply = visagemake.Apply(null, select, pointerMakeArgs.toList()); apply.type = syms.visage_PointerType; blk.stats = stmts.toList(); blk.value = apply; blk.type = apply.type; } } } }