From: Hannu Niemistö Date: Sun, 4 Jun 2017 11:49:30 +0000 (+0300) Subject: (refs #7250) Support for record syntax for CHR relations X-Git-Tag: v1.31.0~339^2 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=6d233d1b05176e40f634766537082d2a2ec65fd0 (refs #7250) Support for record syntax for CHR relations Change-Id: I8dd80eb5216a1b6023ab9097af58d4f1aaa077b2 --- diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java index 359448e1d..fccf26815 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java @@ -376,7 +376,7 @@ public class Elaboration { dataTypes.add(dataType); for(int j=0;j=0;--i) parameterTypes[i] = context.toType(constructor.parameters[i]); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java index b34328a53..7b4a5bc26 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java @@ -7,11 +7,14 @@ import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation; import org.simantics.scl.compiler.elaboration.chr.relations.UnresolvedCHRRelation; import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext.ExistentialFrame; import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.elaboration.expressions.ERecord; import org.simantics.scl.compiler.elaboration.expressions.Expression; import org.simantics.scl.compiler.elaboration.expressions.Variable; import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure; import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; +import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment; import org.simantics.scl.compiler.elaboration.relations.SCLRelation; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.parsing.Symbol; @@ -29,6 +32,7 @@ public class CHRLiteral extends Symbol { public CHRRelation relation; public Type[] typeParameters; public Expression[] parameters; + public FieldAssignment[] fields; // optional public Expression[] typeConstraintEvidenceParameters; public boolean killAfterMatch; public boolean negated; @@ -55,6 +59,10 @@ public class CHRLiteral extends Symbol { if(sclRelation != null) relation = new ExternalCHRRelation(sclRelation); else { + if(parameters == null) { + context.getErrorLog().log(location, "Relation must be declared if record syntax is used."); + return; + } Type[] parameterTypes = new Type[parameters.length]; for(int i=0;i allRefs, TIntHashSet refs) { diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRelation.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRelation.java index 7369d496c..3daae67a9 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRelation.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRelation.java @@ -12,4 +12,7 @@ public interface CHRRelation { TVar[] getTypeVariables(); Type[] getParameterTypes(); TPred[] getTypeConstraints(); + default String[] getFieldNames() { + return null; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java index c0f439288..ee7347791 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java @@ -34,6 +34,7 @@ import gnu.trove.map.hash.TIntObjectHashMap; public class CHRConstraint extends Symbol implements CHRRelation { public final String name; public final Type[] parameterTypes; + public String[] fieldNames; public boolean implicitlyDeclared; @@ -229,4 +230,9 @@ public class CHRConstraint extends Symbol implements CHRRelation { else return w.apply(location, accessor, fact); } + + @Override + public String[] getFieldNames() { + return fieldNames; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/ExternalCHRRelation.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/ExternalCHRRelation.java index 5e4f5868c..6f44bc2ab 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/ExternalCHRRelation.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/ExternalCHRRelation.java @@ -32,4 +32,9 @@ public class ExternalCHRRelation implements CHRRelation { public String toString() { return relation.toString(); } + + @Override + public String[] getFieldNames() { + return relation.getFieldNames(); + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/translation/CHRTranslation.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/translation/CHRTranslation.java index 6972eb864..367960dfa 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/translation/CHRTranslation.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/translation/CHRTranslation.java @@ -3,6 +3,7 @@ package org.simantics.scl.compiler.elaboration.chr.translation; import java.util.ArrayList; import java.util.Arrays; +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.elaboration.chr.CHRLiteral; import org.simantics.scl.compiler.elaboration.chr.CHRQuery; import org.simantics.scl.compiler.elaboration.chr.CHRRule; @@ -12,6 +13,7 @@ import org.simantics.scl.compiler.elaboration.chr.relations.UnresolvedCHRRelatio import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.expressions.EApply; import org.simantics.scl.compiler.elaboration.expressions.EBinary; +import org.simantics.scl.compiler.elaboration.expressions.ERecord; import org.simantics.scl.compiler.elaboration.expressions.EVar; import org.simantics.scl.compiler.elaboration.expressions.Expression; import org.simantics.scl.compiler.elaboration.expressions.block.CHRStatement; @@ -20,9 +22,11 @@ import org.simantics.scl.compiler.elaboration.expressions.list.ListAssignment; import org.simantics.scl.compiler.elaboration.expressions.list.ListGenerator; import org.simantics.scl.compiler.elaboration.expressions.list.ListGuard; import org.simantics.scl.compiler.elaboration.expressions.list.ListQualifier; +import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment; import org.simantics.scl.compiler.environment.AmbiguousNameException; import org.simantics.scl.compiler.environment.Environments; import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst; import org.simantics.scl.compiler.internal.parsing.types.TypeAst; public class CHRTranslation { @@ -35,18 +39,27 @@ public class CHRTranslation { } private static CHRLiteral convertConstraint(boolean remove, boolean negated, Expression expression) { - ArrayList parameters = new ArrayList(4); - while(expression instanceof EApply) { + long location = expression.location; + Expression[] parameters; + FieldAssignment[] fields = null; + if(expression instanceof EApply) { EApply apply = (EApply)expression; - for(int i=apply.parameters.length-1;i>=0;--i) - parameters.add(apply.parameters[i]); + parameters = apply.parameters; expression = apply.function; } - EVar var = (EVar)expression; - Expression[] parametersArray = new Expression[parameters.size()]; - for(int i=0,j=parametersArray.length-1;i variables = new THashSet(4); ArrayList blanks = new ArrayList(2); - boolean disallowNewExistentials; + public boolean disallowNewExistentials; + + public EVariable createBlank(long location) { + Variable variable = new Variable("_"); + blanks.add(variable); + EVariable result = new EVariable(variable); + result.location = location; + return result; + } } THashMap variables = new THashMap(); @@ -128,14 +136,12 @@ public class TranslationContext extends TypeTranslationContext implements Enviro } case '_': { if(name.length()==1) { - variable = new Variable("_"); ExistentialFrame existentialFrame = getCurrentExistentialFrame(); if(existentialFrame == null || existentialFrame.disallowNewExistentials) { errorLog.log(location, "Blank variables can be used only in queries."); return new EError(location); } - existentialFrame.blanks.add(variable); - return new EVariable(variable); + return existentialFrame.createBlank(location); } break; } @@ -143,7 +149,7 @@ public class TranslationContext extends TypeTranslationContext implements Enviro return null; } - private ExistentialFrame getCurrentExistentialFrame() { + public ExistentialFrame getCurrentExistentialFrame() { int size = existentialFrames.size(); if(size == 0) return null; 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 index a41c0f042..e1f444d82 100644 --- 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 @@ -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 recordMap = new THashMap(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)get(i++); Token nameToken = (Token)get(i++); - EVar name = new EVar(nameToken.location, nameToken.text); + EVar name = new EVar(nameToken); ArrayList parameters = new ArrayList(); while(i < length()) { Object symbol = get(i++); @@ -334,7 +334,7 @@ public class SCLParserImpl extends SCLParser { else context = (ArrayList)get(i++); Token nameToken = (Token)get(i++); - EVar name = new EVar(nameToken.location, nameToken.text); + EVar name = new EVar(nameToken); ArrayList parameters = new ArrayList(); while(i < length()) { Object symbol = get(i++); @@ -424,12 +424,12 @@ public class SCLParserImpl extends SCLParser { @Override protected Object reduceVarId() { - return new EVar(((Token)get(0)).text); + return new EVar((Token)get(0)); } @Override protected Object reduceEscapedSymbol() { - return new EVar(((Token)get(0)).text); + return new EVar((Token)get(0)); } @Override @@ -460,7 +460,7 @@ public class SCLParserImpl extends SCLParser { EVar negation = null; if(get(i) instanceof Token) { Token token = (Token)get(i++); - negation = new EVar(token.location, token.text); + negation = new EVar(token); } EBinary binary = new EBinary((Expression)get(i++), negation); while(i < length()) { @@ -527,7 +527,7 @@ public class SCLParserImpl extends SCLParser { TypeAst[] parameters = new TypeAst[length()-idPos-1]; for(int i=0;i print ?x + X V { ?y } => print ?y + True => X V { x = 1.0, y = 2.0 } + True => X V { x = 3.0, y = 4.0 } +-- +1.0 +2.0 +3.0 +4.0 +() +-- +module { export = [main], chr } +import "StandardLibrary" + +data V = V { x :: Double, y :: Double } + +main = () + where + constraint X V + True => X V { x = 1.0 } +-- +9:15-9:28: Field y not defined. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl index edefae634..c59c02dbb 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl @@ -1,8 +1,4 @@ -module { - export = [main], - chr -} - +module { export = [main], chr } import "StandardLibrary" ruleset IntegerSet where diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl index 325af5270..f1e28d08a 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl @@ -1,8 +1,4 @@ -module { - export = [main], - chr -} - +module { export = [main], chr } import "StandardLibrary" ruleset RS where diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl index 6576cf47e..b10257ca8 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl @@ -1,8 +1,4 @@ -module { - export = [main], - chr -} - +module { export = [main], chr } import "StandardLibrary" ruleset RS where diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl index ce3064aa4..c3a88f58a 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl @@ -1,12 +1,8 @@ -module { - export = [main], - chr -} - +module { export = [main], chr } import "StandardLibrary" main = () where X ?x => Y ?y -- -10:15-10:17: New existential variables can be defined only in queries. \ No newline at end of file +6:15-6:17: New existential variables can be defined only in queries. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl new file mode 100644 index 000000000..07514821a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl @@ -0,0 +1,42 @@ +module { export = [main], chr } +import "StandardLibrary" + +main = () + where + constraint V { x :: Double, y :: Double } + V { ?x } => print ?x + True => V { x = 1.0, y = 2.0 } +-- +1.0 +() +-- +module { export = [main], chr } +import "StandardLibrary" + +main = () + where + constraint V { x :: Double, y :: Double } + True => V { x = 1.0 } +-- +7:13-7:26: Field y not defined. +-- +module { export = [main], chr } + +import "StandardLibrary" + +main = () + where + constraint V Double Double + True => V { x = 1.0, y = 2.0 } +-- +8:13-8:35: Relation V does not define field names. +-- +module { export = [main], chr } + +import "StandardLibrary" + +main = () + where + True => V { x = 1.0, y = 2.0 } +-- +7:13-7:35: Relation must be declared if record syntax is used. \ No newline at end of file