Minor refactorings related to SCL constructors 50/2150/1
authorHannuNiemistö <HannuNiemistö@DESKTOP-QLVL3P3.lan>
Sun, 9 Sep 2018 20:08:42 +0000 (23:08 +0300)
committerHannuNiemistö <HannuNiemistö@DESKTOP-QLVL3P3.lan>
Sun, 9 Sep 2018 20:08:42 +0000 (23:08 +0300)
* Moved recordFieldNames from SCLConstructor to SCLValue and renamed as
parameterNames
* Replaced String array fieldNames in SCLConstructor and Constructor by
more generic ComponentAcces array and renamed as componentAccesses.

gitlab #114

Change-Id: I4f8d59a2f028717b6777949c8d8fc6ec6d3b16e9

bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/datatypes/Constructor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstructor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/ComponentAccess.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/FieldComponentAccess.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/MethodComponentAccess.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ERecord.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/modules/SCLValue.java

index 88a45558f55658a4feb55c995753556674c1f8b5..7e57d3d145cc2e958457e466eaff611b5c9f6c61 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.scl.compiler.common.datatypes;
 
 import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.constants.componentaccess.ComponentAccess;
 import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
 import org.simantics.scl.compiler.types.TVar;
@@ -21,7 +22,7 @@ public class Constructor implements Typed {
     public final TVar[] typeVariables;
     public final Type type;
 
-    public String[] fieldNames;
+    public ComponentAccess[] componentAccesses;
 
     public String[] recordFieldNames;
     
index c59df828d93a852cf6c5b03d848f8cad9b3f3792..56e8eb3b66cc0cecaed1d4aa647e57ee7d180b1c 100644 (file)
@@ -12,11 +12,12 @@ import org.simantics.scl.compiler.constants.Constant;
 import org.simantics.scl.compiler.constants.JavaTypeInstanceConstructor;
 import org.simantics.scl.compiler.constants.SCLConstructor;
 import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.constants.componentaccess.ComponentAccess;
+import org.simantics.scl.compiler.constants.componentaccess.FieldComponentAccess;
 import org.simantics.scl.compiler.constants.generic.CallJava;
 import org.simantics.scl.compiler.constants.generic.ClassRef;
 import org.simantics.scl.compiler.constants.generic.ConvertToListFilter;
 import org.simantics.scl.compiler.constants.generic.MethodRef;
-import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
 import org.simantics.scl.compiler.constants.generic.OutputFilter;
 import org.simantics.scl.compiler.constants.generic.ParameterStackItem;
 import org.simantics.scl.compiler.constants.generic.Pop2OutputFilter;
@@ -79,7 +80,6 @@ import org.simantics.scl.compiler.internal.deriving.InstanceDerivers;
 import org.simantics.scl.compiler.internal.elaboration.profiling.BranchPointInjector;
 import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents;
 import org.simantics.scl.compiler.internal.header.ModuleHeader;
-import org.simantics.scl.compiler.internal.parsing.Token;
 import org.simantics.scl.compiler.internal.parsing.declarations.ConstructorAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst;
 import org.simantics.scl.compiler.internal.parsing.declarations.DClassAst;
@@ -96,7 +96,6 @@ 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.exceptions.SCLSyntaxErrorException;
-import org.simantics.scl.compiler.internal.parsing.parser.SCLTerminals;
 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;
@@ -109,7 +108,6 @@ import org.simantics.scl.compiler.module.ModuleUtils;
 import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
 import org.simantics.scl.compiler.module.repository.ImportFailure;
 import org.simantics.scl.compiler.module.repository.ImportFailureException;
-import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
 import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.compiler.types.TForAll;
 import org.simantics.scl.compiler.types.TFun;
@@ -399,7 +397,7 @@ public class Elaboration {
                     parameterTypes[i] = context.toType(constructor.parameters[i]);
                 String javaName = constructors.length == 1 ? className 
                         : compilationContext.namingPolicy.getConstructorClassName(name);
-                String[] fieldNames = null;
+                ComponentAccess[] componentAccesses = null;
                 for(DAnnotationAst annotation : constructor.annotations)
                     if(annotation.id.text.equals("@JavaType")) {
                         try {
@@ -412,24 +410,24 @@ public class Elaboration {
                     else if(annotation.id.text.equals("@FieldNames")) {
                         try {
                             EListLiteral literal = (EListLiteral)annotation.parameters[0];
-                            fieldNames = new String[literal.getComponents().length];
-                            for(int i=0;i<fieldNames.length;++i) {
+                            componentAccesses = new ComponentAccess[literal.getComponents().length];
+                            for(int i=0;i<componentAccesses.length;++i) {
                                 Expression component = literal.getComponents()[i];
                                 if(component instanceof EVar)
-                                    fieldNames[i] = ((EVar)component).name;
+                                    componentAccesses[i] = new FieldComponentAccess(((EVar)component).name);
                                 else if(component instanceof ELiteral)
-                                    fieldNames[i] = ((StringConstant)((ELiteral)component).getValue()).getValue();
+                                    componentAccesses[i] = new FieldComponentAccess(((StringConstant)((ELiteral)component).getValue()).getValue());
                             }
                         } catch(Exception e) {
                             errorLog.log(annotation.parameters[0].location, "Invalid annotation parameter.");
-                            fieldNames = null;
+                            componentAccesses = null;
                         }
                     }   
                 
                 constructors[j] = new Constructor(constructor.location, dataType,
                         Name.create(moduleName, name), 
                         parameterTypes, javaName);
-                constructors[j].fieldNames = fieldNames;
+                constructors[j].componentAccesses = componentAccesses;
                 constructors[j].recordFieldNames = constructor.fieldNames;
             }
             if(constructors.length == 1) {
@@ -439,16 +437,19 @@ public class Elaboration {
                         @Override
                         public void run() {
                             Type in = Types.apply(dataType.name, dataType.parameters);
+                            
+                            ComponentAccess[] componentAccesses = constructor.componentAccesses != null
+                                       ? constructor.componentAccesses
+                                   : SCLConstructor.DEFAULT_FIELD_NAMES[constructor.recordFieldNames.length];
                             for(int i=0;i<constructor.recordFieldNames.length;++i) {
                                 Type out = constructor.parameterTypes[i];
                                 Constant accessor;
                                 if(trivialDataType)
                                     accessor = new SafeCoerce(dataType.parameters, in, out);
-                                else
+                                else 
                                     accessor = new CallJava(dataType.parameters, Types.NO_EFFECTS, out,
                                             new Type[] {in}, new StackItem[] {new ParameterStackItem(0, in)},
-                                            new FieldRef(constructor.javaName, constructor.fieldNames != null ? constructor.fieldNames[i] : "c" + i,
-                                                    javaTypeTranslator.toTypeDesc(out)),
+                                            componentAccesses[i].toMethodRef(constructor.javaName, javaTypeTranslator.toTypeDesc(out)),
                                             null);
                                 module.addFieldAccessor(constructor.recordFieldNames[i], accessor);
                             }
@@ -1131,6 +1132,7 @@ public class Elaboration {
             int constructorTag = 0;
             for(Constructor constructor : dataType.constructors) {
                 SCLValue value = new SCLValue(constructor.name);
+                value.parameterNames = constructor.recordFieldNames;
                 value.definitionLocation = constructor.loc;
                 SCLConstructor sclConstructor = 
                         new SCLConstructor(
@@ -1139,10 +1141,9 @@ public class Elaboration {
                                 constructor.getTypeVariables(),
                                 constructorTag++,
                                 constructor.getReturnType(),
-                                constructor.fieldNames == null 
+                                constructor.componentAccesses == null 
                                         ? SCLConstructor.DEFAULT_FIELD_NAMES[constructor.getParameterTypes().length] 
-                                        : constructor.fieldNames,
-                                constructor.recordFieldNames,
+                                        : constructor.componentAccesses,
                                 constructor.getParameterTypes());
                 if(dataType.constructors.length == 1 && (
                         dataType.getTypeDesc() == null ||
index 9e8c7a0f2310c79b0bc28c26fc505bdb07ae394c..1491c71bd6582cb90c9154f4e478846c3e5f119a 100644 (file)
@@ -2,6 +2,8 @@ package org.simantics.scl.compiler.constants;
 
 import org.cojen.classfile.TypeDesc;
 import org.objectweb.asm.Label;
+import org.simantics.scl.compiler.constants.componentaccess.ComponentAccess;
+import org.simantics.scl.compiler.constants.componentaccess.FieldComponentAccess;
 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
 import org.simantics.scl.compiler.internal.codegen.references.IVal;
@@ -18,40 +20,38 @@ import org.simantics.scl.compiler.types.Types;
 public class SCLConstructor extends FunctionValue {
     
     private static int MAX_FIELD_COUNT = Constants.MAX_TUPLE_LENGTH;
-    public static String[][] DEFAULT_FIELD_NAMES = new String[MAX_FIELD_COUNT+1][];
+    public static ComponentAccess[][] DEFAULT_FIELD_NAMES = new ComponentAccess[MAX_FIELD_COUNT+1][];
     
     static {
         for(int i=0;i<=MAX_FIELD_COUNT;++i) {
-            String[] fieldNames = new String[i];
+               ComponentAccess[] fieldNames = new ComponentAccess[i];
             for(int j=0;j<i;++j)
-                fieldNames[j] = "c" + j;
+                fieldNames[j] = new FieldComponentAccess("c" + j);
             DEFAULT_FIELD_NAMES[i] = fieldNames;
         }
     }
     
-    String name; // For debugging
-    String className;
-    String[] fieldNames;
+    private final String name; // For debugging
+    private final String className;
+    private final ComponentAccess[] componentAccesses;
     boolean onlyConstructor;
-    int constructorTag;
-    public final String[] recordFieldNames;
+    private final int constructorTag;
        
     public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
-            Type returnType, String[] fieldNames, String[] recordFieldNames, Type... parameterTypes) {
+            Type returnType, ComponentAccess[] componentAccesses, Type... parameterTypes) {
         super(typeParameters, Types.NO_EFFECTS, returnType, parameterTypes);
         ClassBuilder.checkClassName(className);
         this.name = name;
         this.className = className;
-        this.fieldNames = fieldNames;
+        this.componentAccesses = componentAccesses;
         this.constructorTag = constructorTag;
-        this.recordFieldNames = recordFieldNames;
     }    
     
     public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
             Type returnType,
             Type ... parameterTypes) {     
         this(name, className, typeParameters, constructorTag, returnType,
-                DEFAULT_FIELD_NAMES[parameterTypes.length], null, parameterTypes);
+                DEFAULT_FIELD_NAMES[parameterTypes.length], parameterTypes);
     }
     
     public void setOnlyConstructor(boolean onlyConstructor) {
@@ -118,7 +118,7 @@ public class SCLConstructor extends FunctionValue {
             
             if(!typeDesc.equals(TypeDesc.VOID)) {
                 mb.dup();
-                mb.loadField(MethodBuilder.getClassName(constructorType), fieldNames[i], typeDesc);                
+                componentAccesses[i].load(mb, MethodBuilder.getClassName(constructorType), typeDesc);
                 if(typeDesc == TypeDesc.OBJECT)
                     mb.unbox(contType);      
             }
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/ComponentAccess.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/ComponentAccess.java
new file mode 100644 (file)
index 0000000..95757e8
--- /dev/null
@@ -0,0 +1,12 @@
+package org.simantics.scl.compiler.constants.componentaccess;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+
+public interface ComponentAccess {
+
+       MethodRef toMethodRef(String baseClass, TypeDesc returnType);
+       void load(MethodBuilder mb, String baseClass, TypeDesc returnType);
+
+}
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/FieldComponentAccess.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/FieldComponentAccess.java
new file mode 100644 (file)
index 0000000..ca0b229
--- /dev/null
@@ -0,0 +1,24 @@
+package org.simantics.scl.compiler.constants.componentaccess;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+
+public class FieldComponentAccess implements ComponentAccess {
+       public final String fieldName;
+
+       public FieldComponentAccess(String fieldName) {
+               this.fieldName = fieldName;
+       }
+
+       @Override
+       public void load(MethodBuilder mb, String baseClass, TypeDesc returnType) {
+               mb.loadField(baseClass, fieldName, returnType);
+       }
+
+       @Override
+       public MethodRef toMethodRef(String baseClass, TypeDesc returnType) {
+               return new FieldRef(baseClass, fieldName, returnType);
+       }
+}
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/MethodComponentAccess.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/componentaccess/MethodComponentAccess.java
new file mode 100644 (file)
index 0000000..7283266
--- /dev/null
@@ -0,0 +1,30 @@
+package org.simantics.scl.compiler.constants.componentaccess;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
+import org.simantics.scl.compiler.internal.codegen.utils.Constants;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+
+public class MethodComponentAccess implements ComponentAccess {
+       public final String methodName;
+       public final boolean isInterface;
+
+       public MethodComponentAccess(String fieldName, boolean isInterface) {
+               this.methodName = fieldName;
+               this.isInterface = isInterface;
+       }
+
+       @Override
+       public void load(MethodBuilder mb, String baseClass, TypeDesc returnType) {
+               if(isInterface)
+                       mb.invokeInterface(baseClass, methodName, returnType, Constants.EMPTY_TYPEDESC_ARRAY);
+               else
+                       mb.invokeVirtual(baseClass, methodName, returnType, Constants.EMPTY_TYPEDESC_ARRAY);
+       }
+
+       @Override
+       public MethodRef toMethodRef(String baseClass, TypeDesc returnType) {
+               return new ObjectMethodRef(isInterface, baseClass, methodName, returnType, Constants.EMPTY_TYPEDESC_ARRAY);
+       }
+}
index 8c8180a66299d7fa1f33a5c85e5ad13d77137ec3..47ef205df17cbce0d9ff1d74dd8f1154adc1bcfa 100644 (file)
@@ -46,16 +46,12 @@ public class ERecord extends ASTExpression {
             context.getErrorLog().log(constructor.location, "Couldn't resolve the record constructor " + constructor.name + ".");
             return new EError(constructor.location);
         }
-        if(!(constructorValue.getValue() instanceof SCLConstructor)) {
+        String[] parameterNames = constructorValue.parameterNames;
+        if(parameterNames == null) {
             context.getErrorLog().log(constructor.location, "Value " + constructor.name + " is not a record constructor.");
             return new EError(constructor.location);
         }
-        String[] fieldNames = ((SCLConstructor)constructorValue.getValue()).recordFieldNames;
-        if(fieldNames == null) {
-            context.getErrorLog().log(constructor.location, "Value " + constructor.name + " is not a record constructor.");
-            return new EError(constructor.location);
-        }
-        Expression[] parameters = translateFieldsToFunctionParameters(context, fields, fieldNames, false);
+        Expression[] parameters = translateFieldsToFunctionParameters(context, fields, parameterNames, false);
         if(parameters == null)
             return new EError(location);
         if(asPattern)
@@ -73,7 +69,7 @@ public class ERecord extends ASTExpression {
                 if(parameter == null) {
                     ExistentialFrame frame = context.getCurrentExistentialFrame();
                     if(frame == null || frame.disallowNewExistentials) {
-                        context.getErrorLog().log(location, "Field " + fieldNames[i] + " not defined.");
+                        context.getErrorLog().log(location, "Field " + parameterNames[i] + " not defined.");
                         error = true;
                     }
                     else
index 0d4651d4852530452959897f87aca2a2f1b7f01d..08b03d04feddc900ae1994bbbe6597ab09b1f1f9 100644 (file)
@@ -35,6 +35,7 @@ public final class SCLValue implements Typed {
     private ArrayList<SCLValueProperty> properties = new ArrayList<SCLValueProperty>(2);
     public String documentation;
     public long definitionLocation = Locations.NO_LOCATION;
+    public String[] parameterNames;
     
     public SCLValue(Name name) {
         this.name = name;