(refs #7371) Support for select keyword for CHR constraints 26/726/2
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 19 Jul 2017 10:42:20 +0000 (13:42 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 19 Jul 2017 10:53:05 +0000 (13:53 +0300)
Change-Id: Ie23a1cd698b230f9be05ff38c937cfcbd13d658b

34 files changed:
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/common/names/Names.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRLiteral.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRQuery.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/plan/PlanOp.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/translation/CHRTranslation.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ASTExpression.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRRuleset.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRSelect.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELet.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRSelect.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreLet.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionTransformer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ExpressionVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionTransformer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/StandardExpressionVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/list/ListQualifier.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/printing/ExpressionToStringVisitor.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCL.grammar
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLLexer.flex
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLLexer.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.dat
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParserImpl.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLTerminals.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/parser/grammar/input/GrammarParser.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR12.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect1.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect2.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect3.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidLambda.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnexpectedToken.scl

index 50729430db70e2a07f7cfa894424b82cfdc058b4..183d857967ea4cbcc3504df734ecefcf33764550 100644 (file)
@@ -20,6 +20,7 @@ public class Names {
     public static final Name JavaBuiltin_unsafeCoerce = Name.create("JavaBuiltin", "unsafeCoerce");
     public static final Name MList_add = Name.create("MList", "add");
     public static final Name MList_create = Name.create("MList", "create");
+    public static final Name MList_freeze = Name.create("MList", "freeze");
     public static final Name MList_removeLast = Name.create("MList", "removeLast");
     public static final TCon MList_T = Types.con("MList", "T");
     public static final Name MSet_add = Name.create("MSet", "add");
index f44609e6c1b13552b9311025f2872c740a10978c..e7b3320d77758d87b023904aa880f980a99f8ec5 100644 (file)
@@ -187,8 +187,10 @@ public class CHRLiteral extends Symbol {
     }
 
     public void collectQueryEffects(THashSet<Type> effects) {
+        // TODO
     }
 
     public void collectEnforceEffects(THashSet<Type> effects) {
+        // TODO
     }
 }
index 5cb0f2aee230acb6f79838fd358612c81edc024f..70559d18f6f223543b4a99d9e7ba144ac9266c1e 100644 (file)
@@ -13,6 +13,7 @@ import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
 import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.parsing.Symbol;
+import org.simantics.scl.compiler.types.Type;
 
 import gnu.trove.map.hash.TObjectIntHashMap;
 import gnu.trove.set.hash.THashSet;
@@ -71,7 +72,7 @@ public class CHRQuery extends Symbol {
             else
                 context.add(literal, i);
         }
-        if(activeLiteralId == -1) {
+        if(activeLiteralId == -1 && inputFact != null) {
             context.addInitFact(initConstraint, inputFact);
         }      
         return context.createQueryPlan();
@@ -95,4 +96,14 @@ public class CHRQuery extends Symbol {
         visitor.visit(this);
         return b.toString();
     }
+
+    public void collectQueryEffects(THashSet<Type> effects) {
+        for(CHRLiteral literal : literals)
+            literal.collectQueryEffects(effects);
+    }
+    
+    public void collectEnforceEffects(THashSet<Type> effects) {
+        for(CHRLiteral literal : literals)
+            literal.collectEnforceEffects(effects);
+    }
 }
index a792256049a1551900d5c26de0f6552c7967f70f..aa317a2b27ee372568a982c138daa2bcaa625eb1 100644 (file)
@@ -17,6 +17,6 @@ public abstract class PlanOp {
         return b.toString();
     }
 
-    public abstract void toString(StringBuilder b);
+    public void toString(StringBuilder b) {}
     public abstract void generateCode(CompilationContext context, PlanContext planContext, CodeWriter w);
 }
index 367960dfafc0a35f5f2ddb0d9870bd9152c6924c..d4f21a7265178bfe2b629066b423349066cd917f 100644 (file)
@@ -3,7 +3,6 @@ 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;
@@ -131,22 +130,20 @@ public class CHRTranslation {
         }
     }
 
