1 package org.simantics.scl.compiler.elaboration.expressions;
3 import org.simantics.scl.compiler.constants.SCLConstructor;
4 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
5 import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
6 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
7 import org.simantics.scl.compiler.environment.AmbiguousNameException;
8 import org.simantics.scl.compiler.errors.Locations;
9 import org.simantics.scl.compiler.internal.parsing.Token;
11 import gnu.trove.map.hash.THashMap;
13 public class ERecord extends ASTExpression {
16 FieldAssignment[] fields;
18 public ERecord(Token constructor, FieldAssignment[] fields) {
19 this.constructor = constructor;
24 public Expression resolve(TranslationContext context) {
25 return resolve(context, false);
29 public Expression resolveAsPattern(TranslationContext context) {
30 return resolve(context, true);
33 public Expression resolve(TranslationContext context, boolean asPattern) {
34 SCLValue constructorValue;
36 constructorValue = context.getEnvironment().getLocalNamespace().getValue(constructor.text);
37 } catch (AmbiguousNameException e) {
38 context.getErrorLog().log(constructor.location, e.getMessage());
39 return new EError(constructor.location);
41 if(constructorValue == null) {
42 context.getErrorLog().log(constructor.location, "Couldn't resolve the record constructor " + constructor.text + ".");
43 return new EError(constructor.location);
45 if(!(constructorValue.getValue() instanceof SCLConstructor)) {
46 context.getErrorLog().log(constructor.location, "Value " + constructor.text + " is not a record constructor.");
47 return new EError(constructor.location);
49 String[] fieldNames = ((SCLConstructor)constructorValue.getValue()).recordFieldNames;
50 if(fieldNames == null) {
51 context.getErrorLog().log(constructor.location, "Value " + constructor.text + " is not a record constructor.");
52 return new EError(constructor.location);
54 THashMap<String,FieldAssignment> recordMap = new THashMap<String,FieldAssignment>(fields.length);
55 for(FieldAssignment field : fields) {
56 if(field.value == null) {
57 String actualName = field.name;
58 if(actualName.charAt(0) == '?')
59 actualName = actualName.substring(1);
60 String bestMatch = null;
61 int bestMatchLength = 0;
62 for(int i=0;i<fieldNames.length;++i) {
63 String fieldName = fieldNames[i];
64 if(actualName.startsWith(fieldName) && fieldName.length() > bestMatchLength) {
65 bestMatch = fieldName;
66 bestMatchLength = fieldName.length();
69 if(bestMatch == null) {
70 context.getErrorLog().log(field.location, "Invalid shorthand field " + field.name + " is defined twice.");
71 return new EError(location);
73 field.value = new EVar(field.location, field.name);
74 field.name = bestMatch;
76 if(recordMap.put(field.name, field) != null) {
77 context.getErrorLog().log(field.location, "Field " + field.name + " is defined more than once.");
78 return new EError(location);
81 Expression[] parameters = new Expression[fieldNames.length];
82 boolean error = false;
83 for(int i=0;i<fieldNames.length;++i) {
84 FieldAssignment assignment = recordMap.remove(fieldNames[i]);
85 if(assignment == null) {
87 parameters[i] = Expressions.blank(null);
90 context.getErrorLog().log(location, "Field " + fieldNames[i] + " not defined.");
95 parameters[i] = asPattern
96 ? assignment.value.resolveAsPattern(context)
97 : assignment.value.resolve(context);
99 if(!recordMap.isEmpty()) {
100 for(FieldAssignment field : recordMap.values())
101 context.getErrorLog().log(field.location, "Field " + field.name + " is not defined in the constructor.");
105 return new EError(location);
107 EApply result = new EApply(new EConstant(constructorValue), parameters);
108 result.setLocationDeep(location);
114 public void setLocationDeep(long loc) {
115 if(location == Locations.NO_LOCATION) {
117 for(FieldAssignment field : fields)
118 if(field.value != null)
119 field.value.setLocationDeep(loc);
124 public Expression accept(ExpressionTransformer transformer) {
125 return transformer.transform(this);
129 public void accept(ExpressionVisitor visitor) {