]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ERecord.java
(refs #7250) Support for record syntax for CHR relations
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / ERecord.java
index a41c0f042d46034e782ec06b78888bfe146cf7c9..e1f444d8220a12801d3ad430c55c11065a4edef8 100644 (file)
@@ -2,20 +2,20 @@ package org.simantics.scl.compiler.elaboration.expressions;
 
 import org.simantics.scl.compiler.constants.SCLConstructor;
 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext.ExistentialFrame;
 import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.environment.AmbiguousNameException;
 import org.simantics.scl.compiler.errors.Locations;
-import org.simantics.scl.compiler.internal.parsing.Token;
 
 import gnu.trove.map.hash.THashMap;
 
 public class ERecord extends ASTExpression {
 
-    Token constructor;
-    FieldAssignment[] fields;
+    public final EVar constructor;
+    public final FieldAssignment[] fields;
     
-    public ERecord(Token constructor, FieldAssignment[] fields) {
+    public ERecord(EVar constructor, FieldAssignment[] fields) {
         this.constructor = constructor;
         this.fields = fields;
     }
@@ -33,30 +33,67 @@ public class ERecord extends ASTExpression {
     public Expression resolve(TranslationContext context, boolean asPattern) {
         SCLValue constructorValue; 
         try {
-            constructorValue = context.getEnvironment().getLocalNamespace().getValue(constructor.text);
+            constructorValue = context.getEnvironment().getLocalNamespace().getValue(constructor.name);
         } catch (AmbiguousNameException e) {
             context.getErrorLog().log(constructor.location, e.getMessage());
             return new EError(constructor.location);
         }
         if(constructorValue == null) {
-            context.getErrorLog().log(constructor.location, "Couldn't resolve the record constructor " + constructor.text + ".");
+            context.getErrorLog().log(constructor.location, "Couldn't resolve the record constructor " + constructor.name + ".");
             return new EError(constructor.location);
         }
         if(!(constructorValue.getValue() instanceof SCLConstructor)) {
-            context.getErrorLog().log(constructor.location, "Value " + constructor.text + " is not a record constructor.");
+            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.text + " is not a record constructor.");
+            context.getErrorLog().log(constructor.location, "Value " + constructor.name + " is not a record constructor.");
             return new EError(constructor.location);
         }
+        Expression[] parameters = translateFieldsToFunctionParameters(context, fields, fieldNames);
+        if(parameters == null)
+            return new EError(location);
+        if(asPattern)
+            for(int i=0;i<parameters.length;++i) {
+                Expression parameter = parameters[i];
+                if(parameter == null)
+                    parameters[i] = Expressions.blank(null);
+                else
+                    parameters[i] = parameter.resolveAsPattern(context);
+            }
+        else {
+            boolean error = false;
+            for(int i=0;i<parameters.length;++i) {
+                Expression parameter = parameters[i];
+                if(parameter == null) {
+                    ExistentialFrame frame = context.getCurrentExistentialFrame();
+                    if(frame == null || frame.disallowNewExistentials) {
+                        context.getErrorLog().log(location, "Field " + fieldNames[i] + " not defined.");
+                        error = true;
+                    }
+                    else
+                        parameters[i] = frame.createBlank(location); 
+                }
+                else
+                    parameters[i] = parameter.resolve(context);
+            }
+            if(error)
+                return new EError(location);
+        }
+        EApply result = new EApply(new EConstant(constructorValue), parameters);
+        result.setLocationDeep(location);
+        return result;
+    }
+    
+    public static Expression[] translateFieldsToFunctionParameters(TranslationContext context, FieldAssignment[] fields, String[] fieldNames) {
         THashMap<String,FieldAssignment> recordMap = new THashMap<String,FieldAssignment>(fields.length);
+        boolean error = false;
         for(FieldAssignment field : fields) {
             if(field.value == null) {
-               String actualName = field.name;
-               if(actualName.charAt(0) == '?')
-                       actualName = actualName.substring(1);
+                String actualName = field.name;
+                if(actualName.charAt(0) == '?')
+                    actualName = actualName.substring(1);
                 String bestMatch = null;
                 int bestMatchLength = 0;
                 for(int i=0;i<fieldNames.length;++i) {
@@ -68,46 +105,30 @@ public class ERecord extends ASTExpression {
                 }
                 if(bestMatch == null) {
                     context.getErrorLog().log(field.location, "Invalid shorthand field " + field.name + " is defined twice.");
-                    return new EError(location);
+                    error = true;
                 }
                 field.value = new EVar(field.location, field.name);
                 field.name = bestMatch;
             }
             if(recordMap.put(field.name, field) != null) {
                 context.getErrorLog().log(field.location, "Field " + field.name + " is defined more than once.");
-                return new EError(location);
+                error = true;
             }
         }
+        if(error)
+            return null;
         Expression[] parameters = new Expression[fieldNames.length];
-        boolean error = false;
         for(int i=0;i<fieldNames.length;++i) {
             FieldAssignment assignment = recordMap.remove(fieldNames[i]);
-            if(assignment == null) {
-                if(asPattern) {
-                    parameters[i] = Expressions.blank(null);
-                }
-                else {
-                    context.getErrorLog().log(location, "Field " + fieldNames[i] + " not defined.");
-                    error = true;
-                }
-            }
-            else
-                parameters[i] = asPattern
-                        ? assignment.value.resolveAsPattern(context) 
-                        : assignment.value.resolve(context);
+            if(assignment != null)
+                parameters[i] = assignment.value;
         }
         if(!recordMap.isEmpty()) {
             for(FieldAssignment field : recordMap.values())
                 context.getErrorLog().log(field.location, "Field " + field.name + " is not defined in the constructor.");
-            error = true;
-        }
-        if(error)
-            return new EError(location);
-        else {
-            EApply result = new EApply(new EConstant(constructorValue), parameters);
-            result.setLocationDeep(location);
-            return result;
+            return null;
         }
+        return parameters;
     }
 
     @Override