]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7601) Wildcard syntax for SCL records 98/1198/2
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Mon, 6 Nov 2017 08:14:39 +0000 (10:14 +0200)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Mon, 6 Nov 2017 08:15:52 +0000 (10:15 +0200)
Change-Id: Ia044ce4598d0897bbd7416527707b49211aba9e3

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/expressions/ERecord.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/records/FieldAssignment.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/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
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/RecordWildcards.scl [new file with mode: 0644]

index e0921dc106fa67f50944ef6ebd9c14c3080972bf..6bea58310c73b24dd8a0e841793252e09d926c53 100644 (file)
@@ -93,7 +93,7 @@ public class CHRLiteral extends Symbol {
                 context.getErrorLog().log(location, "Relation " + relation + " does not define field names.");
                 return;
             }
-            parameters = ERecord.translateFieldsToFunctionParameters(context, fields, fieldNames);
+            parameters = ERecord.translateFieldsToFunctionParameters(context, fields, fieldNames, true);
             if(parameters == null)
                 return;
             for(int i=0;i<parameters.length;++i) {
index e1f444d8220a12801d3ad430c55c11065a4edef8..a859782239caac40c50cf91e34935b43aa303b7e 100644 (file)
@@ -1,5 +1,7 @@
 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;
@@ -12,6 +14,8 @@ 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;
     
@@ -51,7 +55,7 @@ public class ERecord extends ASTExpression {
             context.getErrorLog().log(constructor.location, "Value " + constructor.name + " is not a record constructor.");
             return new EError(constructor.location);
         }
-        Expression[] parameters = translateFieldsToFunctionParameters(context, fields, fieldNames);
+        Expression[] parameters = translateFieldsToFunctionParameters(context, fields, fieldNames, false);
         if(parameters == null)
             return new EError(location);
         if(asPattern)
@@ -86,12 +90,36 @@ public class ERecord extends ASTExpression {
         return result;
     }
     
-    public static Expression[] translateFieldsToFunctionParameters(TranslationContext context, FieldAssignment[] fields, String[] fieldNames) {
+    public static Expression[] translateFieldsToFunctionParameters(TranslationContext context, FieldAssignment[] fields, String[] fieldNames, boolean chrLiteral) {
+        if(DEBUG) {
+            System.out.println("translateFieldsToFunctionParameters");
+            System.out.println("    fieldNames = " + Arrays.toString(fieldNames));
+            System.out.print("    fields = {");
+            for(int i=0;i<fields.length;++i) {
+                FieldAssignment field = fields[i];
+                if(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<String,FieldAssignment> recordMap = new THashMap<String,FieldAssignment>(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;
@@ -122,12 +150,20 @@ public class ERecord extends ASTExpression {
             FieldAssignment assignment = recordMap.remove(fieldNames[i]);
             if(assignment != null)
                 parameters[i] = assignment.value;
+            else if(wildcardField != null) {
+                String variableName = fieldNames[i];
+                if(chrLiteral)
+                    variableName = "?" + variableName;
+                parameters[i] = new EVar(wildcardField.location, variableName);
+            }
         }
         if(!recordMap.isEmpty()) {
             for(FieldAssignment field : recordMap.values())
                 context.getErrorLog().log(field.location, "Field " + field.name + " is not defined in the constructor.");
             return null;
         }
+        if(DEBUG)
+            System.out.println(" => parameters = " + Arrays.toString(parameters));
         return parameters;
     }
 
index af84130f8f6cb8d2310fcc27c40655c1f2c7d60a..ea220f1075c703b42c96b1527606b66bcdff382b 100644 (file)
@@ -5,6 +5,8 @@ import org.simantics.scl.compiler.elaboration.expressions.Expression;
 import org.simantics.scl.compiler.internal.parsing.Symbol;
 
 public class FieldAssignment extends Symbol {
+    public static final String WILDCARD = "..";
+    
     public String name;
     public Expression value; // null if shorthand
     
index e17b5e70fb6d886f9d6e7b40b1bf7c472d8b2d7e..01a66a9ee2fa844722624ce664bcd19e332c2a68 100644 (file)
@@ -244,6 +244,7 @@ guardedExpArrow
 field
     = ID EQUALS exp                                          # Field
     | ID                                                     # FieldShorthand
+    | DOTDOT                                                 # Wildcard
     ;
 
 /******************************************************************************
index 59f0f80fc505a37d635d6d65130cf8a4c7b4ddbf..c24abdb0f00e248cb7844d94fee23ae2c4d6b63b 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 1a163b3b95f0ed6c8ccf660bd39ad6cbfe430261..6852771b1b8558f107758215e1e557d31dc56cf2 100644 (file)
@@ -13,15 +13,15 @@ public abstract class SCLParser {
     public static final boolean TRACE = false;
 
     private static final int INITIAL_CAPACITY = 16;
-    private static final int STATE_COUNT = 362;
+    private static final int STATE_COUNT = 363;
     private static final int TERMINAL_COUNT = 86;
     private static final int NONTERMINAL_COUNT = 52;
-    private static final int PRODUCT_COUNT = 138;
+    private static final int PRODUCT_COUNT = 139;
     
     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[6832];
-    private static final int[] ERROR_TABLE = new int[973];
+    private static final short[] ACTION_TABLE = new short[6765];
+    private static final int[] ERROR_TABLE = new int[976];
     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[1953];
@@ -397,19 +397,19 @@ public abstract class SCLParser {
         return parse(0);
     }
     public Object parseCommands() {
-        return parse(346);
+        return parse(347);
     }
     public Object parseImport() {
-        return parse(354);
+        return parse(355);
     }
     public Object parseType() {
-        return parse(356);
+        return parse(357);
     }
     public Object parseExp() {
-        return parse(358);
+        return parse(359);
     }
     public Object parseEquationBlock() {
-        return parse(360);
+        return parse(361);
     }
 
 
@@ -493,192 +493,194 @@ public abstract class SCLParser {
         case 37:
             return reduceFieldShorthand();
         case 38:
-            return reduceVarId();
+            return reduceWildcard();
         case 39:
-            return reduceEscapedSymbol();
+            return reduceVarId();
         case 40:
-            return reduceTupleConstructor();
+            return reduceEscapedSymbol();
         case 41:
-            return reduceBinary();
+            return reduceTupleConstructor();
         case 42:
-            return reduceSimpleRhs();
+            return reduceBinary();
         case 43:
-            return reduceGuardedRhs();
+            return reduceSimpleRhs();
         case 44:
-            return reduceConstructor();
+            return reduceGuardedRhs();
         case 45:
-            return reduceRecordConstructor();
+            return reduceConstructor();
         case 46:
-            return reduceContext();
+            return reduceRecordConstructor();
         case 47:
-            return reduceFundeps();
+            return reduceContext();
         case 48:
-            return reduceTypeVar();
+            return reduceFundeps();
         case 49:
-            return reduceTupleType();
+            return reduceTypeVar();
         case 50:
-            return reduceListType();
+            return reduceTupleType();
         case 51:
-            return reduceListTypeConstructor();
+            return reduceListType();
         case 52:
-            return reduceTupleTypeConstructor();
+            return reduceListTypeConstructor();
         case 53:
-            return reduceLambda();
+            return reduceTupleTypeConstructor();
         case 54:
-            return reduceLambdaMatch();
+            return reduceLambda();
         case 55:
-            return reduceLet();
+            return reduceLambdaMatch();
         case 56:
-            return reduceIf();
+            return reduceLet();
         case 57:
-            return reduceMatch();
+            return reduceIf();
         case 58:
-            return reduceDo();
+            return reduceMatch();
         case 59:
-            return reduceSelect();
+            return reduceDo();
         case 60:
-            return reduceCHRSelect();
+            return reduceSelect();
         case 61:
-            return reduceEnforce();
+            return reduceCHRSelect();
         case 62:
-            return reduceVar();
+            return reduceEnforce();
         case 63:
-            return reduceHashedId();
+            return reduceVar();
         case 64:
-            return reduceBlank();
+            return reduceHashedId();
         case 65:
-            return reduceInteger();
+            return reduceBlank();
         case 66:
-            return reduceFloat();
+            return reduceInteger();
         case 67:
-            return reduceString();
+            return reduceFloat();
         case 68:
-            return reduceChar();
+            return reduceString();
         case 69:
-            return reduceTuple();
+            return reduceChar();
         case 70:
-            return reduceViewPattern();
+            return reduceTuple();
         case 71:
-            return reduceRightSection();
+            return reduceViewPattern();
         case 72:
-            return reduceLeftSection();
+            return reduceRightSection();
         case 73:
-            return reduceListLiteral();
+            return reduceLeftSection();
         case 74:
-            return reduceRange();
+            return reduceListLiteral();
         case 75:
-            return reduceListComprehension();
+            return reduceRange();
         case 76:
-            return reduceAs();
+            return reduceListComprehension();
         case 77:
-            return reduceRecord();
+            return reduceAs();
         case 78:
-            return reduceTransformation();
+            return reduceRecord();
         case 79:
-            return reduceEq();
+            return reduceTransformation();
         case 80:
-            return reduceRuleDeclarations();
+            return reduceEq();
         case 81:
-            return reduceStatements();
+            return reduceRuleDeclarations();
         case 82:
-            return reduceImportShowing();
+            return reduceStatements();
         case 83:
-            return reduceImportHiding();
+            return reduceImportShowing();
         case 84:
-            return reduceImportValueItem();
+            return reduceImportHiding();
         case 85:
-            return reduceFieldDescription();
+            return reduceImportValueItem();
         case 86:
-            return reduceGuardedExpEq();
+            return reduceFieldDescription();
         case 87:
-            return reduceFundep();
+            return reduceGuardedExpEq();
         case 88:
-            return reduceQueryRuleDeclaration();
+            return reduceFundep();
         case 89:
-            return reduceAnnotation();
+            return reduceQueryRuleDeclaration();
         case 90:
-            return reduceGuardQuery();
+            return reduceAnnotation();
         case 91:
-            return reduceEqualsQuery();
+            return reduceGuardQuery();
         case 92:
-            return reduceBindQuery();
+            return reduceEqualsQuery();
         case 93:
-            return reduceCompositeQuery();
+            return reduceBindQuery();
         case 94:
-            return reduceApply();
+            return reduceCompositeQuery();
         case 95:
-            return reduceSymbol();
+            return reduceApply();
         case 96:
-            return reduceEscapedId();
+            return reduceSymbol();
         case 97:
-            return reduceMinus();
+            return reduceEscapedId();
         case 98:
-            return reduceLess();
+            return reduceMinus();
         case 99:
-            return reduceGreater();
+            return reduceLess();
         case 100:
-            return reduceDot();
+            return reduceGreater();
         case 101:
-            return reduceFieldAccess();
+            return reduceDot();
         case 102:
-            return reduceIdAccessor();
+            return reduceFieldAccess();
         case 103:
-            return reduceStringAccessor();
+            return reduceIdAccessor();
         case 104:
-            return reduceExpAccessor();
+            return reduceStringAccessor();
         case 105:
-            return reduceCase();
+            return reduceExpAccessor();
         case 106:
-            return reduceQueryBlock();
+            return reduceCase();
         case 107:
-            return reduceVerboseCHRConjunction();
+            return reduceQueryBlock();
         case 108:
-            return reduceStringLiteral();
+            return reduceVerboseCHRConjunction();
         case 109:
-            return reduceSymbol();
+            return reduceStringLiteral();
         case 110:
-            return reduceEscapedId();
+            return reduceSymbol();
         case 111:
-            return reduceLess();
+            return reduceEscapedId();
         case 112:
-            return reduceGreater();
+            return reduceLess();
         case 113:
-            return reduceDot();
+            return reduceGreater();
         case 114:
-            return reduceGuardQualifier();
+            return reduceDot();
         case 115:
-            return reduceLetQualifier();
+            return reduceGuardQualifier();
         case 116:
-            return reduceBindQualifier();
+            return reduceLetQualifier();
         case 117:
-            return reduceThenQualifier();
+            return reduceBindQualifier();
         case 118:
-            return reduceCHRConjunction();
+            return reduceThenQualifier();
         case 119:
-            return reduceCHRAtom();
+            return reduceCHRConjunction();
         case 120:
-            return reduceCHREquals();
+            return reduceCHRAtom();
         case 121:
-            return reduceCHRBinds();
+            return reduceCHREquals();
         case 122:
-            return reduceSimpleCaseRhs();
+            return reduceCHRBinds();
         case 123:
-            return reduceGuardedCaseRhs();
+            return reduceSimpleCaseRhs();
         case 124:
-            return reduceGuardedExpArrow();
+            return reduceGuardedCaseRhs();
         case 125:
-            return reduceGuardEquation();
+            return reduceGuardedExpArrow();
         case 126:
-            return reduceBasicEquation();
+            return reduceGuardEquation();
         case 127:
-            return reduceEffect();
+            return reduceBasicEquation();
         case 128:
-            return reduceJustEtype();
+            return reduceEffect();
         case 129:
-            return reduceForAll();
+            return reduceJustEtype();
         case 130:
-            return reduceApplyType();
+            return reduceForAll();
         case 131:
+            return reduceApplyType();
+        case 132:
             return reduceDummy();
 
         default:
@@ -851,6 +853,10 @@ public abstract class SCLParser {
      * field ::= ID
      */
     protected abstract Object reduceFieldShorthand();
+    /**
+     * field ::= DOTDOT
+     */
+    protected abstract Object reduceWildcard();
     /**
      * var ::= ID
      */
index a29368c2af31c33457ba3482cb110aa48fd84c90..7cf1fb754a954a3b29f13415a036f99c364d8b1f 100644 (file)
@@ -1347,4 +1347,9 @@ public class SCLParserImpl extends SCLParser {
         return new CHRStatement((CHRAstQuery)get(0), (CHRAstQuery)get(2));
     }
 
+    @Override
+    protected Object reduceWildcard() {
+        return new FieldAssignment(FieldAssignment.WILDCARD, null);
+    }
+
 }
index 6e11e24a416dbd00e3ecc33e0e6ed24c8e3ba201..e6eb2b5afe5eb2eb5b329131e339fad4a6d34550 100644 (file)
@@ -217,6 +217,7 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void Record2() { test(); }
     @Test public void Record3() { test(); }
     @Test public void RecordShorthand() { test(); }
+    @Test public void RecordWildcards() { test(); }
     @Test public void RecursionBug() { test(); }
     @Test public void RecursiveContext() { test(); }
     @Test public void RecursiveValues2() { test(); }
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecordWildcards.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecordWildcards.scl
new file mode 100644 (file)
index 0000000..2ff5245
--- /dev/null
@@ -0,0 +1,27 @@
+import "Prelude"
+
+data XYZ = XYZ { x :: Double, y :: Double, z :: Double }
+deriving instance Show XYZ
+
+updateX x' XYZ {..} = XYZ {x', ..} 
+
+main = print $ updateX 5 $ XYZ { x = 4, y = 3, .. }
+  where
+    z = 2
+-- 
+XYZ 5.0 3.0 2.0
+()
+--
+import "Prelude"
+
+main = ()
+  where
+    constraint R { a :: Integer, b :: Integer, label :: String }
+    
+    -R { a = 0, ..   } => print "Final: b = \(?b), label = \(?label)"
+    -R { ?a,  ?b, .. } => R { a=?a-1, b=?b+1, .. }
+    
+    True => R { a = 5, b = 5, label = "My label" } 
+--
+Final: b = 10, label = My label
+()
\ No newline at end of file