From b2676209b072592da3425c2efb29f51eb5c4a0e0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Hannu=20Niemist=C3=B6?= Date: Fri, 26 May 2017 10:53:51 +0300 Subject: [PATCH] (refs #6923) Explicit export annotation for SCL modules Added module export list to module header. It looks like this: module { export = [foo, bar] } When using export list, @private annotation is not supported anymore. All symbols not exported are effectively private. Change-Id: I7827f6cf6062388ddd06be0ab401409bd08464fe --- .../scl/compiler/compilation/Elaboration.java | 18 ++++++++++++++- .../annotations/AnnotationUtils.java | 22 +++++++++++++++++++ .../internal/header/ModuleHeader.java | 15 +++++++++++++ .../scl/compiler/tests/ActiveTests.java | 3 +++ .../compiler/tests/ModuleRegressionTests.java | 1 + .../scl/compiler/tests/scl/ModuleExport.scl | 16 ++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleExport.scl diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java index 9dbd94691..1cba44207 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java @@ -1098,7 +1098,8 @@ public class Elaboration { constructor.getParameterTypes()); if(dataType.constructors.length == 1 && ( dataType.getTypeDesc() == null || - dataType.constructors[0].javaName.equals(MethodBuilderBase.getClassName(dataType.getTypeDesc())))) + (dataType.constructors[0].javaName != null && + dataType.constructors[0].javaName.equals(MethodBuilderBase.getClassName(dataType.getTypeDesc()))))) sclConstructor.setOnlyConstructor(true); value.setValue(sclConstructor); value.setType(constructor.getType()); @@ -1170,6 +1171,14 @@ public class Elaboration { typeMap.put(name.name, valueTypeAst); } + THashMap exportMap = null; + if(moduleHeader != null && moduleHeader.export != null) { + exportMap = new THashMap(); + for(EVar export : moduleHeader.export) + if(exportMap.put(export.name, export) != null) + errorLog.log(export.location, "The symbol " + export.name + " is exported multiple times."); + } + for(String name : valueDefinitionsAst.getValueNames()) { ArrayList defs = valueDefinitionsAst.getDefinition(name); try { @@ -1187,11 +1196,16 @@ public class Elaboration { for(DAnnotationAst annotation : annotations) { handleAnnotation(value, defs, annotation); } + if(exportMap != null && exportMap.remove(name) == null) + value.addProperty(PrivateProperty.INSTANCE); } catch(RuntimeException e) { errorLog.setExceptionPosition(defs.get(0).location); throw e; } } + if(exportMap != null) + for(EVar export : exportMap.values()) + errorLog.log(export.location, "The symbol " + export.name + " is not defined in the module."); for(String name : relationDefinitionsAst.getRelationNames()) { ArrayList definitions = relationDefinitionsAst.getDefinition(name); if(definitions.size() > 1) { @@ -1229,6 +1243,8 @@ public class Elaboration { } } else if(annotation.id.text.equals("@private")) { + if(moduleHeader != null && moduleHeader.export != null) + errorLog.log(annotation.location, "Annotation @private is not used when module header contains export property."); value.addProperty(PrivateProperty.INSTANCE); } else if(annotation.id.text.equals("@deprecated")) { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/annotations/AnnotationUtils.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/annotations/AnnotationUtils.java index 8cc088b95..08ea47297 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/annotations/AnnotationUtils.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/annotations/AnnotationUtils.java @@ -1,6 +1,11 @@ package org.simantics.scl.compiler.elaboration.expressions.annotations; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.simantics.scl.compiler.constants.StringConstant; +import org.simantics.scl.compiler.elaboration.expressions.EListLiteral; import org.simantics.scl.compiler.elaboration.expressions.ELiteral; import org.simantics.scl.compiler.elaboration.expressions.EStringLiteral; import org.simantics.scl.compiler.elaboration.expressions.EVar; @@ -46,4 +51,21 @@ public class AnnotationUtils { } return null; } + + public static List extractIdentifierList(Expression expression) { + if(expression instanceof EVar || expression instanceof EStringLiteral || expression instanceof ELiteral) + return Collections.singletonList(new EVar(expression.location, extractString(expression))); + else if(expression instanceof EListLiteral) { + Expression[] components = ((EListLiteral)expression).getComponents(); + EVar[] items = new EVar[components.length]; + for(int i=0;i export; private void read(ErrorLog errorLog, DModuleHeader header) { for(FieldAssignment assignment : header.fields) @@ -25,6 +29,15 @@ public class ModuleHeader { classLoaderLocation = assignment.location; } break; + case "export": + if(assignment.value == null) + errorLog.log(assignment.location, "Property export needs to be given a string list value."); + else { + export = AnnotationUtils.extractIdentifierList(assignment.value); + if(export == null) + errorLog.log(assignment.value.location, "Expected a list of exported items."); + } + break; case "defaultLocalName": if(assignment.value == null) errorLog.log(assignment.location, "Property defaultLocalName needs to be given a string value."); @@ -35,6 +48,8 @@ public class ModuleHeader { } break; case "fields": + if(assignment.value != null) + errorLog.log(assignment.location, "No value expected for property fields."); this.fields = true; break; default: diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java index 82193b481..f3069f13b 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java @@ -1,5 +1,7 @@ package org.simantics.scl.compiler.tests; +import org.junit.Test; + public class ActiveTests extends TestBase { public ActiveTests() { super("scl"); } @@ -18,4 +20,5 @@ public class ActiveTests extends TestBase { //@Test public void Bug6989() { test(); } + } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java index dc2c77524..f50056e8d 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java @@ -157,6 +157,7 @@ public class ModuleRegressionTests extends TestBase { @Test public void Maybe4() { test(); } @Test public void MissingEffect() { test(); } @Test public void MissingMethod() { test(); } + @Test public void ModuleExport() { test(); } @Test public void ModuleInitialization() { test(); } @Test public void MonadBug1() { test(); } @Test public void Monads1() { test(); } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleExport.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleExport.scl new file mode 100644 index 000000000..afc15c72f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleExport.scl @@ -0,0 +1,16 @@ +// module FooBar +module { + export = [foo] +} +foo = "foo" +bar = "bar" +-- +import "FooBar" +main = foo +-- +foo +-- +import "FooBar" +main = bar +-- +2:8-2:11: Couldn't resolve bar. \ No newline at end of file -- 2.43.2