Skip to content

Commit 3942eec

Browse files
committed
Add type calculator for collect operation
1 parent e598e37 commit 3942eec

File tree

7 files changed

+76
-112
lines changed

7 files changed

+76
-112
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.eclipse.epsilon.eol.execute.operations;
2+
3+
import org.eclipse.epsilon.eol.staticanalyser.types.EolType;
4+
5+
public interface ITypeCalculator {
6+
public EolType calculateType(EolType contextType, EolType expressionType);
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.eclipse.epsilon.eol.execute.operations;
2+
3+
import java.lang.annotation.Retention;
4+
import java.lang.annotation.RetentionPolicy;
5+
6+
@Retention(RetentionPolicy.RUNTIME)
7+
public @interface TypeCalculator {
8+
Class<? extends ITypeCalculator> klass();
9+
}

plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/execute/operations/declarative/CollectOperation.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
import org.eclipse.epsilon.eol.dom.Parameter;
1717
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
1818
import org.eclipse.epsilon.eol.execute.context.IEolContext;
19+
import org.eclipse.epsilon.eol.execute.operations.TypeCalculator;
1920
import org.eclipse.epsilon.eol.function.CheckedEolFunction;
2021
import org.eclipse.epsilon.eol.types.EolBag;
2122
import org.eclipse.epsilon.eol.types.EolCollectionType;
2223
import org.eclipse.epsilon.eol.types.EolSequence;
2324

25+
@TypeCalculator(klass=CollectTypeCalculator.class)
2426
public class CollectOperation extends FirstOrderOperation {
2527

2628
@Override
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.eclipse.epsilon.eol.execute.operations.declarative;
2+
3+
import org.eclipse.epsilon.eol.execute.operations.ITypeCalculator;
4+
import org.eclipse.epsilon.eol.staticanalyser.types.EolCollectionType;
5+
import org.eclipse.epsilon.eol.staticanalyser.types.EolType;
6+
7+
public class CollectTypeCalculator implements ITypeCalculator {
8+
9+
@Override
10+
public EolType calculateType(EolType contextType, EolType expressionType) {
11+
String collectionName = ((EolCollectionType)contextType).getName();
12+
return new EolCollectionType(collectionName, expressionType);
13+
}
14+
15+
}

plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/staticanalyser/EolStaticAnalyser.java

Lines changed: 39 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
import org.eclipse.epsilon.eol.dom.NotOperatorExpression;
6666
import org.eclipse.epsilon.eol.dom.Operation;
6767
import org.eclipse.epsilon.eol.dom.OperationCallExpression;
68-
import org.eclipse.epsilon.eol.dom.OperationList;
6968
import org.eclipse.epsilon.eol.dom.OperatorExpression;
7069
import org.eclipse.epsilon.eol.dom.OrOperatorExpression;
7170
import org.eclipse.epsilon.eol.dom.Parameter;
@@ -88,6 +87,8 @@
8887
import org.eclipse.epsilon.eol.dom.XorOperatorExpression;
8988
import org.eclipse.epsilon.eol.staticanalyser.execute.context.FrameStack;
9089
import org.eclipse.epsilon.eol.execute.context.FrameType;
90+
import org.eclipse.epsilon.eol.execute.operations.AbstractOperation;
91+
import org.eclipse.epsilon.eol.execute.operations.TypeCalculator;
9192
import org.eclipse.epsilon.eol.execute.operations.contributors.OperationContributor;
9293
import org.eclipse.epsilon.eol.staticanalyser.execute.context.Variable;
9394
import org.eclipse.epsilon.eol.m3.MetaClass;
@@ -259,124 +260,50 @@ public void visit(ExpressionStatement expressionStatement) {
259260
expressionStatement.getExpression().accept(this);
260261

261262
}
262-
263+
263264
@Override
264265
public void visit(FirstOrderOperationCallExpression firstOrderOperationCallExpression) {
265-
OperationList builtinOperations = new OperationList();
266-
Expression targetExpression = firstOrderOperationCallExpression.getTargetExpression();
267-
EolType contextType = null;
268-
String name = firstOrderOperationCallExpression.getNameExpression().getName();
269-
270-
for (Operation op : ((EolModule) module).getOperations())
271-
if (op.getAnnotation("firstorder") != null)
272-
builtinOperations.add(op);
266+
String name = firstOrderOperationCallExpression.getName();
267+
AbstractOperation operation = context.operationFactory.getOperationFor(name);
268+
if (operation == null) {
269+
errors.add(new ModuleMarker(firstOrderOperationCallExpression.getNameExpression(),
270+
"Undefined first order operation " + name, Severity.Error));
271+
return;
272+
};
273+
TypeCalculator tc = operation.getClass().getAnnotation(TypeCalculator.class);
274+
if (tc == null) {
275+
setResolvedType(firstOrderOperationCallExpression, EolAnyType.Instance);
276+
return;
277+
}
278+
273279

280+
Expression targetExpression = firstOrderOperationCallExpression.getTargetExpression();
274281
targetExpression.accept(this);
275-
276-
if (getResolvedType(targetExpression) instanceof EolCollectionType) {
277-
contextType = ((EolCollectionType) getResolvedType(targetExpression)).getContentType();
278-
} else if (getResolvedType(targetExpression) == EolAnyType.Instance) {
279-
contextType = getResolvedType(targetExpression);
282+
EolType contextType = getResolvedType(targetExpression);
283+
if (!(contextType instanceof EolCollectionType)) {
284+
contextType = new EolCollectionType("Sequence", contextType);
280285
}
281286

282-
if (name.startsWith("sequential"))
283-
name = name.substring(10);
284-
else if (name.startsWith("parallel"))
285-
name = name.substring(8);
286-
287-
if (contextType != null) {
288-
context.getFrameStack().enterLocal(FrameType.UNPROTECTED, firstOrderOperationCallExpression);
289-
Parameter parameter = firstOrderOperationCallExpression.getParameters().get(0);
290-
291-
visit(parameter, false);
292-
293-
if (parameter.isExplicitlyTyped()) {
294-
// TODO: Check that the type of the parameter is a subtype of the type of the
295-
// collection
296-
contextType = getType(parameter);
297-
EolType target = ((EolCollectionType) getResolvedType(targetExpression)).getContentType();
298-
EolType param = contextType;
299-
while (!(param.equals(target))) {
300-
param = getParentType(param);
301-
if (param instanceof EolAnyType) {
302-
// context.addErrorMarker(parameter, );
303-
errors.add(new ModuleMarker(parameter, "The parameter must be instance of " + target.getName(),
304-
Severity.Error));
305-
306-
break;
307-
}
308-
}
309-
} else {
310-
// context.getFrameStack().put(parameter.getName(), contextType);
311-
if (getResolvedType(targetExpression) instanceof EolCollectionType) {
312-
313-
parameter.setTypeExpression(new TypeExpression(
314-
((EolCollectionType) getResolvedType(targetExpression)).getContentType().getName()));
315-
316-
setResolvedType(parameter.getTypeExpression(),
317-
((EolCollectionType) getResolvedType(targetExpression)).getContentType());
318-
} else {
319-
parameter.setTypeExpression(new TypeExpression("Any"));
320-
setResolvedType(parameter.getTypeExpression(), EolAnyType.Instance);
321-
}
322-
setType(parameter, getResolvedType(parameter.getTypeExpression()));
323-
parameter.getTypeExpression().setName(getResolvedType(parameter.getTypeExpression()).toString());
324-
contextType = getType(parameter);
325-
}
326-
327-
context.getFrameStack().put(new Variable(parameter.getName(), getType(parameter)));
328-
329-
Expression expression = firstOrderOperationCallExpression.getExpressions().get(0);
330-
expression.accept(this);
331-
332-
context.getFrameStack().leaveLocal(firstOrderOperationCallExpression);
333-
334-
if (StringUtil.isOneOf(name, "select", "reject", "rejectOne", "closure", "sortBy")) {
335-
setResolvedType(firstOrderOperationCallExpression, new EolCollectionType("Collection", contextType));
336-
} else if (name.equals("selectOne")) {
337-
setResolvedType(firstOrderOperationCallExpression, contextType);
338-
} else if (name.equals("collect")) {
339-
Operation firstOrder = builtinOperations.getOperation(name);
340-
firstOrder.getReturnTypeExpression().accept(this);
341-
setResolvedType(firstOrder.getReturnTypeExpression(), getResolvedType(targetExpression));
342-
343-
if (!(getResolvedType(firstOrder.getReturnTypeExpression()) instanceof EolAnyType))
344-
((EolCollectionType) getResolvedType(firstOrder.getReturnTypeExpression()))
345-
.setContentType(getResolvedType(firstOrderOperationCallExpression.getExpressions().get(0)));
346-
347-
setResolvedType(firstOrderOperationCallExpression,
348-
new EolCollectionType(getResolvedType(targetExpression).getName(),
349-
getResolvedType(firstOrderOperationCallExpression.getExpressions().get(0))));
350-
351-
} else if (StringUtil.isOneOf(name, "exists", "forAll", "one", "none", "nMatch")) {
352-
setResolvedType(firstOrderOperationCallExpression, EolPrimitiveType.Boolean);
353-
} else if (name.equals("aggregate")) {
354-
if (firstOrderOperationCallExpression.getExpressions().size() == 2) {
355-
Expression valueExpression = firstOrderOperationCallExpression.getExpressions().get(1);
356-
valueExpression.accept(this);
357-
358-
setResolvedType(firstOrderOperationCallExpression,
359-
new EolMapType(getResolvedType(expression), getResolvedType(valueExpression)));
360-
} else {
361-
errors.add(new ModuleMarker(firstOrderOperationCallExpression.getNameExpression(),
362-
"Aggregate requires a key and a value expression", Severity.Error));
363-
364-
}
365-
} else if (name.equals("mapBy")) {
366-
setResolvedType(firstOrderOperationCallExpression,
367-
new EolMapType(getResolvedType(expression), new EolCollectionType("Sequence", contextType)));
368-
} else if (name.equals("sortBy")) {
369-
setResolvedType(firstOrderOperationCallExpression, new EolCollectionType("Sequence", contextType));
370-
}
371-
if (StringUtil.isOneOf(name, "select", "selectOne", "reject", "rejectOne", "exists", "one", "none",
372-
"forAll", "closure") && getResolvedType(expression).isNot(EolPrimitiveType.Boolean)) {
287+
Parameter parameter = firstOrderOperationCallExpression.getParameters().get(0);
288+
parameter.accept(this);
289+
EolType parameterType = (EolType) parameter.getData().get("type");
290+
if (parameterType.equals(EolAnyType.Instance)) {
291+
parameterType = ((EolCollectionType) contextType).getContentType();
292+
}
373293

374-
errors.add(new ModuleMarker(expression, "Expression should return a Boolean but returns a "
375-
+ getResolvedType(expression).getName() + " instead", Severity.Error));
376-
}
377-
} else {
378-
errors.add(new ModuleMarker(firstOrderOperationCallExpression.getNameExpression(),
379-
"Operation " + name + " only applies to collections", Severity.Error));
294+
context.getFrameStack().enterLocal(FrameType.UNPROTECTED, firstOrderOperationCallExpression,
295+
new Variable(parameter.getName(), parameterType));
296+
Expression expression = firstOrderOperationCallExpression.getExpressions().get(0);
297+
expression.accept(this);
298+
EolType expressionType = getResolvedType(expression);
299+
context.getFrameStack().leaveLocal(firstOrderOperationCallExpression);
300+
301+
try {
302+
EolType returnType = tc.klass().newInstance().calculateType(contextType, expressionType);
303+
setResolvedType(firstOrderOperationCallExpression, returnType);
304+
} catch (Exception e) {
305+
setResolvedType(firstOrderOperationCallExpression, EolAnyType.Instance);
306+
e.printStackTrace();
380307
}
381308
}
382309

plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/staticanalyser/EolStaticAnalysisContext.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.eclipse.epsilon.eol.dom.ModelDeclaration;
1212
import org.eclipse.epsilon.eol.staticanalyser.execute.context.FrameStack;
1313
import org.eclipse.epsilon.eol.execute.context.IEolContext;
14+
import org.eclipse.epsilon.eol.execute.operations.EolOperationFactory;
1415
import org.eclipse.epsilon.eol.execute.operations.contributors.OperationContributorRegistry;
1516
import org.eclipse.epsilon.eol.models.IRelativePathResolver;
1617
import org.eclipse.epsilon.eol.models.ModelRepository;
@@ -25,6 +26,7 @@ public class EolStaticAnalysisContext {
2526
protected Map<String, ModelDeclaration> modelDeclarations = new HashMap<>();
2627
protected ModelRepository repository = new ModelRepository();
2728
protected OperationContributorRegistry operationContributorRegistry = new OperationContributorRegistry();
29+
protected EolOperationFactory operationFactory = new EolOperationFactory();
2830

2931

3032
public Map<String, ModelDeclaration> getModelDeclarations() {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var seq : Sequence<Integer> = Sequence{0..9};
2+
/*Sequence<Integer>*/seq.collect(e:Integer|e+1);

0 commit comments

Comments
 (0)