]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java
Merge "Improved Statement API in Simantics/DB"
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / compilation / DeclarationClassification.java
1 package org.simantics.scl.compiler.compilation;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5
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;
38
39 import gnu.trove.map.hash.THashMap;
40
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>();
56     
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>();
61     
62     ArrayList<JavaMethodDeclaration> javaMethodDeclarations = new ArrayList<JavaMethodDeclaration>();
63     
64     StringBuilder moduleDocumentation = new StringBuilder();
65     
66     ArrayList<DAnnotationAst> currentAnnotations = new ArrayList<DAnnotationAst>(2); 
67     DDocumentationAst documentation;
68     String inJavaClass;
69     
70     ArrayList<DAnnotationAst> defaultAnnotations = new ArrayList<DAnnotationAst>();
71     
72     ErrorLog errorLog;
73     
74     public DeclarationClassification(CompilationContext compilationContext) {
75         this.errorLog = compilationContext.errorLog;
76     }
77     
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);
113         else
114             throw new InternalCompilerError("Unknown declaration " + declaration.getClass().getSimpleName());
115     }
116
117     public void handle(DFixityAst declaration) {
118         if(!currentAnnotations.isEmpty()) {
119             errorLog.log(declaration.location, "Annotations not supported.");
120             currentAnnotations = new ArrayList<DAnnotationAst>(2);
121         }
122         fixityAst.add(declaration);   
123     }
124     
125     public void handle(DEffectAst declaration) {
126         if(!currentAnnotations.isEmpty()) {
127             errorLog.log(declaration.location, "Annotations not supported.");
128             currentAnnotations = new ArrayList<DAnnotationAst>(2);
129         }
130         if(documentation != null)
131             documentation = null;
132         effectsAst.add(declaration);
133     }
134
135     public void handle(DClassAst declaration) {
136         // TODO errorLog.log(declaration, "Class " + declaration.name + " has already been defined in this module.");
137
138         if(documentation != null) {
139             String name = declaration.name;
140             addClassDocumentation(name, documentation);
141             documentation = null;
142         }
143         
144         ArrayList<DValueTypeAst> typeDeclarations = 
145                 new ArrayList<DValueTypeAst>();
146         ValueRepository defaultValues = new ValueRepository();
147         
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);
156             }
157             else if(decl instanceof DValueAst) {
158                 curDocumentation = null;
159                 try {
160                     defaultValues.add((DValueAst)decl);
161                 } catch (NotPatternException e) {
162                     errorLog.log(e.getExpression().location, "Not a pattern.");
163                 }
164             }
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.");
169                 }
170                 curDocumentation = documentation;
171             }
172             else
173                 errorLog.log(decl.location, "Invalid declaration under class definition.");
174         }
175
176         if(!currentAnnotations.isEmpty()) {
177             declaration.setAnnotations(currentAnnotations);
178             currentAnnotations = new ArrayList<DAnnotationAst>(2);
179         }
180         typeClassesAst.add(new ProcessedDClassAst(declaration,  
181                 typeDeclarations, 
182                 defaultValues));
183     }
184
185     public void handle(ImportDeclaration declaration) {
186         if(!currentAnnotations.isEmpty()) {
187             errorLog.log(declaration.location, "Annotations not supported.");
188             currentAnnotations = new ArrayList<DAnnotationAst>(2);
189         }
190         importsAst.add(declaration);        
191     }
192     
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);
199                 }
200                 else
201                     errorLog.log(declaration.location, "The importJava declaration does not support annotation " + name + ".");
202             }
203             currentAnnotations = new ArrayList<DAnnotationAst>(2);
204         }
205         try {
206             inJavaClass = declaration.className;
207             for(DeclarationAst innerDeclaration : declaration.declarations)
208                 handle(innerDeclaration);
209         } finally {
210             defaultAnnotations.clear();
211             inJavaClass = null;
212         }
213     }
214
215     public void handle(DInstanceAst declaration) {
216         ValueRepository valueDefs = new ValueRepository();
217         
218         ArrayList<DAnnotationAst> localAnnotations = new ArrayList<DAnnotationAst>(2);
219         for(DeclarationAst decl : declaration.declarations) {
220             if(decl instanceof DValueAst) {
221                 try {
222                     String name = valueDefs.add((DValueAst)decl);
223                     if(!localAnnotations.isEmpty()) {
224                         valueDefs.addAnnotations(name, localAnnotations);
225                         localAnnotations = new ArrayList<DAnnotationAst>(2);
226                     }
227                 } catch (NotPatternException e) {
228                     errorLog.log(e.getExpression().location, "Not a pattern.");
229                 }
230             }
231             else if(decl instanceof DAnnotationAst)
232                 localAnnotations.add((DAnnotationAst)decl);
233             else
234                 errorLog.log(decl.location, "Invalid declaration under instance definition.");
235         }
236         for(DAnnotationAst decl : localAnnotations)
237             errorLog.log(decl.location, "Annotation is at invalid location.");
238
239         if(!currentAnnotations.isEmpty()) {
240             errorLog.log(declaration.location, "Annotations not supported.");
241             currentAnnotations = new ArrayList<DAnnotationAst>(2);
242         }
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]);
245             return;
246         }
247         instancesAst.add(new ProcessedDInstanceAst(
248                 declaration,
249                 valueDefs));
250     }
251     
252     public void handle(DDerivingInstanceAst declaration) {
253         if(!currentAnnotations.isEmpty()) {
254             errorLog.log(declaration.location, "Annotations not supported.");
255             currentAnnotations = new ArrayList<DAnnotationAst>(2);
256         }
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]);
259             return;
260         }
261         derivingInstancesAst.add(declaration);
262     }
263
264     public void handle(DTypeAst declaration) {
265         if(!currentAnnotations.isEmpty()) {
266             errorLog.log(declaration.location, "Annotations not supported.");
267             currentAnnotations = new ArrayList<DAnnotationAst>(2);
268         }
269         typeAliasesAst.add(declaration);
270     }
271
272     public void handle(DDataAst declaration) {
273         if(documentation != null) {
274             String name = declaration.name;
275             addTypeDocumentation(name, documentation);
276             documentation = null;
277         }
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);
284         }
285         dataTypesAst.add(declaration);
286     }
287
288     public void handle(DValueTypeAst declaration) {
289         if(documentation != null) {
290             for(EVar name : declaration.names) {
291                 addValueDocumentation(name.name, documentation);
292             }
293             documentation = null;
294         }
295         if(inJavaClass != null) {
296             for(EVar name : declaration.names)
297                 javaMethodDeclarations.add(new JavaMethodDeclaration(
298                         declaration.location, inJavaClass, name, declaration.type));   
299         }
300         else
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);
306         }
307         if(!defaultAnnotations.isEmpty()) {
308             for(EVar name : declaration.names)
309                 valueDefinitionsAst.addAnnotations(name.name, defaultAnnotations);
310         }
311     }
312     
313     public void handle(DValueAst declaration) {
314         String name;
315         try {
316             name = valueDefinitionsAst.add(declaration);
317         } catch (NotPatternException e) {
318             errorLog.log(e.getExpression().location, "Illegal left hand side of the definition.");
319             return;
320         }
321         if(documentation != null) {
322             addValueDocumentation(name, documentation);
323             documentation = null;
324         }
325         if(!currentAnnotations.isEmpty()) {
326             valueDefinitionsAst.addAnnotations(name, currentAnnotations);
327             currentAnnotations = new ArrayList<DAnnotationAst>(2);
328         }
329     }
330     
331     public void handle(DRelationAst declaration) {
332         String name;
333         try {
334             name = relationDefinitionsAst.add(declaration);
335         } catch (NotPatternException e) {
336             errorLog.log(e.getExpression().location, "Not a pattern.");
337             return;
338         }
339         if(documentation != null) {
340             addRelationDocumentation(name, documentation);
341             documentation = null;
342         }
343         if(!currentAnnotations.isEmpty()) {
344             relationDefinitionsAst.addAnnotations(name, currentAnnotations);
345             currentAnnotations = new ArrayList<DAnnotationAst>(2);
346         }
347     }
348     
349     public void handle(DDocumentationAst declaration) {
350         if(documentation != null) {
351             errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
352         }
353         documentation = declaration;                
354     }
355     
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.");
360                 return;
361             }
362             if(!(declaration.parameters[0] instanceof ELiteral)) {
363                 errorLog.log(documentation.location, "A documentation string expected after @documentation.");
364                 return;
365             }
366             ELiteral lit = (ELiteral)declaration.parameters[0];
367             if(!(lit.getValue() instanceof StringConstant)) {
368                 errorLog.log(documentation.location, "A documentation string expected after @documentation.");
369                 return;
370             }
371             String text = ((StringConstant)lit.getValue()).getValue();
372             moduleDocumentation.append(text);
373             moduleDocumentation.append("\n\n");
374         }
375         else
376             currentAnnotations.add(declaration);
377     }
378     
379     public void handle(DRuleAst declaration) {
380         rulesAst.add(declaration);
381     }
382     
383     public void handle(DMappingRelationAst declaration) {
384         mappingRelationsAst.add(declaration);
385     }
386     
387     public void handle(DModuleHeader declaration) {
388         moduleHeader = declaration;
389     }
390     
391     public void addValueDocumentation(String valueName, DDocumentationAst documentation) {
392         DDocumentationAst oldDoc = valueDocumentation.put(valueName, documentation);
393         if(oldDoc != null) {
394             errorLog.log(oldDoc.location, "Multiple documentation strings given to " + valueName + ".");
395         }
396     }
397     
398     public void addRelationDocumentation(String relationName, DDocumentationAst documentation) {
399         DDocumentationAst oldDoc = relationDocumentation.put(relationName, documentation);
400         if(oldDoc != null) {
401             errorLog.log(oldDoc.location, "Multiple documentation strings given to " + relationName + ".");
402         }
403     }
404     
405     public void addTypeDocumentation(String valueName, DDocumentationAst documentation) {
406         DDocumentationAst oldDoc = typeDocumentation.put(valueName, documentation);
407         if(oldDoc != null) {
408             errorLog.log(oldDoc.location, "Multiple documentation strings given to the same type.");
409         }
410     }
411     
412     public void addClassDocumentation(String valueName, DDocumentationAst documentation) {
413         DDocumentationAst oldDoc = classDocumentation.put(valueName, documentation);
414         if(oldDoc != null) {
415             errorLog.log(oldDoc.location, "Multiple documentation strings given to the same class.");
416         }
417     }
418 }