Skip to content

Commit ffda463

Browse files
echebbidvojtise
authored andcommitted
[Type Checker] Refactor duplicated code
Because: - duplicated code makes changes hard How: - introduce a new TypeChecker class responsible of checking compatibility between types - refactor some methods of TypeValidator to remove duplicated code Also improve the type checker to: - check type of variables when using the '+=' and '-=' operators - check type variables declared within for each loops - check types when assigning a value to `result` (:=, += and -= operators) Also improve the AST builder to: - retrieve missing generic type parameters Signed-off-by: Emmanuel Chebbi <emmanuel.chebbi@outlook.fr>
1 parent 531475f commit ffda463

39 files changed

+2539
-829
lines changed

plugins/org.eclipse.emf.ecoretools.ale.core/src/org/eclipse/emf/ecoretools/ale/core/parser/visitor/ModelBuilder.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.antlr.v4.runtime.misc.Interval;
2020
import org.eclipse.acceleo.query.ast.AstFactory;
2121
import org.eclipse.acceleo.query.ast.Binding;
22+
import org.eclipse.acceleo.query.ast.CollectionTypeLiteral;
2223
import org.eclipse.acceleo.query.ast.Expression;
2324
import org.eclipse.acceleo.query.ast.IntegerLiteral;
2425
import org.eclipse.acceleo.query.ast.Let;
@@ -151,7 +152,10 @@ public Method buildMethod(EClass fragment, String name, List<Parameter> params,
151152
});
152153

153154
EClassifier type = resolve(returnType);
154-
operation.setEType(type);
155+
operation.setEType(type); // also set EGenericType
156+
resolveGenericTypeParameter(type, returnType.getText())
157+
.ifPresent(t -> operation.getEGenericType().getETypeArguments().add(t));
158+
155159
fragment.getEOperations().add(operation);
156160

157161
return buildMethod(operation,body,tags);
@@ -197,7 +201,10 @@ public Attribute buildAttribute(EClass fragment, String name, RExpressionContext
197201
}
198202

199203
feature.setName(name);
200-
feature.setEType(featureType);
204+
feature.setEType(featureType); // also set EGenericType
205+
resolveGenericTypeParameter(featureType, type.getText())
206+
.ifPresent(t -> feature.getEGenericType().getETypeArguments().add(t));
207+
201208
attribute.setFeatureRef(feature);
202209

