/******************************************************************************* * Copyright (c) 2010, 2015 Willink Transformations and others. * 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: * E.D.Willink - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.pivot.utilities; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EObject; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.Annotation; import org.eclipse.ocl.pivot.BooleanLiteralExp; import org.eclipse.ocl.pivot.CallExp; import org.eclipse.ocl.pivot.CollectionLiteralExp; import org.eclipse.ocl.pivot.CollectionLiteralPart; import org.eclipse.ocl.pivot.CollectionType; import org.eclipse.ocl.pivot.Constraint; import org.eclipse.ocl.pivot.MapLiteralExp; import org.eclipse.ocl.pivot.MapLiteralPart; import org.eclipse.ocl.pivot.ShadowExp; import org.eclipse.ocl.pivot.Detail; import org.eclipse.ocl.pivot.EnumLiteralExp; import org.eclipse.ocl.pivot.ExpressionInOCL; import org.eclipse.ocl.pivot.Feature; import org.eclipse.ocl.pivot.IfExp; import org.eclipse.ocl.pivot.IntegerLiteralExp; import org.eclipse.ocl.pivot.InvalidLiteralExp; import org.eclipse.ocl.pivot.IteratorExp; import org.eclipse.ocl.pivot.LambdaType; import org.eclipse.ocl.pivot.LetExp; import org.eclipse.ocl.pivot.LoopExp; import org.eclipse.ocl.pivot.Model; import org.eclipse.ocl.pivot.NamedElement; import org.eclipse.ocl.pivot.NullLiteralExp; import org.eclipse.ocl.pivot.OCLExpression; import org.eclipse.ocl.pivot.Operation; import org.eclipse.ocl.pivot.OperationCallExp; import org.eclipse.ocl.pivot.OppositePropertyCallExp; import org.eclipse.ocl.pivot.PivotPackage; import org.eclipse.ocl.pivot.Precedence; import org.eclipse.ocl.pivot.PrimitiveType; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.PropertyCallExp; import org.eclipse.ocl.pivot.RealLiteralExp; import org.eclipse.ocl.pivot.StringLiteralExp; import org.eclipse.ocl.pivot.TemplateBinding; import org.eclipse.ocl.pivot.TemplateParameter; import org.eclipse.ocl.pivot.TemplateParameterSubstitution; import org.eclipse.ocl.pivot.TemplateSignature; import org.eclipse.ocl.pivot.TemplateableElement; import org.eclipse.ocl.pivot.TupleLiteralExp; import org.eclipse.ocl.pivot.TupleType; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.TypeExp; import org.eclipse.ocl.pivot.UnlimitedNaturalLiteralExp; import org.eclipse.ocl.pivot.Variable; import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.internal.utilities.AS2Moniker; import org.eclipse.ocl.pivot.internal.utilities.PivotConstantsInternal; import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; import org.eclipse.ocl.pivot.util.AbstractExtendingVisitor; import org.eclipse.ocl.pivot.util.Visitable; import org.eclipse.ocl.pivot.values.Unlimited; public class AS2MonikerVisitor extends AbstractExtendingVisitor<Object, AS2Moniker> implements PivotConstantsInternal { private static boolean initialized = false; @Deprecated // The TPS policy pursued here is suspect private static @Nullable Map<TemplateParameter, Type> getAllTemplateParameterSubstitutions(@Nullable Map<TemplateParameter, Type> map, @Nullable TemplateableElement templateableElement) { for (EObject eObject = templateableElement; eObject != null; eObject = eObject.eContainer()) { if (eObject instanceof TemplateableElement) { for (TemplateBinding templateBinding : ((TemplateableElement) eObject).getOwnedBindings()) { for (TemplateParameterSubstitution templateParameterSubstitution : templateBinding.getOwnedSubstitutions()) { if (map == null) { map = new HashMap<TemplateParameter, Type>(); } map.put(templateParameterSubstitution.getFormal(), templateParameterSubstitution.getActual()); } } } if (eObject instanceof org.eclipse.ocl.pivot.Class) { for (org.eclipse.ocl.pivot.Class superType : ((org.eclipse.ocl.pivot.Class)eObject).getSuperClasses()) { map = getAllTemplateParameterSubstitutions(map, superType); } } } return map; } public static void initialize() { if (!initialized) { initialized = true; roleNames.put(PivotPackage.Literals.LOOP_EXP__OWNED_BODY, "argument"); // roleNames.put(PivotPackage.Literals.EXPRESSION_IN_OCL__BODY_EXPRESSION, "ownedExpression"); /* roleNames.put(PivotPackage.Literals.CALL_EXP__SOURCE, "s"); roleNames.put(PivotPackage.Literals.CONSTRAINT__SPECIFICATION, "z"); roleNames.put(PivotPackage.Literals.EXPRESSION_IN_OCL__BODY_EXPRESSION, "x"); roleNames.put(PivotPackage.Literals.IF_EXP__CONDITION, "q"); roleNames.put(PivotPackage.Literals.IF_EXP__THEN_EXPRESSION, "t"); roleNames.put(PivotPackage.Literals.IF_EXP__ELSE_EXPRESSION, "f"); roleNames.put(PivotPackage.Literals.LET_EXP__IN, "i"); roleNames.put(PivotPackage.Literals.LET_EXP__VARIABLE, "v"); roleNames.put(PivotPackage.Literals.LOOP_EXP__BODY, "b"); roleNames.put(PivotPackage.Literals.LOOP_EXP__ITERATOR, "i"); roleNames.put(PivotPackage.Literals.OPERATION_CALL_EXP__ARGUMENT, "a"); roleNames.put(PivotPackage.Literals.VARIABLE__INIT_EXPRESSION, "i"); */ } } protected final @Nullable Map<TemplateParameter, Type> templateBindings; public AS2MonikerVisitor(@NonNull AS2Moniker context) { super(context); templateBindings = null; if (!initialized) { initialize(); } } public AS2MonikerVisitor(@NonNull AS2Moniker context, @Nullable Map<TemplateParameter, Type> templateBindings) { super(context); this.templateBindings = templateBindings; } public void appendExpPrefix(@NonNull NamedElement object) { EObject parent = object.eContainer(); if (parent instanceof CallExp) { CallExp callExpParent = (CallExp)parent; if (callExpParent.isIsImplicit()) { if (callExpParent instanceof IteratorExp) { // Bypass implicit collect if (callExpParent.getOwnedSource() == object) { context.appendElement(((IteratorExp)callExpParent).getOwnedBody()); context.append(MONIKER_SCOPE_SEPARATOR); context.appendRole(object); context.append(MONIKER_OPERATOR_SEPARATOR); return; } else { context.appendParent(callExpParent, MONIKER_SCOPE_SEPARATOR); context.appendRole(callExpParent); context.append(MONIKER_OPERATOR_SEPARATOR); return; } } else if (callExpParent.getOwnedSource() == object) { object = callExpParent; } } } context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.appendRole(object); context.append(MONIKER_OPERATOR_SEPARATOR); } @Override public String toString() { return context.toString(); } @Override public Object visitAnnotation(@NonNull Annotation object) { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.append(ANNOTATION_QUOTE); context.append(String.valueOf(object.getName())); context.append(ANNOTATION_QUOTE); Object container = object.eContainer().eGet(object.eContainingFeature()); if (container instanceof List<?>) { int index = 0; for (Object element : (List<?>)container) { if (element == object) { break; } if ((element instanceof Annotation) && (((Annotation)element).getName().equals(object.getName()))) { index++; } } if (index > 0) { context.append(index); } } return true; } @Override public Object visitBooleanLiteralExp(@NonNull BooleanLiteralExp object) { appendExpPrefix(object); context.append(Boolean.toString(object.isBooleanSymbol())); return true; } @Override public Object visitClass(org.eclipse.ocl.pivot.@NonNull Class object) { if (!object.getOwnedBindings().isEmpty()) { Type templateableClass = PivotUtil.getUnspecializedTemplateableElement(object); context.appendParent(templateableClass, MONIKER_SCOPE_SEPARATOR); context.appendName(templateableClass); context.appendTemplateBindings(object, templateBindings); } else if (object.eContainer() instanceof TemplateParameterSubstitution) { TemplateParameter formal = ((TemplateParameterSubstitution)object.eContainer()).getFormal(); int index = formal.getOwningSignature().getOwnedParameters().indexOf(formal); context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.append(WILDCARD_INDICATOR + index); } else { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.appendName(object); context.appendTemplateParameters(object); } if (object instanceof CollectionType) { CollectionType collectionType = (CollectionType)object; Number lower = collectionType.getLower(); Number upper = collectionType.getUpper(); if ((lower.longValue() != 0) || !(upper instanceof Unlimited)) { context.append("_" + lower); if (!(upper instanceof Unlimited)) { context.append("_" + upper); } } } return true; } @Override public Object visitCollectionLiteralExp(@NonNull CollectionLiteralExp object) { appendExpPrefix(object); context.appendName(object.getType()); return true; } @Override public Object visitCollectionLiteralPart(@NonNull CollectionLiteralPart object) { context.appendParent(object, MONIKER_PART_SEPARATOR); context.appendIndex(object); return true; } @Override public Object visitConstraint(@NonNull Constraint object) { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.append(PivotUtilInternal.getStereotype(object)); Object container = object.eContainer().eGet(object.eContainingFeature()); if (container instanceof List<?>) { int index = 0; String name2 = object.getName(); for (Object content : (List<?>)container) { if (content == object) { break; } if (content instanceof Constraint) { Constraint sibling = (Constraint) content; if (PivotUtilInternal.getStereotype(sibling).equals(PivotUtilInternal.getStereotype(object))) { String name1 = sibling.getName(); if (name1 != name2) { if ((name1 == null) || !name1.equals(name2)) { break; } } index++; } } } context.append(MONIKER_OPERATOR_SEPARATOR); if (name2 != null) { context.append(name2); } if (index != 0) { context.append(MONIKER_OPERATOR_SEPARATOR); context.append(index); } } return true; } @Override public Object visitDetail(@NonNull Detail object) { context.appendParent(object, BINDINGS_PREFIX); context.append(object.getName()); return true; } @Override public Object visitEnumLiteralExp(@NonNull EnumLiteralExp object) { appendExpPrefix(object); context.appendName(object.getReferredLiteral()); return true; } @Override public Object visitExpressionInOCL(@NonNull ExpressionInOCL object) { if (object.eContainer() != null) { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.appendRole(object); } else { context.append(MONIKER_ROOT_EXP); } return true; } @Override public Object visitIfExp(@NonNull IfExp object) { appendExpPrefix(object); context.append(MONIKER_IF_EXP); return true; } @Override public Object visitIntegerLiteralExp(@NonNull IntegerLiteralExp object) { appendExpPrefix(object); context.append(object.getIntegerSymbol().toString()); return true; } @Override public Object visitInvalidLiteralExp(@NonNull InvalidLiteralExp object) { appendExpPrefix(object); context.append(MONIKER_INVALID_LITERAL_EXP); return true; } @Override public Object visitLambdaType(@NonNull LambdaType object) { context.append(object.getName()); // context.appendTemplateParameters(object); Map<TemplateParameter, Type> bindings = getAllTemplateParameterSubstitutions(null, object); context.appendLambdaType(object.getContextType(), object.getParameterType(), object.getResultType(), bindings); return true; } @Override public Object visitLetExp(@NonNull LetExp object) { appendExpPrefix(object); context.append(MONIKER_LET_EXP); return true; } @Override public Object visitLoopExp(@NonNull LoopExp object) { appendExpPrefix(object); if (object.isIsImplicit()) { OCLExpression body = object.getOwnedBody(); if (body instanceof CallExp) { Feature referredFeature = PivotUtil.getReferredFeature((CallExp) body); context.appendName(referredFeature); return true; } } context.appendName(object.getReferredIteration()); return true; } @Override public Object visitMapLiteralExp(@NonNull MapLiteralExp object) { appendExpPrefix(object); context.appendName(object.getType()); return true; } @Override public Object visitMapLiteralPart(@NonNull MapLiteralPart object) { context.appendParent(object, MONIKER_PART_SEPARATOR); context.appendIndex(object); return true; } @Override public Object visitModel(@NonNull Model object) { context.append(MONIKER_ROOT); return true; } @Override public Object visitNamedElement(@NonNull NamedElement object) { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.appendName(object); return true; } @Override public Object visitNullLiteralExp(@NonNull NullLiteralExp object) { appendExpPrefix(object); context.append(MONIKER_NULL_LITERAL_EXP); return true; } @Override public Object visitOperation(@NonNull Operation object) { if (!object.getOwnedBindings().isEmpty()) { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.appendName(object); Map<TemplateParameter, Type> bindings = getAllTemplateParameterSubstitutions(null, object); if (templateBindings != null) { if (bindings == null) { bindings = templateBindings; } else { // FIXME merge templateBindings } } context.appendTemplateBindings(object, bindings); context.appendParameters(object, bindings); return true; } else { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); context.appendName(object); context.appendTemplateParameters(object); context.appendParameters(object, null); } return true; } @Override public Object visitOperationCallExp(@NonNull OperationCallExp object) { appendExpPrefix(object); context.appendName(object.getReferredOperation()); return true; } @Override public Object visitOppositePropertyCallExp(@NonNull OppositePropertyCallExp object) { appendExpPrefix(object); context.append("~"); context.appendName(object.getReferredProperty()); return true; } @Override public Object visitPackage(org.eclipse.ocl.pivot.@NonNull Package object) { // if (!object.hasMoniker()) { // throw new IllegalStateException("No moniker has been configured for " + object); // } context.append(PivotUtilInternal.getNsURI(object)); return true; } @Override public Object visitPrecedence(@NonNull Precedence object) { context.appendParent(object, PRECEDENCE_PREFIX); context.appendName(object); return true; } @Override public Object visitPrimitiveType(@NonNull PrimitiveType object) { context.appendName(object); return true; } @Override public Object visitPropertyCallExp(@NonNull PropertyCallExp object) { appendExpPrefix(object); context.appendName(object.getReferredProperty()); return true; } @Override public Object visitRealLiteralExp(@NonNull RealLiteralExp object) { appendExpPrefix(object); context.append(object.getRealSymbol().toString()); return true; } @Override public String visitShadowExp(@NonNull ShadowExp shadowExp) { appendExpPrefix(shadowExp); context.append(MONIKER_TUPLE_LITERAL_EXP); // appendQualifiedName(constructorExp.getReferredType()); // append("{");//$NON-NLS-1$ // String prefix = ""; // for (TupleLiteralPart part : constructorExp.getPart()) { // append(prefix); // safeVisit(part); // prefix = ", ";//$NON-NLS-1$ // } // append("}"); return null; } @Override public Object visitStringLiteralExp(@NonNull StringLiteralExp object) { appendExpPrefix(object); context.append(MONIKER_STRING_LITERAL_EXP); return true; } @Override public Object visitTemplateBinding(@NonNull TemplateBinding object) { TemplateSignature signature = object.getTemplateSignature(); if (signature != null) { context.appendElement(signature.getOwningElement()); } context.append(BINDINGS_PREFIX); return true; } @Override public Object visitTemplateParameter(@NonNull TemplateParameter object) { TemplateableElement owningTemplateElement = object.getOwningSignature().getOwningElement(); context.appendElement(owningTemplateElement); context.append(TEMPLATE_PARAMETER_PREFIX); context.appendName(object); return true; } @Override public Object visitTemplateParameterSubstitution(@NonNull TemplateParameterSubstitution object) { context.appendElement(object.getOwningBinding()); context.appendName(object.getFormal()); return true; } @Override public Object visitTemplateSignature(@NonNull TemplateSignature object) { context.appendParent(object, MONIKER_SCOPE_SEPARATOR); return true; } @Override public Object visitTupleLiteralExp(@NonNull TupleLiteralExp object) { appendExpPrefix(object); context.append(MONIKER_TUPLE_LITERAL_EXP); return true; } @Override public Object visitTupleType(@NonNull TupleType object) { List<Property> ownedAttributes = object.getOwnedProperties(); if (ownedAttributes.isEmpty()) { super.visitTupleType(object); } else { context.appendName(object); context.appendTupleType(ownedAttributes); } return true; } @Override public Object visitTypeExp(@NonNull TypeExp object) { appendExpPrefix(object); context.appendName(object.getReferredType()); return true; } @Override public Object visitUnlimitedNaturalLiteralExp(@NonNull UnlimitedNaturalLiteralExp object) { appendExpPrefix(object); Number unlimitedNaturalSymbol = object.getUnlimitedNaturalSymbol(); context.append(unlimitedNaturalSymbol.toString()); return true; } @Override public Object visitVariable(@NonNull Variable object) { appendExpPrefix(object); context.appendName(object); return true; } @Override public Object visitVariableExp(@NonNull VariableExp object) { appendExpPrefix(object); context.appendName(object.getReferredVariable()); return true; } @Override public Object visiting(@NonNull Visitable visitable) { throw new IllegalArgumentException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); } }