/* * Copyright (c) 2010-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.cal.services; import java.math.BigInteger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import net.sf.orcc.cache.CacheManager; import net.sf.orcc.cache.CachePackage; import net.sf.orcc.cal.cal.AstExpression; import net.sf.orcc.cal.cal.AstPort; import net.sf.orcc.cal.cal.AstType; import net.sf.orcc.cal.cal.AstTypeBool; import net.sf.orcc.cal.cal.AstTypeDouble; import net.sf.orcc.cal.cal.AstTypeFloat; import net.sf.orcc.cal.cal.AstTypeHalf; import net.sf.orcc.cal.cal.AstTypeInt; import net.sf.orcc.cal.cal.AstTypeList; import net.sf.orcc.cal.cal.AstTypeString; import net.sf.orcc.cal.cal.AstTypeUint; import net.sf.orcc.cal.cal.CalFactory; import net.sf.orcc.cal.cal.ExpressionBinary; import net.sf.orcc.cal.cal.ExpressionBoolean; import net.sf.orcc.cal.cal.ExpressionCall; import net.sf.orcc.cal.cal.ExpressionElsif; import net.sf.orcc.cal.cal.ExpressionFloat; import net.sf.orcc.cal.cal.ExpressionIf; import net.sf.orcc.cal.cal.ExpressionIndex; import net.sf.orcc.cal.cal.ExpressionInteger; import net.sf.orcc.cal.cal.ExpressionList; import net.sf.orcc.cal.cal.ExpressionString; import net.sf.orcc.cal.cal.ExpressionUnary; import net.sf.orcc.cal.cal.ExpressionVariable; import net.sf.orcc.cal.cal.Function; import net.sf.orcc.cal.cal.Generator; import net.sf.orcc.cal.cal.InputPattern; import net.sf.orcc.cal.cal.Variable; import net.sf.orcc.cal.cal.util.CalSwitch; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.IrFactory; import net.sf.orcc.ir.OpBinary; import net.sf.orcc.ir.OpUnary; import net.sf.orcc.ir.Type; import net.sf.orcc.ir.TypeList; import net.sf.orcc.ir.TypeString; import net.sf.orcc.ir.TypeUint; import net.sf.orcc.ir.util.TypeUtil; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; /** * This class defines a typer for RVC-CAL AST. Note that types must have been * transformed to IR types first. * * @author Matthieu Wipliez * */ public class Typer extends CalSwitch<Type> { /** * Returns the type of the given object using its URI. * * @param eObject * an AST node * @return the type of the given object */ public static Type getType(EObject eObject) { return CacheManager.instance.getOrCompute(eObject, new Typer(), CachePackage.eINSTANCE.getCache_TypesMap()); } /** * Returns the type of the given list of objects using their URI. * * @param eObject * an AST node * @return the type of the given object */ public static Type getType(List<? extends EObject> eObjects) { Iterator<? extends EObject> it = eObjects.iterator(); if (!it.hasNext()) { return null; } Type type = getType(it.next()); while (it.hasNext()) { type = TypeUtil.getLub(type, getType(it.next())); } return type; } @Override public Type caseAstPort(AstPort port) { return doSwitch(port.getType()); } @Override public Type caseAstTypeBool(AstTypeBool type) { return IrFactory.eINSTANCE.createTypeBool(); } @Override public Type caseAstTypeFloat(AstTypeFloat type) { return IrFactory.eINSTANCE.createTypeFloat(32); } @Override public Type caseAstTypeDouble(AstTypeDouble type) { return IrFactory.eINSTANCE.createTypeFloat(64); } @Override public Type caseAstTypeHalf(AstTypeHalf type) { return IrFactory.eINSTANCE.createTypeFloat(16); } @Override public Type caseAstTypeInt(AstTypeInt type) { AstExpression astSize = type.getSize(); int size; if (astSize == null) { size = 32; } else { size = Evaluator.getIntValue(astSize); } return IrFactory.eINSTANCE.createTypeInt(size); } @Override public Type caseAstTypeList(AstTypeList listType) { Type type = doSwitch(listType.getType()); AstExpression expression = listType.getSize(); Expression size = Evaluator.getValue(expression); size = EcoreUtil.copy(size); return IrFactory.eINSTANCE.createTypeList(size, type); } @Override public Type caseAstTypeString(AstTypeString type) { return IrFactory.eINSTANCE.createTypeString(); } @Override public Type caseAstTypeUint(AstTypeUint type) { AstExpression astSize = type.getSize(); int size; if (astSize == null) { size = 32; } else { size = Evaluator.getIntValue(astSize); } return IrFactory.eINSTANCE.createTypeUint(size); } @Override public Type caseExpressionBinary(ExpressionBinary expression) { OpBinary op = OpBinary.getOperator(expression.getOperator()); Type t1 = getType(expression.getLeft()); Type t2 = getType(expression.getRight()); return TypeUtil.getTypeBinary(op, t1, t2); } @Override public Type caseExpressionBoolean(ExpressionBoolean expression) { return IrFactory.eINSTANCE.createTypeBool(); } @Override public Type caseExpressionCall(ExpressionCall call) { Function function = call.getFunction(); Type type = getType(function); return EcoreUtil.copy(type); } @Override public Type caseExpressionElsif(ExpressionElsif expression) { Type type = getType(expression.getThen()); return EcoreUtil.copy(type); } @Override public Type caseExpressionFloat(ExpressionFloat expression) { return IrFactory.eINSTANCE.createTypeFloat(32); } @Override public Type caseExpressionIf(ExpressionIf expression) { Type type = getType(expression.getCondition()); Type t1 = getType(expression.getThen()); for (ExpressionElsif elsif : expression.getElsifs()) { t1 = TypeUtil.getLub(t1, getType(elsif)); } Type t2 = getType(expression.getElse()); type = TypeUtil.getLub(t1, t2); return type; } @Override public Type caseExpressionIndex(ExpressionIndex expression) { Variable variable = expression.getSource().getVariable(); Type type = getType(variable); List<AstExpression> indexes = expression.getIndexes(); for (AstExpression index : indexes) { Type subType = getType(index); if (type != null && type.isList()) { if (subType != null && (subType.isInt() || subType.isUint())) { type = ((TypeList) type).getType(); } } else { return null; } } return EcoreUtil.copy(type); } @Override public Type caseExpressionInteger(ExpressionInteger expression) { BigInteger value = expression.getValue(); return IrFactory.eINSTANCE.createTypeIntOrUint(value); } @Override public Type caseExpressionList(ExpressionList expression) { List<AstExpression> expressions = expression.getExpressions(); int size = 1; // size of generators for (Generator generator : expression.getGenerators()) { int lower = Evaluator.getIntValue(generator.getLower()); int higher = Evaluator.getIntValue(generator.getHigher()); size *= (higher - lower) + 1; } // size of expressions size *= expressions.size(); Type type = getType(expressions); return IrFactory.eINSTANCE.createTypeList(size, type); } @Override public Type caseExpressionString(ExpressionString expression) { TypeString type = IrFactory.eINSTANCE.createTypeString(); type.setSize(expression.getValue().length()); return type; } @Override public Type caseExpressionUnary(ExpressionUnary expression) { OpUnary op = OpUnary.getOperator(expression.getUnaryOperator()); Type type = getType(expression.getExpression()); if (type == null) { return null; } switch (op) { case BITNOT: case LOGIC_NOT: return EcoreUtil.copy(type); case MINUS: if (type.isUint()) { int size = ((TypeUint) type).getSize() + 1; return IrFactory.eINSTANCE.createTypeInt(size); } else { return EcoreUtil.copy(type); } case NUM_ELTS: if (!type.isList()) { return IrFactory.eINSTANCE.createTypeInt(1); } TypeList listType = (TypeList) type; // uint because the size of a list is always positive return IrFactory.eINSTANCE.createTypeUint(TypeUtil.getSize(listType .getSize())); default: return null; } } @Override public Type caseExpressionVariable(ExpressionVariable expression) { Variable variable = expression.getValue().getVariable(); return EcoreUtil.copy(getType(variable)); } @Override public Type caseFunction(Function function) { return doSwitch(function.getType()); } @Override public Type caseGenerator(Generator expression) { return null; }; @Override public Type caseVariable(Variable variable) { AstType astType; List<AstExpression> dimensions; if (variable.eContainer() instanceof InputPattern) { InputPattern pattern = (InputPattern) variable.eContainer(); astType = EcoreUtil.copy(pattern.getPort().getType()); dimensions = new ArrayList<AstExpression>(); AstExpression repeat = pattern.getRepeat(); if (repeat != null) { dimensions.add(repeat); } } else { astType = EcoreUtil.copy(variable.getType()); dimensions = variable.getDimensions(); } // convert the type of the variable ListIterator<AstExpression> it = dimensions.listIterator(dimensions .size()); while (it.hasPrevious()) { AstExpression expression = it.previous(); AstTypeList newAstType = CalFactory.eINSTANCE.createAstTypeList(); AstExpression size = EcoreUtil.copy(expression); newAstType.setSize(size); newAstType.setType(astType); astType = newAstType; } return doSwitch(astType); } @Override public Type doSwitch(EObject eObject) { if (eObject == null) { return null; } return super.doSwitch(eObject); } }