From: Hannu Niemistö Date: Mon, 6 Nov 2017 08:14:39 +0000 (+0200) Subject: (refs #7601) Wildcard syntax for SCL records X-Git-Tag: v1.31.0~56 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=00b73fe170154840ac11c2a9403c6bcd9a0e673a;p=simantics%2Fplatform.git (refs #7601) Wildcard syntax for SCL records Change-Id: Ia044ce4598d0897bbd7416527707b49211aba9e3 --- 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 e0921dc10..6bea58310 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 @@ -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 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; @@ -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; } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/records/FieldAssignment.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/records/FieldAssignment.java index af84130f8..ea220f107 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/records/FieldAssignment.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/records/FieldAssignment.java @@ -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 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCL.grammar b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCL.grammar index e17b5e70f..01a66a9ee 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCL.grammar +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCL.grammar @@ -244,6 +244,7 @@ guardedExpArrow field = ID EQUALS exp # Field | ID # FieldShorthand + | DOTDOT # Wildcard ; /****************************************************************************** diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.dat b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.dat index 59f0f80fc..c24abdb0f 100644 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 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.java index 1a163b3b9..6852771b1 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParser.java @@ -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 */ diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParserImpl.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParserImpl.java index a29368c2a..7cf1fb754 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParserImpl.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/parser/SCLParserImpl.java @@ -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); + } + } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java index 6e11e24a4..e6eb2b5af 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java @@ -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 index 000000000..2ff5245b6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecordWildcards.scl @@ -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