package org.simantics.scl.compiler.elaboration.expressions; import java.util.Arrays; 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 gnu.trove.map.hash.THashMap; public class ERecord extends ASTExpression { public static final boolean DEBUG = false; public final EVar constructor; public final FieldAssignment[] fields; public ERecord(EVar 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.resolveRecordConstructor(location, 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.name + "."); return new EError(constructor.location); } 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); } Expression[] parameters = translateFieldsToFunctionParameters(context, fields, parameterNames, false); if(parameters == null) return new EError(location); if(asPattern) for(int i=0;i 0) System.out.print(", "); System.out.print(field.name); if(field.value != null) { System.out.print(" = "); System.out.print(field.value); } } System.out.println("}"); } THashMap recordMap = new THashMap(fields.length); boolean error = false; FieldAssignment wildcardField = null; for(FieldAssignment field : fields) { if(field.value == null) { String actualName = field.name; if(actualName.equals(FieldAssignment.WILDCARD)) { if(wildcardField != null) context.getErrorLog().log(field.location, "The record has more than one wildcard."); wildcardField = field; continue; } if(actualName.charAt(0) == '?') actualName = actualName.substring(1); String bestMatch = null; int bestMatchLength = 0; for(int i=0;i bestMatchLength) { bestMatch = fieldName; bestMatchLength = fieldName.length(); } } if(bestMatch == null) { context.getErrorLog().log(field.location, "Invalid shorthand field " + field.name + " is defined twice."); 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."); error = true; } } if(error) return null; Expression[] parameters = new Expression[fieldNames.length]; for(int i=0;i parameters = " + Arrays.toString(parameters)); return parameters; } @Override public void setLocationDeep(long loc) { if(location == Locations.NO_LOCATION) { location = loc; for(FieldAssignment field : fields) if(field.value != null) field.value.setLocationDeep(loc); } } @Override public Expression accept(ExpressionTransformer transformer) { return transformer.transform(this); } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } }