Skip to content

Commit b741fb4

Browse files
committed
Fix plus operator and add relevant unit tests
1 parent 3942eec commit b741fb4

File tree

3 files changed

+101
-83
lines changed

3 files changed

+101
-83
lines changed

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

Lines changed: 76 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@ public class EolStaticAnalyser implements IModuleValidator, IEolVisitor {
119119
protected EolModule module;
120120
protected EolStaticAnalysisContext context = new EolStaticAnalysisContext();
121121
protected List<IStaticOperation> operations = new ArrayList<>();
122-
HashMap<Operation, Boolean> returnFlags = new HashMap<>(); // for every missmatch
122+
HashMap<Operation, Boolean> returnFlags = new HashMap<>(); // for every missmatch
123123

124124
public EolStaticAnalyser() {
125125
}
126-
126+
127127
public EolStaticAnalyser(IModelFactory modelFactory) {
128128
context.modelFactory = modelFactory;
129129
}
@@ -167,8 +167,7 @@ public void visit(AssignmentStatement assignmentStatement) {
167167
if (!targetType.isAncestorOf(valueType)) {
168168
if (canBeCompatible(targetType, valueType)) {
169169
createTypeCompatibilityWarning(targetExpression, valueExpression);
170-
}
171-
else {
170+
} else {
172171
createTypeCompatibilityError(targetExpression, valueExpression);
173172
}
174173
}
@@ -260,7 +259,7 @@ public void visit(ExpressionStatement expressionStatement) {
260259
expressionStatement.getExpression().accept(this);
261260

262261
}
263-
262+
264263
@Override
265264
public void visit(FirstOrderOperationCallExpression firstOrderOperationCallExpression) {
266265
String name = firstOrderOperationCallExpression.getName();
@@ -269,13 +268,12 @@ public void visit(FirstOrderOperationCallExpression firstOrderOperationCallExpre
269268
errors.add(new ModuleMarker(firstOrderOperationCallExpression.getNameExpression(),
270269
"Undefined first order operation " + name, Severity.Error));
271270
return;
272-
};
271+
}
273272
TypeCalculator tc = operation.getClass().getAnnotation(TypeCalculator.class);
274273
if (tc == null) {
275274
setResolvedType(firstOrderOperationCallExpression, EolAnyType.Instance);
276275
return;
277276
}
278-
279277

280278
Expression targetExpression = firstOrderOperationCallExpression.getTargetExpression();
281279
targetExpression.accept(this);
@@ -297,7 +295,7 @@ public void visit(FirstOrderOperationCallExpression firstOrderOperationCallExpre
297295
expression.accept(this);
298296
EolType expressionType = getResolvedType(expression);
299297
context.getFrameStack().leaveLocal(firstOrderOperationCallExpression);
300-
298+
301299
try {
302300
EolType returnType = tc.klass().newInstance().calculateType(contextType, expressionType);
303301
setResolvedType(firstOrderOperationCallExpression, returnType);
@@ -586,11 +584,11 @@ public void visit(OperationCallExpression operationCallExpression) {
586584
for (Expression parameterExpression : parameterExpressions) {
587585
parameterExpression.accept(this);
588586
}
589-
590-
//Name check
587+
588+
// Name check
591589
List<IStaticOperation> temp = new ArrayList<IStaticOperation>();
592-
for (IStaticOperation op: resolvedOperations) {
593-
if(nameExpression.getName().equals(op.getName())) {
590+
for (IStaticOperation op : resolvedOperations) {
591+
if (nameExpression.getName().equals(op.getName())) {
594592
temp.add(op);
595593
}
596594
}
@@ -599,14 +597,13 @@ public void visit(OperationCallExpression operationCallExpression) {
599597
errors.add(new ModuleMarker(nameExpression, "Undefined operation", Severity.Error));
600598
return;
601599
}
602-
603-
//Context check
600+
601+
// Context check
604602
temp = new ArrayList<IStaticOperation>();
605-
for (IStaticOperation op: resolvedOperations) {
603+
for (IStaticOperation op : resolvedOperations) {
606604
EolType opContextType = op.getContextType();
607-
if(contextType == opContextType ||
608-
opContextType.isAncestorOf(contextType) ||
609-
canBeCompatible(opContextType, contextType)) {
605+
if (contextType == opContextType || opContextType.isAncestorOf(contextType)
606+
|| canBeCompatible(opContextType, contextType)) {
610607
temp.add(op);
611608
}
612609
}
@@ -617,10 +614,10 @@ public void visit(OperationCallExpression operationCallExpression) {
617614
Severity.Error));
618615
return;
619616
}
620-
617+
621618
// Number of parameters check
622619
temp = new ArrayList<IStaticOperation>();
623-
for (IStaticOperation op: resolvedOperations) {
620+
for (IStaticOperation op : resolvedOperations) {
624621
List<EolType> reqParams = op.getParameterTypes();
625622
if (reqParams.size() == parameterExpressions.size()) {
626623
temp.add(op);
@@ -631,18 +628,17 @@ public void visit(OperationCallExpression operationCallExpression) {
631628
errors.add(new ModuleMarker(nameExpression, "Parameter number mismatch", Severity.Error));
632629
return;
633630
}
634-
631+
635632
// Parameter type checks
636633
temp = new ArrayList<IStaticOperation>();
637-
for (IStaticOperation op: resolvedOperations) {
634+
for (IStaticOperation op : resolvedOperations) {
638635
int index = 0;
639636
List<EolType> reqParamTypess = op.getParameterTypes();
640637
boolean compatible = true;
641638
for (EolType reqParamType : reqParamTypess) {
642639
EolType provParamType = getResolvedType(parameterExpressions.get(index));
643640
index++;
644-
if (!reqParamType.isAncestorOf(provParamType)
645-
&& !canBeCompatible(reqParamType, provParamType)) {
641+
if (!reqParamType.isAncestorOf(provParamType) && !canBeCompatible(reqParamType, provParamType)) {
646642
compatible = false;
647643
break;
648644
}
@@ -656,22 +652,22 @@ public void visit(OperationCallExpression operationCallExpression) {
656652
errors.add(new ModuleMarker(nameExpression, "Parameters type mismatch", Severity.Error));
657653
return;
658654
}
659-
660-
//Process resolved operations
661-
Set<EolType> returnTypes = resolvedOperations.stream()
662-
.map(op -> op.getReturnType()).collect(Collectors.toSet());
663-
if (returnTypes.size() == 1){
664-
setResolvedType(operationCallExpression, (EolType)returnTypes.toArray()[0]);
665-
}else {
655+
656+
// Process resolved operations
657+
Set<EolType> returnTypes = resolvedOperations.stream().map(op -> op.getReturnType())
658+
.collect(Collectors.toSet());
659+
if (returnTypes.size() == 1) {
660+
setResolvedType(operationCallExpression, (EolType) returnTypes.toArray()[0]);
661+
} else {
666662
setResolvedType(operationCallExpression, new EolUnionType(returnTypes));
667663
}
668-
669-
//Check for warning related to subtypes
664+
665+
// Check for warning related to subtypes
670666
Set<EolType> resolvedOperationContextTypes = new HashSet<EolType>();
671667
for (IStaticOperation op : resolvedOperations) {
672668
resolvedOperationContextTypes.add(op.getContextType());
673669
}
674-
670+
675671
Stack<EolType> stack = new Stack<EolType>();
676672
stack.push(contextType);
677673
outerLoop: while (!stack.isEmpty()) {
@@ -775,7 +771,8 @@ else if (targetExpression instanceof NameExpression && ((NameExpression) targetE
775771
collectionType.setContentType(toStaticAnalyserType(structuralFeature.getType()));
776772
setResolvedType(propertyCallExpression, collectionType);
777773
} else {
778-
setResolvedType(propertyCallExpression, toStaticAnalyserType(structuralFeature.getType()));
774+
setResolvedType(propertyCallExpression,
775+
toStaticAnalyserType(structuralFeature.getType()));
779776
}
780777
if (many) {
781778
setResolvedType(propertyCallExpression,
@@ -1046,21 +1043,21 @@ public void operationPreVisitor(Operation operation) {
10461043
EolType contextType = EolNoType.Instance;
10471044
TypeExpression returnTypeExpression = operation.getReturnTypeExpression();
10481045
EolType returnType = EolAnyType.Instance;
1049-
1046+
10501047
if (contextTypeExpression != null) {
10511048
contextTypeExpression.accept(this);
10521049
contextType = getResolvedType(contextTypeExpression);
10531050
}
1054-
1051+
10551052
if (returnTypeExpression != null) {
10561053
returnTypeExpression.accept(this);
10571054
returnType = getResolvedType(returnTypeExpression);
10581055
}
1059-
1056+
10601057
operation.getData().put("contextType", contextType);
10611058
operation.getData().put("returnType", returnType);
10621059
}
1063-
1060+
10641061
public void preValidate(IEolModule imodule) {
10651062

10661063
EolModule eolModule = (EolModule) imodule;
@@ -1069,19 +1066,20 @@ public void preValidate(IEolModule imodule) {
10691066
for (ModelDeclaration modelDeclaration : module.getDeclaredModelDeclarations()) {
10701067
modelDeclaration.accept(this);
10711068
}
1072-
1069+
10731070
module.getDeclaredOperations().forEach(o -> operationPreVisitor(o));
10741071
module.getDeclaredOperations().forEach(o -> operations.add(new SimpleOperation(o)));
10751072
module.getDeclaredOperations().forEach(o -> o.accept(this));
1076-
1077-
//Parse builtin operations
1078-
List<OperationContributor> operationContributors = context.operationContributorRegistry.stream().collect(Collectors.toList());
1079-
for(OperationContributor oc: operationContributors) {
1073+
1074+
// Parse builtin operations
1075+
List<OperationContributor> operationContributors = context.operationContributorRegistry.stream()
1076+
.collect(Collectors.toList());
1077+
for (OperationContributor oc : operationContributors) {
10801078
EolType contextType = oc.contributesToType();
1081-
1082-
for(Method m: oc.getClass().getDeclaredMethods()) {
1079+
1080+
for (Method m : oc.getClass().getDeclaredMethods()) {
10831081
List<EolType> operationParameterTypes = new ArrayList<EolType>();
1084-
Type[] javaParameterTypes = m.getGenericParameterTypes();
1082+
Type[] javaParameterTypes = m.getGenericParameterTypes();
10851083
for (Type javaParameterType : javaParameterTypes) {
10861084
operationParameterTypes.add(javaTypeToEolType(javaParameterType));
10871085
}
@@ -1090,37 +1088,33 @@ public void preValidate(IEolModule imodule) {
10901088
}
10911089
}
10921090
}
1093-
1091+
10941092
public EolType javaTypeToEolType(Type javaType) {
1095-
1093+
10961094
if (javaType instanceof ParameterizedType) {
1097-
Type rawType = ((ParameterizedType)javaType).getRawType();
1098-
Type[] typeArgs = ((ParameterizedType)javaType).getActualTypeArguments();
1099-
EolType eolType = javaClassToEolType((Class<?>)rawType);
1100-
if (eolType instanceof EolCollectionType){
1095+
Type rawType = ((ParameterizedType) javaType).getRawType();
1096+
Type[] typeArgs = ((ParameterizedType) javaType).getActualTypeArguments();
1097+
EolType eolType = javaClassToEolType((Class<?>) rawType);
1098+
if (eolType instanceof EolCollectionType) {
11011099
EolType contentType = javaTypeToEolType(typeArgs[0]);
11021100
eolType = new EolCollectionType(eolType.getName(), contentType);
11031101
return eolType;
1104-
}
1105-
else if (eolType instanceof EolMapType) {
1102+
} else if (eolType instanceof EolMapType) {
11061103
EolType keyType = javaTypeToEolType(typeArgs[0]);
11071104
EolType valueType = javaTypeToEolType(typeArgs[1]);
11081105
eolType = new EolMapType(keyType, valueType);
11091106
return eolType;
1110-
}
1111-
else {
1107+
} else {
11121108
return EolAnyType.Instance;
11131109
}
1114-
}
1115-
else if (javaType instanceof Class<?>) {
1110+
} else if (javaType instanceof Class<?>) {
11161111
Class<?> javaClass = (Class<?>) javaType;
11171112
return javaClassToEolType(javaClass);
1118-
}
1119-
else {
1113+
} else {
11201114
return EolAnyType.Instance;
11211115
}
11221116
}
1123-
1117+
11241118
public EolType javaClassToEolType(Class<?> javaClass) {
11251119
if (javaClass == String.class || javaClass == char.class) {
11261120
return EolPrimitiveType.String;
@@ -1209,35 +1203,35 @@ public boolean canBeCompatible(EolType targetType, EolType valueType) {
12091203
if (targetType == null || valueType == null) {
12101204
return false;
12111205
}
1212-
1206+
12131207
if (valueType instanceof EolUnionType) {
12141208
EolType tempType;
1215-
for (EolType t : ((EolUnionType)valueType).containedTypes) {
1209+
for (EolType t : ((EolUnionType) valueType).containedTypes) {
12161210
tempType = targetType;
1217-
while(true) {
1211+
while (true) {
12181212
if (tempType instanceof EolAnyType) {
12191213
break;
12201214
}
12211215
if (t.equals(tempType)) {
12221216
return true;
1223-
1217+
12241218
} else {
12251219
tempType = getParentType(tempType);
12261220
}
12271221
}
12281222
}
12291223
return false;
12301224
}
1231-
1225+
12321226
if (targetType instanceof EolUnionType) {
1233-
for (EolType t : ((EolUnionType)targetType).containedTypes) {
1227+
for (EolType t : ((EolUnionType) targetType).containedTypes) {
12341228
if (canBeCompatible(t, valueType)) {
12351229
return true;
12361230
}
12371231
}
12381232
return false;
12391233
}
1240-
1234+
12411235
while (true) {
12421236

12431237
if (!(targetType.equals(valueType)) && !(valueType instanceof EolAnyType)) {
@@ -1294,6 +1288,7 @@ public void visitOperatorExpression(OperatorExpression operatorExpression) {
12941288
firstOperand.accept(this);
12951289
if (secondOperand != null)
12961290
secondOperand.accept(this);
1291+
List<EolType> operandTypes = operands.stream().map(o -> getResolvedType(o)).collect(Collectors.toList());
12971292

12981293
if (StringUtil.isOneOf(operator, "and", "or", "xor", "not", "implies")) {
12991294
for (Expression operand : operatorExpression.getOperands()) {
@@ -1326,21 +1321,19 @@ && getResolvedType(operand) != EolPrimitiveType.Real) {
13261321
}
13271322

13281323
if (StringUtil.isOneOf(operator, "+")) {
1329-
for (Expression operand : operands) {
1330-
if (getResolvedType(operand) == EolPrimitiveType.String) {
1331-
setResolvedType(operatorExpression, EolPrimitiveType.String);
1332-
break;
1333-
}
1334-
1335-
if (getResolvedType(operand) == EolPrimitiveType.Integer)
1336-
setResolvedType(operatorExpression, EolPrimitiveType.Integer);
1337-
1338-
if (getResolvedType(operand) == EolPrimitiveType.Real)
1324+
if (operandTypes.stream().allMatch(
1325+
t -> t.equals(EolNativeType.Number) || t.equals(EolPrimitiveType.Real) || t.equals(EolPrimitiveType.Integer))) {
1326+
if (operandTypes.contains(EolNativeType.Number))
1327+
setResolvedType(operatorExpression, EolNativeType.Number);
1328+
else if (operandTypes.contains(EolPrimitiveType.Real))
13391329
setResolvedType(operatorExpression, EolPrimitiveType.Real);
1340-
}
1341-
1330+
else
1331+
setResolvedType(operatorExpression, EolPrimitiveType.Integer);
1332+
}else if (operandTypes.stream().allMatch(t -> t instanceof EolCollectionType))
1333+
setResolvedType(operatorExpression, operandTypes.get(0));
1334+
else
1335+
setResolvedType(operatorExpression, EolPrimitiveType.String);
13421336
}
1343-
13441337
}
13451338

13461339
public boolean hasReturnStatement(Operation operation) {
@@ -1462,7 +1455,7 @@ public EolModelElementType getModelElementType(String modelAndType, AbstractModu
14621455
}
14631456

14641457
}
1465-
1458+
14661459
private EolType toStaticAnalyserType(org.eclipse.epsilon.eol.types.EolType type) {
14671460
if (type == null) {
14681461
return null;

plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/staticanalyser/types/EolNativeType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public class EolNativeType extends EolType {
88

99
private Class<?> javaClass;
1010

11+
public static final EolNativeType Number = new EolNativeType(java.lang.Number.class);
12+
1113
public EolNativeType(Class<?> javaClass) {
1214
this.javaClass = javaClass;
1315
}

0 commit comments

Comments
 (0)