]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ERecord.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / ERecord.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ERecord.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ERecord.java
new file mode 100644 (file)
index 0000000..cbb69a3
--- /dev/null
@@ -0,0 +1,103 @@
+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.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 ERecord(Token constructor, FieldAssignment[] fields) {
+        this.constructor = constructor;
+        this.fields = fields;
+    }
+
+    @Override
+    public Expression resolve(TranslationContext context) {
+        return resolve(context, false);
+    }
+    
+    @Override
+    public Expression resolveAsPattern(TranslationContext context) {
+        return resolve(context, true);
+    }
+    
+    public Expression resolve(TranslationContext context, boolean asPattern) {
+        SCLValue constructorValue; 
+        try {
+            constructorValue = context.getEnvironment().getLocalNamespace().getValue(constructor.text);
+        } 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 + ".");
+            return new EError(constructor.location);
+        }
+        if(!(constructorValue.getValue() instanceof SCLConstructor)) {
+            context.getErrorLog().log(constructor.location, "Value " + constructor.text + " 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.");
+            return new EError(constructor.location);
+        }
+        THashMap<String,FieldAssignment> recordMap = new THashMap<String,FieldAssignment>(fields.length);
+        for(FieldAssignment field : fields)
+            recordMap.put(field.name, field);
+        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(!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;
+        }
+    }
+
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            location = loc;
+            for(FieldAssignment field : fields)
+                field.value.setLocationDeep(loc);
+        }
+    }
+    
+    @Override
+    public Expression accept(ExpressionTransformer transformer) {
+        return transformer.transform(this);
+    }
+
+}