1 package org.simantics.scl.compiler.compilation;
3 import java.util.ArrayList;
4 import java.util.Arrays;
6 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
7 import org.simantics.scl.compiler.constants.StringConstant;
8 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
9 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
10 import org.simantics.scl.compiler.elaboration.expressions.EVar;
11 import org.simantics.scl.compiler.elaboration.expressions.Expression;
12 import org.simantics.scl.compiler.elaboration.java.JavaMethodDeclaration;
13 import org.simantics.scl.compiler.errors.ErrorLog;
14 import org.simantics.scl.compiler.errors.Locations;
15 import org.simantics.scl.compiler.internal.parsing.Token;
16 import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst;
17 import org.simantics.scl.compiler.internal.parsing.declarations.DClassAst;
18 import org.simantics.scl.compiler.internal.parsing.declarations.DDataAst;
19 import org.simantics.scl.compiler.internal.parsing.declarations.DDerivingInstanceAst;
20 import org.simantics.scl.compiler.internal.parsing.declarations.DDocumentationAst;
21 import org.simantics.scl.compiler.internal.parsing.declarations.DEffectAst;
22 import org.simantics.scl.compiler.internal.parsing.declarations.DFixityAst;
23 import org.simantics.scl.compiler.internal.parsing.declarations.DImportJavaAst;
24 import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
25 import org.simantics.scl.compiler.internal.parsing.declarations.DMappingRelationAst;
26 import org.simantics.scl.compiler.internal.parsing.declarations.DModuleHeader;
27 import org.simantics.scl.compiler.internal.parsing.declarations.DRelationAst;
28 import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
29 import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
30 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
31 import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
32 import org.simantics.scl.compiler.internal.parsing.declarations.DeclarationAst;
33 import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDClassAst;
34 import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
35 import org.simantics.scl.compiler.internal.parsing.translation.RelationRepository;
36 import org.simantics.scl.compiler.internal.parsing.translation.ValueRepository;
37 import org.simantics.scl.compiler.module.ImportDeclaration;
39 import gnu.trove.map.hash.THashMap;
41 public class DeclarationClassification {
42 DModuleHeader moduleHeader;
43 ArrayList<ImportDeclaration> importsAst = new ArrayList<ImportDeclaration>();
44 ArrayList<DDataAst> dataTypesAst = new ArrayList<DDataAst>();
45 ArrayList<DTypeAst> typeAliasesAst = new ArrayList<DTypeAst>();
46 ValueRepository valueDefinitionsAst = new ValueRepository();
47 RelationRepository relationDefinitionsAst = new RelationRepository();
48 ArrayList<DValueTypeAst> typeAnnotationsAst = new ArrayList<DValueTypeAst>();
49 ArrayList<DFixityAst> fixityAst = new ArrayList<DFixityAst>();
50 ArrayList<ProcessedDClassAst> typeClassesAst = new ArrayList<ProcessedDClassAst>();
51 ArrayList<ProcessedDInstanceAst> instancesAst = new ArrayList<ProcessedDInstanceAst>();
52 ArrayList<DDerivingInstanceAst> derivingInstancesAst = new ArrayList<DDerivingInstanceAst>();
53 ArrayList<DEffectAst> effectsAst = new ArrayList<DEffectAst>();
54 ArrayList<DRuleAst> rulesAst = new ArrayList<DRuleAst>();
55 ArrayList<DMappingRelationAst> mappingRelationsAst = new ArrayList<DMappingRelationAst>();
57 THashMap<String, DDocumentationAst> valueDocumentation = new THashMap<String, DDocumentationAst>();
58 THashMap<String, DDocumentationAst> relationDocumentation = new THashMap<String, DDocumentationAst>();
59 THashMap<String, DDocumentationAst> typeDocumentation = new THashMap<String, DDocumentationAst>();
60 THashMap<String, DDocumentationAst> classDocumentation = new THashMap<String, DDocumentationAst>();
62 ArrayList<JavaMethodDeclaration> javaMethodDeclarations = new ArrayList<JavaMethodDeclaration>();
64 StringBuilder moduleDocumentation = new StringBuilder();
66 ArrayList<DAnnotationAst> currentAnnotations = new ArrayList<DAnnotationAst>(2);
67 DDocumentationAst documentation;
70 ArrayList<DAnnotationAst> defaultAnnotations = new ArrayList<DAnnotationAst>();
74 public DeclarationClassification(CompilationContext compilationContext) {
75 this.errorLog = compilationContext.errorLog;
78 public void handle(DeclarationAst declaration) {
79 if(declaration instanceof DValueAst)
80 handle((DValueAst)declaration);
81 else if(declaration instanceof DValueTypeAst)
82 handle((DValueTypeAst)declaration);
83 else if(declaration instanceof DDataAst)
84 handle((DDataAst)declaration);
85 else if(declaration instanceof DTypeAst)
86 handle((DTypeAst)declaration);
87 else if(declaration instanceof DInstanceAst)
88 handle((DInstanceAst)declaration);
89 else if(declaration instanceof DDerivingInstanceAst)
90 handle((DDerivingInstanceAst)declaration);
91 else if(declaration instanceof ImportDeclaration)
92 handle((ImportDeclaration)declaration);
93 else if(declaration instanceof DClassAst)
94 handle((DClassAst)declaration);
95 else if(declaration instanceof DFixityAst)
96 handle((DFixityAst)declaration);
97 else if(declaration instanceof DDocumentationAst)
98 handle((DDocumentationAst)declaration);
99 else if(declaration instanceof DAnnotationAst)
100 handle((DAnnotationAst)declaration);
101 else if(declaration instanceof DEffectAst)
102 handle((DEffectAst)declaration);
103 else if(declaration instanceof DImportJavaAst)
104 handle((DImportJavaAst)declaration);
105 else if(declaration instanceof DRuleAst)
106 handle((DRuleAst)declaration);
107 else if(declaration instanceof DMappingRelationAst)
108 handle((DMappingRelationAst)declaration);
109 else if(declaration instanceof DRelationAst)
110 handle((DRelationAst)declaration);
111 else if(declaration instanceof DModuleHeader)
112 handle((DModuleHeader)declaration);
114 throw new InternalCompilerError("Unknown declaration " + declaration.getClass().getSimpleName());
117 public void handle(DFixityAst declaration) {
118 if(!currentAnnotations.isEmpty()) {
119 errorLog.log(declaration.location, "Annotations not supported.");
120 currentAnnotations = new ArrayList<DAnnotationAst>(2);
122 fixityAst.add(declaration);
125 public void handle(DEffectAst declaration) {
126 if(!currentAnnotations.isEmpty()) {
127 errorLog.log(declaration.location, "Annotations not supported.");
128 currentAnnotations = new ArrayList<DAnnotationAst>(2);
130 if(documentation != null)
131 documentation = null;
132 effectsAst.add(declaration);
135 public void handle(DClassAst declaration) {
136 // TODO errorLog.log(declaration, "Class " + declaration.name + " has already been defined in this module.");
138 if(documentation != null) {
139 String name = declaration.name;
140 addClassDocumentation(name, documentation);
141 documentation = null;
144 ArrayList<DValueTypeAst> typeDeclarations =
145 new ArrayList<DValueTypeAst>();
146 ValueRepository defaultValues = new ValueRepository();
148 DDocumentationAst curDocumentation = null;
149 for(DeclarationAst decl : declaration.declarations) {
150 if(decl instanceof DValueTypeAst) {
151 DValueTypeAst valueType = (DValueTypeAst)decl;
152 for(EVar name : valueType.names)
153 valueDocumentation.put(name.name, curDocumentation);
154 curDocumentation = null;
155 typeDeclarations.add(valueType);
157 else if(decl instanceof DValueAst) {
158 curDocumentation = null;
160 defaultValues.add((DValueAst)decl);
161 } catch (NotPatternException e) {
162 errorLog.log(e.getExpression().location, "Not a pattern.");
165 else if(decl instanceof DDocumentationAst) {
166 DDocumentationAst documentation = (DDocumentationAst)decl;
167 if(curDocumentation != null) {
168 errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
170 curDocumentation = documentation;
173 errorLog.log(decl.location, "Invalid declaration under class definition.");
176 if(!currentAnnotations.isEmpty()) {
177 declaration.setAnnotations(currentAnnotations);
178 currentAnnotations = new ArrayList<DAnnotationAst>(2);
180 typeClassesAst.add(new ProcessedDClassAst(declaration,
185 public void handle(ImportDeclaration declaration) {
186 if(!currentAnnotations.isEmpty()) {
187 errorLog.log(declaration.location, "Annotations not supported.");
188 currentAnnotations = new ArrayList<DAnnotationAst>(2);
190 importsAst.add(declaration);
193 public void handle(DImportJavaAst declaration) {
194 if(!currentAnnotations.isEmpty()) {
195 for(DAnnotationAst annotation : currentAnnotations) {
196 String name = annotation.id.text;
197 if(name.equals("@private")) {
198 defaultAnnotations.add(annotation);
201 errorLog.log(declaration.location, "The importJava declaration does not support annotation " + name + ".");
203 currentAnnotations = new ArrayList<DAnnotationAst>(2);
206 inJavaClass = declaration.className;
207 for(DeclarationAst innerDeclaration : declaration.declarations)
208 handle(innerDeclaration);
210 defaultAnnotations.clear();
215 public void handle(DInstanceAst declaration) {
216 ValueRepository valueDefs = new ValueRepository();
218 ArrayList<DAnnotationAst> localAnnotations = new ArrayList<DAnnotationAst>(2);
219 for(DeclarationAst decl : declaration.declarations) {
220 if(decl instanceof DValueAst) {
222 String name = valueDefs.add((DValueAst)decl);
223 if(!localAnnotations.isEmpty()) {
224 valueDefs.addAnnotations(name, localAnnotations);
225 localAnnotations = new ArrayList<DAnnotationAst>(2);
227 } catch (NotPatternException e) {
228 errorLog.log(e.getExpression().location, "Not a pattern.");
231 else if(decl instanceof DAnnotationAst)
232 localAnnotations.add((DAnnotationAst)decl);
234 errorLog.log(decl.location, "Invalid declaration under instance definition.");
236 for(DAnnotationAst decl : localAnnotations)
237 errorLog.log(decl.location, "Annotation is at invalid location.");
239 if(!currentAnnotations.isEmpty()) {
240 errorLog.log(declaration.location, "Annotations not supported.");
241 currentAnnotations = new ArrayList<DAnnotationAst>(2);
243 if(declaration.name.name.equals("Eq") || declaration.name.name.equals("Hashable")) {
244 errorLog.logWarning(declaration.location, "Skipped instance definition for " + declaration.name + " for " + declaration.types[0]);
247 instancesAst.add(new ProcessedDInstanceAst(
252 public void handle(DDerivingInstanceAst declaration) {
253 if(!currentAnnotations.isEmpty()) {
254 errorLog.log(declaration.location, "Annotations not supported.");
255 currentAnnotations = new ArrayList<DAnnotationAst>(2);
257 if(declaration.name.name.equals("Eq") || declaration.name.name.equals("Hashable")) {
258 errorLog.logWarning(declaration.location, "Skipped instance definition for " + declaration.name + " for " + declaration.types[0]);
261 derivingInstancesAst.add(declaration);
264 public void handle(DTypeAst declaration) {
265 if(!currentAnnotations.isEmpty()) {
266 errorLog.log(declaration.location, "Annotations not supported.");
267 currentAnnotations = new ArrayList<DAnnotationAst>(2);
269 typeAliasesAst.add(declaration);
272 public void handle(DDataAst declaration) {
273 if(documentation != null) {
274 String name = declaration.name;
275 addTypeDocumentation(name, documentation);
276 documentation = null;
278 if(inJavaClass != null)
279 currentAnnotations.add(new DAnnotationAst(new Token(0, Locations.NO_LOCATION, "@JavaType"),
280 Arrays.<Expression>asList(new ELiteral(new StringConstant(inJavaClass)))));
281 if(!currentAnnotations.isEmpty()) {
282 declaration.setAnnotations(currentAnnotations);
283 currentAnnotations = new ArrayList<DAnnotationAst>(2);
285 dataTypesAst.add(declaration);
288 public void handle(DValueTypeAst declaration) {
289 if(documentation != null) {
290 for(EVar name : declaration.names) {
291 addValueDocumentation(name.name, documentation);
293 documentation = null;
295 if(inJavaClass != null) {
296 for(EVar name : declaration.names)
297 javaMethodDeclarations.add(new JavaMethodDeclaration(
298 declaration.location, inJavaClass, name, declaration.type));
301 typeAnnotationsAst.add(declaration);
302 if(!currentAnnotations.isEmpty()) {
303 for(EVar name : declaration.names)
304 valueDefinitionsAst.addAnnotations(name.name, currentAnnotations);
305 currentAnnotations = new ArrayList<DAnnotationAst>(2);
307 if(!defaultAnnotations.isEmpty()) {
308 for(EVar name : declaration.names)
309 valueDefinitionsAst.addAnnotations(name.name, defaultAnnotations);
313 public void handle(DValueAst declaration) {
316 name = valueDefinitionsAst.add(declaration);
317 } catch (NotPatternException e) {
318 errorLog.log(e.getExpression().location, "Illegal left hand side of the definition.");
321 if(documentation != null) {
322 addValueDocumentation(name, documentation);
323 documentation = null;
325 if(!currentAnnotations.isEmpty()) {
326 valueDefinitionsAst.addAnnotations(name, currentAnnotations);
327 currentAnnotations = new ArrayList<DAnnotationAst>(2);
331 public void handle(DRelationAst declaration) {
334 name = relationDefinitionsAst.add(declaration);
335 } catch (NotPatternException e) {
336 errorLog.log(e.getExpression().location, "Not a pattern.");
339 if(documentation != null) {
340 addRelationDocumentation(name, documentation);
341 documentation = null;
343 if(!currentAnnotations.isEmpty()) {
344 relationDefinitionsAst.addAnnotations(name, currentAnnotations);
345 currentAnnotations = new ArrayList<DAnnotationAst>(2);
349 public void handle(DDocumentationAst declaration) {
350 if(documentation != null) {
351 errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
353 documentation = declaration;
356 public void handle(DAnnotationAst declaration) {
357 if(declaration.id.text.equals("@documentation")) {
358 if(declaration.parameters.length != 1) {
359 errorLog.log(documentation.location, "One parameter, a documentation string, expected after @documentation.");
362 if(!(declaration.parameters[0] instanceof ELiteral)) {
363 errorLog.log(documentation.location, "A documentation string expected after @documentation.");
366 ELiteral lit = (ELiteral)declaration.parameters[0];
367 if(!(lit.getValue() instanceof StringConstant)) {
368 errorLog.log(documentation.location, "A documentation string expected after @documentation.");
371 String text = ((StringConstant)lit.getValue()).getValue();
372 moduleDocumentation.append(text);
373 moduleDocumentation.append("\n\n");
376 currentAnnotations.add(declaration);
379 public void handle(DRuleAst declaration) {
380 rulesAst.add(declaration);
383 public void handle(DMappingRelationAst declaration) {
384 mappingRelationsAst.add(declaration);
387 public void handle(DModuleHeader declaration) {
388 moduleHeader = declaration;
391 public void addValueDocumentation(String valueName, DDocumentationAst documentation) {
392 DDocumentationAst oldDoc = valueDocumentation.put(valueName, documentation);
394 errorLog.log(oldDoc.location, "Multiple documentation strings given to " + valueName + ".");
398 public void addRelationDocumentation(String relationName, DDocumentationAst documentation) {
399 DDocumentationAst oldDoc = relationDocumentation.put(relationName, documentation);
401 errorLog.log(oldDoc.location, "Multiple documentation strings given to " + relationName + ".");
405 public void addTypeDocumentation(String valueName, DDocumentationAst documentation) {
406 DDocumentationAst oldDoc = typeDocumentation.put(valueName, documentation);
408 errorLog.log(oldDoc.location, "Multiple documentation strings given to the same type.");
412 public void addClassDocumentation(String valueName, DDocumentationAst documentation) {
413 DDocumentationAst oldDoc = classDocumentation.put(valueName, documentation);
415 errorLog.log(oldDoc.location, "Multiple documentation strings given to the same class.");