/* * Copyright (c) 2009-2011, IETR/INSA of Rennes * 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 IETR/INSA of Rennes 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 net.sf.orcc.frontend; import static net.sf.orcc.ir.IrFactory.eINSTANCE; import java.util.List; import net.sf.orcc.cal.cal.AstExpression; import net.sf.orcc.cal.cal.AstPort; import net.sf.orcc.cal.cal.AstProcedure; import net.sf.orcc.cal.cal.Function; import net.sf.orcc.cal.cal.Statement; import net.sf.orcc.cal.cal.Variable; import net.sf.orcc.cal.cal.util.CalSwitch; import net.sf.orcc.cal.services.Evaluator; import net.sf.orcc.cal.services.Typer; import net.sf.orcc.cal.util.Util; import net.sf.orcc.df.DfFactory; import net.sf.orcc.df.Port; import net.sf.orcc.ir.BlockBasic; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.InstReturn; import net.sf.orcc.ir.Param; import net.sf.orcc.ir.Procedure; import net.sf.orcc.ir.Type; import net.sf.orcc.ir.Var; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; /** * This class transforms an AST actor to its IR equivalent. * * @author Matthieu Wipliez * */ public class StructTransformer extends CalSwitch<EObject> { private Procedure procedure; /** * Creates a new AST to IR transformer. */ public StructTransformer() { } /** * Creates a new AST to IR transformer, which will append instructions and * blocks to the given procedure. * * @param procedure * a procedure */ public StructTransformer(Procedure procedure) { this.procedure = procedure; } /** * Adds a return with the given value at the end of the given procedure. * * @param procedure * a procedure * @param value * an expression, possibly <code>null</code> for procedures that * do not have a return value */ public void addReturn(Procedure procedure, Expression value) { BlockBasic block = procedure.getLast(); InstReturn returnInstr = eINSTANCE.createInstReturn(value); block.add(returnInstr); } @Override public EObject caseAstPort(AstPort astPort) { Type type = EcoreUtil.copy(Typer.getType(astPort)); Port port = DfFactory.eINSTANCE.createPort(type, astPort.getName(), Util.hasAnnotation("native", astPort.getAnnotations())); Frontend.instance.putMapping(astPort, port); return port; } /** * Transforms and adds a mapping from the given AST procedure to an IR * procedure. * * @param astProcedure * an AST procedure * @return the IR procedure */ @Override public Procedure caseAstProcedure(AstProcedure astProcedure) { // Get existing procedure procedure = Frontend.instance.getMapping(astProcedure); // Set attributes procedure.setName(astProcedure.getName()); procedure.setLineNumber(Util.getLocation(astProcedure)); procedure.setReturnType(eINSTANCE.createTypeVoid()); // set native flag if (Util.hasAnnotation("native", astProcedure.getAnnotations())) { procedure.setNative(true); } // Add annotations Util.transformAnnotations(procedure, astProcedure.getAnnotations()); // add mapping now (in case this procedure is recursive) Frontend.instance.putMapping(astProcedure, procedure); transformParameters(astProcedure.getParameters()); transformLocalVariables(astProcedure.getVariables()); transformStatements(astProcedure.getStatements()); addReturn(procedure, null); return procedure; } /** * Transforms and adds a mapping from the given AST function to an IR * procedure. * * @param function * an AST function * @return the IR procedure */ @Override public Procedure caseFunction(Function function) { // Get existing procedure procedure = Frontend.instance.getMapping(function); // Set attributes procedure.setName(function.getName()); procedure.setLineNumber(Util.getLocation(function)); procedure.setReturnType(Typer.getType(function)); // set native flag if (Util.hasAnnotation("native", function.getAnnotations())) { procedure.setNative(true); } // Add annotations Util.transformAnnotations(procedure, function.getAnnotations()); // add mapping now (in case this function is recursive) Frontend.instance.putMapping(function, procedure); transformParameters(function.getParameters()); transformLocalVariables(function.getVariables()); Expression value; if (procedure.isNative()) { value = null; } else { ExprTransformer transformer = new ExprTransformer(procedure, procedure.getBlocks()); value = transformer.doSwitch(function.getExpression()); } addReturn(procedure, value); return procedure; } @Override public EObject caseVariable(Variable variable) { if (Util.isGlobal(variable)) { return caseVariableGlobal(variable); } else { return caseVariableLocal(variable); } } /** * Transforms a global AST variable to its IR equivalent. The initial value * of an AST state variable is evaluated to a constant by * {@link #exprEvaluator}. * * @param variable * an AST variable * @return the IR equivalent of the AST variable */ private Var caseVariableGlobal(Variable variable) { int lineNumber = Util.getLocation(variable); Type type = EcoreUtil.copy(Typer.getType(variable)); String name = variable.getName(); boolean assignable = Util.isAssignable(variable); // retrieve initial value (may be null) Expression initialValue = EcoreUtil.copy(Evaluator.getValue(variable)); // create state variable and put it in the map Var var = eINSTANCE.createVar(lineNumber, type, name, assignable, initialValue); Util.transformAnnotations(var, variable.getAnnotations()); Frontend.instance.putMapping(variable, var); return var; } /** * Transforms the given AST variable to an IR variable that has the name and * type of <code>variable</code>. * * @param variable * an AST variable * @return the IR local variable created */ private Var caseVariableLocal(Variable variable) { int lineNumber = Util.getLocation(variable); Type type = Typer.getType(variable); String name = variable.getName(); boolean assignable = Util.isAssignable(variable); // create local variable with the given name Var local = eINSTANCE.createVar(lineNumber, type, name, assignable, 0); AstExpression value = variable.getValue(); if (value != null) { AstIrUtil.setLocal(local); new ExprTransformer(procedure, procedure.getBlocks(), local) .doSwitch(value); AstIrUtil.unsetLocal(local); } Frontend.instance.putMapping(variable, local); return local; } /** * Transforms the given list of AST variables to IR variables, and adds them * to the current {@link #procedure}'s local variables list. * * @param variables * a list of AST variables */ public void transformLocalVariables(List<Variable> variables) { for (Variable Variable : variables) { Var local = caseVariableLocal(Variable); procedure.getLocals().add(local); } } /** * Transforms the given list of AST parameters to IR variables, and adds * them to the current {@link #procedure}'s parameters list. * * @param parameters * a list of AST parameters */ private void transformParameters(List<Variable> parameters) { List<Param> params = procedure.getParameters(); for (Variable astParameter : parameters) { Var local = caseVariableLocal(astParameter); params.add(eINSTANCE.createParam(local)); } } /** * Transforms the given AST statements to IR instructions and/or blocks that * are added directly to the current {@link #procedure}. * * @param statements * a list of AST statements */ public void transformStatements(List<Statement> statements) { new StmtTransformer(procedure, procedure.getBlocks()) .doSwitch(statements); } }