blob: be89d65f54725a9c1b730679a09e0ca880236c39 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 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.qvtd.xtext.qvtrelation.cs2as;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.PivotPackage;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal;
import org.eclipse.ocl.pivot.internal.scoping.EnvironmentView;
import org.eclipse.ocl.pivot.internal.scoping.ScopeFilter;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.SingletonIterator;
import org.eclipse.ocl.pivot.utilities.StringUtil;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS;
import org.eclipse.ocl.xtext.base.cs2as.CS2ASConversion;
import org.eclipse.ocl.xtext.basecs.ElementCS;
import org.eclipse.ocl.xtext.basecs.ModelElementCS;
import org.eclipse.ocl.xtext.basecs.PathNameCS;
import org.eclipse.ocl.xtext.essentialocl.cs2as.ImplicitSourceTypeIterator;
import org.eclipse.ocl.xtext.essentialocl.cs2as.ImplicitSourceVariableIterator;
import org.eclipse.ocl.xtext.essentialoclcs.AbstractNameExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.ExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.NameExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.NavigatingArgCS;
import org.eclipse.ocl.xtext.essentialoclcs.NavigationRole;
import org.eclipse.ocl.xtext.essentialoclcs.RoundBracketedClauseCS;
import org.eclipse.qvtd.pivot.qvtbase.Domain;
import org.eclipse.qvtd.pivot.qvtbase.Function;
import org.eclipse.qvtd.pivot.qvtbase.Rule;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtrelation.QVTrelationPackage;
import org.eclipse.qvtd.pivot.qvtrelation.Relation;
import org.eclipse.qvtd.pivot.qvtrelation.RelationCallExp;
import org.eclipse.qvtd.pivot.qvtrelation.RelationDomain;
import org.eclipse.qvtd.pivot.qvtrelation.RelationDomainAssignment;
import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil;
import org.eclipse.qvtd.pivot.qvttemplate.CollectionTemplateExp;
import org.eclipse.qvtd.pivot.qvttemplate.ObjectTemplateExp;
import org.eclipse.qvtd.xtext.qvtrelationcs.CollectionTemplateCS;
import org.eclipse.qvtd.xtext.qvtrelationcs.DefaultValueCS;
import org.eclipse.qvtd.xtext.qvtrelationcs.ObjectTemplateCS;
import org.eclipse.qvtd.xtext.qvtrelationcs.TransformationCS;
import org.eclipse.qvtd.xtext.qvtrelationcs.util.AbstractQVTrelationCSLeft2RightVisitor;
public class QVTrelationCSLeft2RightVisitor extends AbstractQVTrelationCSLeft2RightVisitor
{
private static final class OperationOrRuleFilter implements ScopeFilter
{
public static OperationOrRuleFilter INSTANCE = new OperationOrRuleFilter();
@Override
public boolean matches(@NonNull EnvironmentView environmentView, @NonNull Object object) {
return (object instanceof Operation) || (object instanceof Rule);
}
}
public static class ResolvedRuleInvocation implements Invocations
{
protected final @NonNull Rule invocation;
public ResolvedRuleInvocation(@NonNull Rule invocation) {
this.invocation = invocation;
}
@Override
public @NonNull NamedElement getSingleResult() {
return invocation;
}
@Override
public @NonNull Type getSourceType() {
return ClassUtil.nonNullState(invocation.getTransformation());
}
@Override
public Iterator<NamedElement> iterator() {
return new SingletonIterator<NamedElement>(invocation);
}
}
public QVTrelationCSLeft2RightVisitor(@NonNull CS2ASConversion context) {
super(context);
}
@Override
protected @NonNull ImplicitSourceVariableIterator createImplicitSourceVariableIterator(@NonNull ModelElementCS csElement) {
return new ImplicitSourceVariableIterator(csElement)
{
@Override
protected boolean doNext(@NonNull ElementCS csParent, @NonNull ElementCS csChild) {
if (csParent instanceof TransformationCS) {
Transformation asContext = PivotUtil.getPivot(Transformation.class, (TransformationCS)csParent);
if (asContext != null) {
addNext(QVTbaseUtil.getContextVariable(standardLibrary, asContext));
}
return DONE; // no more parents
}
else {
return super.doNext(csParent, csChild);
}
}
};
}
@Override
protected ImplicitSourceTypeIterator createImplicitSourceTypeIterator(@NonNull ElementCS csElement) {
return new ImplicitSourceTypeIterator(csElement)
{
@Override
protected boolean doNext(@NonNull ElementCS csParent, @NonNull ElementCS csChild) {
if (csParent instanceof TransformationCS) {
Transformation asContext = PivotUtil.getPivot(Transformation.class, (TransformationCS)csParent);
if (asContext != null) {
addNext(asContext);
}
return DONE; // no more parents
}
else {
return super.doNext(csParent, csChild);
}
}
};
}
private @Nullable Relation getBestRelation(@NonNull Invocations invocations) {
for (NamedElement invocation : invocations) {
if (invocation instanceof Relation) {
return (Relation)invocation;
}
}
return null;
}
private @Nullable Function getBestFunction(@NonNull Invocations invocations) {
for (NamedElement invocation : invocations) {
if (invocation instanceof Function) {
return (Function)invocation;
}
}
return null;
}
@Override
protected @Nullable Invocations getInvocations(@NonNull Type asType, @Nullable Type asTypeValue, @NonNull String name, int iteratorCount, int expressionCount) {
if (asType instanceof Transformation) {
Rule rule = NameUtil.getNameable(((Transformation)asType).getRule(), name);
if (rule != null) {
return new ResolvedRuleInvocation(rule);
}
Operation function = NameUtil.getNameable(((Transformation)asType).getOwnedOperations(), name);
if (function != null) {
return new ResolvedInvocation(function);
}
return null;
}
return super.getInvocations(asType, asTypeValue, name, iteratorCount, expressionCount);
}
@Override
protected @Nullable OCLExpression resolveBestInvocation(@Nullable OCLExpression sourceExp, @NonNull RoundBracketedClauseCS csRoundBracketedClause, @NonNull Invocations invocations) {
AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp();
if (sourceExp == null) {
Relation relation = getBestRelation(invocations);
if (relation != null) {
@NonNull RelationCallExp relationCallExp = context.refreshModelElement(RelationCallExp.class, QVTrelationPackage.Literals.RELATION_CALL_EXP, csNameExp);
relationCallExp.setReferredRelation(relation);
context.setType(relationCallExp, standardLibrary.getBooleanType(), true);
List<Variable> rootVariables = QVTrelationUtil.getRootVariables(relation);
resolveRelationArgumentTypes(rootVariables, csRoundBracketedClause);
resolveRelationArguments(csRoundBracketedClause, null, relation, relationCallExp);
return relationCallExp;
}
Function function = getBestFunction(invocations);
if (function != null) {
// Operation baseOperation = metamodelManager.resolveBaseOperation(function);
OperationCallExp operationCallExp = context.refreshModelElement(OperationCallExp.class, PivotPackage.Literals.OPERATION_CALL_EXP, csNameExp);
context.setReferredOperation(operationCallExp, function);
context.setType(operationCallExp, function.getType(), function.isIsRequired());
resolveOperationArgumentTypes(function.getOwnedParameters(), csRoundBracketedClause);
resolveOperationArguments(csRoundBracketedClause, function, operationCallExp);
return operationCallExp;
}
}
return super.resolveBestInvocation(sourceExp, csRoundBracketedClause, invocations);
}
@Override
protected @NonNull OCLExpression resolveInvocation(@Nullable OCLExpression sourceExp,@NonNull RoundBracketedClauseCS csRoundBracketedClause) {
AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp();
PathNameCS csPathName = csNameExp.getOwnedPathName();
if (csPathName != null) { // This isn't actually needed but it should be.
CS2AS.setElementType(csPathName, PivotPackage.Literals.NAMED_ELEMENT, csNameExp, OperationOrRuleFilter.INSTANCE);
}
return super.resolveInvocation(sourceExp, csRoundBracketedClause);
}
protected void resolveRelationArguments(@NonNull RoundBracketedClauseCS csRoundBracketedClause, @Nullable OCLExpression source,
@NonNull Relation relation, @NonNull RelationCallExp relationCallExp) {
@SuppressWarnings("null")@NonNull AbstractNameExpCS csNameExp = csRoundBracketedClause.getOwningNameExp();
List<OCLExpression> pivotArguments = new ArrayList<OCLExpression>();
List<NavigatingArgCS> csArguments = csRoundBracketedClause.getOwnedArguments();
int patternsCount = 0;
for (Domain asDomain : relation.getDomain()) {
if (asDomain instanceof RelationDomain) {
patternsCount += ((RelationDomain)asDomain).getPattern().size();
}
}
int csArgumentCount = csArguments.size();
if (csArgumentCount > 0) {
if (csArguments.get(0).getRole() != NavigationRole.EXPRESSION) {
context.addDiagnostic(csNameExp, "Relation calls can only specify expressions");
}
for (int argIndex = 0; argIndex < csArgumentCount; argIndex++) {
NavigatingArgCS csArgument = csArguments.get(argIndex);
if (csArgument.getOwnedInitExpression() != null) {
context.addDiagnostic(csArgument, "Unexpected initializer for expression");
}
if (csArgument.getOwnedType() != null) {
context.addDiagnostic(csArgument, "Unexpected type for expression");
}
OCLExpression arg = context.visitLeft2Right(OCLExpression.class, csArgument);
if (arg != null) {
pivotArguments.add(arg);
}
}
}
if ((csArgumentCount != patternsCount) && (relation != standardLibrary.getOclInvalidOperation())) {
String boundMessage = StringUtil.bind(PivotMessagesInternal.MismatchedArgumentCount_ERROR_, csArgumentCount, patternsCount);
context.addDiagnostic(csNameExp, boundMessage);
}
context.refreshList(relationCallExp.getArgument(), pivotArguments);
}
protected void resolveRelationArgumentTypes(@Nullable List<Variable> rootVariables, @NonNull RoundBracketedClauseCS csRoundBracketedClause) {
int argIndex = 0;
for (NavigatingArgCS csArgument : csRoundBracketedClause.getOwnedArguments()) {
if (csArgument.getRole() == NavigationRole.ITERATOR) {
break;
}
else if (csArgument.getRole() == NavigationRole.ACCUMULATOR) {
break;
}
else if (csArgument.getRole() == NavigationRole.EXPRESSION) {
ExpCS csName = csArgument.getOwnedNameExpression();
if (csName != null) {
OCLExpression arg = null;
boolean isType = false;
if (csName instanceof NameExpCS) {
if ((rootVariables != null) && argIndex < rootVariables.size()) {
Variable rootVariable = rootVariables.get(argIndex);
if (/*rootVariable.isTypeof() ||*/ (rootVariable.getTypeId() == standardLibrary.getOclTypeType().getTypeId())) {
isType = true;
NameExpCS csNameExp = (NameExpCS)csName;
PathNameCS csPathName = csNameExp.getOwnedPathName();
Type type = context.getConverter().lookupType(csNameExp, ClassUtil.nonNullState(csPathName));
if (type != null) {
arg = resolveTypeExp(csNameExp, type);
}
}
}
}
if (!isType) {
arg = context.visitLeft2Right(OCLExpression.class, csName);
}
if (arg != null) {
context.installPivotUsage(csArgument, arg);
}
}
argIndex++;
}
}
}
@Override
public Element visitCollectionTemplateCS(@NonNull CollectionTemplateCS csElement) {
return PivotUtil.getPivot(CollectionTemplateExp.class, csElement);
}
@Override
public Element visitDefaultValueCS(@NonNull DefaultValueCS csElement) {
RelationDomainAssignment pivotElement = PivotUtil.getPivot(RelationDomainAssignment.class, csElement);
return pivotElement;
}
@Override
public Element visitObjectTemplateCS(@NonNull ObjectTemplateCS csElement) {
return PivotUtil.getPivot(ObjectTemplateExp.class, csElement);
}
}