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