]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / compilation / DeclarationClassification.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/DeclarationClassification.java
new file mode 100644 (file)
index 0000000..54f0bb7
--- /dev/null
@@ -0,0 +1,402 @@
+package org.simantics.scl.compiler.compilation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.java.JavaMethodDeclaration;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.parsing.Token;
+import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DClassAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DDataAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DDerivingInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DDocumentationAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DEffectAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DFixityAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DImportJavaAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DMappingRelationAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DRelationAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DeclarationAst;
+import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDClassAst;
+import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.translation.RelationRepository;
+import org.simantics.scl.compiler.internal.parsing.translation.ValueRepository;
+import org.simantics.scl.compiler.module.ImportDeclaration;
+
+import gnu.trove.map.hash.THashMap;
+
+public class DeclarationClassification {
+    ArrayList<ImportDeclaration> importsAst = new ArrayList<ImportDeclaration>();
+    ArrayList<DDataAst> dataTypesAst = new ArrayList<DDataAst>();
+    ArrayList<DTypeAst> typeAliasesAst = new ArrayList<DTypeAst>();
+    ValueRepository valueDefinitionsAst = new ValueRepository(); 
+    RelationRepository relationDefinitionsAst = new RelationRepository();
+    ArrayList<DValueTypeAst> typeAnnotationsAst = new ArrayList<DValueTypeAst>();
+    ArrayList<DFixityAst> fixityAst = new ArrayList<DFixityAst>();
+    ArrayList<ProcessedDClassAst> typeClassesAst = new ArrayList<ProcessedDClassAst>();
+    ArrayList<ProcessedDInstanceAst> instancesAst = new ArrayList<ProcessedDInstanceAst>();
+    ArrayList<DDerivingInstanceAst> derivingInstancesAst = new ArrayList<DDerivingInstanceAst>();
+    ArrayList<DEffectAst> effectsAst = new ArrayList<DEffectAst>();
+    ArrayList<DRuleAst> rulesAst = new ArrayList<DRuleAst>();
+    ArrayList<DMappingRelationAst> mappingRelationsAst = new ArrayList<DMappingRelationAst>();
+    
+    THashMap<String, DDocumentationAst> valueDocumentation = new THashMap<String, DDocumentationAst>();
+    THashMap<String, DDocumentationAst> relationDocumentation = new THashMap<String, DDocumentationAst>();
+    THashMap<String, DDocumentationAst> typeDocumentation = new THashMap<String, DDocumentationAst>();
+    THashMap<String, DDocumentationAst> classDocumentation = new THashMap<String, DDocumentationAst>();
+    
+    ArrayList<JavaMethodDeclaration> javaMethodDeclarations = new ArrayList<JavaMethodDeclaration>();
+    
+    StringBuilder moduleDocumentation = new StringBuilder();
+    
+    ArrayList<DAnnotationAst> currentAnnotations = new ArrayList<DAnnotationAst>(2); 
+    DDocumentationAst documentation;
+    String inJavaClass;
+    
+    ArrayList<DAnnotationAst> defaultAnnotations = new ArrayList<DAnnotationAst>();
+    
+    ErrorLog errorLog;
+    
+    public DeclarationClassification(ErrorLog errorLog) {
+        this.errorLog = errorLog;
+    }
+    
+    public void handle(DeclarationAst declaration) {
+        if(declaration instanceof DValueAst)
+            handle((DValueAst)declaration);
+        else if(declaration instanceof DValueTypeAst)
+            handle((DValueTypeAst)declaration);
+        else if(declaration instanceof DDataAst)
+            handle((DDataAst)declaration);
+        else if(declaration instanceof DTypeAst)
+            handle((DTypeAst)declaration);
+        else if(declaration instanceof DInstanceAst)
+            handle((DInstanceAst)declaration);
+        else if(declaration instanceof DDerivingInstanceAst)
+            handle((DDerivingInstanceAst)declaration);
+        else if(declaration instanceof ImportDeclaration)
+            handle((ImportDeclaration)declaration);            
+        else if(declaration instanceof DClassAst)
+            handle((DClassAst)declaration);
+        else if(declaration instanceof DFixityAst)
+            handle((DFixityAst)declaration);
+        else if(declaration instanceof DDocumentationAst)
+            handle((DDocumentationAst)declaration);            
+        else if(declaration instanceof DAnnotationAst)
+            handle((DAnnotationAst)declaration);
+        else if(declaration instanceof DEffectAst)
+            handle((DEffectAst)declaration);
+        else if(declaration instanceof DImportJavaAst)
+            handle((DImportJavaAst)declaration);
+        else if(declaration instanceof DRuleAst)
+            handle((DRuleAst)declaration);
+        else if(declaration instanceof DMappingRelationAst)
+            handle((DMappingRelationAst)declaration);
+        else if(declaration instanceof DRelationAst)
+            handle((DRelationAst)declaration);
+        else
+            throw new InternalCompilerError("Unknown declaration " + declaration.getClass().getSimpleName());
+    }
+
+    public void handle(DFixityAst declaration) {
+        if(!currentAnnotations.isEmpty()) {
+            errorLog.log(declaration.location, "Annotations not supported.");
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        fixityAst.add(declaration);   
+    }
+    
+    public void handle(DEffectAst declaration) {
+        if(!currentAnnotations.isEmpty()) {
+            errorLog.log(declaration.location, "Annotations not supported.");
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        if(documentation != null)
+            documentation = null;
+        effectsAst.add(declaration);
+    }
+
+    public void handle(DClassAst declaration) {
+        // TODO errorLog.log(declaration, "Class " + declaration.name + " has already been defined in this module.");
+
+        if(documentation != null) {
+            String name = declaration.name;
+            addClassDocumentation(name, documentation);
+            documentation = null;
+        }
+        
+        ArrayList<DValueTypeAst> typeDeclarations = 
+                new ArrayList<DValueTypeAst>();
+        ValueRepository defaultValues = new ValueRepository();
+        
+        DDocumentationAst curDocumentation = null;
+        for(DeclarationAst decl : declaration.declarations) {
+            if(decl instanceof DValueTypeAst) {
+                DValueTypeAst valueType = (DValueTypeAst)decl;
+                for(EVar name : valueType.names)
+                    valueDocumentation.put(name.name, curDocumentation);
+                curDocumentation = null;
+                typeDeclarations.add(valueType);
+            }
+            else if(decl instanceof DValueAst) {
+                curDocumentation = null;
+                try {
+                    defaultValues.add((DValueAst)decl);
+                } catch (NotPatternException e) {
+                    errorLog.log(e.getExpression().location, "Not a pattern.");
+                }
+            }
+            else if(decl instanceof DDocumentationAst) {
+                DDocumentationAst documentation = (DDocumentationAst)decl;
+                if(curDocumentation != null) {
+                    errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
+                }
+                curDocumentation = documentation;
+            }
+            else
+                errorLog.log(decl.location, "Invalid declaration under class definition.");
+        }
+
+        if(!currentAnnotations.isEmpty()) {
+            declaration.setAnnotations(currentAnnotations);
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        typeClassesAst.add(new ProcessedDClassAst(declaration,  
+                typeDeclarations, 
+                defaultValues));
+    }
+
+    public void handle(ImportDeclaration declaration) {
+        if(!currentAnnotations.isEmpty()) {
+            errorLog.log(declaration.location, "Annotations not supported.");
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        importsAst.add(declaration);        
+    }
+    
+    public void handle(DImportJavaAst declaration) {        
+        if(!currentAnnotations.isEmpty()) {
+            for(DAnnotationAst annotation : currentAnnotations) {
+                String name = annotation.id.text;
+                if(name.equals("@private")) {
+                    defaultAnnotations.add(annotation);
+                }
+                else
+                    errorLog.log(declaration.location, "The importJava declaration does not support annotation " + name + ".");
+            }
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        try {
+            inJavaClass = declaration.className;
+            for(DeclarationAst innerDeclaration : declaration.declarations)
+                handle(innerDeclaration);
+        } finally {
+            defaultAnnotations.clear();
+            inJavaClass = null;
+        }
+    }
+
+    public void handle(DInstanceAst declaration) {
+        ValueRepository valueDefs = new ValueRepository();
+        
+        ArrayList<DAnnotationAst> localAnnotations = new ArrayList<DAnnotationAst>(2);
+        for(DeclarationAst decl : declaration.declarations) {
+            if(decl instanceof DValueAst) {
+                try {
+                    String name = valueDefs.add((DValueAst)decl);
+                    if(!localAnnotations.isEmpty()) {
+                        valueDefs.addAnnotations(name, localAnnotations);
+                        localAnnotations = new ArrayList<DAnnotationAst>(2);
+                    }
+                } catch (NotPatternException e) {
+                    errorLog.log(e.getExpression().location, "Not a pattern.");
+                }
+            }
+            else if(decl instanceof DAnnotationAst)
+                localAnnotations.add((DAnnotationAst)decl);
+            else
+                errorLog.log(decl.location, "Invalid declaration under instance definition.");
+        }
+        for(DAnnotationAst decl : localAnnotations)
+            errorLog.log(decl.location, "Annotation is at invalid location.");
+
+        if(!currentAnnotations.isEmpty()) {
+            errorLog.log(declaration.location, "Annotations not supported.");
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        instancesAst.add(new ProcessedDInstanceAst(
+                declaration,
+                valueDefs));
+    }
+    
+    public void handle(DDerivingInstanceAst declaration) {
+        if(!currentAnnotations.isEmpty()) {
+            errorLog.log(declaration.location, "Annotations not supported.");
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        derivingInstancesAst.add(declaration);
+    }
+
+    public void handle(DTypeAst declaration) {
+        if(!currentAnnotations.isEmpty()) {
+            errorLog.log(declaration.location, "Annotations not supported.");
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        typeAliasesAst.add(declaration);
+    }
+
+    public void handle(DDataAst declaration) {
+        if(documentation != null) {
+            String name = declaration.name;
+            addTypeDocumentation(name, documentation);
+            documentation = null;
+        }
+        if(inJavaClass != null)
+            currentAnnotations.add(new DAnnotationAst(new Token(0, Locations.NO_LOCATION, "@JavaType"), 
+                    Arrays.<Expression>asList(new ELiteral(new StringConstant(inJavaClass)))));
+        if(!currentAnnotations.isEmpty()) {
+            declaration.setAnnotations(currentAnnotations);
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        dataTypesAst.add(declaration);
+    }
+
+    public void handle(DValueTypeAst declaration) {
+        if(documentation != null) {
+            for(EVar name : declaration.names) {
+                addValueDocumentation(name.name, documentation);
+            }
+            documentation = null;
+        }
+        if(inJavaClass != null) {
+            for(EVar name : declaration.names)
+                javaMethodDeclarations.add(new JavaMethodDeclaration(
+                        declaration.location, inJavaClass, name, declaration.type));   
+        }
+        else
+            typeAnnotationsAst.add(declaration);
+        if(!currentAnnotations.isEmpty()) {
+            for(EVar name : declaration.names)
+                valueDefinitionsAst.addAnnotations(name.name, currentAnnotations);
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+        if(!defaultAnnotations.isEmpty()) {
+            for(EVar name : declaration.names)
+                valueDefinitionsAst.addAnnotations(name.name, defaultAnnotations);
+        }
+    }
+    
+    public void handle(DValueAst declaration) {
+        String name;
+        try {
+            name = valueDefinitionsAst.add(declaration);
+        } catch (NotPatternException e) {
+            errorLog.log(e.getExpression().location, "Illegal left hand side of the definition.");
+            return;
+        }
+        if(documentation != null) {
+            addValueDocumentation(name, documentation);
+            documentation = null;
+        }
+        if(!currentAnnotations.isEmpty()) {
+            valueDefinitionsAst.addAnnotations(name, currentAnnotations);
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+    }
+    
+    public void handle(DRelationAst declaration) {
+        String name;
+        try {
+            name = relationDefinitionsAst.add(declaration);
+        } catch (NotPatternException e) {
+            errorLog.log(e.getExpression().location, "Not a pattern.");
+            return;
+        }
+        if(documentation != null) {
+            addRelationDocumentation(name, documentation);
+            documentation = null;
+        }
+        if(!currentAnnotations.isEmpty()) {
+            relationDefinitionsAst.addAnnotations(name, currentAnnotations);
+            currentAnnotations = new ArrayList<DAnnotationAst>(2);
+        }
+    }
+    
+    public void handle(DDocumentationAst declaration) {
+        if(documentation != null) {
+            errorLog.log(documentation.location, "Invalid documentation string. It precedes another documentation string.");
+        }
+        documentation = declaration;                
+    }
+    
+    public void handle(DAnnotationAst declaration) {
+        if(declaration.id.text.equals("@documentation")) {
+            if(declaration.parameters.length != 1) {
+                errorLog.log(documentation.location, "One parameter, a documentation string, expected after @documentation.");
+                return;
+            }
+            if(!(declaration.parameters[0] instanceof ELiteral)) {
+                errorLog.log(documentation.location, "A documentation string expected after @documentation.");
+                return;
+            }
+            ELiteral lit = (ELiteral)declaration.parameters[0];
+            if(!(lit.getValue() instanceof StringConstant)) {
+                errorLog.log(documentation.location, "A documentation string expected after @documentation.");
+                return;
+            }
+            String text = ((StringConstant)lit.getValue()).getValue();
+            moduleDocumentation.append(text);
+            moduleDocumentation.append("\n\n");
+        }
+        else
+            currentAnnotations.add(declaration);
+    }
+    
+    public void handle(DRuleAst declaration) {
+        rulesAst.add(declaration);
+    }
+    
+    public void handle(DMappingRelationAst declaration) {
+        mappingRelationsAst.add(declaration);
+    }
+    
+    public void addValueDocumentation(String valueName, DDocumentationAst documentation) {
+        DDocumentationAst oldDoc = valueDocumentation.put(valueName, documentation);
+        if(oldDoc != null) {
+            errorLog.log(oldDoc.location, "Multiple documentation strings given to " + valueName + ".");
+        }
+    }
+    
+    public void addRelationDocumentation(String relationName, DDocumentationAst documentation) {
+        DDocumentationAst oldDoc = relationDocumentation.put(relationName, documentation);
+        if(oldDoc != null) {
+            errorLog.log(oldDoc.location, "Multiple documentation strings given to " + relationName + ".");
+        }
+    }
+    
+    public void addTypeDocumentation(String valueName, DDocumentationAst documentation) {
+        DDocumentationAst oldDoc = typeDocumentation.put(valueName, documentation);
+        if(oldDoc != null) {
+            errorLog.log(oldDoc.location, "Multiple documentation strings given to the same type.");
+        }
+    }
+    
+    public void addClassDocumentation(String valueName, DDocumentationAst documentation) {
+        DDocumentationAst oldDoc = classDocumentation.put(valueName, documentation);
+        if(oldDoc != null) {
+            errorLog.log(oldDoc.location, "Multiple documentation strings given to the same class.");
+        }
+    }
+}