| /** |
| * Copyright (c) 2008 Borland Software Corp. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Alexander Shatalin (Borland) - initial API and implementation |
| */ |
| package org.eclipse.gmf.internal.xpand.migration; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Stack; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EEnum; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.ETypedElement; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.gmf.internal.xpand.BuiltinMetaModel; |
| import org.eclipse.gmf.internal.xpand.BuiltinMetaModelExt; |
| import org.eclipse.gmf.internal.xpand.ResourceManager; |
| import org.eclipse.gmf.internal.xpand.ResourceMarker; |
| import org.eclipse.gmf.internal.xpand.eval.EvaluationListener; |
| import org.eclipse.gmf.internal.xpand.expression.AnalysationIssue; |
| import org.eclipse.gmf.internal.xpand.expression.ExecutionContext; |
| import org.eclipse.gmf.internal.xpand.expression.ExecutionContextImpl; |
| import org.eclipse.gmf.internal.xpand.expression.Variable; |
| import org.eclipse.gmf.internal.xpand.expression.ast.BooleanLiteral; |
| import org.eclipse.gmf.internal.xpand.expression.ast.BooleanOperation; |
| import org.eclipse.gmf.internal.xpand.expression.ast.Case; |
| import org.eclipse.gmf.internal.xpand.expression.ast.Cast; |
| import org.eclipse.gmf.internal.xpand.expression.ast.ChainExpression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.CollectionExpression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.ConstructorCallExpression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.Expression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.FeatureCall; |
| import org.eclipse.gmf.internal.xpand.expression.ast.IfExpression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.IntegerLiteral; |
| import org.eclipse.gmf.internal.xpand.expression.ast.LetExpression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.ListLiteral; |
| import org.eclipse.gmf.internal.xpand.expression.ast.NullLiteral; |
| import org.eclipse.gmf.internal.xpand.expression.ast.OperationCall; |
| import org.eclipse.gmf.internal.xpand.expression.ast.RealLiteral; |
| import org.eclipse.gmf.internal.xpand.expression.ast.StringLiteral; |
| import org.eclipse.gmf.internal.xpand.expression.ast.SwitchExpression; |
| import org.eclipse.gmf.internal.xpand.expression.ast.TypeSelectExpression; |
| import org.eclipse.gmf.internal.xpand.expression.parser.ExpressionLexer; |
| import org.eclipse.gmf.internal.xpand.expression.parser.ExpressionParser; |
| import org.eclipse.gmf.internal.xpand.migration.MigrationException.Type; |
| import org.eclipse.gmf.internal.xpand.util.ClassLoadContext; |
| import org.eclipse.gmf.internal.xpand.xtend.ast.Extension; |
| import org.eclipse.ocl.Environment; |
| import org.eclipse.ocl.ecore.EcoreEnvironmentFactory; |
| |
| public class ExpressionMigrationFacade { |
| |
| public static final String LF = System.getProperty("line.separator"); |
| |
| static final EcoreEnvironmentFactory ECORE_ENV_FACTORY = new EcoreEnvironmentFactory(null); |
| |
| private static final Set<EOperation> infixOperations = new HashSet<EOperation>(Arrays.asList(new EOperation[] { |
| BuiltinMetaModel.Boolean_NE, |
| BuiltinMetaModel.Int_Unary_Minus, |
| BuiltinMetaModel.Double_Unary_Minus, |
| BuiltinMetaModel.Int_Minus_Double, |
| BuiltinMetaModel.Int_Minus_Int, |
| BuiltinMetaModel.Double_Minus_Double, |
| BuiltinMetaModel.Double_Minus_Int, |
| BuiltinMetaModel.Int_Plus_Double, |
| BuiltinMetaModel.Int_Plus_Int, |
| BuiltinMetaModel.Double_Plus_Double, |
| BuiltinMetaModel.Double_Plus_Int, |
| BuiltinMetaModel.Int_Mult_Double, |
| BuiltinMetaModel.Int_Mult_Int, |
| BuiltinMetaModel.Double_Mult_Double, |
| BuiltinMetaModel.Double_Mult_Int, |
| BuiltinMetaModel.Int_Div_Double, |
| BuiltinMetaModel.Double_Div_Double, |
| BuiltinMetaModel.Double_Div_Int, |
| BuiltinMetaModel.Int_Less, |
| BuiltinMetaModel.Int_LessOrEqual, |
| BuiltinMetaModel.Int_Greater, |
| BuiltinMetaModel.Int_GreatOrEqual, |
| BuiltinMetaModel.EString_Plus_EJavaObject, |
| BuiltinMetaModel.Object_EQ, |
| BuiltinMetaModel.Object_NotEQ |
| })); |
| |
| private static final Set<EOperation> collectionOperations = new HashSet<EOperation>(Arrays.asList(new EOperation[] { |
| BuiltinMetaModel.Collection_Add, |
| BuiltinMetaModel.Collection_AddAll, |
| BuiltinMetaModel.Collection_Clear, |
| BuiltinMetaModel.Collection_Contains, |
| BuiltinMetaModel.Collection_ContainsAll, |
| BuiltinMetaModel.Collection_Flatten, |
| BuiltinMetaModel.Collection_Intersect, |
| BuiltinMetaModel.Collection_IsEmpty, |
| BuiltinMetaModel.Collection_Size, |
| BuiltinMetaModel.Collection_ToList, |
| BuiltinMetaModel.Collection_ToSet, |
| BuiltinMetaModel.Collection_Union, |
| BuiltinMetaModel.Collection_Without, |
| BuiltinMetaModel.List_First, |
| BuiltinMetaModel.List_Get, |
| BuiltinMetaModel.List_IndexOf, |
| BuiltinMetaModel.List_Last, |
| BuiltinMetaModel.List_PurgeDups, |
| BuiltinMetaModel.List_WithoutFirst, |
| BuiltinMetaModel.List_WithoutLast |
| })); |
| |
| private Stack<Expression> expressionsStack = new Stack<Expression>(); |
| |
| private StringBuilder output = new StringBuilder(); |
| |
| private MigrationExecutionContext ctx; |
| |
| private int returnPosition; |
| |
| private VariableNameDispatcher variableDispatcher; |
| |
| private Expression rootExpression; |
| |
| private TypeManager typeManager; |
| |
| private ModelManager modelManager; |
| |
| private Stack<QvtExecutionContext> qvtContexts = new Stack<QvtExecutionContext>(); |
| |
| private EClassifier rootExpressionType; |
| |
| private String resourceName; |
| |
| private HashMap<String, EClassifier> envVariables; |
| |
| public ExpressionMigrationFacade(String expression, EClassifier requiredType, Map<String, EClassifier> envVariables, TypeManager typeManager, ModelManager modelManager, VariableNameDispatcher variableDispatcher, |
| MigrationExecutionContext context, String resourceName) throws MigrationException { |
| this(parseXtend(expression), requiredType, envVariables, typeManager, modelManager, variableDispatcher, context, resourceName); |
| Set<AnalysationIssue> issues = new HashSet<AnalysationIssue>(); |
| rootExpression.analyze(ctx, issues); |
| if (MigrationException.hasErrors(issues)) { |
| throw new MigrationException(issues, resourceName); |
| } |
| } |
| |
| public ExpressionMigrationFacade(Expression expression, EClassifier requiredType, Map<String, EClassifier> envVariables, TypeManager typeManager, ModelManager modelManager, VariableNameDispatcher variableDispatcher, |
| MigrationExecutionContext context, String resourceName) { |
| rootExpression = expression; |
| rootExpressionType = requiredType; |
| this.envVariables = new HashMap<String, EClassifier>(envVariables); |
| this.typeManager = typeManager; |
| this.modelManager = modelManager; |
| this.variableDispatcher = variableDispatcher; |
| this.resourceName = resourceName; |
| ctx = context; |
| markReturnPosition(); |
| } |
| |
| private static Expression parseXtend(final String expression) { |
| final ExpressionLexer scanner = new ExpressionLexer(expression.toCharArray(), "nofile"); |
| final ExpressionParser parser = new ExpressionParser(scanner); |
| scanner.lexer(parser); |
| return parser.parser(); |
| } |
| |
| public Expression getRootExpression() { |
| return rootExpression; |
| } |
| |
| public StringBuilder migrate() throws MigrationException { |
| qvtContexts.push(QvtExecutionContext.createNewContext(envVariables)); |
| try { |
| EClassifier expressionQvtType = migrateExpression(rootExpression); |
| internalConvertTypes(expressionQvtType, rootExpressionType); |
| } finally { |
| qvtContexts.pop(); |
| } |
| return output; |
| } |
| |
| // TODO: similar to internalMigrateParameterCollectionToMain() ? |
| private void internalConvertTypes(EClassifier actualType, EClassifier expectedType) { |
| if (expectedType != BuiltinMetaModel.VOID && BuiltinMetaModel.isCollectionType(expectedType)) { |
| assert BuiltinMetaModel.isCollectionType(actualType); |
| |
| if (BuiltinMetaModelExt.isListType(expectedType)) { |
| if (BuiltinMetaModelExt.isSetType(actualType) || BuiltinMetaModelExt.isOrderedSetType(actualType) || BuiltinMetaModelExt.isBagType(actualType)) { |
| write("->asSequence()"); |
| } else if (BuiltinMetaModelExt.isAbstractCollectionType(actualType)) { |
| internalMigrateCollectionToBag(); |
| write("->asSequence()"); |
| } |
| } else if (BuiltinMetaModelExt.isSetType(expectedType)) { |
| if (BuiltinMetaModelExt.isListType(actualType)) { |
| write("->asOrderedSet()"); |
| } else if (BuiltinMetaModelExt.isBagType(actualType)) { |
| write("->asSet()"); |
| } else if (BuiltinMetaModelExt.isAbstractCollectionType(actualType)) { |
| internalMigrateCollectionToBag(); |
| write("->asSet()"); |
| } |
| } |
| // Abstract collection should be compatible with any other kind |
| // on collections |
| } |
| // else if (EcorePackage.eINSTANCE.getEString() == expectedType && actualType != EcorePackage.eINSTANCE.getEString()) { |
| // write(".repr()"); |
| // } |
| } |
| |
| int getReturnPosition() { |
| return returnPosition; |
| } |
| |
| // Returning xpand types from here. This method can be modified to make use |
| // of QVT type system instead. |
| private EClassifier migrateExpression(Expression expression) throws MigrationException { |
| expressionsStack.push(expression); |
| try { |
| if (expression instanceof BooleanOperation) { |
| return migrateBooleanOperation((BooleanOperation) expression); |
| } else if (expression instanceof Cast) { |
| return migrateCast((Cast) expression); |
| } else if (expression instanceof ChainExpression) { |
| return migrateChainExpression((ChainExpression) expression); |
| } else if (expression instanceof ConstructorCallExpression) { |
| return migrateConstructorCallExpression((ConstructorCallExpression) expression); |
| } else if (expression instanceof CollectionExpression) { |
| return migrateCollectionExpression((CollectionExpression) expression); |
| } else if (expression instanceof OperationCall) { |
| return migrateOperationCall((OperationCall) expression); |
| } else if (expression instanceof TypeSelectExpression) { |
| return migrateTypeSelectExpression((TypeSelectExpression) expression); |
| } else if (expression instanceof FeatureCall) { |
| return migrateFeatureCall((FeatureCall) expression); |
| } else if (expression instanceof IfExpression) { |
| return migrateIfExpression((IfExpression) expression); |
| } else if (expression instanceof LetExpression) { |
| return migrateLetExpression((LetExpression) expression); |
| } else if (expression instanceof ListLiteral) { |
| return migrateListLiteral((ListLiteral) expression); |
| } else if (expression instanceof BooleanLiteral) { |
| return migrateBooleanLiteral((BooleanLiteral) expression); |
| } else if (expression instanceof IntegerLiteral) { |
| return migrateIntegerLiteral((IntegerLiteral) expression); |
| } else if (expression instanceof NullLiteral) { |
| return migrateNullLiteral((NullLiteral) expression); |
| } else if (expression instanceof RealLiteral) { |
| return migrateRealLiteral((RealLiteral) expression); |
| } else if (expression instanceof StringLiteral) { |
| return migrateStringLiteral((StringLiteral) expression); |
| } else if (expression instanceof SwitchExpression) { |
| return migrateSwitchExpression((SwitchExpression) expression); |
| } else { |
| throw new MigrationException(Type.UNSUPPORTED_EXPRESSION, resourceName, expression, expression.getClass().getName()); |
| } |
| } finally { |
| expressionsStack.pop(); |
| } |
| } |
| |
| private EClassifier migrateSwitchExpression(SwitchExpression switchExpression) throws MigrationException { |
| Collection<EClassifier> expressionTypes = new ArrayList<EClassifier>(); |
| if (switchExpression.getCases().size() == 0) { |
| expressionTypes.add(migrateExpression(switchExpression.getDefaultExpr())); |
| } else { |
| // TODO: define additional variable here. |
| write("switch { "); |
| for (Case caseExpression : switchExpression.getCases()) { |
| write("case ("); |
| migrateExpression(switchExpression.getSwitchExpr()); |
| write(" = "); |
| migrateExpression(caseExpression.getCondition()); |
| write(") "); |
| expressionTypes.add(migrateExpression(caseExpression.getThenPart())); |
| write("; "); |
| } |
| write("else "); |
| expressionTypes.add(migrateExpression(switchExpression.getDefaultExpr())); |
| write("; }"); |
| } |
| // TODO: check different types of collections was produced |
| return BuiltinMetaModelExt.getCommonSuperType(expressionTypes); |
| } |
| |
| private EClassifier migrateStringLiteral(StringLiteral expression) { |
| write("'"); |
| write(escape(expression.getValue())); |
| write("'"); |
| return EcorePackage.eINSTANCE.getEString(); |
| } |
| |
| private String escape(String value) { |
| StringBuilder sb = new StringBuilder(); |
| for (int i = 0; i < value.length(); i++) { |
| char nextChar = value.charAt(i); |
| if (nextChar == '\b') { |
| sb.append("\\b"); |
| // leaving tab char without escaping |
| // } else if (nextChar == '\t') { |
| // sb.append("\\t"); |
| } else if (nextChar == '\n') { |
| sb.append("\\n"); |
| } else if (nextChar == '\f') { |
| sb.append("\\f"); |
| } else if (nextChar == '\r') { |
| sb.append("\\r"); |
| } else if (nextChar == '\"') { |
| sb.append("\\\""); |
| } else if (nextChar == '\'') { |
| sb.append("\\\'"); |
| } else if (nextChar == '\\') { |
| sb.append("\\\\"); |
| } else { |
| sb.append(nextChar); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| private EClassifier migrateRealLiteral(RealLiteral realLiteral) { |
| write(new Double(realLiteral.getLiteralValue()).toString()); |
| return EcorePackage.eINSTANCE.getEDouble(); |
| } |
| |
| private EClassifier migrateNullLiteral(NullLiteral expression) { |
| write("null"); |
| return BuiltinMetaModel.VOID; |
| } |
| |
| private EClassifier migrateIntegerLiteral(IntegerLiteral integerLiteral) { |
| write(new Integer(integerLiteral.getLiteralValue()).toString()); |
| return EcorePackage.eINSTANCE.getEInt(); |
| } |
| |
| private EClassifier migrateBooleanLiteral(BooleanLiteral booleanLiteral) { |
| write(Boolean.valueOf(booleanLiteral.getLiteralValue()) ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } |
| |
| private EClassifier migrateListLiteral(ListLiteral listLiteral) throws MigrationException { |
| Collection<EClassifier> expressionTypes = new ArrayList<EClassifier>(); |
| write("Sequence { "); |
| for (int i = 0; i < listLiteral.getElements().length; i++) { |
| if (i > 0) { |
| write(", "); |
| } |
| expressionTypes.add(migrateExpression(listLiteral.getElements()[i])); |
| } |
| write(" }"); |
| return BuiltinMetaModelExt.getListType(BuiltinMetaModelExt.getCommonSuperType(expressionTypes)); |
| } |
| |
| private EClassifier migrateLetExpression(LetExpression letExpression) throws MigrationException { |
| String varName = modelManager.getOclKeywordManager().getValidIdentifierValue(letExpression.getVarName()); |
| write("let "); |
| write(varName); |
| write(" = "); |
| pushContextWithVariable(varName, migrateExpression(letExpression.getVarExpression())); |
| try { |
| write(" in "); |
| return migrateExpression(letExpression.getTargetExpression()); |
| } finally { |
| qvtContexts.pop(); |
| } |
| } |
| |
| private EClassifier migrateIfExpression(IfExpression ifExpression) throws MigrationException { |
| write("(if "); |
| migrateExpression(ifExpression.getCondition()); |
| write(" then "); |
| EClassifier thenType = migrateExpression(ifExpression.getThenPart()); |
| write(" else "); |
| EClassifier elseType = migrateExpression(ifExpression.getElsePart()); |
| write(" endif)"); |
| // TODO: check if then/else produces different types of collections.. |
| return BuiltinMetaModelExt.getCommonSuperType(thenType, elseType); |
| } |
| |
| private EClassifier migrateConstructorCallExpression(ConstructorCallExpression constructorCall) throws MigrationException { |
| write("object "); |
| EClassifier type = ctx.getTypeForName(constructorCall.getType().getValue()); |
| if (type == null) { |
| throw new MigrationException(Type.TYPE_NOT_FOUND, resourceName, constructorCall.getType(), constructorCall.getType().getValue()); |
| } |
| |
| write(typeManager.getQvtFQName(type)); |
| write(" {}"); |
| return type; |
| } |
| |
| private EClassifier migrateChainExpression(ChainExpression chainExpression) throws MigrationException { |
| write("compute ("); |
| String varName = variableDispatcher.getNextVariableName(); |
| write(varName); |
| write(" : "); |
| int typePosition = getCurrentPosition(); |
| write(") {"); |
| internalMigrateChainExpressionFirstArg(chainExpression.getFirst()); |
| write(varName); |
| write(" = "); |
| EClassifier varType = migrateExpression(chainExpression.getNext()); |
| write(typeManager.getQvtFQName(varType), typePosition); |
| write("}"); |
| return varType; |
| } |
| |
| private void internalMigrateChainExpressionFirstArg(Expression first) throws MigrationException { |
| if (first instanceof ChainExpression) { |
| ChainExpression innerChain = (ChainExpression) first; |
| internalMigrateChainExpressionFirstArg(innerChain.getFirst()); |
| migrateExpression(innerChain.getNext()); |
| } else { |
| migrateExpression(first); |
| } |
| write("; "); |
| } |
| |
| private EClassifier migrateBooleanOperation(BooleanOperation booleanOperation) throws MigrationException { |
| int operationPrecedence = getPrecedence(booleanOperation); |
| int leftPosition = getCurrentPosition(); |
| migrateExpression(booleanOperation.getLeft()); |
| encloseExpressionIntoParenthesis(booleanOperation.getLeft(), operationPrecedence, leftPosition, false); |
| if (booleanOperation.isAndOperation()) { |
| write(" and "); |
| } else if (booleanOperation.isOrOperation()) { |
| write(" or "); |
| } else if (booleanOperation.isImpliesOperation()) { |
| write(" implies "); |
| } else { |
| throw new MigrationException(Type.UNSUPPORTED_BOOLEAN_OPERATION, resourceName, booleanOperation, booleanOperation.getOperator()); |
| } |
| int rightPosition = getCurrentPosition(); |
| migrateExpression(booleanOperation.getRight()); |
| encloseExpressionIntoParenthesis(booleanOperation.getRight(), operationPrecedence, rightPosition, true); |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } |
| |
| private EClassifier migrateCast(Cast cast) throws MigrationException { |
| EClassifier migratedExpressionType = migrateExpression(cast.getTarget()); |
| EClassifier type = ctx.getTypeForName(cast.getType().getValue()); |
| if (type == null) { |
| throw new MigrationException(Type.TYPE_NOT_FOUND, resourceName, cast.getType(), cast.getType().getValue()); |
| } |
| if (BuiltinMetaModel.isCollectionType(type)) { |
| // This operation is not supported now. |
| return migratedExpressionType; |
| } |
| write(".oclAsType("); |
| write(typeManager.getQvtFQName(type)); |
| write(")"); |
| return type; |
| } |
| |
| private EClassifier migrateTypeSelectExpression(TypeSelectExpression typeSelectExpression) throws MigrationException { |
| int placeholder = getCurrentPosition(); |
| EClassifier targetQvtType = migrateExpression(typeSelectExpression.getTarget()); |
| EClassifier type = ctx.getTypeForName(typeSelectExpression.getTypeLiteral().getValue()); |
| if (type == null) { |
| throw new MigrationException(Type.TYPE_NOT_FOUND, resourceName, typeSelectExpression.getTypeLiteral(), typeSelectExpression.getTypeLiteral().getValue()); |
| } |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(typeSelectExpression); |
| if (false == expressionTrace instanceof TypeSelectExpressionTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_TYPE_SELECT_EXPRESSION_TRACE, resourceName, typeSelectExpression, expressionTrace); |
| } |
| TypeSelectExpressionTrace trace = (TypeSelectExpressionTrace) expressionTrace; |
| if (!trace.isValid()) { |
| throw new MigrationException(Type.UNSUPPORTED_TYPE_SELECT_EXPRESSION, resourceName, typeSelectExpression, trace); |
| } |
| internalMigrateTypeSelectCastingCollectionToBag(targetQvtType, typeManager.getQvtFQName(type), placeholder); |
| if (!BuiltinMetaModelExt.isListType(targetQvtType) && !BuiltinMetaModelExt.isOrderedSetType(targetQvtType)) { |
| write("->asSequence()"); |
| } |
| return BuiltinMetaModelExt.isOrderedSetType(targetQvtType) ? BuiltinMetaModelExt.getOrderedSetType(type) : BuiltinMetaModelExt.getListType(type); |
| } |
| |
| private void internalMigrateTypeSelectCastingCollectionToBag(EClassifier collectionType, String typeName, int placeholder) { |
| assert BuiltinMetaModel.isCollectionType(collectionType); |
| if (BuiltinMetaModelExt.isAbstractCollectionType(collectionType)) { |
| internalMigrateCollectionToBag(); |
| } |
| internalMigrateTypeSelect(typeName, placeholder, getCurrentPosition()); |
| } |
| |
| private void internalMigrateTypeSelect(String typeName, int expressionStartPosition, int expressionEndPosition) { |
| // TODO: This method should write braces around expression starting |
| // at placeholder position conditionally depending on the last char |
| // in output sequence. |
| StringBuilder sb = new StringBuilder(); |
| sb.append(")["); |
| sb.append(typeName); |
| sb.append("]"); |
| write(sb, expressionEndPosition); |
| |
| write("(", expressionStartPosition); |
| } |
| |
| // TODO: use ->asSequence() here in addition? |
| private void internalMigrateCollectionToBag() { |
| String iteratorName = variableDispatcher.getNextIteratorName(); |
| write("->collect("); |
| write(iteratorName); |
| write(" | "); |
| write(iteratorName); |
| write(")"); |
| } |
| |
| private EClassifier migrateCollectionExpression(CollectionExpression collectionExpression) throws MigrationException { |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(collectionExpression); |
| if (false == expressionTrace instanceof CollectionExpressionTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_COLLECTION_EXPRESSION_TRACE, resourceName, collectionExpression, expressionTrace); |
| } |
| CollectionExpressionTrace trace = (CollectionExpressionTrace) expressionTrace; |
| |
| int placeholder = getCurrentPosition(); |
| boolean hasNegation = false; |
| EClassifier targetQvtType; |
| if (collectionExpression.getTarget() != null) { |
| targetQvtType = migrateExpression(collectionExpression.getTarget()); |
| } else { |
| write(Environment.SELF_VARIABLE_NAME); |
| targetQvtType = getEnvVariableType(ExecutionContext.IMPLICIT_VARIABLE); |
| } |
| assert BuiltinMetaModel.isCollectionType(targetQvtType); |
| EClassifier innerTargetQvtType = BuiltinMetaModel.getInnerType(targetQvtType); |
| |
| write("->"); |
| switch (trace.getType()) { |
| case NOTEXISTS_REF: |
| hasNegation = true; |
| write("not ", placeholder); |
| write("exists"); |
| break; |
| case COLLECT_REF: |
| case SELECT_REF: |
| case REJECT_REF: |
| case EXISTS_REF: |
| case FORALL_REF: |
| write(collectionExpression.getName().getValue()); |
| break; |
| case INCORRECT_EXPRESSION_TYPE: |
| case UNDESOLVED_TARGET_TYPE: |
| throw new MigrationException(Type.UNSUPPORTED_COLLECTION_EXPRESSION, resourceName, collectionExpression, trace); |
| default: |
| throw new MigrationException(Type.UNSUPPORTED_COLLECTION_EXPRESSION_TRACE, resourceName, collectionExpression, trace); |
| } |
| write("("); |
| String varName = collectionExpression.getElementName(); |
| write(modelManager.getOclKeywordManager().getValidIdentifierValue(varName)); |
| pushContextWithVariable(varName, innerTargetQvtType); |
| EClassifier expressionType; |
| try { |
| write(" | "); |
| expressionType = migrateExpression(collectionExpression.getClosure()); |
| } finally { |
| qvtContexts.pop(); |
| } |
| write(")"); |
| try { |
| // Determining actual result type |
| switch (trace.getType()) { |
| case NOTEXISTS_REF: |
| case EXISTS_REF: |
| case FORALL_REF: |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| case COLLECT_REF: |
| if (BuiltinMetaModelExt.isSetType(trace.getResultType())) { |
| // Does not work now due to the bug in xpand implementation |
| // - see "TODO [AS]" comment in CollectionExpression |
| write("->asSet()"); |
| // TODO: add flatten here? |
| return BuiltinMetaModel.getSetType(expressionType); |
| }else if (BuiltinMetaModelExt.isListType(trace.getResultType())) { |
| return BuiltinMetaModelExt.getListType(expressionType); |
| } else { |
| return BuiltinMetaModelExt.getBagType(expressionType); |
| } |
| case SELECT_REF: |
| case REJECT_REF: |
| return targetQvtType; |
| } |
| // Unreachable |
| return null; |
| } finally { |
| if (hasNegation) { |
| addNegationBraces(placeholder); |
| } |
| } |
| } |
| |
| private void addNegationBraces(int placeholder) { |
| if (expressionsStack.size() == 1) { |
| return; |
| } |
| // TODO: check for the type of parent expression here + add braces |
| // conditionaly |
| // Expression parentExpression = |
| // expressionsStack.get(expressionsStack.size() - 2); |
| // check for the type of parent expression; |
| write("(", placeholder); |
| write(")"); |
| } |
| |
| private EClassifier migrateOperationCall(OperationCall operationCall) throws MigrationException { |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(operationCall); |
| if (false == expressionTrace instanceof OperationCallTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL_TRACE, resourceName, operationCall, expressionTrace); |
| } |
| OperationCallTrace trace = (OperationCallTrace) expressionTrace; |
| switch (trace.getType()) { |
| case UNDESOLVED_PARAMETER_TYPE: |
| case UNDESOLVED_TARGET_TYPE: |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL, resourceName, operationCall, trace.toString()); |
| case STATIC_EXTENSION_REF: |
| if (trace.isStaticQvtoCall()) { |
| write(modelManager.getName(operationCall, trace)); |
| write("("); |
| internalMigrateOperationCallParameters(operationCall, trace.getParamTypes()); |
| write(")"); |
| } else { |
| List<EClassifier> expectedParameterTypes = trace.getParamTypes(); |
| assert operationCall.getParams().length > 0; |
| assert expectedParameterTypes == null || operationCall.getParams().length == expectedParameterTypes.size(); |
| EClassifier actualParameterType = migrateExpression(operationCall.getParams()[0]); |
| if (expectedParameterTypes != null) { |
| internalConvertTypes(actualParameterType, expectedParameterTypes.get(0)); |
| } |
| if (BuiltinMetaModel.isCollectionType(actualParameterType)) { |
| write("->"); |
| } else { |
| write("."); |
| } |
| |
| write(modelManager.getName(operationCall, trace)); |
| write("("); |
| for (int i = 1; i < operationCall.getParams().length; i++) { |
| if (i > 1) { |
| write(", "); |
| } |
| actualParameterType = migrateExpression(operationCall.getParams()[i]); |
| if (expectedParameterTypes != null) { |
| internalConvertTypes(actualParameterType, expectedParameterTypes.get(i)); |
| } |
| } |
| write(")"); |
| } |
| return trace.getResultType(); |
| case OPERATION_REF: |
| if (isInfixOperation(trace)) { |
| return internalMigrateInfixOperation(trace, operationCall); |
| } else if (isCollectionOperation(trace)) { |
| return internalMigrateCollectionOperationCall(trace, operationCall); |
| } else if (isEClassOperationOnTypeLiteral(trace, operationCall)) { |
| return internalMigrateEClassOperationOnTypeLiteral(trace, operationCall); |
| } |
| // else same as IMPLICIT_COLLECT_OPERATION_REF: |
| case IMPLICIT_COLLECT_OPERATION_REF: |
| EOperation eOperation = trace.getEOperation(); |
| assert eOperation != null; |
| EClassifier targetQvtType = trace.getTargetType(); |
| // getTarget can be null for implicit call to "self" variable in xpand |
| if (operationCall.getTarget() != null) { |
| targetQvtType = migrateExpression(operationCall.getTarget()); |
| write("."); |
| } |
| write(modelManager.getName(operationCall, trace)); |
| write("("); |
| if (BuiltinMetaModel.EString_SubString_StartEnd == eOperation) { |
| write("1 + "); |
| } |
| List<EClassifier> parameterTypes = internalMigrateOperationCallParameters(operationCall, trace.getParamTypes()); |
| if (BuiltinMetaModel.EString_Plus_EJavaObject == eOperation) { |
| assert parameterTypes.size() == 1; |
| if (parameterTypes.get(0) != EcorePackage.eINSTANCE.getEString()) { |
| write(".repr()"); |
| } |
| } |
| write(")"); |
| if (trace.getType() == OperationCallTrace.Type.OPERATION_REF) { |
| return getTypedElementQvtType(eOperation); |
| } else { |
| if (!BuiltinMetaModel.isParameterizedType(targetQvtType)) { |
| throw new MigrationException(Type.UNSUPPORTED_EXPRESSION, resourceName, operationCall.getTarget(), "Implicit collect is not supported for simple types: " + targetQvtType.toString() + "." + operationCall.getName().getValue()); |
| } |
| convertImplicitCollectProduct(targetQvtType); |
| return BuiltinMetaModelExt.getListType(BuiltinMetaModel.getInnerType(targetQvtType)); |
| } |
| case EXTENSION_REF: |
| if (!trace.isStaticQvtoCall()) { |
| if (operationCall.getTarget() != null) { |
| migrateExpression(operationCall.getTarget()); |
| } else { |
| // in case of xpand migration substituting implicit target of static extension call |
| write(Environment.SELF_VARIABLE_NAME); |
| } |
| if (BuiltinMetaModel.isCollectionType(trace.getParamTypes().get(0))) { |
| write("->"); |
| } else { |
| write("."); |
| } |
| } |
| write(modelManager.getName(operationCall, trace)); |
| write("("); |
| if (trace.isStaticQvtoCall()) { |
| if (operationCall.getTarget() != null) { |
| migrateExpression(operationCall.getTarget()); |
| } else { |
| // in case of xpand migration substituting implicit target of static extension call |
| write(Environment.SELF_VARIABLE_NAME); |
| } |
| if (operationCall.getParams().length > 0) { |
| write(", "); |
| } |
| } |
| internalMigrateOperationCallParameters(operationCall, withoutFirst(trace.getParamTypes())); |
| write(")"); |
| return trace.getResultType(); |
| case IMPLICIT_COLLECT_EXTENSION_REF: |
| assert operationCall.getTarget() != null; |
| EClassifier implicitCollectTargetQvtType = migrateExpression(operationCall.getTarget()); |
| if (!BuiltinMetaModel.isParameterizedType(implicitCollectTargetQvtType)) { |
| throw new MigrationException(Type.UNSUPPORTED_EXPRESSION, resourceName, operationCall.getTarget(), "Implicit collect is not supported for simple types: " + implicitCollectTargetQvtType.toString() + "." + operationCall.getName().getValue()); |
| } |
| String iteratorName = variableDispatcher.getNextIteratorName(); |
| write("->collect("); |
| write(iteratorName); |
| write(" | "); |
| if (!trace.isStaticQvtoCall()) { |
| write(iteratorName); |
| if (BuiltinMetaModel.isCollectionType(BuiltinMetaModel.getInnerType(implicitCollectTargetQvtType))) { |
| write("->"); |
| } else { |
| write("."); |
| } |
| } |
| write(modelManager.getName(operationCall, trace)); |
| write("("); |
| if (trace.isStaticQvtoCall()) { |
| write(iteratorName); |
| if (operationCall.getParams().length > 0) { |
| write(", "); |
| } |
| } |
| internalMigrateOperationCallParameters(operationCall, withoutFirst(trace.getParamTypes())); |
| write(")"); |
| write(")"); |
| convertImplicitCollectProduct(implicitCollectTargetQvtType); |
| return trace.getResultType(); |
| default: |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL_TRACE, resourceName, operationCall, trace); |
| } |
| } |
| |
| private EClassifier internalMigrateEClassOperationOnTypeLiteral(OperationCallTrace trace, OperationCall operationCall) throws MigrationException { |
| EOperation eOperation = trace.getEOperation(); |
| assert eOperation != null; |
| if ("isSuperTypeOf".equals(eOperation.getName())) { |
| assert operationCall.getParams().length == 1; |
| Expression parameter = operationCall.getParams()[0]; |
| if (parameter instanceof OperationCall) { |
| OperationCall parameterOpCall = (OperationCall) parameter; |
| if ("eClass".equals(parameterOpCall.getName().getValue()) && parameterOpCall.getTarget() != null && parameterOpCall.getParams().length == 0) { |
| migrateExpression(parameterOpCall.getTarget()); |
| write(".oclIsKindOf("); |
| Expression target = operationCall.getTarget(); |
| assert target instanceof FeatureCall; |
| EClassifier type = ctx.getTypeForName(((FeatureCall) target).getName().getValue()); |
| write(typeManager.getQvtFQName(type)); |
| write(")"); |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } |
| } |
| } |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL, resourceName, operationCall.getName(), "Migration of operation \"" + eOperation.getName() |
| + "\" is not supported for TypeLiteral expressions now"); |
| } |
| |
| private boolean isEClassOperationOnTypeLiteral(OperationCallTrace trace, OperationCall operationCall) throws MigrationException { |
| if (trace.getTargetType() == EcorePackage.eINSTANCE.getEClass()) { |
| Expression target = operationCall.getTarget(); |
| if (target instanceof FeatureCall) { |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(target); |
| if (false == expressionTrace instanceof FeatureCallTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_FEATURE_CALL_TRACE, resourceName, target, expressionTrace); |
| } |
| return ((FeatureCallTrace) expressionTrace).getType() == FeatureCallTrace.Type.UNSUPPORTED_CLASSIFIER_REF; |
| } |
| } |
| return false; |
| } |
| |
| private static <T> List<T> withoutFirst(List<T> parameters) { |
| assert parameters.size() > 0; |
| return parameters.subList(1, parameters.size()); |
| } |
| |
| private EClassifier internalMigrateInfixOperation(OperationCallTrace trace, OperationCall operationCall) throws MigrationException { |
| EOperation eOperation = trace.getEOperation(); |
| assert eOperation != null; |
| |
| TypeSelectExpression typeSelect = getInfixInstanceOfTypeSelect(eOperation, operationCall); |
| if (typeSelect != null) { |
| return internalMigrateInfixInstanceof(typeSelect); |
| } |
| typeSelect = getInfixNotInstanceOfTypeSelect(eOperation, operationCall); |
| if (typeSelect != null) { |
| write("not "); |
| return internalMigrateInfixInstanceof(typeSelect); |
| } |
| |
| OperationCall indexOfOperation = getInfixContains(eOperation, operationCall); |
| if (indexOfOperation != null) { |
| return internalMigrateInfixContains(indexOfOperation); |
| } |
| indexOfOperation = getInfixNotContains(eOperation, operationCall); |
| if (indexOfOperation != null) { |
| write("not "); |
| return internalMigrateInfixContains(indexOfOperation); |
| } |
| |
| int operationPrecedence = getPrecedence(operationCall); |
| int targetStartPosition = getCurrentPosition(); |
| internalMigrateOperationCallTarget(operationCall); |
| encloseExpressionIntoParenthesis(operationCall.getTarget(), operationPrecedence, targetStartPosition, false); |
| String opName = eOperation.getName(); |
| if (BuiltinMetaModel.Boolean_NE == eOperation) { |
| write("not ", targetStartPosition); |
| } else if (BuiltinMetaModel.Int_Unary_Minus == eOperation || BuiltinMetaModel.Double_Unary_Minus == eOperation) { |
| write(opName, targetStartPosition); |
| } else if (BuiltinMetaModel.Int_Minus_Int == eOperation || BuiltinMetaModel.Int_Minus_Double == eOperation || BuiltinMetaModel.Double_Minus_Int == eOperation |
| || BuiltinMetaModel.Double_Minus_Double == eOperation || BuiltinMetaModel.Int_Plus_Int == eOperation || BuiltinMetaModel.Int_Plus_Double == eOperation |
| || BuiltinMetaModel.Double_Plus_Int == eOperation || BuiltinMetaModel.Double_Plus_Double == eOperation || BuiltinMetaModel.Int_Mult_Int == eOperation |
| || BuiltinMetaModel.Int_Mult_Double == eOperation || BuiltinMetaModel.Double_Mult_Int == eOperation || BuiltinMetaModel.Double_Mult_Double == eOperation |
| || BuiltinMetaModel.Int_Div_Double == eOperation || BuiltinMetaModel.Double_Div_Double == eOperation || BuiltinMetaModel.Double_Div_Int == eOperation |
| || BuiltinMetaModel.Int_Less == eOperation || BuiltinMetaModel.Int_LessOrEqual == eOperation || BuiltinMetaModel.Int_Greater == eOperation |
| || BuiltinMetaModel.Int_GreatOrEqual == eOperation || BuiltinMetaModel.EString_Plus_EJavaObject == eOperation) { |
| write(" "); |
| write(opName); |
| write(" "); |
| } else if (BuiltinMetaModel.Object_EQ == eOperation) { |
| write(" = "); |
| } else if (BuiltinMetaModel.Object_NotEQ == eOperation) { |
| write(" <> "); |
| } else { |
| throw new MigrationException(Type.UNSUPPORTED_EXPRESSION, resourceName, operationCall.getName(), "Incorrect infix operation: " + opName); |
| } |
| int parameterStartPosition = getCurrentPosition(); |
| List<EClassifier> parameterTypes = internalMigrateOperationCallParameters(operationCall, null); |
| if (operationCall.getParams().length == 1) { |
| encloseExpressionIntoParenthesis(operationCall.getParams()[0], operationPrecedence, parameterStartPosition, true); |
| } |
| |
| if (BuiltinMetaModel.EString_Plus_EJavaObject == eOperation) { |
| assert parameterTypes.size() == 1; |
| if (parameterTypes.get(0) != EcorePackage.eINSTANCE.getEString()) { |
| write(".repr()"); |
| } |
| } |
| return getTypedElementQvtType(eOperation); |
| } |
| |
| private OperationCall getInfixNotContains(EOperation eOperation, OperationCall operationCall) throws MigrationException { |
| if (operationCall.getParams().length == 1 && operationCall.getTarget() instanceof OperationCall) { |
| Integer intLiteral = getIntLiteralValue(operationCall.getParams()[0]); |
| if (intLiteral != null && ((eOperation == BuiltinMetaModel.Object_EQ && intLiteral == -1) || (eOperation == BuiltinMetaModel.Int_Less && intLiteral == 0))) { |
| return getIndexOfOpCall((OperationCall) operationCall.getTarget()); |
| } |
| } |
| return null; |
| } |
| |
| private Integer getIntLiteralValue(Expression expression) throws MigrationException { |
| if (expression instanceof IntegerLiteral) { |
| return new Integer(((IntegerLiteral) expression).getLiteralValue()); |
| } |
| if (expression instanceof OperationCall) { |
| OperationCall operationCall = (OperationCall) expression; |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(operationCall); |
| if (false == expressionTrace instanceof OperationCallTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL_TRACE, resourceName, operationCall, expressionTrace); |
| } |
| if (((OperationCallTrace) expressionTrace).getEOperation() == BuiltinMetaModel.Int_Unary_Minus) { |
| assert operationCall.getTarget() instanceof IntegerLiteral; |
| return new Integer("-" + ((IntegerLiteral) operationCall.getTarget()).getLiteralValue()); |
| } |
| } |
| return null; |
| } |
| |
| private OperationCall getIndexOfOpCall(OperationCall operationCall) throws MigrationException { |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(operationCall); |
| if (false == expressionTrace instanceof OperationCallTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL_TRACE, resourceName, operationCall, expressionTrace); |
| } |
| OperationCallTrace trace = (OperationCallTrace) expressionTrace; |
| return trace.getEOperation() == BuiltinMetaModel.List_IndexOf ? operationCall : null; |
| } |
| |
| private EClassifier internalMigrateInfixContains(OperationCall indexOfOperation) throws MigrationException { |
| assert indexOfOperation.getParams().length == 1; |
| EClassifier targetType = internalMigrateOperationCallTarget(indexOfOperation); |
| assert BuiltinMetaModelExt.isListType(targetType) || BuiltinMetaModelExt.isOrderedSetType(targetType); |
| write("->includes("); |
| internalMigrateOperationCallParameters(indexOfOperation, null); |
| write(")"); |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } |
| |
| private OperationCall getInfixContains(EOperation eOperation, OperationCall operationCall) throws MigrationException { |
| if (operationCall.getParams().length == 1 && operationCall.getTarget() instanceof OperationCall) { |
| Integer intLiteral = getIntLiteralValue(operationCall.getParams()[0]); |
| if (intLiteral != null |
| && ((eOperation == BuiltinMetaModel.Object_NotEQ && intLiteral == -1) || (eOperation == BuiltinMetaModel.Int_GreatOrEqual && intLiteral == 0) || (eOperation == BuiltinMetaModel.Int_Greater && intLiteral == -1))) { |
| return getIndexOfOpCall((OperationCall) operationCall.getTarget()); |
| } |
| } |
| return null; |
| } |
| |
| private EClassifier internalMigrateInfixInstanceof(TypeSelectExpression typeSelect) throws MigrationException { |
| assert typeSelect.getTarget() instanceof ListLiteral; |
| ListLiteral listLiteral = (ListLiteral) typeSelect.getTarget(); |
| assert listLiteral.getElements().length == 1; |
| migrateExpression(listLiteral.getElements()[0]); |
| write(".oclIsKindOf("); |
| write(typeManager.getQvtFQName(ctx.getTypeForName(typeSelect.getTypeLiteral().getValue()))); |
| write(")"); |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } |
| |
| private TypeSelectExpression getInfixNotInstanceOfTypeSelect(EOperation eOperation, OperationCall operationCall) { |
| if (operationCall.getParams().length == 1 && operationCall.getTarget() instanceof OperationCall) { |
| Expression paramExpression = operationCall.getParams()[0]; |
| OperationCall target = (OperationCall) operationCall.getTarget(); |
| if (eOperation == BuiltinMetaModel.Object_EQ && paramExpression instanceof IntegerLiteral && "0".equals(((IntegerLiteral) paramExpression).getLiteralValue()) |
| && "size".equals(target.getName().getValue()) && target.getTarget() instanceof TypeSelectExpression) { |
| TypeSelectExpression result = (TypeSelectExpression) target.getTarget(); |
| if (isInstanceofTypeselect(result)) { |
| return result; |
| } |
| } else if (eOperation == BuiltinMetaModel.Int_Less && paramExpression instanceof IntegerLiteral && "1".equals(((IntegerLiteral) paramExpression).getLiteralValue()) |
| && "size".equals(target.getName().getValue()) && target.getTarget() instanceof TypeSelectExpression) { |
| TypeSelectExpression result = (TypeSelectExpression) target.getTarget(); |
| if (isInstanceofTypeselect(result)) { |
| return result; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private TypeSelectExpression getInfixInstanceOfTypeSelect(EOperation eOperation, OperationCall operationCall) { |
| if (operationCall.getTarget() instanceof OperationCall) { |
| OperationCall target = (OperationCall) operationCall.getTarget(); |
| if (operationCall.getParams().length == 0) { |
| if (eOperation == BuiltinMetaModel.Boolean_NE && "isEmpty".equals(target.getName().getValue()) && target.getTarget() instanceof TypeSelectExpression) { |
| TypeSelectExpression result = (TypeSelectExpression) target.getTarget(); |
| if (isInstanceofTypeselect(result)) { |
| return result; |
| } |
| } |
| } else if (operationCall.getParams().length == 1) { |
| Expression paramExpression = operationCall.getParams()[0]; |
| if (eOperation == BuiltinMetaModel.Int_Greater && paramExpression instanceof IntegerLiteral && "0".equals(((IntegerLiteral) paramExpression).getLiteralValue()) |
| && "size".equals(target.getName().getValue()) && target.getTarget() instanceof TypeSelectExpression) { |
| TypeSelectExpression result = (TypeSelectExpression) target.getTarget(); |
| if (isInstanceofTypeselect(result)) { |
| return result; |
| } |
| } else if (eOperation == BuiltinMetaModel.Object_EQ && paramExpression instanceof BooleanLiteral && !Boolean.valueOf(((BooleanLiteral) paramExpression).getLiteralValue()) |
| && "isEmpty".equals(target.getName().getValue()) && target.getTarget() instanceof TypeSelectExpression) { |
| TypeSelectExpression result = (TypeSelectExpression) target.getTarget(); |
| if (isInstanceofTypeselect(result)) { |
| return result; |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @return true if passed OperationCall represents typeSelect operation |
| * called for the single element list literal expression like: |
| * |
| * {<var>}.typeSelect(<TypeLiteral>) |
| * |
| * usually repressenting .oclIsKindOf() operation. |
| */ |
| private boolean isInstanceofTypeselect(TypeSelectExpression typeSelect) { |
| if (typeSelect.getTarget() instanceof ListLiteral) { |
| ListLiteral listLiteral = (ListLiteral) typeSelect.getTarget(); |
| return listLiteral.getElements().length == 1; |
| } |
| return false; |
| } |
| |
| /** |
| * @param expression can be null |
| */ |
| private void encloseExpressionIntoParenthesis(Expression expression, int parentPrecedence, int placeholder, boolean ecloseIfEqualPrecenence) throws MigrationException { |
| int expressionPrecedence = getPrecedence(expression); |
| if (ecloseIfEqualPrecenence ? parentPrecedence <= expressionPrecedence : parentPrecedence < expressionPrecedence) { |
| write("(", placeholder); |
| write(")"); |
| } |
| } |
| |
| /** |
| * @return integer value representing position of this operation in a list |
| * from OCL specification (see 7.4.7. "Precedence Rules") |
| */ |
| private int getPrecedence(Expression expression) throws MigrationException { |
| if (expression instanceof OperationCall) { |
| OperationCall operationCall = (OperationCall) expression; |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(operationCall); |
| if (false == expressionTrace instanceof OperationCallTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_OPERATION_CALL_TRACE, resourceName, expression, expressionTrace); |
| } |
| OperationCallTrace trace = (OperationCallTrace) expressionTrace; |
| if (getInfixNotInstanceOfTypeSelect(trace.getEOperation(), operationCall) != null) { |
| /* |
| * this operation will be migrated as |
| * |
| * not <var>.oclIsKindOf(<TypeLiteral>) |
| * |
| * so having Boolean_NE precedence |
| */ |
| return 2; |
| } |
| |
| if (BuiltinMetaModel.Collection_IsEmpty == trace.getEOperation() && operationCall.getTarget() instanceof TypeSelectExpression |
| && isInstanceofTypeselect((TypeSelectExpression) operationCall.getTarget())) { |
| /* |
| * this operation will be migrated as |
| * |
| * not <var>.oclIsKindOf(<TypeLiteral>) |
| * |
| * so having Boolean_NE precedence |
| */ |
| return 2; |
| } |
| |
| if (getInfixNotContains(trace.getEOperation(), operationCall) != null) { |
| /* |
| * this operation will be migrated as |
| * |
| * not <var>.oclIsKindOf(<TypeLiteral>) |
| * |
| * so having Boolean_NE precedence |
| */ |
| return 2; |
| } |
| |
| if (trace.getEOperation() != null && infixOperations.contains(trace.getEOperation())) { |
| EOperation eOperation = trace.getEOperation(); |
| if (BuiltinMetaModel.Boolean_NE == eOperation || BuiltinMetaModel.Int_Unary_Minus == eOperation || BuiltinMetaModel.Double_Unary_Minus == eOperation) { |
| return 2; |
| } else if (BuiltinMetaModel.Int_Mult_Int == eOperation || BuiltinMetaModel.Int_Mult_Double == eOperation || BuiltinMetaModel.Double_Mult_Int == eOperation |
| || BuiltinMetaModel.Double_Mult_Double == eOperation || BuiltinMetaModel.Int_Div_Int == eOperation || BuiltinMetaModel.Int_Div_Double == eOperation |
| || BuiltinMetaModel.Double_Div_Int == eOperation || BuiltinMetaModel.Double_Div_Double == eOperation) { |
| return 3; |
| } else if (BuiltinMetaModel.Int_Minus_Int == eOperation || BuiltinMetaModel.Int_Minus_Double == eOperation || BuiltinMetaModel.Double_Minus_Int == eOperation |
| || BuiltinMetaModel.Double_Minus_Double == eOperation || BuiltinMetaModel.Int_Plus_Int == eOperation || BuiltinMetaModel.Int_Plus_Double == eOperation |
| || BuiltinMetaModel.Double_Plus_Int == eOperation || BuiltinMetaModel.Double_Plus_Double == eOperation || BuiltinMetaModel.EString_Plus_EJavaObject == eOperation) { |
| return 4; |
| } else if (BuiltinMetaModel.Int_Less == eOperation || BuiltinMetaModel.Int_LessOrEqual == eOperation || BuiltinMetaModel.Int_Greater == eOperation |
| || BuiltinMetaModel.Int_GreatOrEqual == eOperation) { |
| return 6; |
| } else if (BuiltinMetaModel.Object_EQ == eOperation || BuiltinMetaModel.Object_NotEQ == eOperation) { |
| return 7; |
| } |
| } |
| } else if (expression instanceof BooleanOperation) { |
| // and/or/xor is on the 9-th row in the list from OCL spec |
| return 8; |
| } |
| // highest precedence |
| return 0; |
| } |
| |
| private EClassifier internalMigrateOperationCallTarget(OperationCall operationCall) throws MigrationException { |
| if (operationCall.getTarget() != null) { |
| return migrateExpression(operationCall.getTarget()); |
| } else { |
| // getTarget() == null if it is an implicit self operation. |
| // TODO: check if it is working with XPand |
| write(Environment.SELF_VARIABLE_NAME); |
| return null; |
| } |
| } |
| |
| // TODO: check if "internalMigrateOperationCallParameters()" can be called |
| // with non-null parameters here (used to transform parameter collection |
| // types too) |
| private EClassifier internalMigrateCollectionOperationCall(OperationCallTrace trace, OperationCall operationCall) throws MigrationException { |
| EOperation eOperation = trace.getEOperation(); |
| assert eOperation != null; |
| EClassifier targetType = trace.getTargetType(); |
| assert targetType != null; |
| assert BuiltinMetaModel.isCollectionType(targetType); |
| EClassifier elementType = BuiltinMetaModel.getInnerType(targetType); |
| |
| if (BuiltinMetaModel.Collection_IsEmpty == eOperation && operationCall.getTarget() instanceof TypeSelectExpression && isInstanceofTypeselect((TypeSelectExpression) operationCall.getTarget())) { |
| write("not "); |
| return internalMigrateInfixInstanceof((TypeSelectExpression) operationCall.getTarget()); |
| } |
| |
| int expressionStartPosition = getCurrentPosition(); |
| if (BuiltinMetaModel.Collection_Clear != eOperation && BuiltinMetaModel.List_WithoutFirst != eOperation && BuiltinMetaModel.List_WithoutLast != eOperation) { |
| EClassifier targetQvtType = internalMigrateOperationCallTarget(operationCall); |
| if (targetQvtType != null && BuiltinMetaModel.isCollectionType(targetQvtType)) { |
| targetType = targetQvtType; |
| elementType = BuiltinMetaModel.getInnerType(targetQvtType); |
| } |
| } |
| |
| if (BuiltinMetaModel.Collection_Add == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->including("); |
| EClassifier parameterType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| write(")"); |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterType); |
| return internalMigrateToConcreteCollection(targetType, commonSuperType, expressionStartPosition, operationStartPosition); |
| } else if (BuiltinMetaModel.Collection_AddAll == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->union("); |
| EClassifier parameterCollectionType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| EClassifier parameterCollectionElementType = getCollectionElementType(parameterCollectionType); |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterCollectionElementType); |
| internalMigrateParameterCollectionToMain(parameterCollectionType, targetType); |
| write(")"); |
| return internalMigrateToConcreteCollection(targetType, commonSuperType, expressionStartPosition, operationStartPosition); |
| } else if (BuiltinMetaModel.Collection_Union == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->union("); |
| EClassifier parameterCollectionType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| EClassifier parameterCollectionElementType = getCollectionElementType(parameterCollectionType); |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterCollectionElementType); |
| internalMigrateParameterCollectionToList(parameterCollectionType); |
| write(")->asOrderedSet()->asSequence()"); |
| return internalMigrateToList(targetType, commonSuperType, expressionStartPosition, operationStartPosition); |
| } else if (BuiltinMetaModel.Collection_Intersect == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->intersection("); |
| EClassifier parameterCollectionType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| EClassifier parameterCollectionElementType = getCollectionElementType(parameterCollectionType); |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterCollectionElementType); |
| internalMigrateParameterCollectionToSet(parameterCollectionType); |
| write(")"); |
| return internalMigrateToSet(targetType, commonSuperType, expressionStartPosition, operationStartPosition); |
| } else if (BuiltinMetaModel.Collection_Without == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->-("); |
| EClassifier parameterCollectionType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| EClassifier parameterCollectionElementType = getCollectionElementType(parameterCollectionType); |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterCollectionElementType); |
| internalMigrateParameterCollectionToSet(parameterCollectionType); |
| write(")"); |
| return internalMigrateToSet(targetType, commonSuperType, expressionStartPosition, operationStartPosition); |
| } else if (BuiltinMetaModel.Collection_Contains == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->includes("); |
| EClassifier parameterType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| write(")"); |
| if (!BuiltinMetaModel.isAssignableFrom(elementType, parameterType)) { |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterType); |
| internalMigrateTypeSelect(typeManager.getQvtFQName(commonSuperType), expressionStartPosition, operationStartPosition); |
| } |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } else if (BuiltinMetaModel.Collection_ContainsAll == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->includesAll("); |
| EClassifier parameterCollectionType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| EClassifier parameterCollectionElementType = getCollectionElementType(parameterCollectionType); |
| write(")"); |
| if (!BuiltinMetaModel.isAssignableFrom(elementType, parameterCollectionElementType)) { |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterCollectionElementType); |
| internalMigrateTypeSelect(typeManager.getQvtFQName(commonSuperType), expressionStartPosition, operationStartPosition); |
| } |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } else if (BuiltinMetaModel.List_IndexOf == eOperation) { |
| int operationStartPosition = getCurrentPosition(); |
| write("->indexOf("); |
| EClassifier parameterType = getSingleParameterType(internalMigrateOperationCallParameters(operationCall, null)); |
| write(")"); |
| if (!BuiltinMetaModel.isAssignableFrom(elementType, parameterType)) { |
| EClassifier commonSuperType = BuiltinMetaModelExt.getCommonSuperType(elementType, parameterType); |
| internalMigrateTypeSelect(typeManager.getQvtFQName(commonSuperType), expressionStartPosition, operationStartPosition); |
| } |
| write("(", expressionStartPosition); |
| write(" - 1)"); |
| return EcorePackage.eINSTANCE.getEInt(); |
| } else if (BuiltinMetaModel.Collection_Clear == eOperation) { |
| EClassifier resultType; |
| if (BuiltinMetaModelExt.isSetType(targetType)) { |
| write("Set{}"); |
| resultType = BuiltinMetaModelExt.getSetType(elementType); |
| } else if (BuiltinMetaModelExt.isListType(targetType) || BuiltinMetaModelExt.isOrderedSetType(targetType)) { |
| write("Sequence{}"); |
| resultType = BuiltinMetaModelExt.getListType(elementType); |
| } else { |
| write("Bag{}"); |
| resultType = BuiltinMetaModelExt.getBagType(elementType); |
| } |
| // write("Bag{}"); |
| if (elementType != EcorePackage.eINSTANCE.getEJavaObject()) { |
| write("["); |
| write(typeManager.getQvtFQName(elementType)); |
| write("]"); |
| } |
| return resultType; |
| } else if (BuiltinMetaModel.Collection_Flatten == eOperation) { |
| EClassifier resultType = internalMigrateToConcreteCollection(targetType, elementType, expressionStartPosition, getCurrentPosition()); |
| write("->flatten()"); |
| if (BuiltinMetaModel.isCollectionType(elementType)) { |
| elementType = BuiltinMetaModel.getInnerType(elementType); |
| } |
| if (BuiltinMetaModelExt.isSetType(resultType) || BuiltinMetaModelExt.isOrderedSetType(resultType)) { |
| return BuiltinMetaModelExt.getSetType(elementType); |
| } else if (BuiltinMetaModelExt.isListType(resultType)) { |
| return BuiltinMetaModelExt.getListType(elementType); |
| } else { |
| return BuiltinMetaModelExt.getBagType(elementType); |
| } |
| } else if (BuiltinMetaModel.Collection_ToSet == eOperation) { |
| return internalMigrateToSet(targetType, elementType, expressionStartPosition, getCurrentPosition()); |
| } else if (BuiltinMetaModel.Collection_ToList == eOperation) { |
| return internalMigrateToList(targetType, elementType, expressionStartPosition); |
| } else if (BuiltinMetaModel.List_Get == eOperation) { |
| write("->at("); |
| internalMigrateOperationCallParameters(operationCall, null); |
| write(" + 1)"); |
| return elementType; |
| } else if (BuiltinMetaModel.List_WithoutFirst == eOperation) { |
| String varName = variableDispatcher.getNextVariableName(); |
| write("let "); |
| write(varName); |
| write(" = "); |
| targetType = internalMigrateOperationCallTarget(operationCall); |
| assert BuiltinMetaModelExt.isListType(targetType) || BuiltinMetaModelExt.isOrderedSetType(targetType); |
| boolean isOrderedSet = BuiltinMetaModelExt.isOrderedSetType(targetType); |
| write(" in "); |
| write("if "); |
| write(varName); |
| write("->size() < 2 then "); |
| if (isOrderedSet) { |
| write("OrderedSet"); |
| } else { |
| write("Sequence"); |
| } |
| write("{}"); |
| if (elementType != EcorePackage.eINSTANCE.getEJavaObject()) { |
| write("["); |
| write(typeManager.getQvtFQName(elementType)); |
| write("]"); |
| } |
| write(" else "); |
| write(varName); |
| write("->"); |
| if (isOrderedSet) { |
| write("subOrderedSet"); |
| } else { |
| write("subSequence"); |
| } |
| write("(2, "); |
| write(varName); |
| write("->size()) endif"); |
| return targetType; |
| } else if (BuiltinMetaModel.List_WithoutLast == eOperation) { |
| String varName = variableDispatcher.getNextVariableName(); |
| write("let "); |
| write(varName); |
| write(" = "); |
| targetType = internalMigrateOperationCallTarget(operationCall); |
| assert BuiltinMetaModelExt.isListType(targetType) || BuiltinMetaModelExt.isOrderedSetType(targetType); |
| boolean isOrderedSet = BuiltinMetaModelExt.isOrderedSetType(targetType); |
| write(" in "); |
| write("if "); |
| write(varName); |
| write("->size() < 2 then "); |
| if (isOrderedSet) { |
| write("OrderedSet"); |
| } else { |
| write("Sequence"); |
| } |
| write("{}"); |
| if (elementType != EcorePackage.eINSTANCE.getEJavaObject()) { |
| write("["); |
| write(typeManager.getQvtFQName(elementType)); |
| write("]"); |
| } |
| write(" else "); |
| write(varName); |
| write("->"); |
| if (isOrderedSet) { |
| write("subOrderedSet"); |
| } else { |
| write("subSequence"); |
| } |
| write("(1, "); |
| write(varName); |
| write("->size() - 1) endif"); |
| return targetType; |
| } else if (BuiltinMetaModel.List_PurgeDups == eOperation) { |
| if (BuiltinMetaModelExt.isListType(targetType)) { |
| write("->asOrderedSet()->asSequence()"); |
| } |
| return targetType; |
| } else { |
| /** |
| * .isEmpty() .size() .first() .last() |
| */ |
| assert operationCall.getParams().length == 0; |
| write("->"); |
| write(eOperation.getName()); |
| write("("); |
| internalMigrateOperationCallParameters(operationCall, null); |
| write(")"); |
| if (BuiltinMetaModel.Collection_IsEmpty == eOperation) { |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } else if (BuiltinMetaModel.Collection_Size == eOperation) { |
| return EcorePackage.eINSTANCE.getEInt(); |
| } else if (BuiltinMetaModel.List_First == eOperation || BuiltinMetaModel.List_Last == eOperation) { |
| return elementType; |
| } else { |
| throw new MigrationException(Type.UNSUPPORTED_COLLECTION_OPERATION, resourceName, operationCall.getName(), eOperation.getName()); |
| } |
| } |
| } |
| |
| private EClassifier getSingleParameterType(List<EClassifier> parameterTypes) { |
| assert parameterTypes.size() == 1; |
| return parameterTypes.get(0); |
| } |
| |
| private EClassifier getCollectionElementType(EClassifier collectionType) { |
| assert BuiltinMetaModel.isCollectionType(collectionType); |
| return BuiltinMetaModel.getInnerType(collectionType); |
| } |
| |
| private EClassifier internalMigrateToConcreteCollection(EClassifier collectionType, EClassifier requestedElementType, int expressionStartPosition, int expressionEndPosition) throws MigrationException { |
| assert BuiltinMetaModel.isCollectionType(collectionType); |
| EClassifier elementType = BuiltinMetaModel.getInnerType(collectionType); |
| if (BuiltinMetaModelExt.isAbstractCollectionType(collectionType)) { |
| String iteratorName = variableDispatcher.getNextIteratorName(); |
| StringBuilder sb = new StringBuilder(); |
| sb.append("->collect("); |
| sb.append(iteratorName); |
| sb.append(" | "); |
| sb.append(iteratorName); |
| if (requestedElementType != elementType) { |
| sb.append(".oclAsType("); |
| sb.append(typeManager.getQvtFQName(requestedElementType)); |
| sb.append(")"); |
| } |
| sb.append(")"); |
| write(sb, expressionEndPosition); |
| return BuiltinMetaModelExt.getBagType(requestedElementType); |
| } else if (requestedElementType != elementType) { |
| internalMigrateTypeSelect(typeManager.getQvtFQName(requestedElementType), expressionStartPosition, expressionEndPosition); |
| return BuiltinMetaModelExt.replaceCollectionElementType(collectionType, requestedElementType); |
| } |
| return collectionType; |
| } |
| |
| private EClassifier internalMigrateToSet(EClassifier collectionType, EClassifier elementSuperType, int expressionStartPosition, int expressionEndPosition) throws MigrationException { |
| if (!BuiltinMetaModelExt.isSetType(collectionType) && !BuiltinMetaModelExt.isOrderedSetType(collectionType)) { |
| if (BuiltinMetaModelExt.isListType(collectionType)) { |
| write("->asOrderedSet()", expressionEndPosition); |
| } else { |
| write("->asSet()", expressionEndPosition); |
| } |
| } |
| internalMigrateToConcreteCollection(collectionType, elementSuperType, expressionStartPosition, expressionEndPosition); |
| return BuiltinMetaModelExt.isOrderedSetType(collectionType) || BuiltinMetaModelExt.isListType(collectionType) ? BuiltinMetaModelExt.getOrderedSetType(elementSuperType) : BuiltinMetaModelExt.getSetType(elementSuperType); |
| } |
| |
| private EClassifier internalMigrateToList(EClassifier collectionType, EClassifier elementSuperType, int placeholder) throws MigrationException { |
| return internalMigrateToList(collectionType, elementSuperType, placeholder, getCurrentPosition()); |
| } |
| |
| private EClassifier internalMigrateToList(EClassifier collectionType, EClassifier elementSuperType, int expressionStartPosition, int expressionEndPosition) throws MigrationException { |
| if (!BuiltinMetaModelExt.isListType(collectionType)) { |
| write("->asSequence()", expressionEndPosition); |
| } |
| internalMigrateToConcreteCollection(collectionType, elementSuperType, expressionStartPosition, expressionEndPosition); |
| return BuiltinMetaModelExt.getListType(elementSuperType); |
| } |
| |
| private void internalMigrateParameterCollectionToMain(EClassifier parameterCollectionType, EClassifier mainCollectionType) { |
| assert BuiltinMetaModel.isCollectionType(parameterCollectionType); |
| assert BuiltinMetaModel.isCollectionType(mainCollectionType); |
| if (BuiltinMetaModelExt.isListType(mainCollectionType)) { |
| if (BuiltinMetaModelExt.isSetType(parameterCollectionType) || BuiltinMetaModelExt.isOrderedSetType(parameterCollectionType)) { |
| write("->asSequence()"); |
| } else if (BuiltinMetaModelExt.isAbstractCollectionType(parameterCollectionType)) { |
| internalMigrateCollectionToBag(); |
| write("->asSequence()"); |
| } |
| } else if (BuiltinMetaModelExt.isSetType(mainCollectionType) || BuiltinMetaModelExt.isOrderedSetType(mainCollectionType)) { |
| if (BuiltinMetaModelExt.isListType(parameterCollectionType) || BuiltinMetaModelExt.isBagType(parameterCollectionType)) { |
| write("->asSet()"); |
| } else if (BuiltinMetaModelExt.isAbstractCollectionType(parameterCollectionType)) { |
| internalMigrateCollectionToBag(); |
| write("->asSet()"); |
| } |
| } else { //For Bag/AbstractCollection (should be transformed to Bag) |
| if (BuiltinMetaModelExt.isListType(parameterCollectionType)) { |
| write("->asBag()"); |
| } else if (BuiltinMetaModelExt.isAbstractCollectionType(parameterCollectionType)) { |
| internalMigrateCollectionToBag(); |
| } |
| } |
| } |
| |
| private void internalMigrateParameterCollectionToSet(EClassifier parameterCollectionType) { |
| assert BuiltinMetaModel.isCollectionType(parameterCollectionType); |
| if (BuiltinMetaModelExt.isListType(parameterCollectionType) || BuiltinMetaModelExt.isBagType(parameterCollectionType)) { |
| write("->asSet()"); |
| } else if (BuiltinMetaModelExt.isAbstractCollectionType(parameterCollectionType)) { |
| internalMigrateCollectionToBag(); |
| write("->asSet()"); |
| } |
| } |
| |
| private void internalMigrateParameterCollectionToList(EClassifier parameterCollectionType) { |
| assert BuiltinMetaModel.isCollectionType(parameterCollectionType); |
| if (BuiltinMetaModelExt.isAbstractCollectionType(parameterCollectionType)) { |
| internalMigrateCollectionToBag(); |
| } |
| if (!BuiltinMetaModelExt.isListType(parameterCollectionType)) { |
| write("->asSequence()"); |
| } |
| } |
| |
| private boolean isCollectionOperation(OperationCallTrace trace) { |
| EOperation eOperation = trace.getEOperation(); |
| assert eOperation != null; |
| return collectionOperations.contains(eOperation); |
| } |
| |
| private EClassifier getTypedElementQvtType(ETypedElement typedElement) { |
| EClassifier type = typedElement.getEType(); |
| if (typedElement.isMany()) { |
| if (typedElement.isOrdered() && typedElement.isUnique()) { |
| type = BuiltinMetaModelExt.getOrderedSetType(type); |
| } else if (typedElement.isOrdered()) { |
| type = BuiltinMetaModelExt.getListType(type); |
| } else if (typedElement.isUnique()) { |
| type = BuiltinMetaModelExt.getSetType(type); |
| } else { |
| type = BuiltinMetaModelExt.getBagType(type); |
| } |
| } |
| return type == null ? BuiltinMetaModel.VOID : type; |
| } |
| |
| private void convertImplicitCollectProduct(EClassifier targetType) { |
| assert targetType != null; |
| if (!BuiltinMetaModelExt.isListType(targetType) && !BuiltinMetaModelExt.isOrderedSetType(targetType)) { |
| write("->asSequence()"); |
| } |
| } |
| |
| private List<EClassifier> internalMigrateOperationCallParameters(OperationCall operationCall, List<EClassifier> expectedParameterTypes) throws MigrationException { |
| assert expectedParameterTypes == null || operationCall.getParams().length == expectedParameterTypes.size(); |
| List<EClassifier> parameterTypes = new ArrayList<EClassifier>(); |
| for (int i = 0; i < operationCall.getParams().length; i++) { |
| if (i > 0) { |
| write(", "); |
| } |
| Expression parameter = operationCall.getParams()[i]; |
| if (operationCall.getTarget() != null && operationCall.getTarget().getLine() != parameter.getLine()) { |
| write(ExpressionMigrationFacade.LF); |
| } |
| parameterTypes.add(migrateExpression(parameter)); |
| if (expectedParameterTypes != null) { |
| internalConvertTypes(parameterTypes.get(i), expectedParameterTypes.get(i)); |
| } |
| } |
| return parameterTypes; |
| } |
| |
| private boolean isInfixOperation(OperationCallTrace trace) { |
| EOperation eOperation = trace.getEOperation(); |
| assert eOperation != null; |
| return infixOperations.contains(eOperation); |
| } |
| |
| private EClassifier migrateFeatureCall(FeatureCall featureCall) throws MigrationException { |
| ExpressionAnalyzeTrace expressionTrace = ctx.getTraces().get(featureCall); |
| if (false == expressionTrace instanceof FeatureCallTrace) { |
| throw new MigrationException(Type.UNSUPPORTED_FEATURE_CALL_TRACE, resourceName, featureCall, expressionTrace); |
| } |
| FeatureCallTrace trace = (FeatureCallTrace) expressionTrace; |
| switch (trace.getType()) { |
| case ENUM_LITERAL_REF: |
| EEnumLiteral enumLiteral = trace.getEnumLiteral(); |
| assert enumLiteral != null; |
| write(typeManager.getQvtFQName(enumLiteral)); |
| return enumLiteral.getEEnum(); |
| case ENV_VAR_REF: |
| write(modelManager.getName(featureCall, trace)); |
| EClassifier variableType = getEnvVariableType(featureCall.getName().getValue()); |
| return variableType != null ? variableType : trace.getResultType(); |
| case UNDESOLVED_TARGET_TYPE: |
| case UNSUPPORTED_CLASSIFIER_REF: |
| throw new MigrationException(Type.UNSUPPORTED_FEATURE_CALL, resourceName, featureCall.getName(), trace); |
| } |
| EClassifier targetType = trace.getTargetType(); |
| // featureCall.getTarget() == null for FeatureCall of implicit variable |
| // feature |
| if (featureCall.getTarget() != null) { |
| migrateExpression(featureCall.getTarget()); |
| // Skipping EnumLiteral.value/EnumLiteral.literal features |
| if (targetType instanceof EEnum && trace.getType() == FeatureCallTrace.Type.FEATURE_REF) { |
| if (skipEnumLiteralFeature(trace.getFeature())) { |
| return targetType; |
| } else if (addEnumLiteralStringRepresentation(trace.getFeature())) { |
| write(".repr()"); |
| return EcorePackage.eINSTANCE.getEString(); |
| } |
| } |
| write("."); |
| } else { |
| if (targetType instanceof EEnum && trace.getType() == FeatureCallTrace.Type.FEATURE_REF) { |
| if (skipEnumLiteralFeature(trace.getFeature())) { |
| write(Environment.SELF_VARIABLE_NAME); |
| return targetType; |
| } else if (addEnumLiteralStringRepresentation(trace.getFeature())) { |
| write(Environment.SELF_VARIABLE_NAME); |
| write(".repr()"); |
| return EcorePackage.eINSTANCE.getEString(); |
| } |
| } |
| if (FeatureCallTrace.Type.IMPLICIT_COLLECT_FEATURE_REF == trace.getType()) { |
| // implicit collect call without explicitly specified target - |
| // writing "self" to make it compilable |
| write(Environment.SELF_VARIABLE_NAME); |
| write("."); |
| } |
| } |
| write(modelManager.getName(featureCall, trace)); |
| assert targetType != null; |
| switch (trace.getType()) { |
| case FEATURE_REF: |
| if (BuiltinMetaModel.isParameterizedType(targetType)) { |
| throw new MigrationException(Type.UNSUPPORTED_EXPRESSION, resourceName, featureCall, "Attribute call is not supported for the collection types: " + targetType.toString() + "." + featureCall.getName().getValue()); |
| } |
| return getTypedElementQvtType(trace.getFeature()); |
| case IMPLICIT_COLLECT_FEATURE_REF: |
| if (!BuiltinMetaModel.isParameterizedType(targetType)) { |
| throw new MigrationException(Type.UNSUPPORTED_EXPRESSION, resourceName, featureCall, "Implicit collect is not supported for simple types: " + targetType.toString() + "." + featureCall.getName().getValue()); |
| } |
| convertImplicitCollectProduct(targetType); |
| return trace.getResultType(); |
| default: |
| throw new MigrationException(Type.UNSUPPORTED_FEATURE_CALL_TRACE, resourceName, featureCall,trace); |
| } |
| } |
| |
| private boolean addEnumLiteralStringRepresentation(EStructuralFeature feature) { |
| return EcorePackage.eINSTANCE.getENamedElement_Name() == feature; |
| } |
| |
| private boolean skipEnumLiteralFeature(EStructuralFeature feature) { |
| return EcorePackage.eINSTANCE.getEEnumLiteral_Value() == feature || EcorePackage.eINSTANCE.getEEnumLiteral_Literal() == feature; |
| } |
| |
| private void markReturnPosition() { |
| returnPosition = getCurrentPosition(); |
| } |
| |
| private int getCurrentPosition() { |
| return output.length(); |
| } |
| |
| private void write(CharSequence cs, int index) { |
| output.insert(index, cs); |
| } |
| |
| private void write(CharSequence cs) { |
| output.append(cs); |
| } |
| |
| private void pushContextWithVariable(String varName, EClassifier varType) { |
| qvtContexts.push(qvtContexts.peek().cloneWithVariable(varName, varType)); |
| } |
| |
| private EClassifier getEnvVariableType(String varName) { |
| return qvtContexts.peek().getVariableType(varName); |
| } |
| |
| /** |
| * This class was intended to store QVT env. variable types during |
| * expression migration. It is necessary for more intelligent QVT |
| * (collections) types transformation during expression migration. |
| * |
| * Only following methods can be used by clients: |
| * {@link ExecutionContext#cloneWithVariable(java.util.Collection)} |
| * {@link ExecutionContext#cloneWithVariable(org.eclipse.gmf.internal.xpand.expression.Variable...)} |
| * {@link ExecutionContext#cloneContext()} |
| */ |
| private static class QvtExecutionContext extends ExecutionContextImpl { |
| |
| public static QvtExecutionContext createNewContext(HashMap<String, EClassifier> envVariables) { |
| QvtExecutionContext result = new QvtExecutionContext(); |
| for (Entry<String, EClassifier> envVar : envVariables.entrySet()) { |
| result = result.cloneWithVariable(envVar.getKey(), envVar.getValue()); |
| } |
| return result; |
| } |
| |
| private QvtExecutionContext() { |
| super((ResourceManager) null); |
| } |
| |
| private QvtExecutionContext(QvtExecutionContext original) { |
| super(original); |
| } |
| |
| public QvtExecutionContext cloneWithVariable(String name, EClassifier type) { |
| return (QvtExecutionContext) super.cloneWithVariable(new Variable(name, type)); |
| } |
| |
| public EClassifier getVariableType(String name) { |
| Variable var = getVariable(name); |
| if (var != null) { |
| return (EClassifier) var.getValue(); |
| } |
| return null; |
| } |
| |
| @Override |
| public QvtExecutionContext cloneContext() { |
| return new QvtExecutionContext(this); |
| } |
| |
| @Override |
| public EClassifier[] findTypesForPrefix(String prefix) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void setContextClassLoader(ClassLoadContext classLoadContext) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Class<?> loadClass(String value) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public EClassifier getTypeForName(String name) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public ExecutionContext cloneWithResource(ResourceMarker ns) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public ResourceMarker currentResource() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Set<Extension> getAllExtensions() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Extension getExtension(String functionName, EClassifier[] parameterTypes) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public EvaluationListener getEvaluationListener() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void setEvaluationListener(EvaluationListener listener) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| } |
| |
| } |