203210
if(exp != null){
@@ -232,6 +239,7 @@ public VariableDeclaration buildVariableDecl(String name, RExpressionContext exp
232239
if(declaredType == EcorePackage.eINSTANCE.getEEList()) {
233240
EClassifier parameterType = resolveParameterType(type);
234241
varDecl.setTypeParameter(parameterType);
242+
// FIXME add generic type
235243
}
236244

237245
return varDecl;
@@ -558,6 +566,7 @@ else if(result instanceof EClassifier) {
558566
return resolve(type.getText()); //default
559567
}
560568

569+
// TODO [Refactor] Can this method be made private safely?
561570
public EClassifier resolveParameterType(RTypeContext type) {
562571
AstResult astResult = builder.build(type.getText());
563572
if(astResult.getAst() instanceof CollectionTypeLiteralImpl ) {
@@ -585,6 +594,36 @@ else if(paramType instanceof EClassifier) {
585594

586595
return null;
587596
}
597+
598+
private Optional<EGenericType> resolveGenericTypeParameter(EClassifier type, String code) {
599+
if (type != null && EList.class.equals(type.getInstanceClass())) {
600+
AstResult ast = builder.build(code);
601+
if (ast.getAst() instanceof CollectionTypeLiteral) {
602+
CollectionTypeLiteral collectionTypeLiteral = (CollectionTypeLiteral) ast.getAst();
603+
604+
EClassifier classifier;
605+
606+
if (collectionTypeLiteral.getElementType().getValue() instanceof Class<?>) {
607+
classifier = EcoreFactory.eINSTANCE.createEDataType();
608+
classifier.setInstanceClass((Class<?>) collectionTypeLiteral.getElementType().getValue());
609+
classifier.setName(classifier.getInstanceClass().getSimpleName());
610+
classifier.setInstanceTypeName(classifier.getInstanceClass().getName());
611+
classifier.setInstanceClassName(classifier.getInstanceClass().getName());
612+
}
613+
else if (collectionTypeLiteral.getElementType().getValue() instanceof EClass) {
614+
classifier = (EClass) collectionTypeLiteral.getElementType().getValue();
615+
}
616+
else {
617+
classifier = null;
618+
}
619+
EGenericType generic = EcoreFactory.eINSTANCE.createEGenericType();
620+
generic.setEClassifier(classifier);
621+
622+
return Optional.of(generic);
623+
}
624+
}
625+
return Optional.empty();
626+
}
588627

589628

590629
public static String getQualifiedName(EClassifier cls) {

plugins/org.eclipse.emf.ecoretools.ale.core/src/org/eclipse/emf/ecoretools/ale/core/parser/visitor/ParseResult.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public Map<Object, Integer> getStartPositions() {
3737
}
3838

3939
public Map<Object, Integer> getEndPositions() {
40+
// FIXME It looks like some end position are missing the last character in source code
4041
return endPositions;
4142
}
4243

plugins/org.eclipse.emf.ecoretools.ale.core/src/org/eclipse/emf/ecoretools/ale/core/validation/BaseValidator.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262

6363
import com.google.common.collect.Sets;
6464

65+
/**
66+
* Visits an ALE program's AST delegating validation of each element to given {@link IValidator validators}.
67+
*/
6568
public class BaseValidator extends ImplementationSwitch<Object> {
6669

6770
List<IValidationMessage> msgs;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2019 Inria and Obeo.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Inria - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.emf.ecoretools.ale.core.validation;
12+
13+
import java.util.Set;
14+
15+
import org.eclipse.acceleo.query.ast.Expression;
16+
import org.eclipse.acceleo.query.validation.type.IType;
17+
import org.eclipse.emf.ecore.EObject;
18+
import org.eclipse.emf.ecoretools.ale.implementation.Method;
19+
import org.eclipse.emf.ecoretools.ale.implementation.Statement;
20+
21+
/**
22+
* Used to retrieve the types of expressions manipulated by ALE.
23+
*/
24+
public interface IAstLookup {
25+
26+
/**
27+
* Infers the types of a given expression.
28+
*
29+
* @param expression
30+
* The expression which types must be inferred
31+
*
32+
* @return the types inferred for the given expression
33+
*/
34+
Set<IType> inferredTypesOf(Expression expression);
35+
36+
/**
37+
* Determines the types used to declare a variable.
38+
*
39+
* @param variableName
40+
* The name of the variable to check
41+
* @param astBranch
42+
* A branch of the AST from which types will be looked for
43+
*
44+
* @return the types found for the given variable
45+
*/
46+
Set<IType> typesDeclaredFor(String variableName, EObject astBranch);
47+
48+
/**
49+
* Determines all the possible types of a feature.
50+
*
51+
* @param featureName
52+
* The name of the feature
53+
* @param featureAccessExpression
54+
* The expression representing the access to the feature
55+
*
56+
* @return all the possible types of the feature
57+
*/
58+
Set<IType> findFeatureTypes(String featureName, Expression featureAccessExpression);
59+
60+
/**
61+
* Determines the method that surrounds a statement.
62+
*
63+
* @param statement
64+
* The statement to check
65+
*
66+
* @return the method enclosing the given statement
67+
*/
68+
// TODO [Refactor] Consider returning Optional<Method>
69+
Method enclosingMethod(Statement statement);
70+
71+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2019 Inria and Obeo.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Inria - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.emf.ecoretools.ale.core.validation;
12+
13+
import java.util.Optional;
14+
15+
import org.eclipse.acceleo.query.validation.type.IType;
16+
import org.eclipse.acceleo.query.validation.type.NothingType;
17+
import org.eclipse.acceleo.query.validation.type.SequenceType;
18+
import org.eclipse.acceleo.query.validation.type.SetType;
19+
import org.eclipse.emf.ecore.EClassifier;
20+
import org.eclipse.emf.ecore.EStructuralFeature;
21+
import org.eclipse.emf.ecore.ETypedElement;
22+
import org.eclipse.emf.ecore.EcorePackage;
23+
24+
/**
25+
* Performs conversions between AQL's {@link IType} and EMF's {@link EClassifier}.
26+
*/
27+
public interface IConvertType {
28+
29+
/**
30+
* Turns an EMF typed element into an AQL type.
31+
* <p>
32+
* <h3>Type matching</h3>
33+
* <ul>
34+
* <li>{@link EcorePackage#getEEList() EEList} are turned into {@link SequenceType},
35+
* <li>{@link EStructuralFeature} with multiplicity "many" are turned into {@link SequenceType},
36+
* <li>{@link EStructuralFeature} with multiplicity "one" are turned into {@link SetType},
37+
* </ul>
38+
* For others, return {@link #toAQL(EClassifier) toAQL(typedElement.getEType())}.
39+
* <p>
40+
* <h3>Genericity</h3>
41+
*
42+
* If the new type should have a generic parameter type but it cannot be resolved,
43+
* {@link NothingType NothingType("?")} is used instead.
44+
*
45+
* @param typedElement
46+
* The EMF element to convert to AQL
47+
*
48+
* @return the AQL type corresponding to the given EMF type
49+
*/
50+
IType toAQL(ETypedElement typedElement);
51+
52+
/**
53+
* Turns an EMF classifier into an AQL type.
54+
* <p>
55+
* If the classifier is turned into a generic type, such as {@link SequenceType},
56+
* its generic type parameter won't be resolved. For this reason you should use
57+
* {@link #toAQL(EClassifier, EClassifier)} whenever possible.
58+
*
59+
* @param type
60+
* The EMF classifier to convert
61+
*
62+
* @return the AQL type corresponding to the given EMF classifier
63+
*
64+
* @see #toAQL(EClassifier, EClassifier)
65+
*/
66+
IType toAQL(EClassifier type);
67+
68+
/**
69+
* Turns an EMF classifier into an AQL type.
70+
*
71+
* @param type
72+
* The EMF classifier to convert
73+
* @param typeParameter
74+
* The EMF generic type parameter or null if the type is not generic
75+
*
76+
* @return the AQL type corresponding to the given EMF classifier
77+
*
78+
* @see #toAQL(EClassifier)
79+
*/
80+
IType toAQL(EClassifier type, EClassifier typeParameter);
81+
82+
/**
83+
* Attempts to turn an AQL type into an EMF classifier.
84+
*
85+
* @param type
86+
* The AQL type to convert
87+
*
88+
* @return the EMF classifier corresponding to the given AQL type
89+
* if able to convert it
90+
*/
91+
Optional<EClassifier> toEMF(IType type);
92+
93+
}

0 commit comments

Comments
 (0)