--- /dev/null
+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.");
+ }
+ }
+}