-    public static CHRRule convertCHRStatement(TranslationContext context, CHRStatement statement) {
-        ArrayList<CHRLiteral> head = new ArrayList<CHRLiteral>(statement.head.length);
-        for(ListQualifier qualifier : statement.head) {
-            CHRLiteral literal = convertListQualifier(context, true, qualifier);
-            if(literal != null)
-                head.add(literal);
-        }
-        ArrayList<CHRLiteral> body = new ArrayList<CHRLiteral>(statement.body.length);
-        for(ListQualifier qualifier : statement.body) {
-            CHRLiteral literal = convertListQualifier(context, false, qualifier);
+    public static CHRQuery convertCHRQuery(TranslationContext context, boolean isHead, ListQualifier[] lqs) {
+        ArrayList<CHRLiteral> query = new ArrayList<CHRLiteral>(lqs.length);
+        for(ListQualifier qualifier : lqs) {
+            CHRLiteral literal = convertListQualifier(context, isHead, qualifier);
             if(literal != null)
-                body.add(literal);
+                query.add(literal);
         }
+        return new CHRQuery(query.toArray(new CHRLiteral[query.size()]));
+    }
+    
+    public static CHRRule convertCHRStatement(TranslationContext context, CHRStatement statement) {
         return new CHRRule(statement.location,
-                new CHRQuery(head.toArray(new CHRLiteral[head.size()])),
-                new CHRQuery(body.toArray(new CHRLiteral[body.size()])),
+                convertCHRQuery(context, true, statement.head),
+                convertCHRQuery(context, false, statement.body),
                 null);
     }
 
index ac9299d77f968a3a7623c5974005eacd5502f87c..b533e922d252d0bcd73c07324564b9e3cde8236a 100644 (file)
@@ -75,6 +75,8 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
     TIntArrayList chrConstraintFrames = new TIntArrayList();
     ArrayList<CHRConstraintEntry> chrConstraintEntries = new ArrayList<CHRConstraintEntry>();
     
+    public CHRRuleset currentRuleset;
+    
     static class Entry {
         String name;
         Variable variable;
index fbc0a79014dcb107c3b17842ef5bbb06fddaac8b..02db9bdec3356e18d151a92bc342acefa8cc8831 100644 (file)
@@ -3,6 +3,7 @@ package org.simantics.scl.compiler.elaboration.expressions;
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
 import org.simantics.scl.compiler.types.Type;
 import org.simantics.scl.compiler.types.exceptions.MatchException;
@@ -23,7 +24,6 @@ public abstract class ASTExpression extends SimplifiableExpression {
     @Override
     final public void collectFreeVariables(THashSet<Variable> vars) {
         throw new InternalCompilerError(getClass().getSimpleName() + " does not support collectFreeVariables.");
-
     }
     
     @Override
@@ -58,6 +58,11 @@ public abstract class ASTExpression extends SimplifiableExpression {
         throw new InternalCompilerError(getClass().getSimpleName() + " does not support accept.");
     }
     
+    @Override
+    public Expression accept(ExpressionTransformer transformer) {
+        throw new InternalCompilerError(getClass().getSimpleName() + " does not support accept.");
+    }
+    
     @Override
     public Expression checkBasicType(TypingContext context, Type requiredType) {
         throw new InternalCompilerError("Class " + 
@@ -75,4 +80,10 @@ public abstract class ASTExpression extends SimplifiableExpression {
         throw new InternalCompilerError("Class " + 
                 getClass().getSimpleName() + " does not implement method forVariables.");
     }
+    
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION)
+            location = loc;
+    }
 }
index 9a8aa78b929199b8e6aad3b4db405d4e9e2e2b15..65ce2e2df974ab28587a537eb75bb7657652e4c9 100644 (file)
@@ -58,12 +58,21 @@ public class ECHRRuleset extends Expression {
     }
     @Override
     public Expression resolve(TranslationContext context) {
+        if(context.currentRuleset != null) {
+            context.getErrorLog().log(location, "Current version of SCL compiler does not support nested rulesets.");
+            return this;
+        }
+        context.currentRuleset = ruleset;
+        
         context.pushFrame();
         context.pushCHRConstraintFrame();
         ruleset.resolve(context);
         in = in.resolve(context);
         context.popCHRConstraintFrame(ruleset.constraints);
         context.popFrame();
+        
+        context.currentRuleset = null;
+        
         return this;
     }
     @Override
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRSelect.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ECHRSelect.java
new file mode 100644 (file)
index 0000000..47c007d
--- /dev/null
@@ -0,0 +1,152 @@
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.common.names.Names;
+import org.simantics.scl.compiler.compilation.CompilationContext;
+import org.simantics.scl.compiler.constants.NoRepConstant;
+import org.simantics.scl.compiler.elaboration.chr.CHRQuery;
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
+import org.simantics.scl.compiler.elaboration.chr.plan.PlanContext;
+import org.simantics.scl.compiler.elaboration.chr.plan.PlanOp;
+import org.simantics.scl.compiler.elaboration.chr.plan.PlanRealizer;
+import org.simantics.scl.compiler.elaboration.chr.planning.QueryPlanningContext;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.codegen.references.IVal;
+import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
+import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+import org.simantics.scl.compiler.types.kinds.Kinds;
+
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.set.hash.TIntHashSet;
+
+public class ECHRSelect extends Expression {
+    CHRQuery query;
+    Variable[] existentialVariables;
+    Expression expression;
+    private ArrayList<PlanOp> planOps;
+    private CHRRuleset currentRuleset;
+    
+    public ECHRSelect(Expression expression, CHRQuery query) {
+        this.expression = expression;
+        this.query = query;
+    }
+
+    @Override
+    public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
+        query.collectRefs(allRefs, refs);
+        expression.collectRefs(allRefs, refs);
+    }
+
+    @Override
+    public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
+        query.collectVars(allVars, vars);
+        expression.collectVars(allVars, vars);
+    }
+
+    @Override
+    public void forVariables(VariableProcedure procedure) {
+        query.forVariables(procedure);
+        expression.forVariables(procedure);
+    }
+
+    @Override
+    protected void updateType() throws MatchException {
+        setType(Types.list(expression.getType()));
+    }
+
+    @Override
+    public Expression inferType(TypingContext context) {
+        for(Variable variable : existentialVariables)
+            variable.setType(Types.metaVar(Kinds.STAR));
+        query.checkType(context);
+        expression = expression.inferType(context);
+        return this;
+    }
+    
+    @Override
+    public Expression simplify(SimplificationContext simplificationContext) {
+        this.expression = expression.simplify(simplificationContext);
+        query.simplify(simplificationContext);
+        
+        CompilationContext compilationContext = simplificationContext.getCompilationContext();
+        QueryPlanningContext context = new QueryPlanningContext(compilationContext, existentialVariables);
+        if(query.createQueryPlan(context, null, -1, null))
+            planOps = context.getPlanOps();
+
+        return this;
+    }
+    
+    @Override
+    public IVal toVal(CompilationContext context, CodeWriter w) {
+        IVal list = w.apply(location, context.getValue(Names.MList_create).getValue(), NoRepConstant.UNIT);
+        planOps.add(new PlanOp(location) {
+            @Override
+            public void generateCode(CompilationContext context, PlanContext planContext, CodeWriter w) {
+                w.apply(location, context.getValue(Names.MList_add).getValue(), list, expression.toVal(context, w));
+            }
+        });
+        PlanRealizer realizer = new PlanRealizer(context, currentRuleset, currentRuleset != null ? currentRuleset.runtimeRulesetVariable : null, null, planOps);
+        realizer.nextOp(w);
+        return w.apply(location, context.getValue(Names.MList_freeze).getValue(), list);
+    }
+
+    @Override
+    public void collectFreeVariables(THashSet<Variable> vars) {
+        query.collectFreeVariables(vars);
+        expression.collectFreeVariables(vars);
+        if(existentialVariables != null)
+            for(Variable variable : existentialVariables)
+                vars.remove(variable);
+    }
+
+    @Override
+    public Expression resolve(TranslationContext context) {
+        currentRuleset = context.currentRuleset;
+        
+        context.pushExistentialFrame();
+        query.resolve(context);
+        context.disallowNewExistentials();
+        expression = expression.resolve(context);
+        existentialVariables = context.popExistentialFrame();
+        return this;
+    }
+
+    @Override
+    public void setLocationDeep(long loc) {
+        if(location == Locations.NO_LOCATION) {
+            query.setLocationDeep(loc);
+            expression.setLocationDeep(loc);
+        }
+    }
+
+    @Override
+    public Expression decorate(ExpressionDecorator decorator) {
+        this.expression = decorator.decorate(expression);
+        return this;
+    }
+
+    @Override
+    public void collectEffects(THashSet<Type> effects) {
+        expression.collectEffects(effects);
+        query.collectQueryEffects(effects);
+        effects.add(Types.PROC);
+    }
+
+    @Override
+    public void accept(ExpressionVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public Expression accept(ExpressionTransformer transformer) {
+        return transformer.transform(this);
+    }
+}
index 2b9e8e2c0d9cc71a71f59ff3f37d798f199a5167..a90c6186d78f8e1e2690d5dab745d56cde171de7 100644 (file)
@@ -25,6 +25,9 @@ import gnu.trove.map.hash.TObjectIntHashMap;
 import gnu.trove.set.hash.THashSet;
 import gnu.trove.set.hash.TIntHashSet;
 
+/**
+ * Generated maily from EPreLet
+ */
 public class ELet extends Expression {
     public Assignment[] assignments;
     public Expression in;
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRSelect.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreCHRSelect.java
new file mode 100644 (file)
index 0000000..80943f7
--- /dev/null
@@ -0,0 +1,22 @@
+package org.simantics.scl.compiler.elaboration.expressions;
+
+import org.simantics.scl.compiler.elaboration.chr.translation.CHRTranslation;
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
+import org.simantics.scl.compiler.elaboration.expressions.list.ListQualifier;
+
+public class EPreCHRSelect extends ASTExpression {
+    ListQualifier[] query;
+    Expression expression;
+    
+    public EPreCHRSelect(ListQualifier[] query, Expression expression) {
+        this.query = query;
+        this.expression = expression;
+    }
+
+    @Override
+    public Expression resolve(TranslationContext context) {
+        return new ECHRSelect(expression, CHRTranslation.convertCHRQuery(context, true, query)).resolve(context);
+    }
+
+
+}
index 035a2cadca6a02413575095ccd83112662961117..c7624039e6e75fdc9f5f4a986c499934eb109942 100644 (file)
@@ -13,6 +13,9 @@ import org.simantics.scl.compiler.errors.Locations;
 import gnu.trove.map.hash.THashMap;
 import gnu.trove.procedure.TObjectObjectProcedure;
 
+/**
+ * Generated mainly from EBlock
+ */
 public class EPreLet extends ASTExpression {
 
     List<LetStatement> assignments;
index 2b75f61cd0c236a2d37a5f7dae20e26224281362..02590273d453b889e489a5a2070b909da911db96 100644 (file)
@@ -252,6 +252,9 @@ public abstract class Expression extends Symbol implements Typed {
         return expression;
     }
 
+    /**
+     * Used during simplification and in toIExpression
+     */
     public THashSet<Variable> getFreeVariables() {
         THashSet<Variable> result = new THashSet<Variable>();
         collectFreeVariables(result);
index 4cf513c542647b1ccc3c8e1dd7cc8f020447c66d..c0c329ba315cca0f90d4a04cd30c74e51be3fb69 100644 (file)
@@ -9,6 +9,7 @@ public interface ExpressionTransformer {
     Expression transform(EBinary expression);
     Expression transform(EBind expression);
     Expression transform(EBlock expression);
+    Expression transform(ECHRSelect expression);
     Expression transform(ECHRRuleset expression);
     Expression transform(ECHRRulesetConstructor expression);
     Expression transform(EConstant expression);
index ad32098baadb7538d27c699c41d4dcf906df486a..861cf48a7daa3146abb26c018b00b3efcb082551 100644 (file)
@@ -8,6 +8,7 @@ public interface ExpressionVisitor {
     void visit(EBinary expression);
     void visit(EBind expression);
     void visit(EBlock expression);
+    void visit(ECHRSelect expression);
     void visit(ECHRRuleset expression);
     void visit(ECHRRulesetConstructor expression);
     void visit(EConstant expression);
index 1bd0d22c4ec4b7f4a075f0375da97a53075714c0..97d409f153837e7bda7090811f71c74400ca26c4 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.scl.compiler.elaboration.expressions;
 
 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
+import org.simantics.scl.compiler.elaboration.chr.CHRQuery;
 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.equation.EqBasic;
@@ -125,14 +126,16 @@ EquationVisitor {
         statement.value = statement.value.accept(this);
     }
     
+    public void transform(CHRQuery query) {
+        for(CHRLiteral lit : query.literals)
+            for(int i=0;i<lit.parameters.length;++i)
+                lit.parameters[i] = lit.parameters[i].accept(this);
+    }
+    
     public void transform(CHRRuleset ruleset) {
         for(CHRRule rule : ruleset.rules) {
-            for(CHRLiteral lit : rule.head.literals)
-                for(int i=0;i<lit.parameters.length;++i)
-                    lit.parameters[i] = lit.parameters[i].accept(this);
-            for(CHRLiteral lit : rule.body.literals)
-                for(int i=0;i<lit.parameters.length;++i)
-                    lit.parameters[i] = lit.parameters[i].accept(this);
+            transform(rule.head);
+            transform(rule.body);
         }
     }
     
@@ -143,6 +146,13 @@ EquationVisitor {
         return expression;
     }
     
+    @Override
+    public Expression transform(ECHRSelect expression) {
+        expression.expression = expression.expression.accept(this);
+        transform(expression.query);
+        return expression;
+    }
+    
     @Override
     public Expression transform(ECHRRulesetConstructor expression) {
         transform(expression.ruleset);
index b7ce06d92fc4ea01e3f9660ba8465514b26afda1..83bbd34d1bfe29356cf14811828fa1bfec7f9270 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.scl.compiler.elaboration.expressions;
 
 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
+import org.simantics.scl.compiler.elaboration.chr.CHRQuery;
 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
 import org.simantics.scl.compiler.elaboration.equation.EqBasic;
@@ -198,6 +199,12 @@ EquationVisitor, StatementVisitor {
         expression.query.accept(this);
         expression.expression.accept(this);
     }
+    
+    @Override
+    public void visit(ECHRSelect expression) {
+        visit(expression.query);
+        expression.expression.accept(this);
+    }
 
     @Override
     public void visit(ESimpleLambda expression) {
@@ -356,14 +363,16 @@ EquationVisitor, StatementVisitor {
             equation.accept(this);
     }
     
+    public void visit(CHRQuery query) {
+        for(CHRLiteral literal : query.literals)
+            for(Expression parameter : literal.parameters)
+                parameter.accept(this);
+    }
+    
     public void visit(CHRRuleset ruleset) {
         for(CHRRule rule : ruleset.rules) {
-            for(CHRLiteral literal : rule.head.literals)
-                for(Expression parameter : literal.parameters)
-                    parameter.accept(this);
-            for(CHRLiteral literal : rule.body.literals)
-                for(Expression parameter : literal.parameters)
-                    parameter.accept(this);
+            visit(rule.head);
+            visit(rule.body);
         }
     }
 
index 67d20374e26cc6619266c53299de7dc6943dc8c9..22e0c6b76cbb571245e5b3b57d21aeb0ba093844 100644 (file)
@@ -19,6 +19,9 @@ public abstract class ListQualifier extends Symbol {
     public abstract void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs);
     public abstract void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars);
     public abstract void collectFreeVariables(THashSet<Variable> vars);
+    /**
+     * Called in simplification.
+     */
     public abstract CompiledQualifier compile(SimplificationContext context);
     public abstract void resolve(TranslationContext context);
     public abstract void decorate(ExpressionDecorator decorator);
index 3f6da74cb9ffd9f7cf0daddd78f4dfe4bbc775ba..edf951711c2c247f763fa7a23ab3e4eee0482652 100644 (file)
@@ -16,6 +16,7 @@ import org.simantics.scl.compiler.elaboration.expressions.EBind;
 import org.simantics.scl.compiler.elaboration.expressions.EBlock;
 import org.simantics.scl.compiler.elaboration.expressions.ECHRRuleset;
 import org.simantics.scl.compiler.elaboration.expressions.ECHRRulesetConstructor;
+import org.simantics.scl.compiler.elaboration.expressions.ECHRSelect;
 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
 import org.simantics.scl.compiler.elaboration.expressions.ECoveringBranchPoint;
 import org.simantics.scl.compiler.elaboration.expressions.EEnforce;
@@ -329,7 +330,12 @@ public class ExpressionToStringVisitor implements ExpressionVisitor, QueryVisito
     public void visit(ESelect expression) {
         b.append("ESelect");
     }
-
+    
+    @Override
+    public void visit(ECHRSelect expression) {
+        b.append("ECHRSelect");
+    }
+    
     @Override
     public void visit(ESimpleLambda expression) {
         b.append('\\');
index f7ea1b263617cee6eae8dbc4e5dda34139e10e45..ea3df9722456cec4163ee9694498ea7b5e7716fb 100644 (file)
@@ -138,7 +138,7 @@ lexp
                                                                shift ESCAPED_SYMBOL, shift CHAR, shift LBRACE,
                                                                shift WHEN, shift ATTACHED_HASH,
                                                                shift SELECT, shift SELECT_FIRST, shift SELECT_DISTINCT,
-                                                               shift TRANSFORMATION, shift EQ
+                                                               shift TRANSFORMATION, shift EQ, shift CHR_SELECT
     ; 
 
 faexp
@@ -161,6 +161,8 @@ aexp
     | (DO | MDO) statements                                  # Do
     | (SELECT | SELECT_FIRST | SELECT_DISTINCT) 
       exp WHERE queryBlock                                   # Select
+    | CHR_SELECT 
+      exp WHERE verboseChrQuery                              # CHRSelect
     | ENFORCE queryBlock                                     # Enforce
     //| WHEN queryBlock SEMICOLON exp                          # When
     | var                                                    # Var
index 0f45c2511b297a3e6575c7a953c6cd5e9f752c34..1277ffe7b373ff03b30da9f46c49541f7094aae3 100644 (file)
@@ -100,7 +100,7 @@ char_literal    = "'" ([^'\\\ufffd] | "\\" [^\ufffd]) "'"
   transformation  { return sym(supportCHR() ? SCLTerminals.ID : SCLTerminals.TRANSFORMATION); }
   select{whitespace}first { return sym(SCLTerminals.SELECT_FIRST); }
   select{whitespace}distinct { return sym(SCLTerminals.SELECT_DISTINCT); }
-  select          { return sym(SCLTerminals.SELECT); }
+  select          { return sym(supportCHR() ? SCLTerminals.CHR_SELECT : SCLTerminals.SELECT); }
   enforce         { return sym(SCLTerminals.ENFORCE); }
   do              { return sym(SCLTerminals.DO); }
   eq              { return sym(options.supportEq ? SCLTerminals.EQ : SCLTerminals.ID); }
index 5944d12e1cf288e701348305082a2d101eb07591..e3efc28ddf3bfb5e84bd8dc33eae07b276c16fd5 100644 (file)
@@ -1276,7 +1276,7 @@ public class SCLLexer {
             }
           case 175: break;
           case 81: 
-            { return sym(SCLTerminals.SELECT);
+            { return sym(supportCHR() ? SCLTerminals.CHR_SELECT : SCLTerminals.SELECT);
             }
           case 176: break;
           case 82: 
index 378013be5fbabbeb1085e6d43b3854b269873bf0..e0aca1bb3fa476ebb227a69b0c51acd92110bac1 100644 (file)
Binary files a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.dat and b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.dat differ
index fc2242dce632d482d95170a31f9bafe86d8a1eb3..612b118ad3d7a3053b11a72d12e52e8fda90bdf5 100644 (file)
@@ -13,18 +13,18 @@ public abstract class SCLParser {
     public static final boolean TRACE = false;
 
     private static final int INITIAL_CAPACITY = 16;
-    private static final int STATE_COUNT = 358;
-    private static final int TERMINAL_COUNT = 84;
-    private static final int NONTERMINAL_COUNT = 52;
+    private static final int STATE_COUNT = 357;
+    private static final int TERMINAL_COUNT = 85;
+    private static final int NONTERMINAL_COUNT = 51;
     private static final int PRODUCT_COUNT = 135;
     
     private static final int[] ACTION_ROW_ID = new int[STATE_COUNT];
     private static final int[] ACTION_COLUMN_ID = new int[TERMINAL_COUNT];
-    private static final short[] ACTION_TABLE = new short[6944];
-    private static final int[] ERROR_TABLE = new int[940];
+    private static final short[] ACTION_TABLE = new short[6765];
+    private static final int[] ERROR_TABLE = new int[949];
     private static final int[] GOTO_ROW_ID = new int[STATE_COUNT];
     private static final int[] GOTO_COLUMN_ID = new int[NONTERMINAL_COUNT];
-    private static final short[] GOTO_TABLE = new short[1708];
+    private static final short[] GOTO_TABLE = new short[1647];
     private static final int[] PRODUCT_LHS = new int[PRODUCT_COUNT];
 
     private static final short STATE_MASK = (short)0x0fff;
@@ -99,6 +99,7 @@ public abstract class SCLParser {
         "SELECT_DISTINCT",
         "TRANSFORMATION",
         "EQ",
+        "CHR_SELECT",
         "ATTACHED_DOT",
         "IN",
         "THEN",
@@ -156,12 +157,11 @@ public abstract class SCLParser {
         "accessor",
         "case",
         "queryBlock",
+        "verboseChrQuery",
         "stringLiteral",
         "symbolWithoutMinus",
         "listQualifier",
         "chrQuery",
-        "verboseChrQuery",
-        "constraintSpec",
         "caseRhs",
         "guardedExpArrow",
         "equation",
@@ -395,19 +395,19 @@ public abstract class SCLParser {
         return parse(0);
     }
     public Object parseCommands() {
-        return parse(342);
+        return parse(341);
     }
     public Object parseImport() {
-        return parse(350);
+        return parse(349);
     }
     public Object parseType() {
-        return parse(352);
+        return parse(351);
     }
     public Object parseExp() {
-        return parse(354);
+        return parse(353);
     }
     public Object parseEquationBlock() {
-        return parse(356);
+        return parse(355);
     }
 
 
@@ -535,123 +535,123 @@ public abstract class SCLParser {
         case 59:
             return reduceSelect();
         case 60:
-            return reduceEnforce();
+            return reduceCHRSelect();
         case 61:
-            return reduceVar();
+            return reduceEnforce();
         case 62:
-            return reduceHashedId();
+            return reduceVar();
         case 63:
-            return reduceBlank();
+            return reduceHashedId();
         case 64:
-            return reduceInteger();
+            return reduceBlank();
         case 65:
-            return reduceFloat();
+            return reduceInteger();
         case 66:
-            return reduceString();
+            return reduceFloat();
         case 67:
-            return reduceChar();
+            return reduceString();
         case 68:
-            return reduceTuple();
+            return reduceChar();
         case 69:
-            return reduceViewPattern();
+            return reduceTuple();
         case 70:
-            return reduceRightSection();
+            return reduceViewPattern();
         case 71:
-            return reduceLeftSection();
+            return reduceRightSection();
         case 72:
-            return reduceListLiteral();
+            return reduceLeftSection();
         case 73:
-            return reduceRange();
+            return reduceListLiteral();
         case 74:
-            return reduceListComprehension();
+            return reduceRange();
         case 75:
-            return reduceAs();
+            return reduceListComprehension();
         case 76:
-            return reduceRecord();
+            return reduceAs();
         case 77:
-            return reduceTransformation();
+            return reduceRecord();
         case 78:
-            return reduceEq();
+            return reduceTransformation();
         case 79:
-            return reduceRuleDeclarations();
+            return reduceEq();
         case 80:
-            return reduceStatements();
+            return reduceRuleDeclarations();
         case 81:
-            return reduceImportShowing();
+            return reduceStatements();
         case 82:
-            return reduceImportHiding();
+            return reduceImportShowing();
         case 83:
-            return reduceImportValueItem();
+            return reduceImportHiding();
         case 84:
-            return reduceFieldDescription();
+            return reduceImportValueItem();
         case 85:
-            return reduceGuardedExpEq();
+            return reduceFieldDescription();
         case 86:
-            return reduceFundep();
+            return reduceGuardedExpEq();
         case 87:
-            return reduceQueryRuleDeclaration();
+            return reduceFundep();
         case 88:
-            return reduceAnnotation();
+            return reduceQueryRuleDeclaration();
         case 89:
-            return reduceGuardQuery();
+            return reduceAnnotation();
         case 90:
-            return reduceEqualsQuery();
+            return reduceGuardQuery();
         case 91:
-            return reduceBindQuery();
+            return reduceEqualsQuery();
         case 92:
-            return reduceCompositeQuery();
+            return reduceBindQuery();
         case 93:
-            return reduceApply();
+            return reduceCompositeQuery();
         case 94:
-            return reduceSymbol();
+            return reduceApply();
         case 95:
-            return reduceEscapedId();
+            return reduceSymbol();
         case 96:
-            return reduceMinus();
+            return reduceEscapedId();
         case 97:
-            return reduceLess();
+            return reduceMinus();
         case 98:
-            return reduceGreater();
+            return reduceLess();
         case 99:
-            return reduceDot();
+            return reduceGreater();
         case 100:
-            return reduceFieldAccess();
+            return reduceDot();
         case 101:
-            return reduceIdAccessor();
+            return reduceFieldAccess();
         case 102:
-            return reduceStringAccessor();
+            return reduceIdAccessor();
         case 103:
-            return reduceExpAccessor();
+            return reduceStringAccessor();
         case 104:
-            return reduceCase();
+            return reduceExpAccessor();
         case 105:
-            return reduceQueryBlock();
+            return reduceCase();
         case 106:
-            return reduceStringLiteral();
+            return reduceQueryBlock();
         case 107:
-            return reduceSymbol();
+            return reduceVerboseCHRQuery();
         case 108:
-            return reduceEscapedId();
+            return reduceStringLiteral();
         case 109:
-            return reduceLess();
+            return reduceSymbol();
         case 110:
-            return reduceGreater();
+            return reduceEscapedId();
         case 111:
-            return reduceDot();
+            return reduceLess();
         case 112:
-            return reduceGuardQualifier();
+            return reduceGreater();
         case 113:
-            return reduceLetQualifier();
+            return reduceDot();
         case 114:
-            return reduceBindQualifier();
+            return reduceGuardQualifier();
         case 115:
-            return reduceThenQualifier();
+            return reduceLetQualifier();
         case 116:
-            return reduceCHRQuery();
+            return reduceBindQualifier();
         case 117:
-            return reduceVerboseCHRQuery();
+            return reduceThenQualifier();
         case 118:
-            return reduceConstraintSpec();
+            return reduceCHRQuery();
         case 119:
             return reduceSimpleCaseRhs();
         case 120:
@@ -824,7 +824,7 @@ public abstract class SCLParser {
      */
     protected abstract Object reduceVerboseCHRStatement();
     /**
-     * statement ::= CONSTRAINT constructor (WHERE constraintSpec)?
+     * statement ::= CONSTRAINT constructor
      */
     protected abstract Object reduceConstraintStatement();
     /**
@@ -931,6 +931,10 @@ public abstract class SCLParser {
      * aexp ::= (SELECT | SELECT_FIRST | SELECT_DISTINCT) exp WHERE queryBlock
      */
     protected abstract Object reduceSelect();
+    /**
+     * aexp ::= CHR_SELECT exp WHERE verboseChrQuery
+     */
+    protected abstract Object reduceCHRSelect();
     /**
      * aexp ::= ENFORCE queryBlock
      */
@@ -1111,6 +1115,10 @@ public abstract class SCLParser {
      * queryBlock ::= LBRACE (query (SEMICOLON (query SEMICOLON)&#42; query)?)? RBRACE
      */
     protected abstract Object reduceQueryBlock();
+    /**
+     * verboseChrQuery ::= LBRACE listQualifier (SEMICOLON listQualifier)&#42; RBRACE
+     */
+    protected abstract Object reduceVerboseCHRQuery();
     /**
      * stringLiteral ::= BEGIN_STRING (SUSPEND_STRING exp CONTINUE_STRING)&#42; END_STRING
      */
@@ -1135,14 +1143,6 @@ public abstract class SCLParser {
      * chrQuery ::= (listQualifier COMMA)&#42; listQualifier
      */
     protected abstract Object reduceCHRQuery();
-    /**
-     * verboseChrQuery ::= LBRACE listQualifier (SEMICOLON listQualifier)&#42; RBRACE
-     */
-    protected abstract Object reduceVerboseCHRQuery();
-    /**
-     * constraintSpec ::= LBRACE exp (SEMICOLON exp)&#42; RBRACE
-     */
-    protected abstract Object reduceConstraintSpec();
     /**
      * caseRhs ::= ARROW exp (WHERE statements)?
      */
index 34f8d6a9f0da95e4e6a01a95021d82f893176ca8..dd614f964630aa8b7de8846a1de65616923f57b9 100644 (file)
@@ -31,6 +31,7 @@ import org.simantics.scl.compiler.elaboration.expressions.EListComprehension;
 import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;
 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
 import org.simantics.scl.compiler.elaboration.expressions.EMatch;
+import org.simantics.scl.compiler.elaboration.expressions.EPreCHRSelect;
 import org.simantics.scl.compiler.elaboration.expressions.ERange;
 import org.simantics.scl.compiler.elaboration.expressions.ERealLiteral;
 import org.simantics.scl.compiler.elaboration.expressions.ERecord;
@@ -1305,12 +1306,17 @@ public class SCLParserImpl extends SCLParser {
         return new IncludeStatement(name, value);
     }
 
-    @Override
+    /*@Override
     protected Object reduceConstraintSpec() {
         Expression[] expressions = new Expression[length()/2-1];
         for(int i=0;i<expressions.length;++i)
             expressions[i] = (Expression)get(2*i+1);
         return expressions;
+    }*/
+
+    @Override
+    protected Object reduceCHRSelect() {
+        return new EPreCHRSelect((ListQualifier[])get(3), (Expression)get(1));
     }
 
 }
index 58a40f61ea64bfce284ace557fd935f5e5cc4356..6aab6c4b6a365ceb9b9fcdefbad6da88162ff362 100644 (file)
@@ -65,24 +65,25 @@ public interface SCLTerminals {
     public static final int SELECT_DISTINCT = 61;
     public static final int TRANSFORMATION = 62;
     public static final int EQ = 63;
-    public static final int ATTACHED_DOT = 64;
-    public static final int IN = 65;
-    public static final int THEN = 66;
-    public static final int ELSE = 67;
-    public static final int WITH = 68;
-    public static final int RBRACKET = 69;
-    public static final int DOTDOT = 70;
-    public static final int AT = 71;
-    public static final int SUSPEND_STRING = 72;
-    public static final int CONTINUE_STRING = 73;
-    public static final int BINDS = 74;
-    public static final int IMPLIES = 75;
-    public static final int THEN_AFTER_WHEN = 76;
-    public static final int CONSTRAINT = 77;
-    public static final int BY = 78;
-    public static final int QUERY_OP = 79;
-    public static final int FORALL = 80;
-    public static final int COMMENT = 81;
-    public static final int EOL = 82;
-    public static final int EOF = 83;
+    public static final int CHR_SELECT = 64;
+    public static final int ATTACHED_DOT = 65;
+    public static final int IN = 66;
+    public static final int THEN = 67;
+    public static final int ELSE = 68;
+    public static final int WITH = 69;
+    public static final int RBRACKET = 70;
+    public static final int DOTDOT = 71;
+    public static final int AT = 72;
+    public static final int SUSPEND_STRING = 73;
+    public static final int CONTINUE_STRING = 74;
+    public static final int BINDS = 75;
+    public static final int IMPLIES = 76;
+    public static final int THEN_AFTER_WHEN = 77;
+    public static final int CONSTRAINT = 78;
+    public static final int BY = 79;
+    public static final int QUERY_OP = 80;
+    public static final int FORALL = 81;
+    public static final int COMMENT = 82;
+    public static final int EOL = 83;
+    public static final int EOF = 84;
 }
index d8526ca12c45024601b39efef4f10cc4a7938057..ed0968b36800d1dc163aba4620ee7ed88ad6ea3b 100644 (file)
@@ -7,7 +7,7 @@ import java.util.Arrays;
 import java.util.Collections;
 
 public abstract class GrammarParser {    
-    public static final boolean TRACE = true;
+    public static final boolean TRACE = false;
 
     private static final int INITIAL_CAPACITY = 16;
     private static final int STATE_COUNT = 19;
index d8f703afc344d209cd18f4a7373a8a9b3caef69f..5403dbf27be828e99bac0e399e549cc0c9ff09e1 100644 (file)
@@ -33,6 +33,10 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void CHR9() { test(); }
     @Test public void CHR10() { test(); }
     @Test public void CHR11() { test(); }
+    @Test public void CHR12() { test(); }
+    @Test public void CHRSelect1() { test(); }
+    @Test public void CHRSelect2() { test(); }
+    @Test public void CHRSelect3() { test(); }
     @Test public void ClosureRecursion() { test(); }
     @Test public void Collaz() { test(); }
     @Test public void Compose() { test(); }
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR12.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR12.scl
new file mode 100644 (file)
index 0000000..7c9376d
--- /dev/null
@@ -0,0 +1,15 @@
+module { export = [main], features = [chr] }
+import "Prelude"
+
+main = ()
+  where
+    when Foo ?x ?x
+    then print (?x :: Integer)
+    
+    when True
+    then Foo 1 2
+         Foo 2 1
+         Foo 2 2
+--
+2
+()
\ No newline at end of file
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect1.scl
new file mode 100644 (file)
index 0000000..63ea561
--- /dev/null
@@ -0,0 +1,10 @@
+module {
+    features = [chr]
+}
+import "StandardLibrary"
+
+main = select (?a,?b) where
+    ?a <- [1,2,3]
+    ?b <- [2,3,4]
+--
+[(1,2), (1,3), (1,4), (2,2), (2,3), (2,4), (3,2), (3,3), (3,4)]
\ No newline at end of file
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect2.scl
new file mode 100644 (file)
index 0000000..e49dd44
--- /dev/null
@@ -0,0 +1,17 @@
+module {
+    features = [chr]
+}
+import "StandardLibrary"
+
+main = 
+    select (?a,?b) where
+        Foo ?a
+        Bar ?b
+  where
+    True => Foo 1
+    True => Foo 2
+    
+    True => Bar 3
+    True => Bar 4
+--
+[(2,4), (2,3), (1,4), (1,3)]
\ No newline at end of file
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHRSelect3.scl
new file mode 100644 (file)
index 0000000..2be9b98
--- /dev/null
@@ -0,0 +1,21 @@
+module {
+    features = [chr]
+}
+import "StandardLibrary"
+
+main = ()
+  where
+    constraint Edge Integer Integer
+  
+    True => Edge 2 3
+    True => Edge 1 2
+    True => Edge 3 4
+    
+    when -Edge ?x ?y
+         [] = select ?z where
+             Edge ?z ?x
+    then print "removed \(?x) \(?y)"
+--
+removed 1 2
+removed 2 3
+()
\ No newline at end of file
index 95d8b03dab09dfae641969b8a7be876a11d35132..3cf6ed74bb4ac610d1419cff486ce21484c987c2 100644 (file)
@@ -1,4 +1,4 @@
 
 main = \ /* no parameters */ -> 3
 --
-2:30-2:32: Unexpected token '->' (ARROW). Expected one of ATTACHED_HASH, BEGIN_STRING, BLANK, CHAR, DO, ENFORCE, EQ, ESCAPED_SYMBOL, FLOAT, ID, IF, INTEGER, LAMBDA, LAMBDA_MATCH, LBRACKET, LET, LPAREN, MATCH, MDO, SELECT, SELECT_DISTINCT, SELECT_FIRST, TRANSFORMATION.
\ No newline at end of file
+2:30-2:32: Unexpected token '->' (ARROW). Expected one of ATTACHED_HASH, BEGIN_STRING, BLANK, CHAR, CHR_SELECT, DO, ENFORCE, EQ, ESCAPED_SYMBOL, FLOAT, ID, IF, INTEGER, LAMBDA, LAMBDA_MATCH, LBRACKET, LET, LPAREN, MATCH, MDO, SELECT, SELECT_DISTINCT, SELECT_FIRST, TRANSFORMATION.
\ No newline at end of file
index 85637b16be7595d0d13159799e3c81da0a518a29..45f6b08535b78369c8827930ed488946ad7c32bd 100644 (file)
@@ -1,4 +1,4 @@
 a = =
 b = 4
 --
-1:5-1:6: Unexpected token '=' (EQUALS). Expected one of ATTACHED_HASH, BEGIN_STRING, BLANK, CHAR, DO, ENFORCE, EQ, ESCAPED_SYMBOL, FLOAT, ID, IF, INTEGER, LAMBDA, LAMBDA_MATCH, LBRACKET, LET, LPAREN, MATCH, MDO, MINUS, SELECT, SELECT_DISTINCT, SELECT_FIRST, TRANSFORMATION.
\ No newline at end of file
+1:5-1:6: Unexpected token '=' (EQUALS). Expected one of ATTACHED_HASH, BEGIN_STRING, BLANK, CHAR, CHR_SELECT, DO, ENFORCE, EQ, ESCAPED_SYMBOL, FLOAT, ID, IF, INTEGER, LAMBDA, LAMBDA_MATCH, LBRACKET, LET, LPAREN, MATCH, MDO, MINUS, SELECT, SELECT_DISTINCT, SELECT_FIRST, TRANSFORMATION.
\ No newline at end of file