]> gerrit.simantics Code Review - simantics/platform.git/blob
7c6d53ac8f698171b3275f533925afb68bee1698
[simantics/platform.git] /
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.DRelationAst;
27 import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
28 import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
29 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
30 import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
31 import org.simantics.scl.compiler.internal.parsing.declarations.DeclarationAst;
32 import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDClassAst;
33 import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
34 import org.simantics.scl.compiler.internal.parsing.translation.RelationRepository;
35 import org.simantics.scl.compiler.internal.parsing.translation.ValueRepository;
36 import org.simantics.scl.compiler.module.ImportDeclaration;
37
38 import gnu.trove.map.hash.THashMap;
39
40 public class DeclarationClassification {
41     ArrayList<ImportDeclaration> importsAst = new ArrayList<ImportDeclaration>();
42     ArrayList<DDataAst> dataTypesAst = new ArrayList<DDataAst>();
43     ArrayList<DTypeAst> typeAliasesAst = new ArrayList<DTypeAst>();
44     ValueRepository valueDefinitionsAst = new ValueRepository(); 
45     RelationRepository relationDefinitionsAst = new RelationRepository();
46     ArrayList<DValueTypeAst> typeAnnotationsAst = new ArrayList<DValueTypeAst>();
47     ArrayList<DFixityAst> fixityAst = new ArrayList<DFixityAst>();
48     ArrayList<ProcessedDClassAst> typeClassesAst = new ArrayList<ProcessedDClassAst>();
49     ArrayList<ProcessedDInstanceAst> instancesAst = new ArrayList<ProcessedDInstanceAst>();
50     ArrayList<DDerivingInstanceAst> derivingInstancesAst = new ArrayList<DDerivingInstanceAst>();
51     ArrayList<DEffectAst> effectsAst = new ArrayList<DEffectAst>();
52     ArrayList<DRuleAst> rulesAst = new ArrayList<DRuleAst>();
53     ArrayList<DMappingRelationAst> mappingRelationsAst = new ArrayList<DMappingRelationAst>();
54     
55     THashMap<String, DDocumentationAst> valueDocumentation = new THashMap<String, DDocumentationAst>();
56     THashMap<String, DDocumentationAst> relationDocumentation = new THashMap<String, DDocumentationAst>();
57     THashMap<String, DDocumentationAst> typeDocumentation = new THashMap<String, DDocumentationAst>();
58     THashMap<String, DDocumentationAst> classDocumentation = new THashMap<String, DDocumentationAst>();
59     
60     ArrayList<JavaMethodDeclaration> javaMethodDeclarations = new ArrayList<JavaMethodDeclaration>();
61     
62     StringBuilder moduleDocumentation = new StringBuilder();
63     
64     ArrayList<DAnnotationAst> currentAnnotations = new ArrayList<DAnnotationAst>(2); 
65     DDocumentationAst documentation;
66     String inJavaClass;
67     
68     ArrayList<DAnnotationAst> defaultAnnotations = new ArrayList<DAnnotationAst>();
69     
70     ErrorLog errorLog;
71     
72     public DeclarationClassification(CompilationContext compilationContext) {
73         this.errorLog = compilationContext.errorLog;
74     }
75     
76     public void handle(DeclarationAst declaration) {
77         if(declaration instanceof DValueAst)
78             handle((DValueAst)declaration);
79         else if(declaration instanceof DValueTypeAst)
80             handle((DValueTypeAst)declaration);
81         else if(declaration instanceof DDataAst)
82             handle((DDataAst)declaration);
83         else if(declaration instanceof DTypeAst)
84             handle((DTypeAst)declaration);
85         else if(declaration instanceof DInstanceAst)
86             handle((DInstanceAst)declaration);
87         else if(declaration instanceof DDerivingInstanceAst)
88             handle((DDerivingInstanceAst)declaration);
89         else if(declaration instanceof ImportDeclaration)
90             handle((ImportDeclaration)declaration);            
91         else if(declaration instanceof DClassAst)
92             handle((DClassAst)declaration);
93         else if(declaration instanceof DFixityAst)
94             handle((DFixityAst)declaration);
95         else if(declaration instanceof DDocumentationAst)
96             handle((DDocumentationAst)declaration);            
97         else if(declaration instanceof DAnnotationAst)
98             handle((DAnnotationAst)declaration);
99         else if(declaration instanceof DEffectAst)
100             handle((DEffectAst)declaration);
101         else if(declaration instanceof DImportJavaAst)
102             handle((DImportJavaAst)declaration);
103         else if(declaration instanceof DRuleAst)
104             handle((DRuleAst)declaration);
105         else if(declaration instanceof DMappingRelationAst)
106             handle((DMappingRelationAst)declaration);
107         else if(declaration instanceof DRelationAst)
108             handle((DRelationAst)declaration);
109         else
110             throw new InternalCompilerError("Unknown declaration " + declaration.getClass().getSimpleName());
111     }
112
113     public void handle(DFixityAst declaration) {
114         if(!currentAnnotations.isEmpty()) {
115             errorLog.log(declaration.location, "Annotations not supported.");
116             currentAnnotations = new ArrayList<DAnnotationAst>(2);
117         }
118         fixityAst.add(declaration);   
119     }
120     
121     public void handle(DEffectAst declaration) {
122         if(!currentAnnotations.isEmpty()) {
123             errorLog.log(declaration.location, "Annotations not supported.");
124             currentAnnotations = new ArrayList<DAnnotationAst>(2);
125         }
126         if(documentation != null)
127             documentation = null;
128         effectsAst.add(declaration);
129     }
130
131     public void handle(DClassAst declaration) {
132         // TODO errorLog.log(declaration, "Class " + declaration.name + " has already been defined in this module.");
133
134         if(documentation != null) {
135             String name = declaration.name;
136             addClassDocumentation(name, documentation);
137             documentation = null;
138         }
139         
140         ArrayList<DValueTypeAst> typeDeclarations = 
141                 new ArrayList<DValueTypeAst>();
142         ValueRepository defaultValues = new ValueRepository();
143         
144         DDocumentationAst curDocumentation = null;
145         for(DeclarationAst decl : declaration.declarations) {
146             if(decl instanceof DValueTypeAst) {
147                 DValueTypeAst valueType = (DValueTypeAst)decl;
148                 for(EVar name : valueType.names)
149                     valueDocumentation.put(name.name, curDocumentation);
150                 curDocumentation = null;
151                 typeDeclarations.add(valueType);
152             }
153             else if(decl instanceof DValueAst) {
154                 curDocumentation = null;
155                 try {
156                     defaultValues.add((DValueAst)decl);
157                 } catch (NotPatternException e) {
158                     errorLog.log(e.getExpression().location, "Not a pattern.");
159                 }
160             }
161             else if(decl instanceof DDocumentationAst) {
162                 DDocumentationAst documentation = (DDocumentationAst)decl;
163                 if(curDocumentation != null) {
164                     errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
165                 }
166                 curDocumentation = documentation;
167             }
168             else
169                 errorLog.log(decl.location, "Invalid declaration under class definition.");
170         }
171
172         if(!currentAnnotations.isEmpty()) {
173             declaration.setAnnotations(currentAnnotations);
174             currentAnnotations = new ArrayList<DAnnotationAst>(2);
175         }
176         typeClassesAst.add(new ProcessedDClassAst(declaration,  
177                 typeDeclarations, 
178                 defaultValues));
179     }
180
181     public void handle(ImportDeclaration declaration) {
182         if(!currentAnnotations.isEmpty()) {
183             errorLog.log(declaration.location, "Annotations not supported.");
184             currentAnnotations = new ArrayList<DAnnotationAst>(2);
185         }
186         importsAst.add(declaration);        
187     }
188     
189     public void handle(DImportJavaAst declaration) {        
190         if(!currentAnnotations.isEmpty()) {
191             for(DAnnotationAst annotation : currentAnnotations) {
192                 String name = annotation.id.text;
193                 if(name.equals("@private")) {
194                     defaultAnnotations.add(annotation);
195                 }
196                 else
197                     errorLog.log(declaration.location, "The importJava declaration does not support annotation " + name + ".");
198             }
199             currentAnnotations = new ArrayList<DAnnotationAst>(2);
200         }
201         try {
202             inJavaClass = declaration.className;
203             for(DeclarationAst innerDeclaration : declaration.declarations)
204                 handle(innerDeclaration);
205         } finally {
206             defaultAnnotations.clear();
207             inJavaClass = null;
208         }
209     }
210
211     public void handle(DInstanceAst declaration) {
212         ValueRepository valueDefs = new ValueRepository();
213         
214         ArrayList<DAnnotationAst> localAnnotations = new ArrayList<DAnnotationAst>(2);
215         for(DeclarationAst decl : declaration.declarations) {
216             if(decl instanceof DValueAst) {
217                 try {
218                     String name = valueDefs.add((DValueAst)decl);
219                     if(!localAnnotations.isEmpty()) {
220                         valueDefs.addAnnotations(name, localAnnotations);
221                         localAnnotations = new ArrayList<DAnnotationAst>(2);
222                     }
223                 } catch (NotPatternException e) {
224                     errorLog.log(e.getExpression().location, "Not a pattern.");
225                 }
226             }
227             else if(decl instanceof DAnnotationAst)
228                 localAnnotations.add((DAnnotationAst)decl);
229             else
230                 errorLog.log(decl.location, "Invalid declaration under instance definition.");
231         }
232         for(DAnnotationAst decl : localAnnotations)
233             errorLog.log(decl.location, "Annotation is at invalid location.");
234
235         if(!currentAnnotations.isEmpty()) {
236             errorLog.log(declaration.location, "Annotations not supported.");
237             currentAnnotations = new ArrayList<DAnnotationAst>(2);
238         }
239         if(declaration.name.name.equals("Eq") || declaration.name.name.equals("Hashable")) {
240                 errorLog.logWarning(declaration.location, "Skipped instance definition for " + declaration.name + " for " + declaration.types[0]);
241             return;
242         }
243         instancesAst.add(new ProcessedDInstanceAst(
244                 declaration,
245                 valueDefs));
246     }
247     
248     public void handle(DDerivingInstanceAst declaration) {
249         if(!currentAnnotations.isEmpty()) {
250             errorLog.log(declaration.location, "Annotations not supported.");
251             currentAnnotations = new ArrayList<DAnnotationAst>(2);
252         }
253         if(declaration.name.name.equals("Eq") || declaration.name.name.equals("Hashable")) {
254                 errorLog.logWarning(declaration.location, "Skipped instance definition for " + declaration.name + " for " + declaration.types[0]);
255             return;
256         }
257         derivingInstancesAst.add(declaration);
258     }
259
260     public void handle(DTypeAst declaration) {
261         if(!currentAnnotations.isEmpty()) {
262             errorLog.log(declaration.location, "Annotations not supported.");
263             currentAnnotations = new ArrayList<DAnnotationAst>(2);
264         }
265         typeAliasesAst.add(declaration);
266     }
267
268     public void handle(DDataAst declaration) {
269         if(documentation != null) {
270             String name = declaration.name;
271             addTypeDocumentation(name, documentation);
272             documentation = null;
273         }
274         if(inJavaClass != null)
275             currentAnnotations.add(new DAnnotationAst(new Token(0, Locations.NO_LOCATION, "@JavaType"), 
276                     Arrays.<Expression>asList(new ELiteral(new StringConstant(inJavaClass)))));
277         if(!currentAnnotations.isEmpty()) {
278             declaration.setAnnotations(currentAnnotations);
279             currentAnnotations = new ArrayList<DAnnotationAst>(2);
280         }
281         dataTypesAst.add(declaration);
282     }
283
284     public void handle(DValueTypeAst declaration) {
285         if(documentation != null) {
286             for(EVar name : declaration.names) {
287                 addValueDocumentation(name.name, documentation);
288             }
289             documentation = null;
290         }
291         if(inJavaClass != null) {
292             for(EVar name : declaration.names)
293                 javaMethodDeclarations.add(new JavaMethodDeclaration(
294                         declaration.location, inJavaClass, name, declaration.type));   
295         }
296         else
297             typeAnnotationsAst.add(declaration);
298         if(!currentAnnotations.isEmpty()) {
299             for(EVar name : declaration.names)
300                 valueDefinitionsAst.addAnnotations(name.name, currentAnnotations);
301             currentAnnotations = new ArrayList<DAnnotationAst>(2);
302         }
303         if(!defaultAnnotations.isEmpty()) {
304             for(EVar name : declaration.names)
305                 valueDefinitionsAst.addAnnotations(name.name, defaultAnnotations);
306         }
307     }
308     
309     public void handle(DValueAst declaration) {
310         String name;
311         try {
312             name = valueDefinitionsAst.add(declaration);
313         } catch (NotPatternException e) {
314             errorLog.log(e.getExpression().location, "Illegal left hand side of the definition.");
315             return;
316         }
317         if(documentation != null) {
318             addValueDocumentation(name, documentation);
319             documentation = null;
320         }
321         if(!currentAnnotations.isEmpty()) {
322             valueDefinitionsAst.addAnnotations(name, currentAnnotations);
323             currentAnnotations = new ArrayList<DAnnotationAst>(2);
324         }
325     }
326     
327     public void handle(DRelationAst declaration) {
328         String name;
329         try {
330             name = relationDefinitionsAst.add(declaration);
331         } catch (NotPatternException e) {
332             errorLog.log(e.getExpression().location, "Not a pattern.");
333             return;
334         }
335         if(documentation != null) {
336             addRelationDocumentation(name, documentation);
337             documentation = null;
338         }
339         if(!currentAnnotations.isEmpty()) {
340             relationDefinitionsAst.addAnnotations(name, currentAnnotations);
341             currentAnnotations = new ArrayList<DAnnotationAst>(2);
342         }
343     }
344     
345     public void handle(DDocumentationAst declaration) {
346         if(documentation != null) {
347             errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
348         }
349         documentation = declaration;                
350     }
351     
352     public void handle(DAnnotationAst declaration) {
353         if(declaration.id.text.equals("@documentation")) {
354             if(declaration.parameters.length != 1) {
355                 errorLog.log(documentation.location, "One parameter, a documentation string, expected after @documentation.");
356                 return;
357             }
358             if(!(declaration.parameters[0] instanceof ELiteral)) {
359                 errorLog.log(documentation.location, "A documentation string expected after @documentation.");
360                 return;
361             }
362             ELiteral lit = (ELiteral)declaration.parameters[0];
363             if(!(lit.getValue() instanceof StringConstant)) {
364                 errorLog.log(documentation.location, "A documentation string expected after @documentation.");
365                 return;
366             }
367             String text = ((StringConstant)lit.getValue()).getValue();
368             moduleDocumentation.append(text);
369             moduleDocumentation.append("\n\n");
370         }
371         else
372             currentAnnotations.add(declaration);
373     }
374     
375     public void handle(DRuleAst declaration) {
376         rulesAst.add(declaration);
377     }
378     
379     public void handle(DMappingRelationAst declaration) {
380         mappingRelationsAst.add(declaration);
381     }
382     
383     public void addValueDocumentation(String valueName, DDocumentationAst documentation) {
384         DDocumentationAst oldDoc = valueDocumentation.put(valueName, documentation);
385         if(oldDoc != null) {
386             errorLog.log(oldDoc.location, "Multiple documentation strings given to " + valueName + ".");
387         }
388     }
389     
390     public void addRelationDocumentation(String relationName, DDocumentationAst documentation) {
391         DDocumentationAst oldDoc = relationDocumentation.put(relationName, documentation);
392         if(oldDoc != null) {
393             errorLog.log(oldDoc.location, "Multiple documentation strings given to " + relationName + ".");
394         }
395     }
396     
397     public void addTypeDocumentation(String valueName, DDocumentationAst documentation) {
398         DDocumentationAst oldDoc = typeDocumentation.put(valueName, documentation);
399         if(oldDoc != null) {
400             errorLog.log(oldDoc.location, "Multiple documentation strings given to the same type.");
401         }
402     }
403     
404     public void addClassDocumentation(String valueName, DDocumentationAst documentation) {
405         DDocumentationAst oldDoc = classDocumentation.put(valueName, documentation);
406         if(oldDoc != null) {
407             errorLog.log(oldDoc.location, "Multiple documentation strings given to the same class.");
408         }
409     }
410 }