Skip to content

Commit

Permalink
Initial version of operation parameter typing with operation overload…
Browse files Browse the repository at this point in the history
… support #11
  • Loading branch information
ujhelyiz committed Sep 9, 2015
1 parent 0ff6fe4 commit f9a54fe
Show file tree
Hide file tree
Showing 9 changed files with 358 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ pattern operationsOfClass(cl : Classifier, op : Operation) {
DataType.ownedOperation(sup, op);
}

pattern operationsOfClassByName(cl : Classifier, op : Operation, name) {
find operationsOfClass(cl, op);
Operation.name(op, name);
}

pattern staticOperations(op : Operation) {
find operation(_, op);
Operation.isStatic(op, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
package com.incquerylabs.uml.ralf;

import org.eclipse.xtext.conversion.IValueConverterService;
import org.eclipse.xtext.linking.ILinkingService;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy;
import org.eclipse.xtext.resource.XtextResource;

import com.incquerylabs.uml.ralf.resource.ReducedAlfLanguageResource;
import com.incquerylabs.uml.ralf.scoping.ReducedAlfLanguageLinkingService;
import com.incquerylabs.uml.ralf.scoping.ReducedAlfLanguageQualifiedNameConverter;
import com.incquerylabs.uml.ralf.scoping.ReducedAlfLanguageResourceDescriptionStrategy;

Expand All @@ -34,6 +36,10 @@ public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() {
public Class<? extends XtextResource> bindXtextResource() {
return ReducedAlfLanguageResource.class;
}


@Override
public Class<? extends ILinkingService> bindILinkingService() {
return ReducedAlfLanguageLinkingService.class;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import com.incquerylabs.uml.ralf.reducedAlfLanguage.LeftHandSide
import com.incquerylabs.uml.ralf.reducedAlfLanguage.SignalDataExpression
import com.incquerylabs.uml.ralf.reducedAlfLanguage.ClassExtentExpression
import com.incquerylabs.uml.ralf.reducedAlfLanguage.CastExpression
import org.eclipse.uml2.uml.ParameterDirectionKind

inject extension TypeFactory typeFactory
inject extension UMLScopeHelper scopeHelper
Expand All @@ -91,6 +92,7 @@ judgments {
type |- EObject expression : output IUMLTypeReference
error "Cannot type " + stringRep(expression)
source expression
operationParametersType |- Operation op <: Tuple params
operationType |- Operation op <: Tuple params :> output IUMLTypeReference
error "Invalid parameter types " + stringRep(op)
source op
Expand Down Expand Up @@ -277,30 +279,42 @@ from {
/**
* Operation typing
*/
rule OperationTyping
G |- Operation op <: Tuple params :> IUMLTypeReference result
rule OperationTypingWith
G |- Operation op <: Tuple params
from {
fail
}
rule OperationTypingWithResult
G |- Operation op <: Tuple params :> IUMLTypeReference result
from {
G |- op <: params
G |- op : result
}
rule ParameterListTyping
G |- Operation op <: ExpressionList params :> IUMLTypeReference result
G |- Operation op <: ExpressionList params
from {
val opParamLength = op.ownedParameters.size
val declaredParameters = op.ownedParameters.filter[direction != ParameterDirectionKind.RETURN_LITERAL]

val opParamLength = declaredParameters.size
val paramLength = params.expressions.size
opParamLength == paramLength

for (var i = 0; i < paramLength; i++) {
val declaredType = op.ownedParameters.get(i).type.typeReference
val declaredType = declaredParameters.get(i).type.typeReference
G |- params.expressions.get(i) |> declaredType
}

G |- op : result
}

rule NamedTupleTyping
G |- Operation op <: NamedTuple params :> IUMLTypeReference result
from {

result = op.returnParameter.type.typeReference
G |- Operation op <: NamedTuple params
from {
val paramMap = <String, Expression> newHashMap(params.expressions.map[it.name -> it.expression])

op.ownedParameters.filter[direction != ParameterDirectionKind.RETURN_LITERAL].forEach[
val paramExpression = paramMap.get(it.name)
val declaredType = it.type.typeReference
G |- paramExpression |> declaredType
]
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package com.incquerylabs.uml.ralf.resource;

import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.diagnostics.DiagnosticMessage;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.linking.lazy.LazyLinkingResource;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.util.Triple;

import com.google.inject.Inject;
import com.incquerylabs.uml.ralf.scoping.IUMLContextProvider;
Expand All @@ -13,4 +21,39 @@ public class ReducedAlfLanguageResource extends LazyLinkingResource {
public IUMLContextProvider getUmlContextProvider() {
return umlContextProvider;
}

@Override
protected EObject getEObject(String uriFragment, Triple<EObject, EReference, INode> triple) throws AssertionError {
try {
return super.getEObject(uriFragment, triple);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("linkingService returned more than one object for fragment ")) {
List<EObject> linkedObjects = getLinkingService().getLinkedObjects(
triple.getFirst(),
triple.getSecond(),
triple.getThird());
createAndAddDiagnostic(triple, linkedObjects);
return null;
} else {
throw e;
}
}
}

protected void createAndAddDiagnostic(Triple<EObject, EReference, INode> triple, List<EObject> linkedObjects) {
if (isValidationDisabled())
return;

String messageText = "Cannot select between multiple linking candidates";

DiagnosticMessage message = new DiagnosticMessage(messageText, Severity.ERROR, org.eclipse.xtext.diagnostics.Diagnostic.LINKING_DIAGNOSTIC);

if (message != null) {
List<Diagnostic> list = getDiagnosticList(message);
Diagnostic diagnostic = createDiagnostic(triple, message);
if (!list.contains(diagnostic))
list.add(diagnostic);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public interface IUMLContextProvider {
Iterable<Property> getPropertiesOfClass(Classifier cl);
Iterable<Property> getAssociationsOfClass(Classifier cl);
Iterable<Operation> getOperationsOfClass(Classifier cl);
Set<Operation> getOperationCandidatesOfClass(Classifier cl, String name);
Iterable<Operation> getStaticOperations();

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.incquerylabs.uml.ralf.scoping;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Type;
import org.eclipse.xtext.linking.impl.DefaultLinkingService;
import org.eclipse.xtext.linking.impl.IllegalNodeException;
import org.eclipse.xtext.nodemodel.INode;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.incquerylabs.uml.ralf.ReducedAlfSystem;
import com.incquerylabs.uml.ralf.reducedAlfLanguage.Expression;
import com.incquerylabs.uml.ralf.reducedAlfLanguage.FeatureInvocationExpression;
import com.incquerylabs.uml.ralf.reducedAlfLanguage.Tuple;
import com.incquerylabs.uml.ralf.resource.ReducedAlfLanguageResource;

import it.xsemantics.runtime.Result;

public class ReducedAlfLanguageLinkingService extends DefaultLinkingService {


private boolean parametersMatch(List<Parameter> parameters, List<Parameter> otherParameters) {
if (parameters.size() != otherParameters.size()) {
return false;
}
for (int i = 0; i < parameters.size(); i++) {
Parameter param = parameters.get(i);
Parameter otherParam = otherParameters.get(i);
if (param.getDirection() != otherParam.getDirection() ||
param.getType().conformsTo(otherParam.getType())) {
return false;
}
}
return true;
}

private boolean operationRedefines(Operation op, Operation redefinedOp) {
if (op.getRedefinedOperations().contains(redefinedOp)) {
return true;
}
Class opClass = op.getClass_();
Class redefinedClass = redefinedOp.getClass_();
if (!opClass.allParents().contains(redefinedClass)) {
return false;
}
return parametersMatch(op.getOwnedParameters(), redefinedOp.getOwnedParameters());
}

private boolean operationMatchesParameters(Operation op, Tuple parameters) {
Result<Boolean> result = typeSystem.operationParametersType(op, parameters);
return !result.failed();
}

@Inject
ReducedAlfSystem typeSystem;

@Override
public List<EObject> getLinkedObjects(EObject context, EReference ref, INode node) throws IllegalNodeException {
List<EObject> linkedObjects = super.getLinkedObjects(context, ref, node);
//If the linked object is an operation, search for possible alternates
if (linkedObjects.size() == 1 && linkedObjects.get(0) instanceof Operation) {
Operation op = (Operation) linkedObjects.get(0);
IUMLContextProvider umlContext = ((ReducedAlfLanguageResource)context.eResource()).getUmlContextProvider();
Expression ctx = null;
Tuple parameters = null;
if (context instanceof FeatureInvocationExpression) {
FeatureInvocationExpression featureInvocationExpression = (FeatureInvocationExpression) context;
ctx = featureInvocationExpression.getContext();
parameters = featureInvocationExpression.getParameters();
}
Type contextType = typeSystem.type(ctx).getValue().getUmlType();
Set<Operation> candidates = umlContext.getOperationCandidatesOfClass((Classifier) contextType, op.getName());
if (candidates.size() > 1) {
linkedObjects = calculateBestCandidates(candidates, parameters);
}
}
return linkedObjects;
}

private List<EObject> calculateBestCandidates(Set<Operation> candidates, Tuple parameters) {
Set<Operation> remainingCandidates = Sets.newHashSet(candidates);

for (Operation op : candidates) {
Iterator<Operation> it = remainingCandidates.iterator();
while (it.hasNext()) {
Operation next = it.next();
if (operationRedefines(op, next)) {
it.remove();
}
}
}

Iterator<Operation> it = remainingCandidates.iterator();
while(it.hasNext()) {
Operation next = it.next();
if (!operationMatchesParameters(next, parameters)) {
it.remove();
}
}

return Lists.newArrayList(remainingCandidates);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,9 @@ class SimpleUMLContextProvider extends AbstractUMLContextProvider {
null
}

override getOperationCandidatesOfClass(Classifier cl, String name) {
newHashSet()
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.incquerylabs.emdw.umlintegration.queries.AssociationsOfClassifierMatcher;
import com.incquerylabs.emdw.umlintegration.queries.AttributesOfClassifierMatcher;
import com.incquerylabs.emdw.umlintegration.queries.CommonAncestorSignalMatcher;
import com.incquerylabs.emdw.umlintegration.queries.OperationsOfClassByNameMatcher;
import com.incquerylabs.emdw.umlintegration.queries.OperationsOfClassMatcher;
import com.incquerylabs.emdw.umlintegration.queries.SignalsMatcher;
import com.incquerylabs.emdw.umlintegration.queries.StaticOperationsMatcher;
Expand All @@ -58,6 +59,7 @@ protected IncQueryEngine getEngine() throws IncQueryException, IncQueryBaseExcep
SignalsMatcher.querySpecification(),
UmlTypesMatcher.querySpecification(),
OperationsOfClassMatcher.querySpecification(),
OperationsOfClassByNameMatcher.querySpecification(),
StaticOperationsMatcher.querySpecification(),
TriggerSignalOfBehaviorMatcher.querySpecification(),
CommonAncestorSignalMatcher.querySpecification()
Expand Down Expand Up @@ -181,6 +183,18 @@ public Set<Operation> getOperationsOfClass(Classifier cl, final boolean staticCl
return Sets.newHashSet();
}

@Override
public Set<Operation> getOperationCandidatesOfClass(Classifier cl, String name) {
try {
OperationsOfClassByNameMatcher matcher = OperationsOfClassByNameMatcher.on(getEngine());
return matcher.getAllValuesOfop(cl, name);
} catch (IncQueryException | IncQueryBaseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Sets.newHashSet();
}

@Override
public Signal getIncomingSignalType() {
try {
Expand Down
Loading

0 comments on commit f9a54fe

Please sign in to comment.