From 74da6a0ae2e5646ee964b79c73eab03ac0e23a0f Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 19:09:29 +0200 Subject: [PATCH 01/17] shorter tests --- .../Reducer_MathJsParse_test.res | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 4acfc1c1..4e67f3d6 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -7,32 +7,38 @@ open Expect let expectParseToBe = (expr, answer) => Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(answer) +let testParse = (expr, answer) => + test(expr, () => expectParseToBe(expr, answer)) + +let skipTestParse = (expr, answer) => + Skip.test(expr, () => expectParseToBe(expr, answer)) + describe("MathJs parse", () => { describe("literals operators paranthesis", () => { - test("1", () => expectParseToBe("1", "1")) - test("'hello'", () => expectParseToBe("'hello'", "'hello'")) - test("true", () => expectParseToBe("true", "true")) - test("1+2", () => expectParseToBe("1+2", "add(1, 2)")) - test("add(1,2)", () => expectParseToBe("add(1,2)", "add(1, 2)")) - test("(1)", () => expectParseToBe("(1)", "(1)")) - test("(1+2)", () => expectParseToBe("(1+2)", "(add(1, 2))")) + testParse("1", "1") + testParse("'hello'", "'hello'") + testParse("true", "true") + testParse("1+2", "add(1, 2)") + testParse("add(1,2)", "add(1, 2)") + testParse("(1)", "(1)") + testParse("(1+2)", "(add(1, 2))") }) describe("variables", () => { - Skip.test("define", () => expectParseToBe("x = 1", "???")) - Skip.test("use", () => expectParseToBe("x", "???")) + skipTestParse("x = 1", "???") + skipTestParse("x", "???") }) describe("functions", () => { - Skip.test("define", () => expectParseToBe("identity(x) = x", "???")) - Skip.test("use", () => expectParseToBe("identity(x)", "???")) + skipTestParse("identity(x) = x", "???") + skipTestParse("identity(x)", "???") }) describe("arrays", () => { test("empty", () => expectParseToBe("[]", "[]")) test("define", () => expectParseToBe("[0, 1, 2]", "[0, 1, 2]")) test("define with strings", () => expectParseToBe("['hello', 'world']", "['hello', 'world']")) - Skip.test("range", () => expectParseToBe("range(0, 4)", "range(0, 4)")) + skipTestParse("range(0, 4)", "range(0, 4)") test("index", () => expectParseToBe("([0,1,2])[1]", "([0, 1, 2])[1]")) }) From bbcd7f26409b73ea8206ef90897cb7e6bddc2470 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 19:18:10 +0200 Subject: [PATCH 02/17] shorter tests --- .../__tests__/Reducer/Reducer_test.res | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 288cbabe..436c4f7c 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,6 +1,12 @@ open Jest open Reducer_TestHelpers +let testParseToBe = (expr, answer) => + test(expr, () => expectParseToBe(expr, answer)) + +let testEvalToBe = (expr, answer) => + test(expr, () => expectEvalToBe(expr, answer)) + describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility // Those tests toString that there is a semantic mapping from MathJs to Expression @@ -10,20 +16,20 @@ describe("reducer using mathjs parse", () => { // Those tests toString that we are converting mathjs parse tree to what we need describe("expressions", () => { - test("1", () => expectParseToBe("1", "Ok(1)")) - test("(1)", () => expectParseToBe("(1)", "Ok(1)")) - test("1+2", () => expectParseToBe("1+2", "Ok((:add 1 2))")) - test("(1+2)", () => expectParseToBe("1+2", "Ok((:add 1 2))")) - test("add(1,2)", () => expectParseToBe("1+2", "Ok((:add 1 2))")) - test("1+2*3", () => expectParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))")) + testParseToBe("1", "Ok(1)") + testParseToBe("(1)", "Ok(1)") + testParseToBe("1+2", "Ok((:add 1 2))") + testParseToBe("1+2", "Ok((:add 1 2))") + testParseToBe("1+2", "Ok((:add 1 2))") + testParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))") }) describe("arrays", () => { //Note. () is a empty list in Lisp // The only builtin structure in Lisp is list. There are no arrays // [1,2,3] becomes (1 2 3) test("empty", () => expectParseToBe("[]", "Ok(())")) - test("[1, 2, 3]", () => expectParseToBe("[1, 2, 3]", "Ok((1 2 3))")) - test("['hello', 'world']", () => expectParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")) + testParseToBe("[1, 2, 3]", "Ok((1 2 3))") + testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") test("index", () => expectParseToBe("([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")) }) describe("records", () => { @@ -45,20 +51,20 @@ describe("eval", () => { // See https://mathjs.org/docs/expressions/syntax.html // See https://mathjs.org/docs/reference/functions.html describe("expressions", () => { - test("1", () => expectEvalToBe("1", "Ok(1)")) - test("1+2", () => expectEvalToBe("1+2", "Ok(3)")) - test("(1+2)*3", () => expectEvalToBe("(1+2)*3", "Ok(9)")) - test("2>1", () => expectEvalToBe("2>1", "Ok(true)")) - test("concat('a ', 'b')", () => expectEvalToBe("concat('a ', 'b')", "Ok('a b')")) - test("log(10)", () => expectEvalToBe("log(10)", "Ok(2.302585092994046)")) - test("cos(10)", () => expectEvalToBe("cos(10)", "Ok(-0.8390715290764524)")) + testEvalToBe("1", "Ok(1)") + testEvalToBe("1+2", "Ok(3)") + testEvalToBe("(1+2)*3", "Ok(9)") + testEvalToBe("2>1", "Ok(true)") + testEvalToBe("concat('a ', 'b')", "Ok('a b')") + testEvalToBe("log(10)", "Ok(2.302585092994046)") + testEvalToBe("cos(10)", "Ok(-0.8390715290764524)") // TODO more built ins }) describe("arrays", () => { test("empty array", () => expectEvalToBe("[]", "Ok([])")) - test("[1, 2, 3]", () => expectEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])")) - test("['hello', 'world']", () => expectEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])")) - test("index", () => expectEvalToBe("([0,1,2])[1]", "Ok(1)")) + testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") + testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") + testEvalToBe("([0,1,2])[1]", "Ok(1)") test("index not found", () => expectEvalToBe("([0,1,2])[10]", "Error(Array index not found: 10)") ) From 4e6a2341f08bc86de9a57b3b51b9cf36fe5d759a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 19:36:19 +0200 Subject: [PATCH 03/17] shorter tests --- .../Reducer_MathJsParse_test.res | 14 +++++-- .../__tests__/Reducer/Reducer_test.res | 39 +++++++++---------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 4e67f3d6..41ba6239 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -10,9 +10,15 @@ let expectParseToBe = (expr, answer) => let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) +let testDescParse = (desc, expr, answer) => + test(desc, () => expectParseToBe(expr, answer)) + let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) +let skipDescTestParse = (desc, expr, answer) => + Skip.test(desc, () => expectParseToBe(expr, answer)) + describe("MathJs parse", () => { describe("literals operators paranthesis", () => { testParse("1", "1") @@ -43,15 +49,15 @@ describe("MathJs parse", () => { }) describe("records", () => { - test("define", () => expectParseToBe("{a: 1, b: 2}", "{a: 1, b: 2}")) - test("use", () => expectParseToBe("record.property", "record['property']")) + testDescParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") + testDescParse("use", "record.property", "record['property']") }) describe("comments", () => { - Skip.test("define", () => expectParseToBe("# This is a comment", "???")) + skipDescTestParse("define", "# This is a comment", "???") }) describe("if statement", () => { - Skip.test("define", () => expectParseToBe("if (true) { 1 } else { 0 }", "???")) + skipDescTestParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 436c4f7c..7f6ae6f1 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,12 +1,19 @@ open Jest open Reducer_TestHelpers + let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) +let testDescParseToBe = (desc, expr, answer) => + test(desc, () => expectParseToBe(expr, answer)) + let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) +let testDescEvalToBe = (desc, expr, answer) => + test(desc, () => expectEvalToBe(expr, answer)) + describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility // Those tests toString that there is a semantic mapping from MathJs to Expression @@ -27,21 +34,17 @@ describe("reducer using mathjs parse", () => { //Note. () is a empty list in Lisp // The only builtin structure in Lisp is list. There are no arrays // [1,2,3] becomes (1 2 3) - test("empty", () => expectParseToBe("[]", "Ok(())")) + testDescParseToBe("empty", "[]", "Ok(())") testParseToBe("[1, 2, 3]", "Ok((1 2 3))") testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") - test("index", () => expectParseToBe("([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")) + testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") }) describe("records", () => { - test("define", () => - expectParseToBe("{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") - ) - test("use", () => - expectParseToBe( + testDescParseToBe("define", + "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescParseToBe("use", "{a: 1, b: 2}.a", - "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", - ) - ) + "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))") }) }) @@ -65,9 +68,8 @@ describe("eval", () => { testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") - test("index not found", () => - expectEvalToBe("([0,1,2])[10]", "Error(Array index not found: 10)") - ) + testDescEvalToBe("index not found", + "([0,1,2])[10]", "Error(Array index not found: 10)") }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})")) @@ -77,11 +79,8 @@ describe("eval", () => { }) describe("test exceptions", () => { - test("javascript exception", () => - expectEvalToBe("jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')") - ) - - test("rescript exception", () => - expectEvalToBe("resraise()", "Error(TODO: unhandled rescript exception)") - ) + testDescEvalToBe("javascript exception", + "jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')") + testDescEvalToBe("rescript exception", + "resraise()", "Error(TODO: unhandled rescript exception)") }) From 05e8540b316336b23d87afc5c31fe85f22e4b8e3 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 20:51:54 +0200 Subject: [PATCH 04/17] rescript:format --- packages/squiggle-lang/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 02de65be..f7fd85f3 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -10,7 +10,8 @@ "test:reducer": "jest --testPathPattern '.*__tests__/Reducer.*'", "test": "jest", "test:watch": "jest --watchAll", - "all": "yarn build && yarn bundle && yarn test" + "all": "yarn build && yarn bundle && yarn test", + "rescript:format": "find . -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;" }, "keywords": [ "Rescript" From a5bb390370a8e730418c3dbc92c87f27311669e1 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 20:54:51 +0200 Subject: [PATCH 05/17] reformat --- .../__tests__/Reducer/Reducer_test.res | 37 +++++++++---------- .../Reducer_Expression.resi | 20 ++-------- .../Reducer_MathJs_ToExpression.res | 5 ++- .../ReducerInterface_ExpressionValue.res | 5 ++- 4 files changed, 29 insertions(+), 38 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 7f6ae6f1..a7539b7f 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,18 +1,13 @@ open Jest open Reducer_TestHelpers +let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testParseToBe = (expr, answer) => - test(expr, () => expectParseToBe(expr, answer)) +let testDescParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let testDescParseToBe = (desc, expr, answer) => - test(desc, () => expectParseToBe(expr, answer)) +let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) -let testEvalToBe = (expr, answer) => - test(expr, () => expectEvalToBe(expr, answer)) - -let testDescEvalToBe = (desc, expr, answer) => - test(desc, () => expectEvalToBe(expr, answer)) +let testDescEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility @@ -40,11 +35,12 @@ describe("reducer using mathjs parse", () => { testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") }) describe("records", () => { - testDescParseToBe("define", - "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") - testDescParseToBe("use", - "{a: 1, b: 2}.a", - "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))") + testDescParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescParseToBe( + "use", + "{a: 1, b: 2}.a", + "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", + ) }) }) @@ -68,8 +64,7 @@ describe("eval", () => { testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") - testDescEvalToBe("index not found", - "([0,1,2])[10]", "Error(Array index not found: 10)") + testDescEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)") }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})")) @@ -79,8 +74,10 @@ describe("eval", () => { }) describe("test exceptions", () => { - testDescEvalToBe("javascript exception", - "jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')") - testDescEvalToBe("rescript exception", - "resraise()", "Error(TODO: unhandled rescript exception)") + testDescEvalToBe( + "javascript exception", + "jsraise('div by 0')", + "Error(JS Exception: Error: 'div by 0')", + ) + testDescEvalToBe("rescript exception", "resraise()", "Error(TODO: unhandled rescript exception)") }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi index 8b09c516..afd0105f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi @@ -9,20 +9,8 @@ let parse: string => result module MapString = Belt.Map.String type bindings = MapString.t let defaultBindings: bindings -let reduceValueList: list => result< - expressionValue, - Reducer_ErrorValue.t, -> -let reduceExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindingsExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindings: (string, bindings) => Result.t< - expressionValue, - Reducer_ErrorValue.t, -> +let reduceValueList: list => result +let reduceExpression: (expression, 'a) => result +let evalWBindingsExpression: (expression, 'a) => result +let evalWBindings: (string, bindings) => Result.t let eval: string => Result.t diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res index 5b16fb54..edd0313b 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res @@ -54,7 +54,10 @@ let rec fromNode = (mathJsNode: Parse.node): result => Ok(list{}), (racc, currentPropertyMathJsNode) => racc->Result.flatMap(acc => - fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{propertyCode, ...acc}) + fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{ + propertyCode, + ...acc, + }) ), ) rpropertyCodeList->Result.map(propertyCodeList => ExtressionT.EList(propertyCodeList)) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 8c94d752..1aeca2f1 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -23,7 +23,10 @@ let rec toString = aValue => | EvSymbol(aString) => `:${aString}` | EvArray(anArray) => { let args = - anArray->Belt.Array.map(each => toString(each))->Extra_Array.interperse(", ")->Js.String.concatMany("") + anArray + ->Belt.Array.map(each => toString(each)) + ->Extra_Array.interperse(", ") + ->Js.String.concatMany("") `[${args}]` } | EvRecord(aRecord) => { From 84f3420369d990fdc4fbda73975cf44ceca79d3a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 22:02:06 +0200 Subject: [PATCH 06/17] parse assignment --- .../Reducer_MathJsParse_test.res | 14 +++----- .../rescript/Reducer/Reducer_ErrorValue.res | 2 ++ .../Reducer_MathJs/Reducer_MathJs_Parse.res | 33 ++++++++++++++++--- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 41ba6239..31cbeb63 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -7,17 +7,13 @@ open Expect let expectParseToBe = (expr, answer) => Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(answer) -let testParse = (expr, answer) => - test(expr, () => expectParseToBe(expr, answer)) +let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParse = (desc, expr, answer) => - test(desc, () => expectParseToBe(expr, answer)) +let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let skipTestParse = (expr, answer) => - Skip.test(expr, () => expectParseToBe(expr, answer)) +let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) -let skipDescTestParse = (desc, expr, answer) => - Skip.test(desc, () => expectParseToBe(expr, answer)) +let skipDescTestParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) describe("MathJs parse", () => { describe("literals operators paranthesis", () => { @@ -31,7 +27,7 @@ describe("MathJs parse", () => { }) describe("variables", () => { - skipTestParse("x = 1", "???") + testParse("x = 1", "x = 1") skipTestParse("x", "???") }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 4f57bc2c..70601726 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -3,6 +3,7 @@ type errorValue = | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception | RERecordPropertyNotFound(string, string) + | RESyntaxError(string) | RETodo(string) // To do type t = errorValue @@ -24,5 +25,6 @@ let errorToString = err => answer } | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}` + | RESyntaxError(desc) => `Syntax Error: ${desc}` | RETodo(msg) => `TODO: ${msg}` } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index bfd186e0..15ef6e26 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -7,7 +7,6 @@ open Reducer_ErrorValue type node = {"type": string, "isNode": bool, "comment": string} type arrayNode = {...node, "items": array} -//assignmentNode //blockNode //conditionalNode type constantNode = {...node, "value": unit} @@ -23,9 +22,15 @@ type parenthesisNode = {...node, "content": node} //rangeNode //relationalNode type symbolNode = {...node, "name": string} +type assignmentNode = {...node, "object": symbolNode, "value": node} +type assignmentNodeWAccessor = {...node, "object": accessorNode, "value": node} +type assignmentNodeWIndex = {...assignmentNodeWAccessor, "index": Js.null} external castAccessorNode: node => accessorNode = "%identity" external castArrayNode: node => arrayNode = "%identity" +external castAssignmentNode: node => assignmentNode = "%identity" +external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" +external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" external castConstantNode: node => constantNode = "%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" @@ -50,6 +55,7 @@ let parse = (expr: string): result => type mathJsNode = | MjAccessorNode(accessorNode) | MjArrayNode(arrayNode) + | MjAssignmentNode(assignmentNode) | MjConstantNode(constantNode) | MjFunctionNode(functionNode) | MjIndexNode(indexNode) @@ -58,10 +64,20 @@ type mathJsNode = | MjParenthesisNode(parenthesisNode) | MjSymbolNode(symbolNode) -let castNodeType = (node: node) => +let castNodeType = (node: node) => { + let decideAssignmentNode = node => { + let iNode = node->castAssignmentNodeWIndex + if Js.Null.test(iNode["index"]) && iNode["object"]["type"] == "SymbolNode" { + node->castAssignmentNode->MjAssignmentNode->Ok + } else { + RESyntaxError("Assignment to index or property not supported")->Error + } + } + switch node["type"] { | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok + | "AssignmentNode" => node->decideAssignmentNode | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | "IndexNode" => node->castIndexNode->MjIndexNode->Ok @@ -71,6 +87,7 @@ let castNodeType = (node: node) => | "SymbolNode" => node->castSymbolNode->MjSymbolNode->Ok | _ => RETodo(`Argg, unhandled MathJsNode: ${node["type"]}`)->Error } +} let rec toString = (mathJsNode: mathJsNode): string => { let toStringValue = (a: 'a): string => @@ -89,7 +106,8 @@ let rec toString = (mathJsNode: mathJsNode): string => { let toStringFunctionNode = (fnode: functionNode): string => `${fnode["fn"]}(${fnode["args"]->toStringNodeArray})` - let toStringObjectEntry = ((key: string, value: node)): string => `${key}: ${value->toStringMathJsNode}` + let toStringObjectEntry = ((key: string, value: node)): string => + `${key}: ${value->toStringMathJsNode}` let toStringObjectNode = (oNode: objectNode): string => `{${oNode["properties"] @@ -103,16 +121,21 @@ let rec toString = (mathJsNode: mathJsNode): string => { ->Belt.Array.map(each => toStringResult(each->castNodeType)) ->Js.String.concatMany("") + let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"] + switch mathJsNode { - | MjAccessorNode(aNode) => `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` + | MjAccessorNode(aNode) => + `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]` + | MjAssignmentNode(aNode) => + `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` | MjConstantNode(cNode) => cNode["value"]->toStringValue | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode | MjObjectNode(oNode) => oNode->toStringObjectNode | MjOperatorNode(opNode) => opNode->castOperatorNodeToFunctionNode->toStringFunctionNode | MjParenthesisNode(pNode) => `(${toStringMathJsNode(pNode["content"])})` - | MjSymbolNode(sNode) => sNode["name"] + | MjSymbolNode(sNode) => sNode->toStringSymbolNode } } and toStringResult = (rMathJsNode: result): string => From cd7a4b748ee73f87db406080606a2bc33230bce2 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 22:03:03 +0200 Subject: [PATCH 07/17] assignment test --- .../Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 31cbeb63..ea302776 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -29,6 +29,7 @@ describe("MathJs parse", () => { describe("variables", () => { testParse("x = 1", "x = 1") skipTestParse("x", "???") + skipTestParse("x = 1; x", "???") }) describe("functions", () => { From 63a765a4fe515f48d3e3efbbce3508d318c4ffb9 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 23:03:32 +0200 Subject: [PATCH 08/17] mathjs parse assignment --- .../Reducer_MathJs/Reducer_MathJsParse_test.res | 4 ++-- .../Reducer_MathJs/Reducer_MathJs_Parse.res | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index ea302776..4ec86785 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -28,8 +28,8 @@ describe("MathJs parse", () => { describe("variables", () => { testParse("x = 1", "x = 1") - skipTestParse("x", "???") - skipTestParse("x = 1; x", "???") + testParse("x", "x") + testParse("x = 1; x", "{x = 1; x}") }) describe("functions", () => { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index 15ef6e26..7f20bacf 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -7,7 +7,8 @@ open Reducer_ErrorValue type node = {"type": string, "isNode": bool, "comment": string} type arrayNode = {...node, "items": array} -//blockNode +type block = {"node": node} +type blockNode = {...node, "blocks": array} //conditionalNode type constantNode = {...node, "value": unit} //functionAssignmentNode @@ -31,6 +32,7 @@ external castArrayNode: node => arrayNode = "%identity" external castAssignmentNode: node => assignmentNode = "%identity" external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" +external castBlockNode: node => blockNode = "%identity" external castConstantNode: node => constantNode = "%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" @@ -56,6 +58,7 @@ type mathJsNode = | MjAccessorNode(accessorNode) | MjArrayNode(arrayNode) | MjAssignmentNode(assignmentNode) + | MjBlockNode(blockNode) | MjConstantNode(constantNode) | MjFunctionNode(functionNode) | MjIndexNode(indexNode) @@ -67,7 +70,7 @@ type mathJsNode = let castNodeType = (node: node) => { let decideAssignmentNode = node => { let iNode = node->castAssignmentNodeWIndex - if Js.Null.test(iNode["index"]) && iNode["object"]["type"] == "SymbolNode" { + if Js.null == iNode["index"] && iNode["object"]["type"] == "SymbolNode" { node->castAssignmentNode->MjAssignmentNode->Ok } else { RESyntaxError("Assignment to index or property not supported")->Error @@ -78,6 +81,7 @@ let castNodeType = (node: node) => { | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok | "AssignmentNode" => node->decideAssignmentNode + | "BlockNode" => node->castBlockNode->MjBlockNode->Ok | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | "IndexNode" => node->castIndexNode->MjIndexNode->Ok @@ -123,12 +127,19 @@ let rec toString = (mathJsNode: mathJsNode): string => { let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"] + let toStringBlocks = (blocks: array): string => + blocks + ->Belt.Array.map(each => each["node"]->castNodeType->toStringResult) + ->Extra.Array.interperse("; ") + ->Js.String.concatMany("") + switch mathJsNode { | MjAccessorNode(aNode) => `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]` | MjAssignmentNode(aNode) => `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` + | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}` | MjConstantNode(cNode) => cNode["value"]->toStringValue | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode From 660c0c70aec2ca56ad6e4f26471f481ec25a967e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 8 Apr 2022 14:14:37 +0200 Subject: [PATCH 09/17] variables and statements format only reducer reformat lint multi-line test spelling multi-line semantic mapping todo multi-line eval multi-line tests todo change context to bindings simplify tests rename exception test methods bindings is an expression value make bindings callable reformat Emphasize the nature of Lisp AST Initial definition of macros make functions private fixed functionNode type casting macro call skeleton sort ReducerInterface fix test macros skeleton bindings is not a value assignment semantics let semantics defined format reformat reformat TODO function calls and list hd variables are confused reformat tmp works reformat reformat add test reformat add test --- .../Reducer_Dispatch_BuiltIn_test.res | 11 +- .../Reducer_MathJsParse_test.res | 30 ++-- .../__tests__/Reducer/Reducer_test.res | 26 ++- packages/squiggle-lang/package.json | 1 + .../Reducer_Dispatch_BuiltIn.res | 4 +- .../rescript/Reducer/Reducer_ErrorValue.res | 8 + .../Reducer_Expression/Reducer_Expression.res | 152 ++++++++++++++---- .../Reducer_Expression.resi | 16 -- .../Reducer_Expression_T.res | 10 ++ .../Reducer_MathJs/Reducer_MathJs_Parse.res | 21 ++- .../Reducer_MathJs_ToExpression.res | 101 +++++++++--- .../ReducerInterface_ExpressionValue.res | 11 +- 12 files changed, 288 insertions(+), 103 deletions(-) delete mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res index 2fd2a976..d8a6748c 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res @@ -6,15 +6,18 @@ open Expect let expectEvalToBe = (expr: string, answer: string) => Reducer.eval(expr)->ExpressionValue.toStringResult->expect->toBe(answer) +let testEval = (expr, answer) => + test(expr, () => expectEvalToBe(expr, answer)) + describe("builtin", () => { // All MathJs operators and functions are available for string, number and boolean // .e.g + - / * > >= < <= == /= not and or // See https://mathjs.org/docs/expressions/syntax.html // See https://mathjs.org/docs/reference/functions.html - test("-1", () => expectEvalToBe("-1", "Ok(-1)")) - test("1-1", () => expectEvalToBe("1-1", "Ok(0)")) - test("2>1", () => expectEvalToBe("2>1", "Ok(true)")) - test("concat('a','b')", () => expectEvalToBe("concat('a','b')", "Ok('ab')")) + testEval("-1", "Ok(-1)") + testEval("1-1", "Ok(0)") + testEval("2>1", "Ok(true)") + testEval("concat('a','b')", "Ok('ab')") }) describe("builtin exception", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 4ec86785..fce588f1 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -11,9 +11,11 @@ let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer) let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) +module MySkip = { + let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) -let skipDescTestParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) + let testDescParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) +} describe("MathJs parse", () => { describe("literals operators paranthesis", () => { @@ -26,6 +28,10 @@ describe("MathJs parse", () => { testParse("(1+2)", "(add(1, 2))") }) + describe("multi-line", () => { + testParse("1; 2", "{1; 2}") + }) + describe("variables", () => { testParse("x = 1", "x = 1") testParse("x", "x") @@ -33,16 +39,16 @@ describe("MathJs parse", () => { }) describe("functions", () => { - skipTestParse("identity(x) = x", "???") - skipTestParse("identity(x)", "???") + MySkip.testParse("identity(x) = x", "???") + MySkip.testParse("identity(x)", "???") }) describe("arrays", () => { - test("empty", () => expectParseToBe("[]", "[]")) - test("define", () => expectParseToBe("[0, 1, 2]", "[0, 1, 2]")) - test("define with strings", () => expectParseToBe("['hello', 'world']", "['hello', 'world']")) - skipTestParse("range(0, 4)", "range(0, 4)") - test("index", () => expectParseToBe("([0,1,2])[1]", "([0, 1, 2])[1]")) + testDescParse("empty", "[]", "[]") + testDescParse("define", "[0, 1, 2]", "[0, 1, 2]") + testDescParse("define with strings", "['hello', 'world']", "['hello', 'world']") + MySkip.testParse("range(0, 4)", "range(0, 4)") + testDescParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") }) describe("records", () => { @@ -51,10 +57,10 @@ describe("MathJs parse", () => { }) describe("comments", () => { - skipDescTestParse("define", "# This is a comment", "???") + MySkip.testDescParse("define", "# This is a comment", "???") }) - describe("if statement", () => { - skipDescTestParse("define", "if (true) { 1 } else { 0 }", "???") + describe("if statement", () => { // TODO Tertiary operator instead + MySkip.testDescParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index a7539b7f..035ba7d9 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -42,6 +42,15 @@ describe("reducer using mathjs parse", () => { "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", ) }) + describe("multi-line", () => { + testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))") + testParseToBe("1+1; 2+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))") + }) + describe("assignment", () => { + testParseToBe("x=1; x", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))") + testParseToBe("x=1+1; x+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))") + }) + }) describe("eval", () => { @@ -71,13 +80,26 @@ describe("eval", () => { test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)")) test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)")) }) + + describe("multi-line", () => { + testEvalToBe("1; 2", "Error(Assignment expected)") + testEvalToBe("1+1; 2+1", "Error(Assignment expected)") + }) + describe("assignment", () => { + testEvalToBe("x=1; x", "Ok(1)") + testEvalToBe("x=1+1; x+1", "Ok(3)") + testEvalToBe("x=1; y=x+1; y+1", "Ok(3)") + testEvalToBe("1; x=1", "Error(Assignment expected)") + testEvalToBe("1; 1", "Error(Assignment expected)") + testEvalToBe("x=1; x=1", "Error(Expression expected)") + }) }) describe("test exceptions", () => { testDescEvalToBe( "javascript exception", - "jsraise('div by 0')", + "javascriptraise('div by 0')", "Error(JS Exception: Error: 'div by 0')", ) - testDescEvalToBe("rescript exception", "resraise()", "Error(TODO: unhandled rescript exception)") + testDescEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") }) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index a968a156..6c920067 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -12,6 +12,7 @@ "test:watch": "jest --watchAll", "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html", "rescript:format": "find . -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;", + "reducer:format": "find src/rescript/Reducer src/rescript/ReducerInterface -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;", "all": "yarn build && yarn bundle && yarn test" }, "keywords": [ diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res index 824e36ef..01ce67cb 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res @@ -14,8 +14,8 @@ exception TestRescriptException let callInternal = (call: functionCall): result<'b, errorValue> => { let callMathJs = (call: functionCall): result<'b, errorValue> => switch call { - | ("jsraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests - | ("resraise", _) => raise(TestRescriptException) // For Tests + | ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests + | ("rescriptraise", _) => raise(TestRescriptException) // For Tests | call => call->toStringFunctionCall->MathJs.Eval.eval } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 70601726..0e23bc99 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -1,8 +1,12 @@ type errorValue = | REArrayIndexNotFound(string, int) + | REAssignmentExpected + | REExpressionExpected | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception + | REMacroNotFound(string) | RERecordPropertyNotFound(string, string) + | RESymbolNotFound(string) | RESyntaxError(string) | RETodo(string) // To do @@ -11,6 +15,8 @@ type t = errorValue let errorToString = err => switch err { | REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}` + | REAssignmentExpected => "Assignment expected" + | REExpressionExpected => "Expression expected" | REFunctionExpected(msg) => `Function expected: ${msg}` | REJavaScriptExn(omsg, oname) => { let answer = "JS Exception:" @@ -24,7 +30,9 @@ let errorToString = err => } answer } + | REMacroNotFound(macro) => `Macro not found: ${macro}` | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}` + | RESymbolNotFound(symbolName) => `${symbolName} is not defined` | RESyntaxError(desc) => `Syntax Error: ${desc}` | RETodo(msg) => `TODO: ${msg}` } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 76e75e07..6aeaa81d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -15,6 +15,7 @@ type t = expression */ let rec toString = expression => switch expression { + | T.EBindings(bindings) => "$$bound" | T.EList(aList) => `(${Belt.List.map(aList, aValue => toString(aValue)) ->Extra.List.interperse(" ") @@ -38,50 +39,137 @@ let parse_ = (expr: string, parser, converter): result => let parse = (mathJsCode: string): result => mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode) -module MapString = Belt.Map.String -type bindings = MapString.t -let defaultBindings: bindings = MapString.fromArray([]) -// TODO Define bindings for function execution context +let defaultBindings: T.bindings = Belt.Map.String.empty /* - After reducing each level of code tree, we have a value list to evaluate + Recursively evaluate/reduce the expression (Lisp AST) */ -let reduceValueList = (valueList: list): result => - switch valueList { - | list{EvSymbol(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch - | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok - } - -/* - Recursively evaluate/reduce the code tree -*/ -let rec reduceExpression = (expression: t, bindings): result => - switch expression { - | T.EValue(value) => value->Ok - | T.EList(list) => { - let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( - racc, - each: expression, - ) => - racc->Result.flatMap(acc => { - each - ->reduceExpression(bindings) - ->Result.flatMap(newNode => { - acc->Belt.List.add(newNode)->Ok - }) - }) - ) - racc->Result.flatMap(acc => acc->reduceValueList) +let rec reduceExpression = (expression: t, bindings: T.bindings): result => { + /* + After reducing each level of expression(Lisp AST), we have a value list to evaluate + */ + let reduceValueList = (valueList: list): result => + switch valueList { + | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch + | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok } + + /* + Macros are like functions but instead of taking values as parameters, + they take expressions as parameters and return a new expression. + Macros are used to define language building blocks. They are like Lisp macros. + */ + let doMacroCall = (list: list, bindings: T.bindings): result => { + let dispatchMacroCall = (list: list, bindings: T.bindings): result => { + let rec replaceSymbols = (expression: t, bindings: T.bindings): result => + switch expression { + | T.EValue(EvSymbol(aSymbol)) => + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => RESymbolNotFound(aSymbol)->Error + } + | T.EValue(_) => expression->Ok + | T.EBindings(_) => expression->Ok + | T.EList(list) => + list + ->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => + racc->Result.flatMap(acc => { + each + ->replaceSymbols(bindings) + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + ->Result.map(acc => acc->T.EList) + } + + let doBindStatement = (statement: t, bindings: T.bindings) => { + switch statement { + | T.EList(list{T.EValue(EvCall("$let")), T.EValue(EvSymbol(aSymbol)), expression}) => { + let rNewExpression = replaceSymbols(expression, bindings) + rNewExpression->Result.map(newExpression => + Belt.Map.String.set(bindings, aSymbol, newExpression)->T.EBindings + ) + } + | _ => REAssignmentExpected->Error + } + } + + let doBindExpression = (expression: t, bindings: T.bindings) => { + switch expression { + | T.EList(list{T.EValue(EvCall("$let")), ..._}) => REExpressionExpected->Error + | _ => replaceSymbols(expression, bindings) + } + } + + switch list { + | list{T.EValue(EvCall("$$bindings"))} => bindings->EBindings->Ok + + | list{T.EValue(EvCall("$$bindStatement")), T.EBindings(bindings), statement} => + doBindStatement(statement, bindings) + | list{T.EValue(EvCall("$$bindExpression")), T.EBindings(bindings), expression} => + doBindExpression(expression, bindings) + | _ => list->T.EList->Ok + } + } + + list->dispatchMacroCall(bindings) } + let rec seekMacros = (expression: t, bindings: T.bindings): result => + switch expression { + | T.EValue(value) => expression->Ok + | T.EList(list) => { + let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( + racc, + each: expression, + ) => + racc->Result.flatMap(acc => { + each + ->seekMacros(bindings) + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + racc->Result.flatMap(acc => acc->doMacroCall(bindings)) + } + } + + let rec reduceExpandedExpression = (expression: t): result => + switch expression { + | T.EValue(value) => value->Ok + | T.EList(list) => { + let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( + racc, + each: expression, + ) => + racc->Result.flatMap(acc => { + each + ->reduceExpandedExpression + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + racc->Result.flatMap(acc => acc->reduceValueList) + } + } + + let rExpandedExpression: result = expression->seekMacros(bindings) + rExpandedExpression->Result.flatMap(expandedExpression => + expandedExpression->reduceExpandedExpression + ) +} + let evalWBindingsExpression = (aExpression, bindings): result => reduceExpression(aExpression, bindings) /* Evaluates MathJs code via Lisp using bindings and answers the result */ -let evalWBindings = (codeText: string, bindings: bindings) => { +let evalWBindings = (codeText: string, bindings: T.bindings) => { parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings)) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi deleted file mode 100644 index afd0105f..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ /dev/null @@ -1,16 +0,0 @@ -module Result = Belt.Result -module T = Reducer_Expression_T -type expression = T.expression -type expressionValue = ReducerInterface.ExpressionValue.expressionValue -type t = expression -let toString: T.expression => Js.String.t -let toStringResult: result => string -let parse: string => result -module MapString = Belt.Map.String -type bindings = MapString.t -let defaultBindings: bindings -let reduceValueList: list => result -let reduceExpression: (expression, 'a) => result -let evalWBindingsExpression: (expression, 'a) => result -let evalWBindings: (string, bindings) => Result.t -let eval: string => Result.t diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res index 5f376050..fe938316 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res @@ -1,5 +1,15 @@ open ReducerInterface.ExpressionValue +/* + An expression is a Lisp AST. An expression is either a primitive value or a list of expressions. + In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is + apply e1, e2 -> apply e3 -> ... -> apply eN + This is Lisp semantics. It holds true in both eager and lazy evaluations. + A Lisp AST contains only expressions/primitive values to apply to their left. + The act of defining the semantics of a functional language is to write it in terms of Lisp AST. +*/ type rec expression = | EList(list) // A list to map-reduce | EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible + | EBindings(bindings) // let/def kind of statements return bindings +and bindings = Belt.Map.String.t diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index 7f20bacf..e3e2955c 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -12,17 +12,16 @@ type blockNode = {...node, "blocks": array} //conditionalNode type constantNode = {...node, "value": unit} //functionAssignmentNode -type functionNode = {...node, "fn": string, "args": array} type indexNode = {...node, "dimensions": array} type objectNode = {...node, "properties": Js.Dict.t} -type accessorNode = {...node, "object": node, "index": indexNode} -type operatorNode = {...functionNode, "op": string} +type accessorNode = {...node, "object": node, "index": indexNode, "name": string} -//parenthesisNode type parenthesisNode = {...node, "content": node} //rangeNode //relationalNode type symbolNode = {...node, "name": string} +type functionNode = {...node, "fn": unit, "args": array} +type operatorNode = {...functionNode, "op": string} type assignmentNode = {...node, "object": symbolNode, "value": node} type assignmentNodeWAccessor = {...node, "object": accessorNode, "value": node} type assignmentNodeWIndex = {...assignmentNodeWAccessor, "index": Js.null} @@ -93,6 +92,18 @@ let castNodeType = (node: node) => { } } +external unitAsSymbolNode: unit => symbolNode = "%identity" +external unitAsString: unit => string = "%identity" + +let nameOfFunctionNode = (fNode: functionNode): string => { + let name = fNode["fn"] + if Js.typeof(name) == "string" { + name->unitAsString + } else { + (name->unitAsSymbolNode)["name"] + } +} + let rec toString = (mathJsNode: mathJsNode): string => { let toStringValue = (a: 'a): string => if Js.typeof(a) == "string" { @@ -108,7 +119,7 @@ let rec toString = (mathJsNode: mathJsNode): string => { ->Js.String.concatMany("") let toStringFunctionNode = (fnode: functionNode): string => - `${fnode["fn"]}(${fnode["args"]->toStringNodeArray})` + `${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})` let toStringObjectEntry = ((key: string, value: node)): string => `${key}: ${value->toStringMathJsNode}` diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res index edd0313b..30c8651d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res @@ -1,11 +1,11 @@ module ErrorValue = Reducer_ErrorValue module ExpressionValue = ReducerInterface.ExpressionValue -module ExtressionT = Reducer_Expression_T +module ExpressionT = Reducer_Expression_T module JavaScript = Reducer_Js module Parse = Reducer_MathJs_Parse module Result = Belt.Result -type expression = ExtressionT.expression +type expression = ExpressionT.expression type expressionValue = ExpressionValue.expressionValue type errorValue = ErrorValue.errorValue @@ -18,10 +18,19 @@ let rec fromNode = (mathJsNode: Parse.node): result => ) ) - let castFunctionNode = fNode => { - let fn = fNode["fn"]->ExpressionValue.EvSymbol->ExtressionT.EValue + let toEvCallValue = (name: string): expression => + name->ExpressionValue.EvCall->ExpressionT.EValue + let toEvSymbolValue = (name: string): expression => + name->ExpressionValue.EvSymbol->ExpressionT.EValue + + let passToFunction = (fName: string, rLispArgs): result => { + let fn = fName->toEvCallValue + rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok) + } + + let caseFunctionNode = fNode => { let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList - lispArgs->Result.map(argsCode => list{fn, ...argsCode}->ExtressionT.EList) + passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs) } let caseObjectNode = oNode => { @@ -34,15 +43,16 @@ let rec fromNode = (mathJsNode: Parse.node): result => fromNode(value)->Result.map(valueExpression => { let entryCode = list{ - key->ExpressionValue.EvString->ExtressionT.EValue, + key->ExpressionValue.EvString->ExpressionT.EValue, valueExpression, - }->ExtressionT.EList + }->ExpressionT.EList list{entryCode, ...acc} }) ) ) - let lispName = "$constructRecord"->ExpressionValue.EvSymbol->ExtressionT.EValue - rargs->Result.map(args => list{lispName, ExtressionT.EList(args)}->ExtressionT.EList) + rargs->Result.flatMap(args => + passToFunction("$constructRecord", list{ExpressionT.EList(args)}->Ok) + ) // $consturctRecord gets a single argument: List of key-value paiers } oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries @@ -60,30 +70,69 @@ let rec fromNode = (mathJsNode: Parse.node): result => }) ), ) - rpropertyCodeList->Result.map(propertyCodeList => ExtressionT.EList(propertyCodeList)) + rpropertyCodeList->Result.map(propertyCodeList => ExpressionT.EList(propertyCodeList)) } let caseAccessorNode = (objectNode, indexNode) => { - let fn = "$atIndex"->ExpressionValue.EvSymbol->ExtressionT.EValue - caseIndexNode(indexNode)->Result.flatMap(indexCode => { - fromNode(objectNode)->Result.map(objectCode => - list{fn, objectCode, indexCode}->ExtressionT.EList + fromNode(objectNode)->Result.flatMap(objectCode => + passToFunction("$atIndex", list{objectCode, indexCode}->Ok) ) }) } - switch typedMathJsNode { - | MjArrayNode(aNode) => - aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExtressionT.EList(list)) - | MjConstantNode(cNode) => - cNode["value"]->JavaScript.Gate.jsToEv->Result.map(v => v->ExtressionT.EValue) - | MjFunctionNode(fNode) => fNode->castFunctionNode - | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->castFunctionNode - | MjParenthesisNode(pNode) => pNode["content"]->fromNode - | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) - | MjObjectNode(oNode) => caseObjectNode(oNode) - | MjSymbolNode(sNode) => sNode["name"]->ExpressionValue.EvSymbol->ExtressionT.EValue->Ok - | MjIndexNode(iNode) => caseIndexNode(iNode) + let caseAssignmentNode = aNode => { + let symbol = aNode["object"]["name"]->toEvSymbolValue + let rValueExpression = fromNode(aNode["value"]) + rValueExpression->Result.flatMap(valueExpression => { + let lispArgs = list{symbol, valueExpression}->Ok + passToFunction("$let", lispArgs) + }) } + + let caseArrayNode = aNode => { + aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) + } + + let caseBlockNode = (bNode): result => { + let blocks = bNode["blocks"] + let initialBindings = passToFunction("$$bindings", list{}->Ok) + let lastIndex = Belt.Array.length(blocks) - 1 + blocks->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, block, i) => { + rPreviousBindings->Result.flatMap(previousBindings => { + let node = block["node"] + let rStatement: result = node->fromNode + let bindName = if i == lastIndex { + "$$bindExpression" + } else { + "$$bindStatement" + } + rStatement->Result.flatMap((statement: expression) => { + let lispArgs = list{previousBindings, statement}->Ok + passToFunction(bindName, lispArgs) + }) + }) + }) + } + + let rFinalExpression: result = switch typedMathJsNode { + | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) + | MjArrayNode(aNode) => caseArrayNode(aNode) + | MjAssignmentNode(aNode) => caseAssignmentNode(aNode) + | MjSymbolNode(sNode) => { + let expr: expression = toEvSymbolValue(sNode["name"]) + let rExpr: result = expr->Ok + rExpr + } + | MjBlockNode(bNode) => caseBlockNode(bNode) + // | MjBlockNode(bNode) => "statement"->toEvSymbolValue->Ok + | MjConstantNode(cNode) => + cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) + | MjFunctionNode(fNode) => fNode->caseFunctionNode + | MjIndexNode(iNode) => caseIndexNode(iNode) + | MjObjectNode(oNode) => caseObjectNode(oNode) + | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode + | MjParenthesisNode(pNode) => pNode["content"]->fromNode + } + rFinalExpression }) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 10ac33aa..064f2db3 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -6,19 +6,21 @@ module Extra_Array = Reducer_Extra_Array module ErrorValue = Reducer_ErrorValue type rec expressionValue = + | EvArray(array) | EvBool(bool) + | EvCall(string) // External function call + | EvDistribution(GenericDist_Types.genericDist) | EvNumber(float) + | EvRecord(Js.Dict.t) | EvString(string) | EvSymbol(string) - | EvArray(array) - | EvRecord(Js.Dict.t) - | EvDistribution(GenericDist_Types.genericDist) type functionCall = (string, array) let rec toString = aValue => switch aValue { | EvBool(aBool) => Js.String.make(aBool) + | EvCall(fName) => `:${fName}` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` @@ -39,12 +41,13 @@ let rec toString = aValue => ->Js.String.concatMany("") `{${pairs}}` } - | EvDistribution(dist) => `${GenericDist.toString(dist)}` + | EvDistribution(dist) => GenericDist.toString(dist) } let toStringWithType = aValue => switch aValue { | EvBool(_) => `Bool::${toString(aValue)}` + | EvCall(_) => `Call::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` | EvSymbol(_) => `Symbol::${toString(aValue)}` From 87116d12d58b138047c2525c554db0bd4e1115c4 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 11 Apr 2022 16:51:15 +0200 Subject: [PATCH 10/17] reformat --- .../ReducerInterface/ReducerInterface_GenericDistribution.res | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index ea65b963..ed40e5d7 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -128,7 +128,8 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist) | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist) | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist) - | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist) + | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => + Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist) | ("exp", [EvDistribution(a)]) => // https://mathjs.org/docs/reference/functions/exp.html Helpers.twoDiststoDistFn(Algebraic, "pow", GenericDist.fromFloat(Math.e), a)->Some From f0008c1e206fccb98775f6d7e30c8646672a677e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 11 Apr 2022 16:51:44 +0200 Subject: [PATCH 11/17] offer reducer:format as an example --- packages/squiggle-lang/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index a2c93a54..28d8aaa1 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -11,6 +11,7 @@ "test": "jest", "test:watch": "jest --watchAll", "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html", + "reducer:format": "find src/rescript/Reducer src/rescript/ReducerInterface -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;", "all": "yarn build && yarn bundle && yarn test" }, "keywords": [ From 4fe72b8fb416fee7336071143f99efa0a37d2c9e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 15:47:46 +0200 Subject: [PATCH 12/17] remove Reduce_Expression.rsi. Too many changes. Hot target. Preventing development --- .../Reducer_Expression.resi | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi deleted file mode 100644 index 2a6db9bd..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ /dev/null @@ -1,29 +0,0 @@ -module Result = Belt.Result -module T = Reducer_Expression_T -type expression = T.expression -@genType -type expressionValue = ReducerInterface_ExpressionValue.expressionValue -type t = expression -let toString: T.expression => Js.String.t -let toStringResult: result => string -let parse: string => result -module MapString = Belt.Map.String -type bindings = MapString.t -let defaultBindings: bindings -let reduceValueList: list => result< - expressionValue, - Reducer_ErrorValue.t, -> -let reduceExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindingsExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindings: (string, bindings) => Result.t< - expressionValue, - Reducer_ErrorValue.t, -> -let eval: string => Result.t From 05b5efce1895304e1a2c165bb3b61105a8c777f5 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 16:15:27 +0200 Subject: [PATCH 13/17] remove -> in switch cases. close umuro/squiggle#59 squiggle --- .../Reducer_Expression/Reducer_Expression.res | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 6aeaa81d..ee1495d9 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -70,18 +70,18 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result expression->Ok | T.EBindings(_) => expression->Ok - | T.EList(list) => - list - ->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => - racc->Result.flatMap(acc => { - each - ->replaceSymbols(bindings) - ->Result.flatMap(newNode => { - acc->Belt.List.add(newNode)->Ok + | T.EList(list) => { + let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => + racc->Result.flatMap(acc => { + each + ->replaceSymbols(bindings) + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) }) - }) - ) - ->Result.map(acc => acc->T.EList) + ) + racc->Result.map(acc => acc->T.EList) + } } let doBindStatement = (statement: t, bindings: T.bindings) => { From a95cdfabe340475ad2ac940a550a2e571367a647 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 16:19:50 +0200 Subject: [PATCH 14/17] dont use short Desc - close umuro/squiggle#51 --- .../Reducer_MathJsParse_test.res | 20 +++++++++---------- .../__tests__/Reducer/Reducer_test.res | 18 ++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index fce588f1..879e20f9 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -9,12 +9,12 @@ let expectParseToBe = (expr, answer) => let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) +let testDescriptionParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) module MySkip = { let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) - let testDescParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) + let testDescriptionParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) } describe("MathJs parse", () => { @@ -44,23 +44,23 @@ describe("MathJs parse", () => { }) describe("arrays", () => { - testDescParse("empty", "[]", "[]") - testDescParse("define", "[0, 1, 2]", "[0, 1, 2]") - testDescParse("define with strings", "['hello', 'world']", "['hello', 'world']") + testDescriptionParse("empty", "[]", "[]") + testDescriptionParse("define", "[0, 1, 2]", "[0, 1, 2]") + testDescriptionParse("define with strings", "['hello', 'world']", "['hello', 'world']") MySkip.testParse("range(0, 4)", "range(0, 4)") - testDescParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") + testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") }) describe("records", () => { - testDescParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") - testDescParse("use", "record.property", "record['property']") + testDescriptionParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") + testDescriptionParse("use", "record.property", "record['property']") }) describe("comments", () => { - MySkip.testDescParse("define", "# This is a comment", "???") + MySkip.testDescriptionParse("define", "# This is a comment", "???") }) describe("if statement", () => { // TODO Tertiary operator instead - MySkip.testDescParse("define", "if (true) { 1 } else { 0 }", "???") + MySkip.testDescriptionParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 035ba7d9..8e65328b 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -3,11 +3,11 @@ open Reducer_TestHelpers let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) +let testDescriptionParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) -let testDescEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) +let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility @@ -29,14 +29,14 @@ describe("reducer using mathjs parse", () => { //Note. () is a empty list in Lisp // The only builtin structure in Lisp is list. There are no arrays // [1,2,3] becomes (1 2 3) - testDescParseToBe("empty", "[]", "Ok(())") + testDescriptionParseToBe("empty", "[]", "Ok(())") testParseToBe("[1, 2, 3]", "Ok((1 2 3))") testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") - testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") + testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") }) describe("records", () => { - testDescParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") - testDescParseToBe( + testDescriptionParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescriptionParseToBe( "use", "{a: 1, b: 2}.a", "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", @@ -73,7 +73,7 @@ describe("eval", () => { testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") - testDescEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)") + testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)") }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})")) @@ -96,10 +96,10 @@ describe("eval", () => { }) describe("test exceptions", () => { - testDescEvalToBe( + testDescriptionEvalToBe( "javascript exception", "javascriptraise('div by 0')", "Error(JS Exception: Error: 'div by 0')", ) - testDescEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") + testDescriptionEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") }) From 1b4422bb906e41067e1aef6541115ec9ebcedf54 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 16:26:43 +0200 Subject: [PATCH 15/17] revise lisp references - close umuro/squiggle#50 --- .../Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 2 +- .../Reducer/Reducer_Expression/Reducer_Expression.res | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res index 01ce67cb..21c91dc2 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res @@ -58,7 +58,7 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { } /* - Lisp engine uses Result monad while reducing expressions + Reducer uses Result monad while reducing expressions */ let dispatch = (call: functionCall): result => try { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index ee1495d9..8498c294 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -11,7 +11,7 @@ type expressionValue = ExpressionValue.expressionValue type t = expression /* - Shows the Lisp Code as text lisp code + Shows the expression as text of expression */ let rec toString = expression => switch expression { @@ -31,7 +31,7 @@ let toStringResult = codeResult => } /* - Converts a MathJs code to Lisp Code + Converts a MathJs code to expression */ let parse_ = (expr: string, parser, converter): result => expr->parser->Result.flatMap(node => converter(node)) @@ -167,13 +167,13 @@ let evalWBindingsExpression = (aExpression, bindings): result { parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings)) } /* - Evaluates MathJs code via Lisp and answers the result + Evaluates MathJs code via Reducer and answers the result */ let eval = (code: string) => evalWBindings(code, defaultBindings) From d1ea15e4f938c357db11da0bf7086b574e15351c Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 17:12:19 +0200 Subject: [PATCH 16/17] fix ts export --- packages/squiggle-lang/src/js/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 8455c601..1a53aa6c 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -117,6 +117,8 @@ function createTsExport( ); case "EvBool": return tag("boolean", x.value); + case "EvCall": + return tag("call", x.value); case "EvDistribution": return tag("distribution", new Distribution(x.value, sampEnv)); case "EvNumber": From fea990de2d314187f166c24e62ddb56230eea5dd Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 13 Apr 2022 01:34:06 +0200 Subject: [PATCH 17/17] Sam's patch PR#226 --- packages/squiggle-lang/src/js/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 1a53aa6c..4b8cddab 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -88,6 +88,7 @@ function tag(x: a, y: b): tagged { export type squiggleExpression = | tagged<"symbol", string> | tagged<"string", string> + | tagged<"call", string> | tagged<"array", squiggleExpression[]> | tagged<"boolean", boolean> | tagged<"distribution", Distribution>