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 f3c92f78..4932af3b 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 @@ -1,10 +1,14 @@ -module ExpressionValue = ReducerInterface.ExternalExpressionValue +module ExpressionValue = ReducerInterface.InternalExpressionValue +module Expression = Reducer_Expression open Jest open Expect -let expectEvalToBe = (expr: string, answer: string) => - Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) +let expectEvalToBe = (sourceCode: string, answer: string) => + Expression.BackCompatible.evaluateString(sourceCode) + ->ExpressionValue.toStringResult + ->expect + ->toBe(answer) let testEval = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Helpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Helpers.res index 05eb1b01..e915bfc1 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Helpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Helpers.res @@ -1,6 +1,5 @@ // Reducer_Helpers module ErrorValue = Reducer_ErrorValue -module ExternalExpressionValue = ReducerInterface.ExternalExpressionValue module InternalExpressionValue = ReducerInterface.InternalExpressionValue module Bindings = Reducer_Bindings @@ -15,8 +14,4 @@ let removeDefaultsInternal = (iev: InternalExpressionValue.t) => { } } -let removeDefaultsExternal = (ev: ExternalExpressionValue.t): ExternalExpressionValue.t => - ev->InternalExpressionValue.toInternal->removeDefaultsInternal->InternalExpressionValue.toExternal - let rRemoveDefaultsInternal = r => Belt.Result.map(r, removeDefaultsInternal) -let rRemoveDefaultsExternal = r => Belt.Result.map(r, removeDefaultsExternal) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res index ed00e957..e56c04d7 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res @@ -1,5 +1,5 @@ module MathJs = Reducer_MathJs -module ErrorValue = Reducer.ErrorValue +module ErrorValue = Reducer_ErrorValue open Jest open ExpectJs diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res index f17fe9aa..80093afb 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res @@ -3,359 +3,464 @@ open Reducer_Peggy_TestHelpers describe("Peggy parse", () => { describe("float", () => { - testParse("1.", "{1}") - testParse("1.1", "{1.1}") - testParse(".1", "{0.1}") - testParse("0.1", "{0.1}") - testParse("1e1", "{10}") - testParse("1e-1", "{0.1}") - testParse(".1e1", "{1}") - testParse("0.1e1", "{1}") + testParse("1.", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("1.1", "{(::$_endOfOuterBlock_$ () 1.1)}") + testParse(".1", "{(::$_endOfOuterBlock_$ () 0.1)}") + testParse("0.1", "{(::$_endOfOuterBlock_$ () 0.1)}") + testParse("1e1", "{(::$_endOfOuterBlock_$ () 10)}") + testParse("1e-1", "{(::$_endOfOuterBlock_$ () 0.1)}") + testParse(".1e1", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("0.1e1", "{(::$_endOfOuterBlock_$ () 1)}") }) describe("literals operators parenthesis", () => { // Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement - 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)}") + testParse("1", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("'hello'", "{(::$_endOfOuterBlock_$ () 'hello')}") + testParse("true", "{(::$_endOfOuterBlock_$ () true)}") + testParse("1+2", "{(::$_endOfOuterBlock_$ () (::add 1 2))}") + testParse("add(1,2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}") + testParse("(1)", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("(1+2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}") }) describe("unary", () => { - testParse("-1", "{(::unaryMinus 1)}") - testParse("!true", "{(::not true)}") - testParse("1 + -1", "{(::add 1 (::unaryMinus 1))}") - testParse("-a[0]", "{(::unaryMinus (::$_atIndex_$ :a 0))}") - testParse("!a[0]", "{(::not (::$_atIndex_$ :a 0))}") + testParse("-1", "{(::$_endOfOuterBlock_$ () (::unaryMinus 1))}") + testParse("!true", "{(::$_endOfOuterBlock_$ () (::not true))}") + testParse("1 + -1", "{(::$_endOfOuterBlock_$ () (::add 1 (::unaryMinus 1)))}") + testParse("-a[0]", "{(::$_endOfOuterBlock_$ () (::unaryMinus (::$_atIndex_$ :a 0)))}") + testParse("!a[0]", "{(::$_endOfOuterBlock_$ () (::not (::$_atIndex_$ :a 0)))}") }) describe("multiplicative", () => { - testParse("1 * 2", "{(::multiply 1 2)}") - testParse("1 / 2", "{(::divide 1 2)}") - testParse("1 * 2 * 3", "{(::multiply (::multiply 1 2) 3)}") - testParse("1 * 2 / 3", "{(::divide (::multiply 1 2) 3)}") - testParse("1 / 2 * 3", "{(::multiply (::divide 1 2) 3)}") - testParse("1 / 2 / 3", "{(::divide (::divide 1 2) 3)}") - testParse("1 * 2 + 3 * 4", "{(::add (::multiply 1 2) (::multiply 3 4))}") - testParse("1 * 2 - 3 * 4", "{(::subtract (::multiply 1 2) (::multiply 3 4))}") - testParse("1 * 2 .+ 3 * 4", "{(::dotAdd (::multiply 1 2) (::multiply 3 4))}") - testParse("1 * 2 .- 3 * 4", "{(::dotSubtract (::multiply 1 2) (::multiply 3 4))}") - testParse("1 * 2 + 3 .* 4", "{(::add (::multiply 1 2) (::dotMultiply 3 4))}") - testParse("1 * 2 + 3 / 4", "{(::add (::multiply 1 2) (::divide 3 4))}") - testParse("1 * 2 + 3 ./ 4", "{(::add (::multiply 1 2) (::dotDivide 3 4))}") - testParse("1 * 2 - 3 .* 4", "{(::subtract (::multiply 1 2) (::dotMultiply 3 4))}") - testParse("1 * 2 - 3 / 4", "{(::subtract (::multiply 1 2) (::divide 3 4))}") - testParse("1 * 2 - 3 ./ 4", "{(::subtract (::multiply 1 2) (::dotDivide 3 4))}") - testParse("1 * 2 - 3 * 4^5", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5)))}") + testParse("1 * 2", "{(::$_endOfOuterBlock_$ () (::multiply 1 2))}") + testParse("1 / 2", "{(::$_endOfOuterBlock_$ () (::divide 1 2))}") + testParse("1 * 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::multiply 1 2) 3))}") + testParse("1 * 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::multiply 1 2) 3))}") + testParse("1 / 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::divide 1 2) 3))}") + testParse("1 / 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::divide 1 2) 3))}") + testParse( + "1 * 2 + 3 * 4", + "{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::multiply 3 4)))}", + ) + testParse( + "1 * 2 - 3 * 4", + "{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 4)))}", + ) + testParse( + "1 * 2 .+ 3 * 4", + "{(::$_endOfOuterBlock_$ () (::dotAdd (::multiply 1 2) (::multiply 3 4)))}", + ) + testParse( + "1 * 2 .- 3 * 4", + "{(::$_endOfOuterBlock_$ () (::dotSubtract (::multiply 1 2) (::multiply 3 4)))}", + ) + testParse( + "1 * 2 + 3 .* 4", + "{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::dotMultiply 3 4)))}", + ) + testParse( + "1 * 2 + 3 / 4", + "{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::divide 3 4)))}", + ) + testParse( + "1 * 2 + 3 ./ 4", + "{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::dotDivide 3 4)))}", + ) + testParse( + "1 * 2 - 3 .* 4", + "{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::dotMultiply 3 4)))}", + ) + testParse( + "1 * 2 - 3 / 4", + "{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::divide 3 4)))}", + ) + testParse( + "1 * 2 - 3 ./ 4", + "{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::dotDivide 3 4)))}", + ) + testParse( + "1 * 2 - 3 * 4^5", + "{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5))))}", + ) testParse( "1 * 2 - 3 * 4^5^6", - "{(::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6)))}", + "{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6))))}", + ) + testParse( + "1 * -a[-2]", + "{(::$_endOfOuterBlock_$ () (::multiply 1 (::unaryMinus (::$_atIndex_$ :a (::unaryMinus 2)))))}", ) - testParse("1 * -a[-2]", "{(::multiply 1 (::unaryMinus (::$_atIndex_$ :a (::unaryMinus 2))))}") }) describe("multi-line", () => { - testParse("x=1; 2", "{:x = {1}; 2}") - testParse("x=1; y=2", "{:x = {1}; :y = {2}}") + testParse("x=1; 2", "{:x = {1}; (::$_endOfOuterBlock_$ () 2)}") + testParse("x=1; y=2", "{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}") }) describe("variables", () => { - testParse("x = 1", "{:x = {1}}") - testParse("x", "{:x}") - testParse("x = 1; x", "{:x = {1}; :x}") + testParse("x = 1", "{:x = {1}; (::$_endOfOuterBlock_$ () ())}") + testParse("x", "{(::$_endOfOuterBlock_$ () :x)}") + testParse("x = 1; x", "{:x = {1}; (::$_endOfOuterBlock_$ () :x)}") }) describe("functions", () => { - testParse("identity(x) = x", "{:identity = {|:x| {:x}}}") // Function definitions become lambda assignments - testParse("identity(x)", "{(::identity :x)}") + testParse("identity(x) = x", "{:identity = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions become lambda assignments + testParse("identity(x)", "{(::$_endOfOuterBlock_$ () (::identity :x))}") }) describe("arrays", () => { - testParse("[]", "{(::$_constructArray_$ ())}") - testParse("[0, 1, 2]", "{(::$_constructArray_$ (0 1 2))}") - testParse("['hello', 'world']", "{(::$_constructArray_$ ('hello' 'world'))}") - testParse("([0,1,2])[1]", "{(::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1)}") + testParse("[]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ ()))}") + testParse("[0, 1, 2]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ (0 1 2)))}") + testParse( + "['hello', 'world']", + "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ ('hello' 'world')))}", + ) + testParse( + "([0,1,2])[1]", + "{(::$_endOfOuterBlock_$ () (::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1))}", + ) }) describe("records", () => { - testParse("{a: 1, b: 2}", "{(::$_constructRecord_$ ('a': 1 'b': 2))}") - testParse("{1+0: 1, 2+0: 2}", "{(::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2))}") // key can be any expression - testParse("record.property", "{(::$_atIndex_$ :record 'property')}") + testParse( + "{a: 1, b: 2}", + "{(::$_endOfOuterBlock_$ () (::$_constructRecord_$ ('a': 1 'b': 2)))}", + ) + testParse( + "{1+0: 1, 2+0: 2}", + "{(::$_endOfOuterBlock_$ () (::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2)))}", + ) // key can be any expression + testParse("record.property", "{(::$_endOfOuterBlock_$ () (::$_atIndex_$ :record 'property'))}") }) describe("post operators", () => { //function call, array and record access are post operators with higher priority than unary operators - testParse("a==!b(1)", "{(::equal :a (::not (::b 1)))}") - testParse("a==!b[1]", "{(::equal :a (::not (::$_atIndex_$ :b 1)))}") - testParse("a==!b.one", "{(::equal :a (::not (::$_atIndex_$ :b 'one')))}") + testParse("a==!b(1)", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::b 1))))}") + testParse("a==!b[1]", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 1))))}") + testParse( + "a==!b.one", + "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 'one'))))}", + ) }) describe("comments", () => { - testParse("1 # This is a line comment", "{1}") - testParse("1 // This is a line comment", "{1}") - testParse("1 /* This is a multi line comment */", "{1}") - testParse("/* This is a multi line comment */ 1", "{1}") + testParse("1 # This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("1 // This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("1 /* This is a multi line comment */", "{(::$_endOfOuterBlock_$ () 1)}") + testParse("/* This is a multi line comment */ 1", "{(::$_endOfOuterBlock_$ () 1)}") testParse( ` - /* This is - a multi line - comment */ - 1`, - "{1}", + /* This is + a multi line + comment */ + 1`, + "{(::$_endOfOuterBlock_$ () 1)}", ) }) describe("ternary operator", () => { - testParse("true ? 2 : 3", "{(::$$_ternary_$$ true 2 3)}") + testParse("true ? 2 : 3", "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true 2 3))}") testParse( "false ? 2 : false ? 4 : 5", - "{(::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5))}", + "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5)))}", ) // nested ternary }) describe("if then else", () => { - testParse("if true then 2 else 3", "{(::$$_ternary_$$ true {2} {3})}") - testParse("if false then {2} else {3}", "{(::$$_ternary_$$ false {2} {3})}") + testParse( + "if true then 2 else 3", + "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true {2} {3}))}", + ) + testParse( + "if false then {2} else {3}", + "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} {3}))}", + ) testParse( "if false then {2} else if false then {4} else {5}", - "{(::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5}))}", + "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5})))}", ) //nested if }) describe("logical", () => { - testParse("true || false", "{(::or true false)}") - testParse("true && false", "{(::and true false)}") - testParse("a * b + c", "{(::add (::multiply :a :b) :c)}") // for comparison - testParse("a && b || c", "{(::or (::and :a :b) :c)}") - testParse("a && b || c && d", "{(::or (::and :a :b) (::and :c :d))}") - testParse("a && !b || c", "{(::or (::and :a (::not :b)) :c)}") - testParse("a && b==c || d", "{(::or (::and :a (::equal :b :c)) :d)}") - testParse("a && b!=c || d", "{(::or (::and :a (::unequal :b :c)) :d)}") - testParse("a && !(b==c) || d", "{(::or (::and :a (::not (::equal :b :c))) :d)}") - testParse("a && b>=c || d", "{(::or (::and :a (::largerEq :b :c)) :d)}") - testParse("a && !(b>=c) || d", "{(::or (::and :a (::not (::largerEq :b :c))) :d)}") - testParse("a && b<=c || d", "{(::or (::and :a (::smallerEq :b :c)) :d)}") - testParse("a && b>c || d", "{(::or (::and :a (::larger :b :c)) :d)}") - testParse("a && b=c || d", + "{(::$_endOfOuterBlock_$ () (::or (::and :a (::largerEq :b :c)) :d))}", + ) + testParse( + "a && !(b>=c) || d", + "{(::$_endOfOuterBlock_$ () (::or (::and :a (::not (::largerEq :b :c))) :d))}", + ) + testParse( + "a && b<=c || d", + "{(::$_endOfOuterBlock_$ () (::or (::and :a (::smallerEq :b :c)) :d))}", + ) + testParse("a && b>c || d", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::larger :b :c)) :d))}") + testParse( + "a && b { - testParse("1 -> add(2)", "{(::add 1 2)}") - testParse("-1 -> add(2)", "{(::add (::unaryMinus 1) 2)}") - testParse("-a[1] -> add(2)", "{(::add (::unaryMinus (::$_atIndex_$ :a 1)) 2)}") - testParse("-f(1) -> add(2)", "{(::add (::unaryMinus (::f 1)) 2)}") - testParse("1 + 2 -> add(3)", "{(::add 1 (::add 2 3))}") - testParse("1 -> add(2) * 3", "{(::multiply (::add 1 2) 3)}") - testParse("1 -> subtract(2)", "{(::subtract 1 2)}") - testParse("-1 -> subtract(2)", "{(::subtract (::unaryMinus 1) 2)}") - testParse("1 -> subtract(2) * 3", "{(::multiply (::subtract 1 2) 3)}") + testParse("1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}") + testParse("-1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus 1) 2))}") + testParse( + "-a[1] -> add(2)", + "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::$_atIndex_$ :a 1)) 2))}", + ) + testParse("-f(1) -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::f 1)) 2))}") + testParse("1 + 2 -> add(3)", "{(::$_endOfOuterBlock_$ () (::add 1 (::add 2 3)))}") + testParse("1 -> add(2) * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::add 1 2) 3))}") + testParse("1 -> subtract(2)", "{(::$_endOfOuterBlock_$ () (::subtract 1 2))}") + testParse("-1 -> subtract(2)", "{(::$_endOfOuterBlock_$ () (::subtract (::unaryMinus 1) 2))}") + testParse( + "1 -> subtract(2) * 3", + "{(::$_endOfOuterBlock_$ () (::multiply (::subtract 1 2) 3))}", + ) }) describe("elixir pipe", () => { //handled together with -> so there is no need for seperate tests - testParse("1 |> add(2)", "{(::add 1 2)}") + testParse("1 |> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}") }) describe("to", () => { - testParse("1 to 2", "{(::credibleIntervalToDistribution 1 2)}") - testParse("-1 to -2", "{(::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2))}") // lower than unary + testParse("1 to 2", "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution 1 2))}") + testParse( + "-1 to -2", + "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2)))}", + ) // lower than unary testParse( "a[1] to a[2]", - "{(::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2))}", + "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2)))}", ) // lower than post testParse( "a.p1 to a.p2", - "{(::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2'))}", + "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2')))}", ) // lower than post - testParse("1 to 2 + 3", "{(::add (::credibleIntervalToDistribution 1 2) 3)}") // higher than binary operators + testParse( + "1 to 2 + 3", + "{(::$_endOfOuterBlock_$ () (::add (::credibleIntervalToDistribution 1 2) 3))}", + ) // higher than binary operators testParse( "1->add(2) to 3->add(4) -> add(4)", - "{(::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4))}", + "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4)))}", ) // lower than chain }) describe("inner block", () => { // inner blocks are 0 argument lambdas. They can be used whenever a value is required. // Like lambdas they have a local scope. - testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; :x}") + testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; (::$_endOfOuterBlock_$ () :x)}") }) describe("lambda", () => { - testParse("{|x| x}", "{{|:x| {:x}}}") - testParse("f={|x| x}", "{:f = {{|:x| {:x}}}}") - testParse("f(x)=x", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments - testParse("f(x)=x ? 1 : 0", "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}") // Function definitions are lambda assignments + testParse("{|x| x}", "{(::$_endOfOuterBlock_$ () {|:x| {:x}})}") + testParse("f={|x| x}", "{:f = {{|:x| {:x}}}; (::$_endOfOuterBlock_$ () ())}") + testParse("f(x)=x", "{:f = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions are lambda assignments + testParse( + "f(x)=x ? 1 : 0", + "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}; (::$_endOfOuterBlock_$ () ())}", + ) // Function definitions are lambda assignments }) describe("Using lambda as value", () => { testParse( "myadd(x,y)=x+y; z=myadd; z", - "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; :z}", + "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; (::$_endOfOuterBlock_$ () :z)}", ) testParse( "myadd(x,y)=x+y; z=[myadd]; z", - "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructArray_$ (:myadd))}; :z}", + "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructArray_$ (:myadd))}; (::$_endOfOuterBlock_$ () :z)}", ) testParse( "myaddd(x,y)=x+y; z={x: myaddd}; z", - "{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructRecord_$ ('x': :myaddd))}; :z}", + "{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructRecord_$ ('x': :myaddd))}; (::$_endOfOuterBlock_$ () :z)}", + ) + testParse("f({|x| x+1})", "{(::$_endOfOuterBlock_$ () (::f {|:x| {(::add :x 1)}}))}") + testParse( + "map(arr, {|x| x+1})", + "{(::$_endOfOuterBlock_$ () (::map :arr {|:x| {(::add :x 1)}}))}", ) - testParse("f({|x| x+1})", "{(::f {|:x| {(::add :x 1)}})}") - testParse("map(arr, {|x| x+1})", "{(::map :arr {|:x| {(::add :x 1)}})}") testParse( "map([1,2,3], {|x| x+1})", - "{(::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}})}", + "{(::$_endOfOuterBlock_$ () (::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}}))}", ) testParse( "[1,2,3]->map({|x| x+1})", - "{(::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}})}", + "{(::$_endOfOuterBlock_$ () (::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}}))}", ) }) describe("unit", () => { - testParse("1m", "{(::fromUnit_m 1)}") - testParse("1M", "{(::fromUnit_M 1)}") - testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}") + testParse("1m", "{(::$_endOfOuterBlock_$ () (::fromUnit_m 1))}") + testParse("1M", "{(::$_endOfOuterBlock_$ () (::fromUnit_M 1))}") + testParse("1m+2cm", "{(::$_endOfOuterBlock_$ () (::add (::fromUnit_m 1) (::fromUnit_cm 2)))}") }) describe("Module", () => { - testParse("x", "{:x}") - testParse("Math.pi", "{:Math.pi}") + testParse("x", "{(::$_endOfOuterBlock_$ () :x)}") + testParse("Math.pi", "{(::$_endOfOuterBlock_$ () :Math.pi)}") }) }) describe("parsing new line", () => { testParse( ` - a + - b`, - "{(::add :a :b)}", + a + + b`, + "{(::$_endOfOuterBlock_$ () (::add :a :b))}", ) testParse( ` - x= - 1`, - "{:x = {1}}", + x= + 1`, + "{:x = {1}; (::$_endOfOuterBlock_$ () ())}", ) testParse( ` - x=1 - y=2`, - "{:x = {1}; :y = {2}}", + x=1 + y=2`, + "{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}", ) testParse( ` - x={ - y=2; - y } - x`, - "{:x = {:y = {2}; :y}; :x}", + x={ + y=2; + y } + x`, + "{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}", ) testParse( ` - x={ - y=2 - y } - x`, - "{:x = {:y = {2}; :y}; :x}", + x={ + y=2 + y } + x`, + "{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}", ) testParse( ` - x={ - y=2 - y - } - x`, - "{:x = {:y = {2}; :y}; :x}", + x={ + y=2 + y + } + x`, + "{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}", ) testParse( ` + x=1 + y=2 + z=3 + `, + "{:x = {1}; :y = {2}; :z = {3}; (::$_endOfOuterBlock_$ () ())}", + ) + testParse( + ` + f={ x=1 y=2 z=3 - `, - "{:x = {1}; :y = {2}; :z = {3}}", + x+y+z + } + `, + "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; (::$_endOfOuterBlock_$ () ())}", ) testParse( ` - f={ - x=1 - y=2 - z=3 - x+y+z + f={ + x=1 + y=2 + z=3 + x+y+z + } + g=f+4 + g + `, + "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () :g)}", + ) + testParse( + ` + f = + { + x=1; //x + y=2 //y + z= + 3 + x+ + y+ + z } - `, - "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}}", + g = + f + + 4 + g -> + h -> + p -> + q + `, + "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () (::q (::p (::h :g))))}", ) testParse( ` - f={ - x=1 - y=2 - z=3 - x+y+z - } - g=f+4 - g - `, - "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; :g}", + a |> + b |> + c |> + d + `, + "{(::$_endOfOuterBlock_$ () (::d (::c (::b :a))))}", ) testParse( ` - f = - { - x=1; //x - y=2 //y - z= - 3 - x+ - y+ - z - } - g = - f + - 4 - g -> - h -> - p -> - q - `, - "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::q (::p (::h :g)))}", - ) - testParse( - ` - a |> - b |> - c |> - d - `, - "{(::d (::c (::b :a)))}", - ) - testParse( - ` - a |> - b |> - c |> - d + - e - `, - "{(::add (::d (::c (::b :a))) :e)}", + a |> + b |> + c |> + d + + e + `, + "{(::$_endOfOuterBlock_$ () (::add (::d (::c (::b :a))) :e))}", ) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res index 4f7dabdc..010486be 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res @@ -3,77 +3,83 @@ open Reducer_Peggy_TestHelpers describe("Peggy parse type", () => { describe("type of", () => { - testParse("p: number", "{(::$_typeOf_$ :p #number)}") + testParse("p: number", "{(::$_typeOf_$ :p #number); (::$_endOfOuterBlock_$ () ())}") }) describe("type alias", () => { - testParse("type index=number", "{(::$_typeAlias_$ #index #number)}") + testParse( + "type index=number", + "{(::$_typeAlias_$ #index #number); (::$_endOfOuterBlock_$ () ())}", + ) }) describe("type or", () => { testParse( "answer: number|string", - "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string))))}", + "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string)))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("type function", () => { testParse( "f: number=>number=>number", - "{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}", + "{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number)))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("high priority contract", () => { testParse( "answer: number<-min<-max(100)|string", - "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string))))}", + "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string)))); (::$_endOfOuterBlock_$ () ())}", ) testParse( "answer: number<-memberOf([1,3,5])", - "{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5))))}", + "{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5)))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("low priority contract", () => { testParse( "answer: number | string $ opaque", - "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", + "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string))))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("type array", () => { - testParse("answer: [number]", "{(::$_typeOf_$ :answer (::$_typeArray_$ #number))}") + testParse( + "answer: [number]", + "{(::$_typeOf_$ :answer (::$_typeArray_$ #number)); (::$_endOfOuterBlock_$ () ())}", + ) }) describe("type record", () => { testParse( "answer: {a: number, b: string}", - "{(::$_typeOf_$ :answer (::$_typeRecord_$ (::$_constructRecord_$ ('a': #number 'b': #string))))}", + "{(::$_typeOf_$ :answer (::$_typeRecord_$ (::$_constructRecord_$ ('a': #number 'b': #string)))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("type constructor", () => { testParse( "answer: Age(number)", - "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number))))}", + "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number)))); (::$_endOfOuterBlock_$ () ())}", ) testParse( "answer: Complex(number, number)", - "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number))))}", + "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number)))); (::$_endOfOuterBlock_$ () ())}", ) testParse( "answer: Person({age: number, name: string})", - "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Person (::$_constructArray_$ ((::$_typeRecord_$ (::$_constructRecord_$ ('age': #number 'name': #string)))))))}", + "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Person (::$_constructArray_$ ((::$_typeRecord_$ (::$_constructRecord_$ ('age': #number 'name': #string))))))); (::$_endOfOuterBlock_$ () ())}", ) testParse( "weekend: Saturday | Sunday", - "{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ()))))))}", + "{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ())))))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("type parenthesis", () => { //$ is introduced to avoid parenthesis testParse( "answer: (number|string)<-opaque", - "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", + "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string))))); (::$_endOfOuterBlock_$ () ())}", ) }) describe("squiggle expressions in type contracts", () => { testParse( "odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))", - "{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2)))}", + "{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2))); (::$_endOfOuterBlock_$ () ())}", ) }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res index b434fdb9..303f66ee 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res @@ -23,13 +23,7 @@ let expectToExpressionToBe = (expr, answer, ~v="_", ()) => { } else { let a2 = rExpr - ->Result.flatMap(expr => - Expression.reduceExpression( - expr, - ReducerInterface_StdLib.internalStdLib, - ExpressionValue.defaultEnvironment, - ) - ) + ->Result.flatMap(expr => Expression.BackCompatible.evaluate(expr)) ->Reducer_Helpers.rRemoveDefaultsInternal ->ExpressionValue.toStringResultOkless (a1, a2)->expect->toEqual((answer, v)) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_outerBlock_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_outerBlock_test.res new file mode 100644 index 00000000..951005c2 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_outerBlock_test.res @@ -0,0 +1,23 @@ +module Bindings = Reducer_Bindings +module InternalExpressionValue = ReducerInterface_InternalExpressionValue + +open Jest +open Reducer_Peggy_TestHelpers + +describe("Peggy Outer Block", () => { + testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ()) + testToExpression("x=1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ~v="()", ()) + testToExpression( + "x=1; y=2", + "{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}", + ~v="()", + (), + ) + testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ()) + testToExpression( + "x={a=1; a}; x", + "{(:$_let_$ :x {(:$_let_$ :a {1}); :a}); (:$_endOfOuterBlock_$ () :x)}", + ~v="1", + (), + ) +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res index b8a81f25..3b20fafc 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res @@ -7,101 +7,138 @@ open Reducer_Peggy_TestHelpers describe("Peggy to Expression", () => { describe("literals operators parenthesis", () => { // Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement - testToExpression("1", "{1}", ~v="1", ()) - testToExpression("'hello'", "{'hello'}", ~v="'hello'", ()) - testToExpression("true", "{true}", ~v="true", ()) - testToExpression("1+2", "{(:add 1 2)}", ~v="3", ()) - testToExpression("add(1,2)", "{(:add 1 2)}", ~v="3", ()) - testToExpression("(1)", "{1}", ()) - testToExpression("(1+2)", "{(:add 1 2)}", ()) + testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ()) + testToExpression("'hello'", "{(:$_endOfOuterBlock_$ () 'hello')}", ~v="'hello'", ()) + testToExpression("true", "{(:$_endOfOuterBlock_$ () true)}", ~v="true", ()) + testToExpression("1+2", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ()) + testToExpression("add(1,2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ()) + testToExpression("(1)", "{(:$_endOfOuterBlock_$ () 1)}", ()) + testToExpression("(1+2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ()) }) describe("unary", () => { - testToExpression("-1", "{(:unaryMinus 1)}", ~v="-1", ()) - testToExpression("!true", "{(:not true)}", ~v="false", ()) - testToExpression("1 + -1", "{(:add 1 (:unaryMinus 1))}", ~v="0", ()) - testToExpression("-a[0]", "{(:unaryMinus (:$_atIndex_$ :a 0))}", ()) + testToExpression("-1", "{(:$_endOfOuterBlock_$ () (:unaryMinus 1))}", ~v="-1", ()) + testToExpression("!true", "{(:$_endOfOuterBlock_$ () (:not true))}", ~v="false", ()) + testToExpression("1 + -1", "{(:$_endOfOuterBlock_$ () (:add 1 (:unaryMinus 1)))}", ~v="0", ()) + testToExpression("-a[0]", "{(:$_endOfOuterBlock_$ () (:unaryMinus (:$_atIndex_$ :a 0)))}", ()) }) describe("multi-line", () => { - testToExpression("x=1; 2", "{(:$_let_$ :x {1}); 2}", ~v="2", ()) - testToExpression("x=1; y=2", "{(:$_let_$ :x {1}); (:$_let_$ :y {2})}", ~v="@{x: 1,y: 2}", ()) + testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ()) + testToExpression( + "x=1; y=2", + "{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}", + (), + ) }) describe("variables", () => { - testToExpression("x = 1", "{(:$_let_$ :x {1})}", ~v="@{x: 1}", ()) - testToExpression("x", "{:x}", ~v=":x", ()) //TODO: value should return error - testToExpression("x = 1; x", "{(:$_let_$ :x {1}); :x}", ~v="1", ()) + testToExpression("x = 1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ()) + testToExpression("x", "{(:$_endOfOuterBlock_$ () :x)}", ~v="Error(x is not defined)", ()) //TODO: value should return error + testToExpression("x = 1; x", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () :x)}", ~v="1", ()) }) describe("functions", () => { testToExpression( "identity(x) = x", - "{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x}))}", - ~v="@{identity: lambda(x=>internal code)}", + "{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}", (), ) // Function definitions become lambda assignments - testToExpression("identity(x)", "{(:identity :x)}", ()) // Note value returns error properly + testToExpression("identity(x)", "{(:$_endOfOuterBlock_$ () (:identity :x))}", ()) // Note value returns error properly testToExpression( "f(x) = x> 2 ? 0 : 1; f(3)", - "{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ (:larger :x 2) 0 1)})); (:f 3)}", + "{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ (:larger :x 2) 0 1)})); (:$_endOfOuterBlock_$ () (:f 3))}", ~v="0", (), ) }) describe("arrays", () => { - testToExpression("[]", "{(:$_constructArray_$ ())}", ~v="[]", ()) - testToExpression("[0, 1, 2]", "{(:$_constructArray_$ (0 1 2))}", ~v="[0,1,2]", ()) + testToExpression("[]", "{(:$_endOfOuterBlock_$ () (:$_constructArray_$ ()))}", ~v="[]", ()) + testToExpression( + "[0, 1, 2]", + "{(:$_endOfOuterBlock_$ () (:$_constructArray_$ (0 1 2)))}", + ~v="[0,1,2]", + (), + ) testToExpression( "['hello', 'world']", - "{(:$_constructArray_$ ('hello' 'world'))}", + "{(:$_endOfOuterBlock_$ () (:$_constructArray_$ ('hello' 'world')))}", ~v="['hello','world']", (), ) - testToExpression("([0,1,2])[1]", "{(:$_atIndex_$ (:$_constructArray_$ (0 1 2)) 1)}", ~v="1", ()) + testToExpression( + "([0,1,2])[1]", + "{(:$_endOfOuterBlock_$ () (:$_atIndex_$ (:$_constructArray_$ (0 1 2)) 1))}", + ~v="1", + (), + ) }) describe("records", () => { testToExpression( "{a: 1, b: 2}", - "{(:$_constructRecord_$ (('a' 1) ('b' 2)))}", + "{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (('a' 1) ('b' 2))))}", ~v="{a: 1,b: 2}", (), ) testToExpression( "{1+0: 1, 2+0: 2}", - "{(:$_constructRecord_$ (((:add 1 0) 1) ((:add 2 0) 2)))}", + "{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (((:add 1 0) 1) ((:add 2 0) 2))))}", (), ) // key can be any expression - testToExpression("record.property", "{(:$_atIndex_$ :record 'property')}", ()) + testToExpression( + "record.property", + "{(:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}", + (), + ) testToExpression( "record={property: 1}; record.property", - "{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_atIndex_$ :record 'property')}", + "{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}", ~v="1", (), ) }) describe("comments", () => { - testToExpression("1 # This is a line comment", "{1}", ~v="1", ()) - testToExpression("1 // This is a line comment", "{1}", ~v="1", ()) - testToExpression("1 /* This is a multi line comment */", "{1}", ~v="1", ()) - testToExpression("/* This is a multi line comment */ 1", "{1}", ~v="1", ()) + testToExpression("1 # This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ()) + testToExpression("1 // This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ()) + testToExpression( + "1 /* This is a multi line comment */", + "{(:$_endOfOuterBlock_$ () 1)}", + ~v="1", + (), + ) + testToExpression( + "/* This is a multi line comment */ 1", + "{(:$_endOfOuterBlock_$ () 1)}", + ~v="1", + (), + ) }) describe("ternary operator", () => { - testToExpression("true ? 1 : 0", "{(:$$_ternary_$$ true 1 0)}", ~v="1", ()) - testToExpression("false ? 1 : 0", "{(:$$_ternary_$$ false 1 0)}", ~v="0", ()) + testToExpression( + "true ? 1 : 0", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 0))}", + ~v="1", + (), + ) + testToExpression( + "false ? 1 : 0", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 0))}", + ~v="0", + (), + ) testToExpression( "true ? 1 : false ? 2 : 0", - "{(:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0))}", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0)))}", ~v="1", (), ) // nested ternary testToExpression( "false ? 1 : false ? 2 : 0", - "{(:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0))}", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0)))}", ~v="0", (), ) // nested ternary @@ -109,21 +146,21 @@ describe("Peggy to Expression", () => { testToExpression( // expression binding "f(a) = a > 5 ? 1 : 0; f(6)", - "{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) 1 0)})); (:f 6)}", + "{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) 1 0)})); (:$_endOfOuterBlock_$ () (:f 6))}", ~v="1", (), ) testToExpression( // when true binding "f(a) = a > 5 ? a : 0; f(6)", - "{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) :a 0)})); (:f 6)}", + "{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) :a 0)})); (:$_endOfOuterBlock_$ () (:f 6))}", ~v="6", (), ) testToExpression( // when false binding "f(a) = a < 5 ? 1 : a; f(6)", - "{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:smaller :a 5) 1 :a)})); (:f 6)}", + "{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:smaller :a 5) 1 :a)})); (:$_endOfOuterBlock_$ () (:f 6))}", ~v="6", (), ) @@ -131,23 +168,41 @@ describe("Peggy to Expression", () => { }) describe("if then else", () => { - testToExpression("if true then 2 else 3", "{(:$$_ternary_$$ true {2} {3})}", ()) - testToExpression("if true then {2} else {3}", "{(:$$_ternary_$$ true {2} {3})}", ()) + testToExpression( + "if true then 2 else 3", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}", + (), + ) + testToExpression( + "if true then {2} else {3}", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}", + (), + ) testToExpression( "if false then {2} else if false then {4} else {5}", - "{(:$$_ternary_$$ false {2} (:$$_ternary_$$ false {4} {5}))}", + "{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false {2} (:$$_ternary_$$ false {4} {5})))}", (), ) //nested if }) describe("pipe", () => { - testToExpression("1 -> add(2)", "{(:add 1 2)}", ~v="3", ()) - testToExpression("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}", ~v="1", ()) // note that unary has higher priority naturally - testToExpression("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}", ~v="9", ()) + testToExpression("1 -> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ()) + testToExpression( + "-1 -> add(2)", + "{(:$_endOfOuterBlock_$ () (:add (:unaryMinus 1) 2))}", + ~v="1", + (), + ) // note that unary has higher priority naturally + testToExpression( + "1 -> add(2) * 3", + "{(:$_endOfOuterBlock_$ () (:multiply (:add 1 2) 3))}", + ~v="9", + (), + ) }) describe("elixir pipe", () => { - testToExpression("1 |> add(2)", "{(:add 1 2)}", ~v="3", ()) + testToExpression("1 |> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ()) }) // see testParse for priorities of to and credibleIntervalToDistribution @@ -157,30 +212,31 @@ describe("Peggy to Expression", () => { // Like lambdas they have a local scope. testToExpression( "y=99; x={y=1; y}", - "{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y})}", - ~v="@{x: 1,y: 99}", + "{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y}); (:$_endOfOuterBlock_$ () ())}", (), ) }) describe("lambda", () => { - testToExpression("{|x| x}", "{(:$$_lambda_$$ [x] {:x})}", ~v="lambda(x=>internal code)", ()) + testToExpression( + "{|x| x}", + "{(:$_endOfOuterBlock_$ () (:$$_lambda_$$ [x] {:x}))}", + ~v="lambda(x=>internal code)", + (), + ) testToExpression( "f={|x| x}", - "{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})})}", - ~v="@{f: lambda(x=>internal code)}", + "{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})}); (:$_endOfOuterBlock_$ () ())}", (), ) testToExpression( "f(x)=x", - "{(:$_let_$ :f (:$$_lambda_$$ [x] {:x}))}", - ~v="@{f: lambda(x=>internal code)}", + "{(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}", (), ) // Function definitions are lambda assignments testToExpression( "f(x)=x ? 1 : 0", - "{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)}))}", - ~v="@{f: lambda(x=>internal code)}", + "{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)})); (:$_endOfOuterBlock_$ () ())}", (), ) }) @@ -188,12 +244,12 @@ describe("Peggy to Expression", () => { describe("module", () => { // testToExpression("Math.pi", "{:Math.pi}", ~v="3.141592653589793", ()) // Only.test("stdlibrary", () => { - // ReducerInterface_StdLib.internalStdLib - // ->IEvBindings - // ->InternalExpressionValue.toString - // ->expect - // ->toBe("") + // ReducerInterface_StdLib.internalStdLib + // ->IEvBindings + // ->InternalExpressionValue.toString + // ->expect + // ->toBe("") // }) - testToExpression("Math.pi", "{:Math.pi}", ~v="3.141592653589793", ()) + testToExpression("Math.pi", "{(:$_endOfOuterBlock_$ () :Math.pi)}", ~v="3.141592653589793", ()) }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res index 9849adb0..b0cfb676 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res @@ -5,92 +5,92 @@ describe("Peggy Types to Expression", () => { describe("type of", () => { testToExpression( "p: number", - "{(:$_typeOf_$ :p #number)}", - ~v="@{_typeReferences_: {p: #number}}", + "{(:$_typeOf_$ :p #number); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {p: #number}}", (), ) }) describe("type alias", () => { testToExpression( "type index=number", - "{(:$_typeAlias_$ #index #number)}", - ~v="@{_typeAliases_: {index: #number}}", + "{(:$_typeAlias_$ #index #number); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeAliases_: {index: #number}}", (), ) }) describe("type or", () => { testToExpression( "answer: number|string|distribution", - "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution))))}", - ~v="@{_typeReferences_: {answer: {typeOr: [#number,#string,#distribution],typeTag: 'typeOr'}}}", + "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution)))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {typeOr: [#number,#string,#distribution],typeTag: 'typeOr'}}}", (), ) }) describe("type function", () => { testToExpression( "f: number=>number=>number", - "{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number))))}", - ~v="@{_typeReferences_: {f: {inputs: [#number,#number],output: #number,typeTag: 'typeFunction'}}}", + "{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number)))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {f: {inputs: [#number,#number],output: #number,typeTag: 'typeFunction'}}}", (), ) testToExpression( "f: number=>number", - "{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number))))}", - ~v="@{_typeReferences_: {f: {inputs: [#number],output: #number,typeTag: 'typeFunction'}}}", + "{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number)))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {f: {inputs: [#number],output: #number,typeTag: 'typeFunction'}}}", (), ) }) describe("high priority contract", () => { testToExpression( "answer: number<-min(1)<-max(100)|string", - "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}", - ~v="@{_typeReferences_: {answer: {typeOr: [{max: 100,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'},#string],typeTag: 'typeOr'}}}", + "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string)))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {typeOr: [{max: 100,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'},#string],typeTag: 'typeOr'}}}", (), ) testToExpression( "answer: number<-memberOf([1,3,5])", - "{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5))))}", - ~v="@{_typeReferences_: {answer: {memberOf: [1,3,5],typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", + "{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5)))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {memberOf: [1,3,5],typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", (), ) testToExpression( "answer: number<-min(1)", - "{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1))}", - ~v="@{_typeReferences_: {answer: {min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", + "{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1)); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", (), ) testToExpression( "answer: number<-max(10)", - "{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10))}", - ~v="@{_typeReferences_: {answer: {max: 10,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", + "{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10)); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {max: 10,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", (), ) testToExpression( "answer: number<-min(1)<-max(10)", - "{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10))}", - ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", + "{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10)); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", (), ) testToExpression( "answer: number<-max(10)<-min(1)", - "{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1))}", - ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", + "{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1)); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}", (), ) }) describe("low priority contract", () => { testToExpression( "answer: number | string $ opaque", - "{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}", - ~v="@{_typeReferences_: {answer: {opaque: true,typeOr: [#number,#string],typeTag: 'typeOr'}}}", + "{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string))))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeReferences_: {answer: {opaque: true,typeOr: [#number,#string],typeTag: 'typeOr'}}}", (), ) }) describe("squiggle expressions in type contracts", () => { testToExpression( "odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))", - "{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2)))}", - ~v="@{_typeAliases_: {odds: {memberOf: [1,3,5,7,9],typeIdentifier: #number,typeTag: 'typeIdentifier'}},odds1: [1,3,5],odds2: [7,9]}", + "{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2))); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_typeAliases_: {odds: {memberOf: [1,3,5,7,9],typeIdentifier: #number,typeTag: 'typeIdentifier'}},odds1: [1,3,5],odds2: [7,9]}", (), ) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_void_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_void_test.res index a106a188..f46d387f 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_void_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_void_test.res @@ -3,18 +3,23 @@ open Reducer_Peggy_TestHelpers describe("Peggy void", () => { //literal - testToExpression("()", "{()}", ~v="()", ()) + testToExpression("()", "{(:$_endOfOuterBlock_$ () ())}", ~v="()", ()) testToExpression( "fn()=1", - "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1}))}", - ~v="@{fn: lambda(_=>internal code)}", + "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{fn: lambda(_=>internal code)}", + (), + ) + testToExpression( + "fn()=1; fn()", + "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:$_endOfOuterBlock_$ () (:fn ()))}", + ~v="1", (), ) - testToExpression("fn()=1; fn()", "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:fn ())}", ~v="1", ()) testToExpression( "fn(a)=(); call fn(1)", - "{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)})}", - ~v="@{_: (),fn: lambda(a=>internal code)}", + "{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)}); (:$_endOfOuterBlock_$ () ())}", + // ~v="@{_: (),fn: lambda(a=>internal code)}", (), ) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index 736c9c2f..34a21573 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -1,6 +1,7 @@ -module ExpressionT = Reducer_Expression_T -module ExternalExpressionValue = ReducerInterface.ExternalExpressionValue module ErrorValue = Reducer_ErrorValue +module Expression = Reducer_Expression +module ExpressionT = Reducer_Expression_T +module InternalExpressionValue = ReducerInterface.InternalExpressionValue open Jest open Expect @@ -8,30 +9,26 @@ open Expect let unwrapRecord = rValue => rValue->Belt.Result.flatMap(value => switch value { - | ExternalExpressionValue.EvRecord(aRecord) => Ok(aRecord) - | _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error + | InternalExpressionValue.IEvRecord(aRecord) => Ok(aRecord) + | _ => ErrorValue.RETodo("TODO: Internal bindings must be returned")->Error } ) -let expectParseToBe = (expr: string, answer: string) => - Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer) +let expectParseToBe = (code: string, answer: string) => + Expression.BackCompatible.parse(code)->ExpressionT.toStringResult->expect->toBe(answer) -let expectEvalToBe = (expr: string, answer: string) => - Reducer.evaluate(expr) - ->Reducer_Helpers.rRemoveDefaultsExternal - ->ExternalExpressionValue.toStringResult +let expectEvalToBe = (code: string, answer: string) => + Expression.BackCompatible.evaluateString(code) + ->Reducer_Helpers.rRemoveDefaultsInternal + ->InternalExpressionValue.toStringResult ->expect ->toBe(answer) -let expectEvalError = (expr: string) => - Reducer.evaluate(expr)->ExternalExpressionValue.toStringResult->expect->toMatch("Error\(") - -let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => - Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None) - ->Reducer_Helpers.rRemoveDefaultsExternal - ->ExternalExpressionValue.toStringResult +let expectEvalError = (code: string) => + Expression.BackCompatible.evaluateString(code) + ->InternalExpressionValue.toStringResult ->expect - ->toBe(answer) + ->toMatch("Error\(") let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) let testDescriptionParseToBe = (desc, expr, answer) => @@ -40,18 +37,12 @@ let testDescriptionParseToBe = (desc, expr, answer) => let testEvalError = expr => test(expr, () => expectEvalError(expr)) let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) -let testEvalBindingsToBe = (expr, bindingsList, answer) => - test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) module MySkip = { let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer)) - let testEvalBindingsToBe = (expr, bindingsList, answer) => - Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) } module MyOnly = { let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer)) - let testEvalBindingsToBe = (expr, bindingsList, answer) => - Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) } diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res index ffd5d964..752cc9c7 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res @@ -1,14 +1,14 @@ open Jest open Expect +module Bindings = Reducer_Bindings module BindingsReplacer = Reducer_Expression_BindingsReplacer module Expression = Reducer_Expression -// module ExpressionValue = ReducerInterface.ExpressionValue -module InternalExpressionValue = ReducerInterface.InternalExpressionValue module ExpressionWithContext = Reducer_ExpressionWithContext +module InternalExpressionValue = ReducerInterface.InternalExpressionValue module Macro = Reducer_Expression_Macro +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T module T = Reducer_Expression_T -module Bindings = Reducer_Bindings let testMacro_ = ( tester, @@ -21,8 +21,8 @@ let testMacro_ = ( expr ->Macro.expandMacroCall( bindings, - InternalExpressionValue.defaultEnvironment, - Expression.reduceExpression, + ProjectAccessorsT.identityAccessors, + Expression.reduceExpressionInProject, ) ->ExpressionWithContext.toStringResult ->expect @@ -41,8 +41,8 @@ let testMacroEval_ = ( expr ->Macro.doMacroCall( bindings, - InternalExpressionValue.defaultEnvironment, - Expression.reduceExpression, + ProjectAccessorsT.identityAccessors, + Expression.reduceExpressionInProject, ) ->InternalExpressionValue.toStringResult ->expect diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res index 71f90373..55ed36bd 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res @@ -8,7 +8,7 @@ open Jest open Expect let myIevEval = (aTypeSourceCode: string) => - TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpression) + TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpressionInProject) let myIevEvalToString = (aTypeSourceCode: string) => myIevEval(aTypeSourceCode)->InternalExpressionValue.toStringResult @@ -19,7 +19,7 @@ let myIevTest = (test, aTypeSourceCode, answer) => test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer)) let myTypeEval = (aTypeSourceCode: string) => - TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpression) + TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpressionInProject) let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode)->T.toStringResult let myTypeExpectEqual = (aTypeSourceCode, answer) => diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res index 07da15bb..29fa8249 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res @@ -1,8 +1,9 @@ +module Bindings = Reducer_Bindings +module ErrorValue = Reducer_ErrorValue module Expression = Reducer_Expression module ExpressionT = Reducer_Expression_T -module ErrorValue = Reducer_ErrorValue module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Bindings = Reducer_Bindings +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T module T = Reducer_Type_T module TypeChecker = Reducer_Type_TypeChecker @@ -13,10 +14,10 @@ let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): re 'v, ErrorValue.t, > => { - let reducerFn = Expression.reduceExpression + let reducerFn = Expression.reduceExpressionInProject let rResult = - Reducer.parse(sourceCode)->Belt.Result.flatMap(expr => - reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment) + Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => + reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors) ) rResult->Belt.Result.flatMap(result => switch result { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res index a3ee2712..fccff738 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res @@ -5,6 +5,7 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue module Bindings = Reducer_Bindings module T = Reducer_Type_T module TypeChecker = Reducer_Type_TypeChecker +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T open Jest open Expect @@ -16,10 +17,10 @@ let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result< 'v, ErrorValue.t, > => { - let reducerFn = Expression.reduceExpression + let reducerFn = Expression.reduceExpressionInProject let rResult = - Reducer.parse(sourceCode)->Belt.Result.flatMap(expr => - reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment) + Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => + reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors) ) rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn)) } diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_switch_replacement_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_switch_replacement_test.res index 16f0f118..9dbe08c5 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_switch_replacement_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_switch_replacement_test.res @@ -4,8 +4,11 @@ open Expect module DispatchT = Reducer_Dispatch_T module Expression = Reducer_Expression module ExpressionT = Reducer_Expression_T -module TypeCompile = Reducer_Type_Compile +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module TypeChecker = Reducer_Type_TypeChecker +module TypeCompile = Reducer_Type_Compile + open ReducerInterface_InternalExpressionValue type errorValue = Reducer_ErrorValue.errorValue @@ -14,13 +17,14 @@ type errorValue = Reducer_ErrorValue.errorValue // In dispatchChainPiece, we execute an return the result of execution if there is a type match. // Otherwise we return None so that the call chain can continue. // So we want to build a function like -// dispatchChainPiece = (call: functionCall, environment): option> +// dispatchChainPiece = (call: functionCall, accessors): option> +// Use accessors.environment to get the environment finally. // Now lets make the dispatchChainPiece itself. // Note that I am not passing the reducer to the dispatchChainPiece as an argument because it is in the context anyway. // Keep in mind that reducerFn is necessary for map/reduce so dispatchChainPiece should have a reducerFn in context. -let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispatchChainPiece => { +let makeMyDispatchChainPiece = (reducer: ProjectReducerFnT.t): DispatchT.dispatchChainPiece => { // Let's have a pure implementations module Implementation = { let stringConcat = (a: string, b: string): string => Js.String2.concat(a, b) @@ -45,15 +49,15 @@ let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispa // Let's bridge the pure implementation to expression values module Bridge = { - let stringConcat: DispatchT.genericIEvFunction = (args, _environment) => { + let stringConcat: DispatchT.genericIEvFunction = (args, _accessors: ProjectAccessorsT.t) => { let (a, b) = extractStringString(args) Implementation.stringConcat(a, b)->IEvString->Ok } - let arrayConcat: DispatchT.genericIEvFunction = (args, _environment) => { + let arrayConcat: DispatchT.genericIEvFunction = (args, _accessors: ProjectAccessorsT.t) => { let (a, b) = extractArrayArray(args) Implementation.arrayConcat(a, b)->IEvArray->Ok } - let plot: DispatchT.genericIEvFunction = (args, _environment) => { + let plot: DispatchT.genericIEvFunction = (args, _accessors: ProjectAccessorsT.t) => { switch args { // Just assume that we are doing the business of extracting and converting the deep record | [IEvRecord(_)] => Implementation.plot({"title": "This is a plot"})->IEvString->Ok @@ -98,12 +102,12 @@ let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispa // Exactly the same as the one used in real life let _dispatch = ( call: functionCall, - environment, - reducer: Reducer_Expression_T.reducerFn, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, chain, ): result => { let dispatchChainPiece = makeMyDispatchChainPiece(reducer) - dispatchChainPiece(call, environment)->E.O2.defaultFn(() => chain(call, environment, reducer)) + dispatchChainPiece(call, accessors)->E.O2.defaultFn(() => chain(call, accessors, reducer)) } // What is important about this implementation? @@ -112,12 +116,12 @@ let _dispatch = ( // B) Complicated recursive record types are not a problem. describe("Type Dispatch", () => { - let reducerFn = Expression.reduceExpression + let reducerFn = Expression.reduceExpressionInProject let dispatchChainPiece = makeMyDispatchChainPiece(reducerFn) test("stringConcat", () => { let call: functionCall = ("concat", [IEvString("hello"), IEvString("world")]) - let result = dispatchChainPiece(call, defaultEnvironment) + let result = dispatchChainPiece(call, ProjectAccessorsT.identityAccessors) expect(result)->toEqual(Some(Ok(IEvString("helloworld")))) }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res deleted file mode 100644 index bb1a4d35..00000000 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res +++ /dev/null @@ -1,14 +0,0 @@ -open Jest -open Reducer_TestHelpers - -describe("Eval with Bindings", () => { - testEvalBindingsToBe("x", list{("x", ExternalExpressionValue.EvNumber(1.))}, "Ok(1)") - testEvalBindingsToBe("x+1", list{("x", ExternalExpressionValue.EvNumber(1.))}, "Ok(2)") - testParseToBe("y = x+1; y", "Ok({(:$_let_$ :y {(:add :x 1)}); :y})") - testEvalBindingsToBe("y = x+1; y", list{("x", ExternalExpressionValue.EvNumber(1.))}, "Ok(2)") - testEvalBindingsToBe( - "y = x+1", - list{("x", ExternalExpressionValue.EvNumber(1.))}, - "Ok(@{x: 1,y: 2})", - ) -}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res index 30725cfe..a2abb85d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res @@ -2,8 +2,14 @@ open Jest open Reducer_TestHelpers describe("Parse function assignment", () => { - testParseToBe("f(x)=x", "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {:x}))})") - testParseToBe("f(x)=2*x", "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {(:multiply 2 :x)}))})") + testParseToBe( + "f(x)=x", + "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())})", + ) + testParseToBe( + "f(x)=2*x", + "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {(:multiply 2 :x)})); (:$_endOfOuterBlock_$ () ())})", + ) //MathJs does not allow blocks in function definitions }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 68614f89..9b111354 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -39,33 +39,27 @@ describe("symbol not defined", () => { }) describe("call and bindings", () => { - testEvalToBe("f(x)=x+1", "Ok(@{f: lambda(x=>internal code)})") + testEvalToBe("f(x)=x+1; f(0)", "Ok(1)") testEvalToBe("f(x)=x+1; f(1)", "Ok(2)") - testEvalToBe("f=1;y=2", "Ok(@{f: 1,y: 2})") - testEvalToBe("f(x)=x+1; y=f(1)", "Ok(@{f: lambda(x=>internal code),y: 2})") + testEvalToBe("f=1;y=2", "Ok(())") + testEvalToBe("f(x)=x+1; y=f(1); y", "Ok(2)") testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)") - testEvalToBe("f(x)=x+1; y=f(1); z=f(1)", "Ok(@{f: lambda(x=>internal code),y: 2,z: 2})") - testEvalToBe( - "f(x)=x+1; g(x)=f(x)+1", - "Ok(@{f: lambda(x=>internal code),g: lambda(x=>internal code)})", - ) + testEvalToBe("f(x)=x+1; y=f(1); z=f(1); z", "Ok(2)") + testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(0)", "Ok(2)") testParseToBe( "f=99; g(x)=f; g(2)", - "Ok({(:$_let_$ :f {99}); (:$_let_$ :g (:$$_lambda_$$ [x] {:f})); (:g 2)})", + "Ok({(:$_let_$ :f {99}); (:$_let_$ :g (:$$_lambda_$$ [x] {:f})); (:$_endOfOuterBlock_$ () (:g 2))})", ) testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)") testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)") - testEvalToBe( - "f(x)=x+1; g(x)=f(x)+1; y=g(2)", - "Ok(@{f: lambda(x=>internal code),g: lambda(x=>internal code),y: 4})", - ) + testEvalToBe("f(x)=x+1; g(x)=f(x)+1; y=g(2); y", "Ok(4)") testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)") }) describe("function tricks", () => { testEvalError("f(x)=f(y)=2; f(2)") //Error because chain assignment is not allowed testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") - testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok(@{g: lambda(x=>internal code),y: 2})") + testEvalToBe("y=2;g(x)=inspect(y)+1;y", "Ok(2)") MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters testEvalToBe("myadd(x,y)=x+y; z=myadd; z", "Ok(lambda(x,y=>internal code))") @@ -73,10 +67,7 @@ describe("function tricks", () => { }) describe("lambda in structures", () => { - testEvalToBe( - "myadd(x,y)=x+y; z=[myadd]", - "Ok(@{myadd: lambda(x,y=>internal code),z: [lambda(x,y=>internal code)]})", - ) + testEvalToBe("myadd(x,y)=x+y; z=[myadd]", "Ok(())") testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0]", "Ok(lambda(x,y=>internal code))") testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0](3,2)", "Ok(5)") testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z", "Ok({x: lambda(x,y=>internal code)})") diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res index 22fa8328..c86f4bca 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res @@ -2,7 +2,10 @@ open Jest open Reducer_TestHelpers describe("Parse ternary operator", () => { - testParseToBe("true ? 'YES' : 'NO'", "Ok({(:$$_ternary_$$ true 'YES' 'NO')})") + testParseToBe( + "true ? 'YES' : 'NO'", + "Ok({(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 'YES' 'NO'))})", + ) }) describe("Evaluate ternary operator", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index dc403e7d..f70aa934 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -48,7 +48,7 @@ describe("eval", () => { testEvalToBe("x=1; y=x+1; y+1", "Ok(3)") testEvalError("1; x=1") testEvalError("1; 1") - testEvalToBe("x=1; x=1", "Ok(@{x: 1})") + testEvalToBe("x=1; x=1; x", "Ok(1)") }) }) diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 3083b71b..4adb363f 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -118,28 +118,40 @@ describe("eval on distribution functions", () => { describe("parse on distribution functions", () => { describe("power", () => { - testParse("normal(5,2) ^ normal(5,1)", "Ok({(:pow (:normal 5 2) (:normal 5 1))})") - testParse("3 ^ normal(5,1)", "Ok({(:pow 3 (:normal 5 1))})") - testParse("normal(5,2) ^ 3", "Ok({(:pow (:normal 5 2) 3)})") + testParse( + "normal(5,2) ^ normal(5,1)", + "Ok({(:$_endOfOuterBlock_$ () (:pow (:normal 5 2) (:normal 5 1)))})", + ) + testParse("3 ^ normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:pow 3 (:normal 5 1)))})") + testParse("normal(5,2) ^ 3", "Ok({(:$_endOfOuterBlock_$ () (:pow (:normal 5 2) 3))})") }) describe("subtraction", () => { - testParse("10 - normal(5,1)", "Ok({(:subtract 10 (:normal 5 1))})") - testParse("normal(5,1) - 10", "Ok({(:subtract (:normal 5 1) 10)})") + testParse("10 - normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:subtract 10 (:normal 5 1)))})") + testParse("normal(5,1) - 10", "Ok({(:$_endOfOuterBlock_$ () (:subtract (:normal 5 1) 10))})") }) describe("pointwise arithmetic expressions", () => { testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))") testParse( ~skip=true, "normal(5,2) .- normal(5,1)", - "Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))", + "Ok((:$_endOfOuterBlock_$ () (:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1)))))", // TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})" ) - testParse("normal(5,2) .* normal(5,1)", "Ok({(:dotMultiply (:normal 5 2) (:normal 5 1))})") - testParse("normal(5,2) ./ normal(5,1)", "Ok({(:dotDivide (:normal 5 2) (:normal 5 1))})") - testParse("normal(5,2) .^ normal(5,1)", "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})") + testParse( + "normal(5,2) .* normal(5,1)", + "Ok({(:$_endOfOuterBlock_$ () (:dotMultiply (:normal 5 2) (:normal 5 1)))})", + ) + testParse( + "normal(5,2) ./ normal(5,1)", + "Ok({(:$_endOfOuterBlock_$ () (:dotDivide (:normal 5 2) (:normal 5 1)))})", + ) + testParse( + "normal(5,2) .^ normal(5,1)", + "Ok({(:$_endOfOuterBlock_$ () (:dotPow (:normal 5 2) (:normal 5 1)))})", + ) }) describe("equality", () => { - testParse("5 == normal(5,2)", "Ok({(:equal 5 (:normal 5 2))})") + testParse("5 == normal(5,2)", "Ok({(:$_endOfOuterBlock_$ () (:equal 5 (:normal 5 2)))})") }) describe("pointwise adding two normals", () => { testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))") diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res index b09e20ae..71fd9f61 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res @@ -1,11 +1,11 @@ -open ReducerInterface.ExternalExpressionValue +open ReducerInterface.InternalExpressionValue open Jest open Expect describe("ExpressionValue", () => { - test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1,'a'")) + test("argsToString", () => expect([IEvNumber(1.), IEvString("a")]->argsToString)->toBe("1,'a'")) test("toStringFunctionCall", () => - expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')") + expect(("fn", [IEvNumber(1.), IEvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')") ) }) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res new file mode 100644 index 00000000..bce7c84b --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res @@ -0,0 +1,33 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +Only.describe("Parse includes", () => { + let project = Project.createProject() + Project.setSource( + project, + "main", + ` +#include 'common' +x=1`, + ) + Project.parseIncludes(project, "main") + test("dependencies", () => { + expect(Project.getDependencies(project, "main")) == ["common"] + }) + test("dependents", () => { + expect(Project.getDependents(project, "main")) == [] + }) + test("getIncludes", () => { + let mainIncludes = Project.getIncludes(project, "main") + switch mainIncludes { + | Ok(includes) => expect(includes) == ["common"] + | Error(error) => fail(error->Reducer_ErrorValue.errorToString) + } + }) +}) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res new file mode 100644 index 00000000..d258d71a --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res @@ -0,0 +1,174 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +// test("", () => expect(1)->toBe(1)) + +let runFetchResult = (project, sourceId) => { + Project.run(project, sourceId) + Project.getResult(project, sourceId)->InternalExpressionValue.toStringResult +} + +let runFetchBindings = (project, sourceId) => { + Project.run(project, sourceId) + Project.getBindings(project, sourceId) + ->InternalExpressionValue.IEvBindings + ->InternalExpressionValue.toString +} + +test("setting continuation", () => { + let project = Project.createProject() + let privateProject = project->Project.T.Private.castToInternalProject + let sampleBindings = Bindings.emptyBindings->Bindings.set("test", IEvVoid) + Project.Private.setContinuation(privateProject, "main", sampleBindings) + let answer = Project.Private.getContinuation(privateProject, "main") + expect(answer)->toBe(sampleBindings) +}) + +test("test result true", () => { + let project = Project.createProject() + Project.setSource(project, "main", "true") + runFetchResult(project, "main")->expect->toBe("Ok(true)") +}) + +test("test result false", () => { + let project = Project.createProject() + Project.setSource(project, "main", "false") + runFetchResult(project, "main")->expect->toBe("Ok(false)") +}) + +test("test library", () => { + let project = Project.createProject() + Project.setSource(project, "main", "x=Math.pi; x") + runFetchResult(project, "main")->expect->toBe("Ok(3.141592653589793)") +}) + +test("test bindings", () => { + let project = Project.createProject() + Project.setSource(project, "variables", "myVariable=666") + runFetchBindings(project, "variables")->expect->toBe("@{myVariable: 666}") +}) + +describe("project1", () => { + let project = Project.createProject() + Project.setSource(project, "first", "x=1") + Project.setSource(project, "main", "x") + Project.setContinues(project, "main", ["first"]) + + test("runOrder", () => { + expect(Project.getRunOrder(project)) == ["first", "main"] + }) + test("dependents first", () => { + expect(Project.getDependents(project, "first")) == ["main"] + }) + test("dependencies first", () => { + expect(Project.getDependencies(project, "first")) == [] + }) + test("dependents main", () => { + expect(Project.getDependents(project, "main")) == [] + }) + test("dependencies main", () => { + expect(Project.getDependencies(project, "main")) == ["first"] + }) + test("test result", () => { + runFetchResult(project, "main")->expect->toBe("Ok(1)") + }) + test("test bindings", () => { + runFetchBindings(project, "main")->expect->toBe("@{x: 1}") + }) +}) + +describe("project2", () => { + let project = Project.createProject() + Project.setContinues(project, "main", ["second"]) + Project.setContinues(project, "second", ["first"]) + Project.setSource(project, "first", "x=1") + Project.setSource(project, "second", "y=2") + Project.setSource(project, "main", "y") + + test("runOrder", () => { + expect(Project.getRunOrder(project)) == ["first", "second", "main"] + }) + test("runOrderFor", () => { + expect(Project.getRunOrderFor(project, "first")) == ["first"] + }) + test("dependencies first", () => { + expect(Project.getDependencies(project, "first")) == [] + }) + test("dependents first", () => { + expect(Project.getDependents(project, "first")) == ["second", "main"] + }) + test("dependents main", () => { + expect(Project.getDependents(project, "main")) == [] + }) + test("dependencies main", () => { + expect(Project.getDependencies(project, "main")) == ["first", "second"] + }) + test("test result", () => { + runFetchResult(project, "main")->expect->toBe("Ok(2)") + }) + test("test bindings", () => { + runFetchBindings(project, "main")->expect->toBe("@{x: 1,y: 2}") + }) +}) + +describe("project with include", () => { + let project = Project.createProject() + Project.setContinues(project, "main", ["second"]) + Project.setContinues(project, "second", ["first"]) + + Project.setSource( + project, + "first", + ` + #include 'common' + x=1`, + ) + Project.parseIncludes(project, "first") + Project.parseIncludes(project, "first") //The only way of setting includes + //Don't forget to parse includes after changing the source + + Project.setSource(project, "common", "common=0") + Project.setSource( + project, + "second", + ` + #include 'common' + y=2`, + ) + Project.parseIncludes(project, "second") //The only way of setting includes + + Project.setSource(project, "main", "y") + + test("runOrder", () => { + expect(Project.getRunOrder(project)) == ["common", "first", "second", "main"] + }) + + test("runOrderFor", () => { + expect(Project.getRunOrderFor(project, "first")) == ["common", "first"] + }) + + test("dependencies first", () => { + expect(Project.getDependencies(project, "first")) == ["common"] + }) + test("dependents first", () => { + expect(Project.getDependents(project, "first")) == ["second", "main"] + }) + test("dependents main", () => { + expect(Project.getDependents(project, "main")) == [] + }) + test("dependencies main", () => { + expect(Project.getDependencies(project, "main")) == ["common", "first", "second"] + }) + test("test result", () => { + runFetchResult(project, "main")->expect->toBe("Ok(2)") + }) + test("test bindings", () => { + runFetchBindings(project, "main")->expect->toBe("@{common: 0,x: 1,y: 2}") + }) +}) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_0_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_0_test.res new file mode 100644 index 00000000..d6f43904 --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_0_test.res @@ -0,0 +1,109 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +describe("ReducerProject Tutorial", () => { + describe("Single source", () => { + /* +Case "Running a single source". +*/ + test("run", () => { + /* Let's start with running a single source and getting Result as well as the Bindings + First you need to create a project. A project is a collection of sources. + Project takes care of the dependencies between the sources, correct compilation and run order. + You can run any source in the project. It will be compiled and run if it is not already done else already existing results will be presented. + The dependencies will be automatically compiled and run. So you don't need to worry about that in a multi source project. + In summary you issue a run command on the whole project or on a specific source to ensure that there is a result for that source. + */ + let project = Project.createProject() + /* Every source has a name. This is used for debugging, dependencies and error messages. */ + Project.setSource(project, "main", "1 + 2") + /* Let's run "main" source. */ + project->Project.run("main") + /* Now you have a result for "main" source. + Running one by one is necessary for UI to navigate among the sources and to see the results by source. + And you're free to run any source you want. + You will look at the results of this source and you don't want to run the others if not required. + */ + + /* However, you could also run the whole project. + If you have all the sources, you can always run the whole project. + Dependencies and recompiling on demand will be taken care of by the project. + */ + project->Project.runAll + + /* Either with run or runAll you executed the project. + You can get the result of a specific source by calling getResult for that source. + You can get the bindings of a specific source by calling getBindings for that source. + If there is any runtime error, getResult will return the error. + + Note that getResult returns None if the source has not been run. + Getting None means you have forgotten to run the source. + */ + let result = project->Project.getResult("main") + let bindings = project->Project.getBindings("main") + + /* Let's display the result and bindings */ + ( + result->InternalExpressionValue.toStringResult, + bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(3)", "@{}") + /* You've got 3 with empty bindings. */ + }) + + test("run summary", () => { + let project = Project.createProject() + Project.setSource(project, "main", "1 + 2") + Project.runAll(project) + let result = Project.getResult(project, "main") + let bindings = Project.getBindings(project, "main") + /* Now you have external bindings and external result. */ + ( + result->InternalExpressionValue.toStringResult, + bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(3)", "@{}") + }) + + test("run with an environment", () => { + /* Running the source code like above allows you to set a custom environment */ + let project = Project.createProject() + + /* Optional. Set your custom environment anytime before running */ + Project.setEnvironment(project, InternalExpressionValue.defaultEnvironment) + + Project.setSource(project, "main", "1 + 2") + Project.runAll(project) + let result = Project.getResult(project, "main") + let _bindings = Project.getBindings(project, "main") + result->InternalExpressionValue.toStringResult->expect == "Ok(3)" + }) + + test("shortcut", () => { + /* If you are running single source without includes and you don't need a custom environment, you can use the shortcut. */ + /* Examples above was to prepare you for the multi source tutorial. */ + let (result, bindings) = Project.evaluate("1+2") + ( + result->InternalExpressionValue.toStringResult, + bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(3)", "@{}") + }) + }) +}) + +//TODO multiple sources +//TODO multiple sources with includes. Introduction to includes +//TODO multiple sources with multi level includes. Cycle detection +//TODO +//TODO: Implement a runOrder consideration - clean results based on run order. +//TODO: runOrder vs setSource/touchSource +//TODO: Advanced details: (below) +//TODO runOrder. includes vs continues. Run order based reexecution +//TODO: dependents and reexecution +//TODO: dependencies and reexecution +//TODO: cleanAllResults clean +//TODO: cleanAll clean diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_1_multisource_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_1_multisource_test.res new file mode 100644 index 00000000..4362fcf6 --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_1_multisource_test.res @@ -0,0 +1,112 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +describe("ReducerProject Tutorial", () => { + describe("Multi source", () => { + /* + Case "Running multiple sources" */ + test("Chaining", () => { + let project = Project.createProject() + /* This time let's add 3 sources and chain them together */ + Project.setSource(project, "source1", "x=1") + + Project.setSource(project, "source2", "y=2") + /* To run, source2 depends on source1 */ + Project.setContinues(project, "source2", ["source1"]) + + Project.setSource(project, "source3", "z=3") + /* To run, source3 depends on source2 */ + Project.setContinues(project, "source3", ["source2"]) + + /* Now we can run the project */ + Project.runAll(project) + + /* And let's check the result and bindings of source3 */ + let result3 = Project.getResult(project, "source3") + let bindings3 = Project.getBindings(project, "source3") + + ( + result3->InternalExpressionValue.toStringResult, + bindings3->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}") + }) + + test("Depending", () => { + /* Instead of chaining the sources, we could have a dependency tree */ + /* The point here is that any source can depend on multiple sources */ + let project = Project.createProject() + + /* This time source1 and source2 are not depending on anything */ + Project.setSource(project, "source1", "x=1") + Project.setSource(project, "source2", "y=2") + + Project.setSource(project, "source3", "z=3") + /* To run, source3 depends on source1 and source3 together */ + Project.setContinues(project, "source3", ["source1", "source2"]) + + /* Now we can run the project */ + Project.runAll(project) + + /* And let's check the result and bindings of source3 */ + let result3 = Project.getResult(project, "source3") + let bindings3 = Project.getBindings(project, "source3") + + ( + result3->InternalExpressionValue.toStringResult, + bindings3->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}") + }) + + test("Intro to including", () => { + /* Though it would not be practical for a storybook, + let's write the same project above with includes. + You will see that parsing includes is setting the dependencies the same way as before. */ + let project = Project.createProject() + + /* This time source1 and source2 are not depending on anything */ + Project.setSource(project, "source1", "x=1") + Project.setSource(project, "source2", "y=2") + + Project.setSource( + project, + "source3", + ` + #include "source1" + #include "source2" + z=3`, + ) + /* We need to parse the includes to set the dependencies */ + Project.parseIncludes(project, "source3") + + /* Now we can run the project */ + Project.runAll(project) + + /* And let's check the result and bindings of source3 + This time you are getting all the variables because we are including the other sources + Behind the scenes parseIncludes is setting the dependencies */ + let result3 = Project.getResult(project, "source3") + let bindings3 = Project.getBindings(project, "source3") + + ( + result3->InternalExpressionValue.toStringResult, + bindings3->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}") + /* + Doing it like this is too verbose for a storybook + But I hope you have seen the relation of setContinues and parseIncludes */ + /* + Dealing with includes needs more. + - There are parse errors + - There are cyclic includes + - And the depended source1 and source2 is not already there in the project + - If you knew the includes before hand there would not be point of the include directive. + More on those on the next section. */ + }) + }) +}) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_2_includes_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_2_includes_test.res new file mode 100644 index 00000000..a4c2e0a3 --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_2_includes_test.res @@ -0,0 +1,156 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +describe("ReducerProject Tutorial", () => { + /* Case: Includes +In the previous tutorial we have set the similarity between setContinues and parseIncludes. +Here we will finally proceed to a real life scenario. */ + + describe("parseIncludes", () => { + /* Here we investigate the details about parseIncludes, before setting up a real life senario in the next section. */ + /* Everything happens inside a project, so let's have a project */ + let project = Project.createProject() + Project.setSource( + project, + "main", + ` + #include "common" + x=1 + `, + ) + /* We need to parse includes after changing the source */ + Project.parseIncludes(project, "main") + test("getDependencies", () => { + /* Parse includes has set the dependencies */ + Project.getDependencies(project, "main")->expect == ["common"] + /* If there were no includes than there would be no dependencies */ + /* However if there was a syntax error at includes then would be no dependencies also */ + /* Therefore looking at dependencies is not the right way to load includes */ + /* getDependencies does not distinguish between setContinues or parseIncludes */ + }) + test("getIncludes", () => { + /* Parse includes has set the includes */ + switch Project.getIncludes(project, "main") { + | Ok(includes) => includes->expect == ["common"] + | Error(err) => err->Reducer_ErrorValue.errorToString->fail + } + /* If the includes cannot be parsed then you get a syntax error. + Otherwise you get the includes. + If there is no syntax error then you can load that file and use setSource to add it to the project. + And so on recursively... */ + }) + test("getDependents", () => { + /* For any reason, you are able to query what other sources + include or depend on the current source. + But you don't need to use this to execute the projects. + It is provided for completeness of information. */ + Project.getDependents(project, "main")->expect == [] + /* Nothing is depending on or including main */ + }) + + describe("Real Like", () => { + /* Now let's look at recursive and possibly cyclic includes */ + /* There is no function provided to load the include files. + Because we have no idea if will it be an ordinary function or will it use promises. + Therefore one has to write a function to load sources recursively and and setSources + while checking for dependencies */ + + /* Let's make a dummy loader */ + let loadSource = (sourceName: string) => + switch sourceName { + | "source1" => "x=1" + | "source2" => ` + #include "source1" + y=2` + | "source3" => ` + #include "source2" + z=3` + | _ => `source ${sourceName} not found`->Js.Exn.raiseError + } + + /* let's recursively load the sources */ + let rec loadIncludesRecursively = (project, sourceName, visited) => { + if Js.Array2.includes(visited, sourceName) { + /* Oh we have already visited this source. There is an include cycle */ + "Cyclic include ${sourceName}"->Js.Exn.raiseError + } else { + let newVisited = Js.Array2.copy(visited) + let _ = Js.Array2.push(newVisited, sourceName) + /* Let's parse the includes and dive into them */ + Project.parseIncludes(project, sourceName) + let rIncludes = Project.getIncludes(project, sourceName) + switch rIncludes { + /* Maybe there is an include syntax error */ + | Error(err) => err->Reducer_ErrorValue.errorToString->Js.Exn.raiseError + + | Ok(includes) => + Belt.Array.forEach(includes, newIncludeName => { + /* We have got one of the new includes. + Let's load it and add it to the project */ + let newSource = loadSource(newIncludeName) + Project.setSource(project, newIncludeName, newSource) + /* The new source is loaded and added to the project. */ + /* Of course the new source might have includes too. */ + /* Let's recursively load them */ + loadIncludesRecursively(project, newIncludeName, newVisited) + }) + } + } + } + /* As we have a fake source loader and a recursive include handler, + We can not set up a real project */ + + /* * Here starts our real life project! * */ + + let project = Project.createProject() + + /* main includes source3 which includes source2 which includes source1 */ + Project.setSource( + project, + "main", + ` + #include "source3" + x+y+z + `, + ) + /* Setting source requires parsing and loading the includes recursively */ + loadIncludesRecursively(project, "main", []) //No visited yet + + /* Let's salt it more. Let's have another source in the project which also has includes */ + /* doubleX includes source1 which is eventually included by main as well */ + Project.setSource( + project, + "doubleX", + ` + #include "source1" + doubleX = x * 2 + `, + ) + loadIncludesRecursively(project, "doubleX", []) + /* Remember, any time you set a source, you need to load includes recursively */ + + /* As doubleX is not included by main, it is not loaded recursively. + So we link it to the project as a dependency */ + Project.setContinues(project, "main", ["doubleX"]) + + /* Let's run the project */ + Project.runAll(project) + let result = Project.getResult(project, "main") + let bindings = Project.getBindings(project, "main") + /* And see the result and bindings.. */ + test("recursive includes", () => { + ( + result->InternalExpressionValue.toStringResult, + bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString, + )->expect == ("Ok(6)", "@{doubleX: 2,x: 1,y: 2,z: 3}") + /* Everything as expected */ + }) + }) + }) +}) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_injecting_user_values.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_injecting_user_values.res new file mode 100644 index 00000000..38d655c1 --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_injecting_user_values.res @@ -0,0 +1,39 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +describe("ReducerProject Tutorial", () => { + /* Let's build a project that depends on values from the UI */ + let project = Project.createProject() + Project.setSource(project, "main", "x+y+z") + /* x, y and z is not defined in the project but they has to come from the user */ + test("Injecting user values", () => { + /* User has input the values */ + let x = 1 + let y = 2 + let z = 3 + /* Then we construct a source code to define those values */ + let userCode = ` + x = ${x->Js.Int.toString} + y = ${y->Js.Int.toString} + z = ${z->Js.Int.toString} + ` + /* We inject the user code into the project */ + Project.setSource(project, "userCode", userCode) + /* "main" is depending on the user code */ + Project.setContinues(project, "main", ["userCode"]) + /* We can now run the project */ + Project.runAll(project) + let result = Project.getResult(project, "main") + result->InternalExpressionValue.toStringResult->expect == "Ok(6)" + }) +}) + +/* Note that this is not final version of the project */ +/* In the future, for safety, we will provide a way to inject values instead of a source code */ +/* But time is limited for now... */ diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_4_calling_functions.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_4_calling_functions.res new file mode 100644 index 00000000..7e2471b5 --- /dev/null +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_4_calling_functions.res @@ -0,0 +1,39 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Project = ForTS_ReducerProject +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +describe("ReducerProject Tutorial", () => { + /* Let's build a project to provide a function. */ + /* But we will call that function on an array of user input. */ + let project = Project.createProject() + Project.setSource(project, "library", "double(x) = x * 2") + /* userCode is not here yet but its dependency is fixed. So we can set it once and for all */ + Project.setContinues(project, "userCode", ["library"]) + + let userValues = [1, 2, 3, 4, 5] + + let userResults = Belt.Array.map(userValues, aUserValue => { + let userCode = `double(${aUserValue->Js.Int.toString})` + /* Put the constructed source in the project */ + /* We have already set that it depends on "library" */ + Project.setSource(project, "userCode", userCode) + /* Run the project */ + Project.runAll(project) + /* Get the result */ + Project.getResult(project, "userCode") + /* I have to remind you that the "library" is run only once and for all. + The library is not run for each user value. */ + }) + + test("userResults", () => { + let userResultsAsString = Belt.Array.map(userResults, aResult => + aResult->InternalExpressionValue.toStringResult + ) + userResultsAsString->expect == ["Ok(2)", "Ok(4)", "Ok(6)", "Ok(8)", "Ok(10)"] + }) +}) diff --git a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res index 2418b4d8..693dffa5 100644 --- a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res +++ b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res @@ -2,8 +2,12 @@ open Jest open Expect open Reducer_TestHelpers -let expectEvalToBeOk = (expr: string) => - Reducer.evaluate(expr)->Reducer_Helpers.rRemoveDefaultsExternal->E.R.isOk->expect->toBe(true) +let expectEvalToBeOk = (code: string) => + Reducer_Expression.BackCompatible.evaluateString(code) + ->Reducer_Helpers.rRemoveDefaultsInternal + ->E.R.isOk + ->expect + ->toBe(true) let registry = FunctionRegistry_Library.registry let examples = E.A.to_list(FunctionRegistry_Core.Registry.allExamples(registry)) @@ -88,8 +92,8 @@ describe("FunctionRegistry Library", () => { ((fn, example)) => { let responseType = example - ->Reducer.evaluate - ->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType) + ->Reducer_Expression.BackCompatible.evaluateString + ->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType) let expectedOutputType = fn.output |> E.O.toExn("") expect(responseType)->toEqual(Ok(expectedOutputType)) }, diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index acee005c..c5f66eed 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -1,3 +1,15 @@ +/* Some of the types have moved to ForTS__Types. +Needs to be reimported here if necessary and distribution related + +We only need distribution related extras for back compatibility. Umur + +Instead of a global function namespace we should use modules under ForTS directly maybe renaming them for ease. + +.e.g. Project.run(project) +.e.g. Distribution.makeSampleSetDist + +*/ + import * as _ from "lodash"; import type { environment, @@ -44,162 +56,164 @@ export let defaultSamplingInputs: environment = { xyPointLength: 10000, }; -export function run( - squiggleString: string, - bindings?: externalBindings, - environment?: environment, - imports?: jsImports -): result { - let b = bindings ? bindings : defaultBindings; - let i = imports ? imports : defaultImports; - let e = environment ? environment : defaultEnvironment; - let res: result = evaluateUsingOptions( - { externalBindings: mergeImportsWithBindings(b, i), environment: e }, - squiggleString - ); - return resultMap(res, (x) => createTsExport(x, e)); -} +/* Umur: All the functions below are invalid. ForTS_Reducer project is the new way to do this. */ -// Run Partial. A partial is a block of code that doesn't return a value -export function runPartial( - squiggleString: string, - bindings?: externalBindings, - environment?: environment, - imports?: jsImports -): result { - let b = bindings ? bindings : defaultBindings; - let i = imports ? imports : defaultImports; - let e = environment ? environment : defaultEnvironment; +// export function run( +// squiggleString: string, +// bindings?: externalBindings, +// environment?: environment, +// imports?: jsImports +// ): result { +// let b = bindings ? bindings : defaultBindings; +// let i = imports ? imports : defaultImports; +// let e = environment ? environment : defaultEnvironment; +// let res: result = evaluateUsingOptions( +// { externalBindings: mergeImportsWithBindings(b, i), environment: e }, +// squiggleString +// ); +// return resultMap(res, (x) => createTsExport(x, e)); +// } - return evaluatePartialUsingExternalBindings( - squiggleString, - mergeImportsWithBindings(b, i), - e - ); -} +// // Run Partial. A partial is a block of code that doesn't return a value +// export function runPartial( +// squiggleString: string, +// bindings?: externalBindings, +// environment?: environment, +// imports?: jsImports +// ): result { +// let b = bindings ? bindings : defaultBindings; +// let i = imports ? imports : defaultImports; +// let e = environment ? environment : defaultEnvironment; -export function runForeign( - fn: lambdaValue, - args: jsValue[], - environment?: environment -): result { - let e = environment ? environment : defaultEnvironment; - let res: result = foreignFunctionInterface( - fn, - args.map(jsValueToExpressionValue), - e - ); - return resultMap(res, (x) => createTsExport(x, e)); -} +// return evaluatePartialUsingExternalBindings( +// squiggleString, +// mergeImportsWithBindings(b, i), +// e +// ); +// } -function mergeImportsWithBindings( - bindings: externalBindings, - imports: jsImports -): externalBindings { - let transformedImports = Object.fromEntries( - Object.entries(imports).map(([key, value]) => [ - "$" + key, - jsValueToBinding(value), - ]) - ); - return _.merge(bindings, transformedImports); -} +// export function runForeign( +// fn: lambdaValue, +// args: jsValue[], +// environment?: environment +// ): result { +// let e = environment ? environment : defaultEnvironment; +// let res: result = foreignFunctionInterface( +// fn, +// args.map(jsValueToExpressionValue), +// e +// ); +// return resultMap(res, (x) => createTsExport(x, e)); +// } -type jsImports = { [key: string]: jsValue }; +// function mergeImportsWithBindings( +// bindings: externalBindings, +// imports: jsImports +// ): externalBindings { +// let transformedImports = Object.fromEntries( +// Object.entries(imports).map(([key, value]) => [ +// "$" + key, +// jsValueToBinding(value), +// ]) +// ); +// return _.merge(bindings, transformedImports); +// } -export let defaultImports: jsImports = {}; -export let defaultBindings: externalBindings = {}; +// type jsImports = { [key: string]: jsValue }; -export function mergeBindings( - allBindings: externalBindings[] -): externalBindings { - return allBindings.reduce((acc, x) => ({ ...acc, ...x })); -} +// export let defaultImports: jsImports = {}; +// export let defaultBindings: externalBindings = {}; -function createTsExport( - x: expressionValue, - environment: environment -): squiggleExpression { - switch (x) { - case "EvVoid": - return tag("void", ""); - default: { - switch (x.tag) { - case "EvArray": - // genType doesn't convert anything more than 2 layers down into {tag: x, value: x} - // format, leaving it as the raw values. This converts the raw values - // directly into typescript values. - // - // The casting here is because genType is about the types of the returned - // values, claiming they are fully recursive when that's not actually the - // case - return tag( - "array", - x.value.map( - (arrayItem): squiggleExpression => - convertRawToTypescript( - arrayItem as unknown as rescriptExport, - environment - ) - ) - ); - case "EvArrayString": - return tag("arraystring", x.value); - case "EvBool": - return tag("boolean", x.value); - case "EvCall": - return tag("call", x.value); - case "EvLambda": - return tag("lambda", x.value); - case "EvDistribution": - return tag("distribution", new Distribution(x.value, environment)); - case "EvNumber": - return tag("number", x.value); - case "EvRecord": - // genType doesn't support records, so we have to do the raw conversion ourself - let result: tagged<"record", { [key: string]: squiggleExpression }> = - tag( - "record", - _.mapValues(x.value, (x: unknown) => - convertRawToTypescript(x as rescriptExport, environment) - ) - ); - return result; - case "EvString": - return tag("string", x.value); - case "EvSymbol": - return tag("symbol", x.value); - case "EvDate": - return tag("date", x.value); - case "EvTimeDuration": - return tag("timeDuration", x.value); - case "EvDeclaration": - return tag("lambdaDeclaration", x.value); - case "EvTypeIdentifier": - return tag("typeIdentifier", x.value); - case "EvType": - let typeResult: tagged< - "type", - { [key: string]: squiggleExpression } - > = tag( - "type", - _.mapValues(x.value, (x: unknown) => - convertRawToTypescript(x as rescriptExport, environment) - ) - ); - return typeResult; - case "EvModule": - let moduleResult: tagged< - "module", - { [key: string]: squiggleExpression } - > = tag( - "module", - _.mapValues(x.value, (x: unknown) => - convertRawToTypescript(x as rescriptExport, environment) - ) - ); - return moduleResult; - } - } - } -} +// export function mergeBindings( +// allBindings: externalBindings[] +// ): externalBindings { +// return allBindings.reduce((acc, x) => ({ ...acc, ...x })); +// } + +// function createTsExport( +// x: expressionValue, +// environment: environment +// ): squiggleExpression { +// switch (x) { +// case "EvVoid": +// return tag("void", ""); +// default: { +// switch (x.tag) { +// case "EvArray": +// // genType doesn't convert anything more than 2 layers down into {tag: x, value: x} +// // format, leaving it as the raw values. This converts the raw values +// // directly into typescript values. +// // +// // The casting here is because genType is about the types of the returned +// // values, claiming they are fully recursive when that's not actually the +// // case +// return tag( +// "array", +// x.value.map( +// (arrayItem): squiggleExpression => +// convertRawToTypescript( +// arrayItem as unknown as rescriptExport, +// environment +// ) +// ) +// ); +// case "EvArrayString": +// return tag("arraystring", x.value); +// case "EvBool": +// return tag("boolean", x.value); +// case "EvCall": +// return tag("call", x.value); +// case "EvLambda": +// return tag("lambda", x.value); +// case "EvDistribution": +// return tag("distribution", new Distribution(x.value, environment)); +// case "EvNumber": +// return tag("number", x.value); +// case "EvRecord": +// // genType doesn't support records, so we have to do the raw conversion ourself +// let result: tagged<"record", { [key: string]: squiggleExpression }> = +// tag( +// "record", +// _.mapValues(x.value, (x: unknown) => +// convertRawToTypescript(x as rescriptExport, environment) +// ) +// ); +// return result; +// case "EvString": +// return tag("string", x.value); +// case "EvSymbol": +// return tag("symbol", x.value); +// case "EvDate": +// return tag("date", x.value); +// case "EvTimeDuration": +// return tag("timeDuration", x.value); +// case "EvDeclaration": +// return tag("lambdaDeclaration", x.value); +// case "EvTypeIdentifier": +// return tag("typeIdentifier", x.value); +// case "EvType": +// let typeResult: tagged< +// "type", +// { [key: string]: squiggleExpression } +// > = tag( +// "type", +// _.mapValues(x.value, (x: unknown) => +// convertRawToTypescript(x as rescriptExport, environment) +// ) +// ); +// return typeResult; +// case "EvModule": +// let moduleResult: tagged< +// "module", +// { [key: string]: squiggleExpression } +// > = tag( +// "module", +// _.mapValues(x.value, (x: unknown) => +// convertRawToTypescript(x as rescriptExport, environment) +// ) +// ); +// return moduleResult; +// } +// } +// } +// } diff --git a/packages/squiggle-lang/src/js/rescript_interop.ts b/packages/squiggle-lang/src/js/rescript_interop.ts index 3dca8165..1031dd3e 100644 --- a/packages/squiggle-lang/src/js/rescript_interop.ts +++ b/packages/squiggle-lang/src/js/rescript_interop.ts @@ -1,269 +1,279 @@ -import * as _ from "lodash"; -import type { - expressionValue, - mixedShape, - sampleSetDist, - genericDist, - environment, - symbolicDist, - discreteShape, - continuousShape, - lambdaValue, - lambdaDeclaration, - declarationArg, -} from "../rescript/TypescriptInterface.gen"; -import { Distribution } from "./distribution"; -import { tagged, tag } from "./types"; +/** + Umur: Delete this file! There is nothing left to see here. +**/ + +// import * as _ from "lodash"; +// import type { +// // expressionValue, +// mixedShape, +// sampleSetDist, +// genericDist, +// // environment, +// symbolicDist, +// discreteShape, +// continuousShape, +// // lambdaValue, +// // lambdaDeclaration, +// // declarationArg, +// } from "../rescript/TypescriptInterface.gen"; +// import { Distribution } from "./distribution"; +// import { tagged, tag } from "./types"; // This file is here to compensate for genType not fully recursively converting types // Raw rescript types. -export type rescriptExport = - | 0 // EvVoid - | { - TAG: 0; // EvArray - _0: rescriptExport[]; - } - | { - TAG: 1; // EvString - _0: string[]; - } - | { - TAG: 2; // EvBool - _0: boolean; - } - | { - TAG: 3; // EvCall - _0: string; - } - | { - TAG: 4; // EvDistribution - _0: rescriptDist; - } - | { - TAG: 5; // EvLambda - _0: lambdaValue; - } - | { - TAG: 6; // EvNumber - _0: number; - } - | { - TAG: 7; // EvRecord - _0: { [key: string]: rescriptExport }; - } - | { - TAG: 8; // EvString - _0: string; - } - | { - TAG: 9; // EvSymbol - _0: string; - } - | { - TAG: 10; // EvDate - _0: Date; - } - | { - TAG: 11; // EvTimeDuration - _0: number; - } - | { - TAG: 12; // EvDeclaration - _0: rescriptLambdaDeclaration; - } - | { - TAG: 13; // EvTypeIdentifier - _0: string; - } - | { - TAG: 14; // EvModule - _0: { [key: string]: rescriptExport }; - }; +// Umur: Rescript expression values are opaque! +// export type rescriptExport = +// | 0 // EvVoid +// | { +// TAG: 0; // EvArray +// _0: rescriptExport[]; +// } +// | { +// TAG: 1; // EvString +// _0: string[]; +// } +// | { +// TAG: 2; // EvBool +// _0: boolean; +// } +// | { +// TAG: 3; // EvCall +// _0: string; +// } +// | { +// TAG: 4; // EvDistribution +// _0: rescriptDist; +// } +// | { +// TAG: 5; // EvLambda +// _0: lambdaValue; +// } +// | { +// TAG: 6; // EvNumber +// _0: number; +// } +// | { +// TAG: 7; // EvRecord +// _0: { [key: string]: rescriptExport }; +// } +// | { +// TAG: 8; // EvString +// _0: string; +// } +// | { +// TAG: 9; // EvSymbol +// _0: string; +// } +// | { +// TAG: 10; // EvDate +// _0: Date; +// } +// | { +// TAG: 11; // EvTimeDuration +// _0: number; +// } +// | { +// TAG: 12; // EvDeclaration +// _0: rescriptLambdaDeclaration; +// } +// | { +// TAG: 13; // EvTypeIdentifier +// _0: string; +// } +// | { +// TAG: 14; // EvModule +// _0: { [key: string]: rescriptExport }; +// }; -type rescriptDist = - | { TAG: 0; _0: rescriptPointSetDist } - | { TAG: 1; _0: sampleSetDist } - | { TAG: 2; _0: symbolicDist }; +// Umur: opaque type +// type rescriptDist = +// | { TAG: 0; _0: rescriptPointSetDist } +// | { TAG: 1; _0: sampleSetDist } +// | { TAG: 2; _0: symbolicDist }; -type rescriptPointSetDist = - | { - TAG: 0; // Mixed - _0: mixedShape; - } - | { - TAG: 1; // Discrete - _0: discreteShape; - } - | { - TAG: 2; // ContinuousShape - _0: continuousShape; - }; +// Umur: opaque type, no conversion +// type rescriptPointSetDist = +// | { +// TAG: 0; // Mixed +// _0: mixedShape; +// } +// | { +// TAG: 1; // Discrete +// _0: discreteShape; +// } +// | { +// TAG: 2; // ContinuousShape +// _0: continuousShape; +// }; -type rescriptLambdaDeclaration = { - readonly fn: lambdaValue; - readonly args: rescriptDeclarationArg[]; -}; +// type rescriptLambdaDeclaration = { +// readonly fn: lambdaValue; +// readonly args: rescriptDeclarationArg[]; +// }; -type rescriptDeclarationArg = - | { - TAG: 0; // Float - min: number; - max: number; - } - | { - TAG: 1; // Date - min: Date; - max: Date; - }; +// type rescriptDeclarationArg = +// | { +// TAG: 0; // Float +// min: number; +// max: number; +// } +// | { +// TAG: 1; // Date +// min: Date; +// max: Date; +// }; -export type squiggleExpression = - | tagged<"symbol", string> - | tagged<"string", string> - | tagged<"call", string> - | tagged<"lambda", lambdaValue> - | tagged<"array", squiggleExpression[]> - | tagged<"arraystring", string[]> - | tagged<"boolean", boolean> - | tagged<"distribution", Distribution> - | tagged<"number", number> - | tagged<"date", Date> - | tagged<"timeDuration", number> - | tagged<"lambdaDeclaration", lambdaDeclaration> - | tagged<"record", { [key: string]: squiggleExpression }> - | tagged<"type", { [key: string]: squiggleExpression }> - | tagged<"typeIdentifier", string> - | tagged<"module", { [key: string]: squiggleExpression }> - | tagged<"void", string>; +// Umur: Squiggle expressions are opaque! +// export type squiggleExpression = +// | tagged<"symbol", string> +// | tagged<"string", string> +// | tagged<"call", string> +// | tagged<"lambda", lambdaValue> +// | tagged<"array", squiggleExpression[]> +// | tagged<"arraystring", string[]> +// | tagged<"boolean", boolean> +// | tagged<"distribution", Distribution> +// | tagged<"number", number> +// | tagged<"date", Date> +// | tagged<"timeDuration", number> +// | tagged<"lambdaDeclaration", lambdaDeclaration> +// | tagged<"record", { [key: string]: squiggleExpression }> +// | tagged<"type", { [key: string]: squiggleExpression }> +// | tagged<"typeIdentifier", string> +// | tagged<"module", { [key: string]: squiggleExpression }> +// | tagged<"void", string>; -export { lambdaValue }; +// export { lambdaValue }; -export function convertRawToTypescript( - result: rescriptExport, - environment: environment -): squiggleExpression { - if (typeof result === "number") { - // EvVoid - return tag("void", ""); - } - switch (result.TAG) { - case 0: // EvArray - return tag( - "array", - result._0.map((x) => convertRawToTypescript(x, environment)) - ); - case 1: // EvArrayString - return tag("arraystring", result._0); - case 2: // EvBool - return tag("boolean", result._0); - case 3: // EvCall - return tag("call", result._0); - case 4: // EvDistribution - return tag( - "distribution", - new Distribution( - convertRawDistributionToGenericDist(result._0), - environment - ) - ); - case 5: // EvDistribution - return tag("lambda", result._0); - case 6: // EvNumber - return tag("number", result._0); - case 7: // EvRecord - return tag( - "record", - _.mapValues(result._0, (x) => convertRawToTypescript(x, environment)) - ); - case 8: // EvString - return tag("string", result._0); - case 9: // EvSymbol - return tag("symbol", result._0); - case 10: // EvDate - return tag("date", result._0); - case 11: // EvTimeDuration - return tag("number", result._0); - case 12: // EvDeclaration - return tag("lambdaDeclaration", { - fn: result._0.fn, - args: result._0.args.map(convertDeclaration), - }); - case 13: // EvSymbol - return tag("typeIdentifier", result._0); - case 14: // EvModule - return tag( - "module", - _.mapValues(result._0, (x) => convertRawToTypescript(x, environment)) - ); - } -} +// Umur: Opaque type no conversion! +// export function convertRawToTypescript( +// result: rescriptExport, +// environment: environment +// ): squiggleExpression { +// if (typeof result === "number") { +// // EvVoid +// return tag("void", ""); +// } +// switch (result.TAG) { +// case 0: // EvArray +// return tag( +// "array", +// result._0.map((x) => convertRawToTypescript(x, environment)) +// ); +// case 1: // EvArrayString +// return tag("arraystring", result._0); +// case 2: // EvBool +// return tag("boolean", result._0); +// case 3: // EvCall +// return tag("call", result._0); +// case 4: // EvDistribution +// return tag( +// "distribution", +// new Distribution( +// convertRawDistributionToGenericDist(result._0), +// environment +// ) +// ); +// case 5: // EvDistribution +// return tag("lambda", result._0); +// case 6: // EvNumber +// return tag("number", result._0); +// case 7: // EvRecord +// return tag( +// "record", +// _.mapValues(result._0, (x) => convertRawToTypescript(x, environment)) +// ); +// case 8: // EvString +// return tag("string", result._0); +// case 9: // EvSymbol +// return tag("symbol", result._0); +// case 10: // EvDate +// return tag("date", result._0); +// case 11: // EvTimeDuration +// return tag("number", result._0); +// case 12: // EvDeclaration +// return tag("lambdaDeclaration", { +// fn: result._0.fn, +// args: result._0.args.map(convertDeclaration), +// }); +// case 13: // EvSymbol +// return tag("typeIdentifier", result._0); +// case 14: // EvModule +// return tag( +// "module", +// _.mapValues(result._0, (x) => convertRawToTypescript(x, environment)) +// ); +// } +// } -function convertDeclaration( - declarationArg: rescriptDeclarationArg -): declarationArg { - switch (declarationArg.TAG) { - case 0: // Float - return tag("Float", { min: declarationArg.min, max: declarationArg.max }); - case 1: // Date - return tag("Date", { min: declarationArg.min, max: declarationArg.max }); - } -} +// function convertDeclaration( +// declarationArg: rescriptDeclarationArg +// ): declarationArg { +// switch (declarationArg.TAG) { +// case 0: // Float +// return tag("Float", { min: declarationArg.min, max: declarationArg.max }); +// case 1: // Date +// return tag("Date", { min: declarationArg.min, max: declarationArg.max }); +// } +// } -function convertRawDistributionToGenericDist( - result: rescriptDist -): genericDist { - switch (result.TAG) { - case 0: // Point Set Dist - switch (result._0.TAG) { - case 0: // Mixed - return tag("PointSet", tag("Mixed", result._0._0)); - case 1: // Discrete - return tag("PointSet", tag("Discrete", result._0._0)); - case 2: // Continuous - return tag("PointSet", tag("Continuous", result._0._0)); - } - case 1: // Sample Set Dist - return tag("SampleSet", result._0); - case 2: // Symbolic Dist - return tag("Symbolic", result._0); - } -} +// Umur: opaque type no conversion! +// function convertRawDistributionToGenericDist( +// result: rescriptDist +// ): genericDist { +// switch (result.TAG) { +// case 0: // Point Set Dist +// switch (result._0.TAG) { +// case 0: // Mixed +// return tag("PointSet", tag("Mixed", result._0._0)); +// case 1: // Discrete +// return tag("PointSet", tag("Discrete", result._0._0)); +// case 2: // Continuous +// return tag("PointSet", tag("Continuous", result._0._0)); +// } +// case 1: // Sample Set Dist +// return tag("SampleSet", result._0); +// case 2: // Symbolic Dist +// return tag("Symbolic", result._0); +// } +// } -export type jsValue = - | string - | number - | jsValue[] - | { [key: string]: jsValue } - | boolean; +// export type jsValue = +// | string +// | number +// | jsValue[] +// | { [key: string]: jsValue } +// | boolean; -export function jsValueToBinding(value: jsValue): rescriptExport { - if (typeof value === "boolean") { - return { TAG: 2, _0: value as boolean }; - } else if (typeof value === "string") { - return { TAG: 8, _0: value as string }; - } else if (typeof value === "number") { - return { TAG: 6, _0: value as number }; - } else if (Array.isArray(value)) { - return { TAG: 0, _0: value.map(jsValueToBinding) }; - } else { - // Record - return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) }; - } -} +// export function jsValueToBinding(value: jsValue): rescriptExport { +// if (typeof value === "boolean") { +// return { TAG: 2, _0: value as boolean }; +// } else if (typeof value === "string") { +// return { TAG: 8, _0: value as string }; +// } else if (typeof value === "number") { +// return { TAG: 6, _0: value as number }; +// } else if (Array.isArray(value)) { +// return { TAG: 0, _0: value.map(jsValueToBinding) }; +// } else { +// // Record +// return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) }; +// } +// } -export function jsValueToExpressionValue(value: jsValue): expressionValue { - if (typeof value === "boolean") { - return { tag: "EvBool", value: value as boolean }; - } else if (typeof value === "string") { - return { tag: "EvString", value: value as string }; - } else if (typeof value === "number") { - return { tag: "EvNumber", value: value as number }; - } else if (Array.isArray(value)) { - return { tag: "EvArray", value: value.map(jsValueToExpressionValue) }; - } else { - // Record - return { - tag: "EvRecord", - value: _.mapValues(value, jsValueToExpressionValue), - }; - } -} +// export function jsValueToExpressionValue(value: jsValue): expressionValue { +// if (typeof value === "boolean") { +// return { tag: "EvBool", value: value as boolean }; +// } else if (typeof value === "string") { +// return { tag: "EvString", value: value as string }; +// } else if (typeof value === "number") { +// return { tag: "EvNumber", value: value as number }; +// } else if (Array.isArray(value)) { +// return { tag: "EvArray", value: value.map(jsValueToExpressionValue) }; +// } else { +// // Record +// return { +// tag: "EvRecord", +// value: _.mapValues(value, jsValueToExpressionValue), +// }; +// } +// } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index 0c119ea4..93f934e1 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -1,4 +1,5 @@ -@genType +//FIXME accessor methods or not opaque? +@genType.opaque type genericDist = | PointSet(PointSetTypes.pointSetDist) | SampleSet(SampleSetDist.t) @@ -6,7 +7,7 @@ type genericDist = type asAlgebraicCombinationStrategy = AsDefault | AsSymbolic | AsMonteCarlo | AsConvolution -@genType +@genType.opaque type error = | NotYetImplemented | Unreachable @@ -27,7 +28,6 @@ module Error = { let fromString = (s: string): t => OtherError(s) - @genType let toString = (err: error): string => switch err { | NotYetImplemented => "Function not yet implemented" diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res index f536d54d..c2bdd299 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res @@ -1,4 +1,5 @@ //TODO: multimodal, add interface, test somehow, track performance, refactor sampleSet, refactor ASTEvaluator.res. + type t = DistributionTypes.genericDist type error = DistributionTypes.error type toPointSetFn = t => result diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res index fcc796ec..76720290 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res @@ -47,7 +47,7 @@ type pointSetDistMonad<'a, 'b, 'c> = | Discrete('b) | Continuous('c) -@genType +@genType.opaque type pointSetDist = pointSetDistMonad module ShapeMonad = { diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution.res new file mode 100644 index 00000000..ca4c02ad --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution.res @@ -0,0 +1,57 @@ +// Genetic Distribution happens to be abstract distribution +@genType type distribution = DistributionTypes.genericDist +@genType type pointSetDistribution = ForTS_Distribution_PointSetDistribution.pointSetDistribution +@genType type sampleSetDistribution = ForTS_Distribution_SampleSetDistribution.sampleSetDistribution +@genType type symbolicDistribution = ForTS_Distribution_SymbolicDistribution.symbolicDistribution + +type environment = ForTS_Distribution_Environment.environment //use + +@genType +let defaultEnvironment: environment = DistributionOperation.defaultEnv + +@module("ForTS_Distribution_tag") @scope("distributionTag") +external dtPointSet_: int = "DtPointSet" + +@module("ForTS_Distribution_tag") @scope("distributionTag") +external dtSampleSet_: int = "DtSampleSet" + +@module("ForTS_Distribution_tag") @scope("distributionTag") +external dtSymbolic_: int = "DtSymbolic" + +@genType.import("./ForTS_Distribution_tag") +type distributionTag + +external castEnum: int => distributionTag = "%identity" + +// type genericDist = +// | PointSet(PointSetTypes.pointSetDist) +// | SampleSet(SampleSetDist.t) +// | Symbolic(SymbolicDistTypes.symbolicDist) +@genType +let getTag = (variant: distribution): distributionTag => + switch variant { + | PointSet(_) => dtPointSet_->castEnum + | SampleSet(_) => dtSampleSet_->castEnum + | Symbolic(_) => dtSymbolic_->castEnum + } + +@genType +let getPointSet = (variant: distribution): option => + switch variant { + | PointSet(dist) => dist->Some + | _ => None + } + +@genType +let getSampleSet = (variant: distribution): option => + switch variant { + | SampleSet(dist) => dist->Some + | _ => None + } + +@genType +let getSymbolic = (variant: distribution): option => + switch variant { + | Symbolic(dist) => dist->Some + | _ => None + } diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.res new file mode 100644 index 00000000..d6f89fb9 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.res @@ -0,0 +1 @@ +@genType type environment = GenericDist.env //re-export diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Error.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Error.res new file mode 100644 index 00000000..d228e7b2 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Error.res @@ -0,0 +1,4 @@ +@genType type distributionError = DistributionTypes.error + +@genType +let toString = (e: distributionError) => DistributionTypes.Error.toString(e) diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution.res new file mode 100644 index 00000000..59750a15 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution.res @@ -0,0 +1,44 @@ +@genType type pointSetDistribution = PointSetTypes.pointSetDist + +@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag") +external pstMixed_: int = "PstMixed" + +@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag") +external pstDiscrete_: int = "PstDiscrete" + +@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag") +external pstContinuous_: int = "PstContinuous" + +@genType.import("./ForTS_Distribution_PointSetDistribution_tag") +type pointSetDistributionTag + +external castEnum: int => pointSetDistributionTag = "%identity" + +@genType +let getTag = (variant: pointSetDistribution): pointSetDistributionTag => + switch variant { + | Mixed(_) => pstMixed_->castEnum + | Discrete(_) => pstDiscrete_->castEnum + | Continuous(_) => pstContinuous_->castEnum + } + +@genType +let getMixed = (variant: pointSetDistribution): 'd => + switch variant { + | Mixed(mixed) => mixed->Some + | _ => None + } + +@genType +let getDiscrete = (variant: pointSetDistribution): 'd => + switch variant { + | Discrete(discrete) => discrete->Some + | _ => None + } + +@genType +let getContinues = (variant: pointSetDistribution): 'd => + switch variant { + | Continuous(continuous) => continuous->Some + | _ => None + } diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag.js b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag.js new file mode 100644 index 00000000..106c13d2 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag.js @@ -0,0 +1,15 @@ +"use strict"; +exports.__esModule = true; +exports.pointSetDistributionTag = void 0; +var pointSetDistributionTag; +(function (pointSetDistributionTag) { + pointSetDistributionTag[(pointSetDistributionTag["PstMixed"] = 0)] = + "PstMixed"; + pointSetDistributionTag[(pointSetDistributionTag["PstDiscrete"] = 1)] = + "PstDiscrete"; + pointSetDistributionTag[(pointSetDistributionTag["PstContinuous"] = 2)] = + "PstContinuous"; +})( + (pointSetDistributionTag = + exports.pointSetDistributionTag || (exports.pointSetDistributionTag = {})) +); diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag.ts b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag.ts new file mode 100644 index 00000000..e1e16d89 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag.ts @@ -0,0 +1,5 @@ +export enum pointSetDistributionTag { + PstMixed, + PstDiscrete, + PstContinuous, +} diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_SampleSetDistribution.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_SampleSetDistribution.res new file mode 100644 index 00000000..29f0c2aa --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_SampleSetDistribution.res @@ -0,0 +1 @@ +@genType type sampleSetDistribution = SampleSetDist.t diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_SymbolicDistribution.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_SymbolicDistribution.res new file mode 100644 index 00000000..32e8614b --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_SymbolicDistribution.res @@ -0,0 +1 @@ +@genType type symbolicDistribution = SymbolicDistTypes.symbolicDist diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag.ts b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag.ts new file mode 100644 index 00000000..72466c91 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag.ts @@ -0,0 +1,5 @@ +export enum distributionTag { + DtPointSet, + DtSampleSet, + DtSymbolic, +} diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res new file mode 100644 index 00000000..27302313 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res @@ -0,0 +1,235 @@ +@genType type reducerProject = ReducerProject_T.t //re-export + +type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use + +type squiggleValue = ForTS_SquiggleValue.squiggleValue //use +type squiggleValue_Module = ForTS_SquiggleValue_Module.squiggleValue_Module //use + +type environment = ForTS_Distribution_Environment.environment //use + +module T = ReducerProject_T +module Private = ReducerProject.Private + +/* + PUBLIC FUNCTIONS +*/ + +/* +A project links and runs sources that continue or include each other. + +Creates a new project to hold the sources, executables, bindings, and other data. +The new project runs the sources according to their topological sorting because of the includes and continues. + +Any source can include or continue other sources. "Therefore, the project is a graph data structure." +The difference between including and continuing is that includes are stated inside the source code while continues are stated in the project. + +To run a group of source codes and get results/bindings, the necessary methods are +- setSource +- setContinues +- parseIncludes +- run or runAll +- getExternalBindings +- getExternalResult + +A project has a public field tag with a constant value "reducerProject" +project = {tag: "reducerProject"} +*/ +@genType +let createProject = (): reducerProject => Private.createProject()->T.Private.castFromInternalProject + +/* +Answer all the source ids of all the sources in the project. +*/ +@genType +let getSourceIds = (project: reducerProject): array => + project->T.Private.castToInternalProject->Private.getSourceIds + +/* +Sets the source for a given source Id. +*/ +@genType +let setSource = (project: reducerProject, sourceId: string, value: string): unit => + project->T.Private.castToInternalProject->Private.setSource(sourceId, value) + +/* +Gets the source for a given source id. +*/ +@genType +let getSource = (project: reducerProject, sourceId: string): option => + project->T.Private.castToInternalProject->Private.getSource(sourceId) + +/* +Touches the source for a given source id. This and dependent, sources are set to be re-evaluated. +*/ +@genType +let touchSource = (project: reducerProject, sourceId: string): unit => + project->T.Private.castToInternalProject->Private.touchSource(sourceId) + +/* +Cleans the compilation artifacts for a given source ID. The results stay untouched, so compilation won't be run again. + +Normally, you would never need the compilation artifacts again as the results with the same sources would never change. However, they are needed in case of any debugging reruns +*/ +@genType +let clean = (project: reducerProject, sourceId: string): unit => + project->T.Private.castToInternalProject->Private.clean(sourceId) + +/* +Cleans all the compilation artifacts in all of the project +*/ +@genType +let cleanAll = (project: reducerProject): unit => + project->T.Private.castToInternalProject->Private.cleanAll + +/* +Cleans results. Compilation stays untouched to be able to re-run the source. +You would not do this if you were not trying to debug the source code. +*/ +@genType +let cleanResults = (project: reducerProject, sourceId: string): unit => + project->T.Private.castToInternalProject->Private.cleanResults(sourceId) + +/* +Cleans all results. Compilations remains untouched to rerun the source. +*/ +@genType +let cleanAllResults = (project: reducerProject): unit => + project->T.Private.castToInternalProject->Private.cleanAllResults + +/* +To set the includes one first has to call "parseIncludes". The parsed includes or the parser error is returned. +*/ +@genType +let getIncludes = (project: reducerProject, sourceId: string): result< + array, + reducerErrorValue, +> => project->T.Private.castToInternalProject->Private.getIncludes(sourceId) + +/* +Answers the source codes after which this source code is continuing +*/ +@genType +let getContinues = (project: reducerProject, sourceId: string): array => + project->T.Private.castToInternalProject->Private.getContinues(sourceId) + +/* + "continues" acts like hidden includes in the source. + It is used to define a continuation that is not visible in the source code. + You can chain source codes on the web interface for example +*/ +@genType +let setContinues = (project: reducerProject, sourceId: string, continues: array): unit => + project->T.Private.castToInternalProject->Private.setContinues(sourceId, continues) + +/* +This source depends on the array of sources returned. +*/ +@genType +let getDependencies = (project: reducerProject, sourceId: string): array => + project->T.Private.castToInternalProject->Private.getDependencies(sourceId) + +/* +The sources returned are dependent on this +*/ +@genType +let getDependents = (project: reducerProject, sourceId: string): array => + project->T.Private.castToInternalProject->Private.getDependents(sourceId) + +/* +Get the run order for the sources in the project. +*/ +@genType +let getRunOrder = (project: reducerProject): array => + project->T.Private.castToInternalProject->Private.getRunOrder + +/* +Get the run order to get the results of this specific source +*/ +@genType +let getRunOrderFor = (project: reducerProject, sourceId: string) => + project->T.Private.castToInternalProject->Private.getRunOrderFor(sourceId) + +/* +Parse includes so that you can load them before running. +Load includes by calling getIncludes which returns the includes that have been parsed. +It is your responsibility to load the includes before running. +*/ + +@genType +let parseIncludes = (project: reducerProject, sourceId: string): unit => + project->T.Private.castToInternalProject->Private.parseIncludes(sourceId) + +/* +Parse the source code if it is not done already. +Use getRawParse to get the parse tree. +You would need this function if you want to see the parse tree without running the source code. +*/ +@genType +let rawParse = (project: reducerProject, sourceId: string): unit => + project->T.Private.castToInternalProject->Private.rawParse(sourceId) + +/* +Runs a specific source code if it is not done already. The code is parsed if it is not already done. It runs the dependencies if it is not already done. +*/ +@genType +let run = (project: reducerProject, sourceId: string): unit => + project->T.Private.castToInternalProject->Private.run(sourceId) + +/* +Runs all of the sources in a project. Their results and bindings will be available +*/ +@genType +let runAll = (project: reducerProject): unit => + project->T.Private.castToInternalProject->Private.runAll + +/* +Get the bindings after running this source file or the project +*/ +@genType +let getBindings = (project: reducerProject, sourceId: string): squiggleValue_Module => + project->T.Private.castToInternalProject->Private.getBindings(sourceId) + +/* +Get the result after running this source file or the project +*/ +@genType +let getResult = (project: reducerProject, sourceId: string): result< + squiggleValue, + reducerErrorValue, +> => project->T.Private.castToInternalProject->Private.getResult(sourceId) + +/* +This is a convenience function to get the result of a single source without creating a project. +However, without a project, you cannot handle include directives. +The source has to be include free +*/ +@genType +let evaluate = (sourceCode: string): ( + result, + squiggleValue_Module, +) => Private.evaluate(sourceCode) + +@genType +let setEnvironment = (project: reducerProject, environment: environment): unit => + project->T.Private.castToInternalProject->Private.setEnvironment(environment) + +/* +Foreign function interface is intentionally demolished. +There is another way to do that: Umur. +Also there is no more conversion from javascript to squiggle values currently. +If the conversion to the new project is too difficult, I can add it later. +*/ + +// let foreignFunctionInterface = ( +// lambdaValue: squiggleValue_Lambda, +// argArray: array, +// environment: environment, +// ): result => { +// let accessors = ReducerProject_ProjectAccessors_T.identityAccessorsWithEnvironment(environment) +// Reducer_Expression_Lambda.foreignFunctionInterface( +// lambdaValue, +// argArray, +// accessors, +// Reducer_Expression.reduceExpressionInProject, +// ) +// } diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Reducer_ErrorValue.res new file mode 100644 index 00000000..61dc3bac --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Reducer_ErrorValue.res @@ -0,0 +1,12 @@ +@genType type reducerErrorValue = Reducer_ErrorValue.errorValue //alias +@genType type syntaxErrorLocation = Reducer_ErrorValue.syntaxErrorLocation //alias + +@genType +let toString = (e: reducerErrorValue): string => Reducer_ErrorValue.errorToString(e) + +@genType +let getLocation = (e: reducerErrorValue): option => + switch e { + | RESyntaxError(_, optionalLocation) => optionalLocation + | _ => None + } diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_Result_tag.ts b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Result_tag.ts new file mode 100644 index 00000000..73da47b3 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_Result_tag.ts @@ -0,0 +1,9 @@ +export type result = + | { + tag: "Ok"; + value: a; + } + | { + tag: "Error"; + value: b; + }; diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue.res new file mode 100644 index 00000000..df5510d5 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue.res @@ -0,0 +1,213 @@ +@genType type squiggleValue = ReducerInterface_InternalExpressionValue.t //re-export +type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use + +@genType type squiggleValue_Array = ReducerInterface_InternalExpressionValue.squiggleArray //re-export recursive type +@genType type squiggleValue_Module = ReducerInterface_InternalExpressionValue.nameSpace //re-export recursive type +@genType type squiggleValue_Record = ReducerInterface_InternalExpressionValue.map //re-export recursive type +@genType type squiggleValue_Type = ReducerInterface_InternalExpressionValue.map //re-export recursive type +type squiggleValue_Declaration = ForTS_SquiggleValue_Declaration.squiggleValue_Declaration //use +type squiggleValue_Distribution = ForTS_SquiggleValue_Distribution.squiggleValue_Distribution //use +type squiggleValue_Lambda = ForTS_SquiggleValue_Lambda.squiggleValue_Lambda //use + +// Return values are kept as they are if they are JavaScript types. + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtArray_: string = "SvtArray" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtArrayString_: string = "SvtArrayString" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtBool_: string = "SvtBool" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtCall_: string = "SvtCall" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtDate_: string = "SvtDate" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtDeclaration_: string = "SvtDeclaration" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtDistribution_: string = "SvtDistribution" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtLambda_: string = "SvtLambda" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtModule_: string = "SvtModule" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtNumber_: string = "SvtNumber" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtRecord_: string = "SvtRecord" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtString_: string = "SvtString" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtSymbol_: string = "SvtSymbol" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtTimeDuration_: string = "SvtTimeDuration" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtType_: string = "SvtType" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtTypeIdentifier_: string = "SvtUndefined" + +@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag") +external svtVoid_: string = "SvtVoid" + +@genType.import("./ForTS_SquiggleValue_tag") +type squiggleValueTag + +external castEnum: string => squiggleValueTag = "%identity" + +@genType +let getTag = (variant: squiggleValue): squiggleValueTag => + switch variant { + | IEvArray(_) => svtArray_->castEnum + | IEvArrayString(_) => svtArrayString_->castEnum + | IEvBool(_) => svtBool_->castEnum + | IEvCall(_) => svtCall_->castEnum //Impossible + | IEvDate(_) => svtDate_->castEnum + | IEvDeclaration(_) => svtDeclaration_->castEnum + | IEvDistribution(_) => svtDistribution_->castEnum + | IEvLambda(_) => svtLambda_->castEnum + | IEvBindings(_) => svtModule_->castEnum //Impossible + | IEvNumber(_) => svtNumber_->castEnum + | IEvRecord(_) => svtRecord_->castEnum + | IEvString(_) => svtString_->castEnum + | IEvSymbol(_) => svtSymbol_->castEnum + | IEvTimeDuration(_) => svtTimeDuration_->castEnum + | IEvType(_) => svtType_->castEnum + | IEvTypeIdentifier(_) => svtTypeIdentifier_->castEnum + | IEvVoid => svtVoid_->castEnum + } + +@genType +let toString = (variant: squiggleValue) => + ReducerInterface_InternalExpressionValue.toString(variant) + +// This is a useful method for unit tests. +// Convert the result along with the error message to a string. +@genType +let toStringResult = (variantResult: result) => + ReducerInterface_InternalExpressionValue.toStringResult(variantResult) + +@genType +let getArray = (variant: squiggleValue): option => + //FIXME: Convert + switch variant { + | IEvArray(arrayLike) => arrayLike->Some + | _ => None + } + +@genType +let getArrayString = (variant: squiggleValue): option> => + switch variant { + | IEvArrayString(value) => value->Some + | _ => None + } + +@genType +let getBool = (variant: squiggleValue): option => + switch variant { + | IEvBool(value) => value->Some + | _ => None + } + +@genType +let getCall = (variant: squiggleValue): option => + switch variant { + | IEvCall(value) => value->Some + | _ => None + } + +@genType +let getDate = (variant: squiggleValue): option => + switch variant { + | IEvDate(value) => value->Some + | _ => None + } + +@genType +let getDeclaration = (variant: squiggleValue): option => + switch variant { + | IEvDeclaration(value) => value->Some + | _ => None + } + +@genType +let getDistribution = (variant: squiggleValue): option => + switch variant { + | IEvDistribution(value) => value->Some + | _ => None + } + +@genType +let getLambda = (variant: squiggleValue): option => + switch variant { + | IEvLambda(value) => value->Some + | _ => None + } + +@genType +let getModule = (variant: squiggleValue): option => + switch variant { + | IEvBindings(value) => value->Some + | _ => None + } + +@genType +let getNumber = (variant: squiggleValue): option => + switch variant { + | IEvNumber(value) => value->Some + | _ => None + } + +@genType +let getRecord = (variant: squiggleValue): option => + switch variant { + | IEvRecord(value) => value->Some + | _ => None + } + +@genType +let getString = (variant: squiggleValue): option => + switch variant { + | IEvString(value) => value->Some + | _ => None + } + +@genType +let getSymbol = (variant: squiggleValue): option => + switch variant { + | IEvSymbol(value) => value->Some + | _ => None + } + +@genType +let getTimeDuration = (variant: squiggleValue): option => + switch variant { + | IEvTimeDuration(value) => value->Some + | _ => None + } + +@genType +let getType = (variant: squiggleValue): option => + switch variant { + | IEvType(value) => value->Some + | _ => None + } + +@genType +let getTypeIdentifier = (variant: squiggleValue): option => + switch variant { + | IEvTypeIdentifier(value) => value->Some + | _ => None + } diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Array.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Array.res new file mode 100644 index 00000000..61b84d74 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Array.res @@ -0,0 +1,6 @@ +type squiggleValue = ForTS_SquiggleValue.squiggleValue +@genType type squiggleValue_Array = ForTS_SquiggleValue.squiggleValue_Array //re-export recursive type + +@genType +let getValues = (v: squiggleValue_Array): array => + ReducerInterface_InternalExpressionValue.arrayToValueArray(v) diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Declaration.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Declaration.res new file mode 100644 index 00000000..b53fb4bf --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Declaration.res @@ -0,0 +1 @@ +@genType type squiggleValue_Declaration = ReducerInterface_InternalExpressionValue.lambdaDeclaration //re-export diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Distribution.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Distribution.res new file mode 100644 index 00000000..ef20d02f --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Distribution.res @@ -0,0 +1 @@ +@genType type squiggleValue_Distribution = ForTS_Distribution.distribution diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Lambda.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Lambda.res new file mode 100644 index 00000000..c41a5727 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Lambda.res @@ -0,0 +1 @@ +@genType type squiggleValue_Lambda = ReducerInterface_InternalExpressionValue.lambdaValue //re-export diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Module.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Module.res new file mode 100644 index 00000000..8bb113a2 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Module.res @@ -0,0 +1,6 @@ +type squiggleValue = ForTS_SquiggleValue.squiggleValue //use +@genType type squiggleValue_Module = ForTS_SquiggleValue.squiggleValue_Module //re-export recursive type + +@genType +let getKeyValuePairs = (v: squiggleValue_Module): array<(string, squiggleValue)> => + ReducerInterface_InternalExpressionValue.nameSpaceToKeyValuePairs(v) diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Record.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Record.res new file mode 100644 index 00000000..bc226f95 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Record.res @@ -0,0 +1,6 @@ +type squiggleValue = ForTS_SquiggleValue.squiggleValue //use +@genType type squiggleValue_Record = ForTS_SquiggleValue.squiggleValue_Record //re-export recursive type + +@genType +let getKeyValuePairs = (value: squiggleValue_Record): array<(string, squiggleValue)> => + ReducerInterface_InternalExpressionValue.recordToKeyValuePairs(value) diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Type.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Type.res new file mode 100644 index 00000000..d9a18bfc --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Type.res @@ -0,0 +1,6 @@ +type squiggleValue = ForTS_SquiggleValue.squiggleValue //use +@genType type squiggleValue_Type = ForTS_SquiggleValue.squiggleValue_Type //re-export recursive type + +@genType +let getKeyValuePairs = (value: squiggleValue_Type): array<(string, squiggleValue)> => + ReducerInterface_InternalExpressionValue.recordToKeyValuePairs(value) diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_tag.ts b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_tag.ts new file mode 100644 index 00000000..f8b4a9e3 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_tag.ts @@ -0,0 +1,19 @@ +export enum squiggleValueTag { + SvtArray = "Array", + SvtArrayString = "ArrayString", + SvtBool = "Bool", + SvtCall = "Call", + SvtDate = "Date", + SvtDeclaration = "Declaration", + SvtDistribution = "Distribution", + SvtLambda = "Lambda", + SvtModule = "Module", + SvtNumber = "Number", + SvtRecord = "Record", + SvtString = "String", + SvtSymbol = "Symbol", + SvtTimeDuration = "TimeDuration", + SvtType = "Type", + SvtTypeIdentifier = "TypeIdentifier", + SvtVoid = "Void", +} diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS__Types.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS__Types.res new file mode 100644 index 00000000..b97c93e0 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS__Types.res @@ -0,0 +1,21 @@ +@genType type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //re-export +@genType type syntaxErrorLocation = ForTS_Reducer_ErrorValue.syntaxErrorLocation //re-export + +@genType type reducerProject = ForTS_ReducerProject.reducerProject //re-export +@genType type squiggleValue = ForTS_SquiggleValue.squiggleValue //re-export +@genType type squiggleValue_Array = ForTS_SquiggleValue_Array.squiggleValue_Array //re-export +@genType type squiggleValue_Declaration = ForTS_SquiggleValue_Declaration.squiggleValue_Declaration //re-export +@genType type squiggleValue_Lambda = ForTS_SquiggleValue_Lambda.squiggleValue_Lambda //re-export +@genType type squiggleValue_Module = ForTS_SquiggleValue_Module.squiggleValue_Module //re-export +@genType type squiggleValue_Record = ForTS_SquiggleValue_Record.squiggleValue_Record //re-export +@genType type squiggleValue_Type = ForTS_SquiggleValue_Type.squiggleValue_Type //re-export + +/* Distribution related */ +@genType type squiggleValue_Distribution = ForTS_Distribution.distribution //re-export +@genType type distribution = squiggleValue_Distribution //candid +@genType type distributionError = ForTS_Distribution_Error.distributionError //re-export +@genType type environment = ForTS_Distribution_Environment.environment //re-export + +@genType type pointSetDistribution = ForTS_Distribution_PointSetDistribution.pointSetDistribution //re-export +@genType type sampleSetDistribution = ForTS_Distribution_SampleSetDistribution.sampleSetDistribution //re-export +@genType type symbolicDistribution = ForTS_Distribution_SymbolicDistribution.symbolicDistribution //re-export diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 4b27c221..edce5ac2 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -1,3 +1,5 @@ +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T type internalExpressionValue = ReducerInterface_InternalExpressionValue.t type internalExpressionValueType = ReducerInterface_InternalExpressionValue.internalExpressionValueType @@ -46,8 +48,8 @@ type fnDefinition = { run: ( array, array, - GenericDist.env, - Reducer_Expression_T.reducerFn, + ProjectAccessorsT.t, + ProjectReducerFnT.t, ) => result, } @@ -382,12 +384,12 @@ module FnDefinition = { let run = ( t: t, args: array, - env: GenericDist.env, - reducer: Reducer_Expression_T.reducerFn, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, ) => { let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) switch argValues { - | Some(values) => t.run(args, values, env, reducer) + | Some(values) => t.run(args, values, accessors, reducer) | None => Error("Incorrect Types") } } @@ -493,8 +495,8 @@ module Registry = { ~registry: registry, ~fnName: string, ~args: array, - ~env: GenericDist.env, - ~reducer: Reducer_Expression_T.reducerFn, + ~accessors: ProjectAccessorsT.t, + ~reducer: ProjectReducerFnT.t, ) => { let relevantFunctions = Js.Dict.get(registry.fnNameDict, fnName) |> E.O.default([]) let modified = {functions: relevantFunctions, fnNameDict: registry.fnNameDict} @@ -512,7 +514,7 @@ module Registry = { switch Matcher.Registry.findMatches(modified, fnName, args) { | Matcher.Match.FullMatch(match) => - match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, env, reducer)) + match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, accessors, reducer)) | SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m))) | _ => None } @@ -521,10 +523,10 @@ module Registry = { let dispatch = ( registry, (fnName, args): ReducerInterface_InternalExpressionValue.functionCall, - env, - reducer: Reducer_Expression_T.reducerFn, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, ) => { - _matchAndRun(~registry, ~fnName, ~args, ~env, ~reducer)->E.O2.fmap( + _matchAndRun(~registry, ~fnName, ~args, ~accessors, ~reducer)->E.O2.fmap( E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), ) } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res index 9e10577b..23619187 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res @@ -21,8 +21,8 @@ module DistributionCreation = { FnDefinition.make( ~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], - ~run=(_, inputs, env, _) => - inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), + ~run=(_, inputs, accessors, _) => + inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env=accessors.environment), (), ) } @@ -31,8 +31,10 @@ module DistributionCreation = { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=(_, inputs, env, _) => - inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + ~run=(_, inputs, accessors, _) => + inputs + ->Prepare.ToValueTuple.Record.twoDistOrNumber + ->process(~fn, ~env=accessors.environment), (), ) } @@ -41,8 +43,10 @@ module DistributionCreation = { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=(_, inputs, env, _) => - inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + ~run=(_, inputs, accessors, _) => + inputs + ->Prepare.ToValueTuple.Record.twoDistOrNumber + ->process(~fn, ~env=accessors.environment), (), ) } @@ -58,8 +62,8 @@ module DistributionCreation = { FnDefinition.make( ~name, ~inputs=[FRTypeDistOrNumber], - ~run=(_, inputs, env, _) => - inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), + ~run=(_, inputs, accessors, _) => + inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env=accessors.environment), (), ) } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res index 762fe31b..e0b83d18 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res @@ -1,3 +1,6 @@ +// module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +// module ProjectReducerFnT = ReducerProject_ReducerFn_T + open FunctionRegistry_Core open FunctionRegistry_Helpers @@ -24,17 +27,19 @@ module Internals = { Belt.Array.reverse(array), ) - let map = (array: array, environment, eLambdaValue, reducer): result< - ReducerInterface_InternalExpressionValue.t, - Reducer_ErrorValue.errorValue, - > => { + let map = ( + array: array, + accessors: ProjectAccessorsT.t, + eLambdaValue, + reducer: ProjectReducerFnT.t, + ): result => { let rMappedList = array->E.A.reduceReverse(Ok(list{}), (rAcc, elem) => rAcc->E.R.bind(_, acc => { let rNewElem = Reducer_Expression_Lambda.doLambdaCall( eLambdaValue, list{elem}, - environment, - reducer, + (accessors: ProjectAccessorsT.t), + (reducer: ProjectReducerFnT.t), ) rNewElem->E.R2.fmap(newElem => list{newElem, ...acc}) }) @@ -42,29 +47,46 @@ module Internals = { rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray) } - let reduce = (aValueArray, initialValue, aLambdaValue, environment, reducer) => { + let reduce = ( + aValueArray, + initialValue, + aLambdaValue, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, + ) => { aValueArray->E.A.reduce(Ok(initialValue), (rAcc, elem) => rAcc->E.R.bind(_, acc => - Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer) + Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer) ) ) } - let reduceReverse = (aValueArray, initialValue, aLambdaValue, environment, reducer) => { + let reduceReverse = ( + aValueArray, + initialValue, + aLambdaValue, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, + ) => { aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) => rAcc->Belt.Result.flatMap(acc => - Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer) + Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer) ) ) } - let filter = (aValueArray, aLambdaValue, environment, reducer) => { + let filter = ( + aValueArray, + aLambdaValue, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, + ) => { let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) => rAcc->E.R.bind(_, acc => { let rNewElem = Reducer_Expression_Lambda.doLambdaCall( aLambdaValue, list{elem}, - environment, + accessors, reducer, ) rNewElem->E.R2.fmap(newElem => { @@ -189,10 +211,10 @@ let library = [ FnDefinition.make( ~name="map", ~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => switch inputs { | [IEvArray(array), IEvLambda(lambda)] => - Internals.map(array, env, lambda, reducer)->E.R2.errMap(_ => "Error!") + Internals.map(array, accessors, lambda, reducer)->E.R2.errMap(_ => "Error!") | _ => Error(impossibleError) }, (), @@ -209,10 +231,12 @@ let library = [ FnDefinition.make( ~name="reduce", ~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => switch inputs { | [IEvArray(array), initialValue, IEvLambda(lambda)] => - Internals.reduce(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ => "Error!") + Internals.reduce(array, initialValue, lambda, accessors, reducer)->E.R2.errMap(_ => + "Error!" + ) | _ => Error(impossibleError) }, (), @@ -229,12 +253,16 @@ let library = [ FnDefinition.make( ~name="reduceReverse", ~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) => switch inputs { | [IEvArray(array), initialValue, IEvLambda(lambda)] => - Internals.reduceReverse(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ => - "Error!" - ) + Internals.reduceReverse( + array, + initialValue, + lambda, + accessors, + reducer, + )->E.R2.errMap(_ => "Error!") | _ => Error(impossibleError) }, (), @@ -251,10 +279,10 @@ let library = [ FnDefinition.make( ~name="filter", ~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) => switch inputs { | [IEvArray(array), IEvLambda(lambda)] => - Internals.filter(array, lambda, env, reducer)->E.R2.errMap(_ => "Error!") + Internals.filter(array, lambda, accessors, reducer)->E.R2.errMap(_ => "Error!") | _ => Error(impossibleError) }, (), diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res index 44b6abd2..0d950ce5 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res @@ -58,13 +58,13 @@ let library = [ FnDefinition.make( ~name="fromDist", ~inputs=[FRTypeDist], - ~run=(_, inputs, env, _) => + ~run=(_, inputs, accessors, _) => switch inputs { | [FRValueDist(dist)] => GenericDist.toPointSet( dist, - ~xyPointLength=env.xyPointLength, - ~sampleCount=env.sampleCount, + ~xyPointLength=accessors.environment.xyPointLength, + ~sampleCount=accessors.environment.sampleCount, (), ) ->E.R2.fmap(Wrappers.pointSet) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Sampleset.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Sampleset.res index c40fe349..016383f5 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Sampleset.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Sampleset.res @@ -1,3 +1,5 @@ +// module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +// module ProjectReducerFnT = ReducerProject_ReducerFn_T open FunctionRegistry_Core open FunctionRegistry_Helpers @@ -6,8 +8,14 @@ let requiresNamespace = true module Internal = { type t = SampleSetDist.t - let doLambdaCall = (aLambdaValue, list, environment, reducer) => - switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) { + + let doLambdaCall = ( + aLambdaValue, + list, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, + ) => + switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) { | Ok(IEvNumber(f)) => Ok(f) | _ => Error(Operation.SampleMapNeedsNtoNFunction) } @@ -22,29 +30,26 @@ module Internal = { } //TODO: I don't know why this seems to need at least one input - let fromFn = ( - aLambdaValue, - env: ReducerInterface_InternalExpressionValue.environment, - reducer, - ) => { - let sampleCount = env.sampleCount - let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer) + let fromFn = (aLambdaValue, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) => { + let sampleCount = accessors.environment.sampleCount + let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, accessors, reducer) Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen } - let map1 = (sampleSetDist: t, aLambdaValue, env, reducer) => { - let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer) + let map1 = (sampleSetDist: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => { + let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, accessors, reducer) SampleSetDist.samplesMap(~fn, sampleSetDist)->toType } - let map2 = (t1: t, t2: t, aLambdaValue, env, reducer) => { - let fn = (a, b) => doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, env, reducer) + let map2 = (t1: t, t2: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => { + let fn = (a, b) => + doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, accessors, reducer) SampleSetDist.map2(~fn, ~t1, ~t2)->toType } - let map3 = (t1: t, t2: t, t3: t, aLambdaValue, env, reducer) => { + let map3 = (t1: t, t2: t, t3: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => { let fn = (a, b, c) => - doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)}, env, reducer) + doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)}, accessors, reducer) SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType } @@ -59,14 +64,19 @@ module Internal = { E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr)) } - let mapN = (aValueArray: array, aLambdaValue, env, reducer) => { + let mapN = ( + aValueArray: array, + aLambdaValue, + accessors: ProjectAccessorsT.t, + reducer, + ) => { switch parseSampleSetArray(aValueArray) { | Some(t1) => let fn = a => doLambdaCall( aLambdaValue, list{IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))}, - env, + accessors, reducer, ) SampleSetDist.mapN(~fn, ~t1)->toType @@ -86,10 +96,10 @@ let library = [ FnDefinition.make( ~name="fromDist", ~inputs=[FRTypeDist], - ~run=(_, inputs, env, _) => + ~run=(_, inputs, accessors: ProjectAccessorsT.t, _) => switch inputs { | [FRValueDist(dist)] => - GenericDist.toSampleSetDist(dist, env.sampleCount) + GenericDist.toSampleSetDist(dist, accessors.environment.sampleCount) ->E.R2.fmap(Wrappers.sampleSet) ->E.R2.fmap(Wrappers.evDistribution) ->E.R2.errMap(DistributionTypes.Error.toString) @@ -153,10 +163,10 @@ let library = [ FnDefinition.make( ~name="fromFn", ~inputs=[FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) => switch inputs { | [IEvLambda(lambda)] => - switch Internal.fromFn(lambda, env, reducer) { + switch Internal.fromFn(lambda, accessors, reducer) { | Ok(r) => Ok(r->Wrappers.sampleSet->Wrappers.evDistribution) | Error(e) => Error(Operation.Error.toString(e)) } @@ -177,10 +187,10 @@ let library = [ FnDefinition.make( ~name="map", ~inputs=[FRTypeDist, FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => switch inputs { | [IEvDistribution(SampleSet(dist)), IEvLambda(lambda)] => - Internal.map1(dist, lambda, env, reducer)->E.R2.errMap(Reducer_ErrorValue.errorToString) + Internal.map1(dist, lambda, accessors, reducer)->E.R2.errMap(_ => "") | _ => Error(impossibleError) }, (), @@ -200,16 +210,14 @@ let library = [ FnDefinition.make( ~name="map2", ~inputs=[FRTypeDist, FRTypeDist, FRTypeLambda], - ~run=(inputs, _, env, reducer) => { + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => { switch inputs { | [ IEvDistribution(SampleSet(dist1)), IEvDistribution(SampleSet(dist2)), IEvLambda(lambda), ] => - Internal.map2(dist1, dist2, lambda, env, reducer)->E.R2.errMap( - Reducer_ErrorValue.errorToString, - ) + Internal.map2(dist1, dist2, lambda, accessors, reducer)->E.R2.errMap(_ => "") | _ => Error(impossibleError) } }, @@ -230,7 +238,7 @@ let library = [ FnDefinition.make( ~name="map3", ~inputs=[FRTypeDist, FRTypeDist, FRTypeDist, FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => switch inputs { | [ IEvDistribution(SampleSet(dist1)), @@ -238,9 +246,7 @@ let library = [ IEvDistribution(SampleSet(dist3)), IEvLambda(lambda), ] => - Internal.map3(dist1, dist2, dist3, lambda, env, reducer)->E.R2.errMap( - Reducer_ErrorValue.errorToString, - ) + Internal.map3(dist1, dist2, dist3, lambda, accessors, reducer)->E.R2.errMap(_ => "") | _ => Error(impossibleError) }, (), @@ -260,12 +266,12 @@ let library = [ FnDefinition.make( ~name="mapN", ~inputs=[FRTypeArray(FRTypeDist), FRTypeLambda], - ~run=(inputs, _, env, reducer) => + ~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => switch inputs { | [IEvArray(dists), IEvLambda(lambda)] => - Internal.mapN(dists, lambda, env, reducer)->E.R2.errMap( - Reducer_ErrorValue.errorToString, - ) + Internal.mapN(dists, lambda, accessors, reducer)->E.R2.errMap(_e => { + "AHHH doesn't work" + }) | _ => Error(impossibleError) }, (), diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res index 972501e9..d45b1a81 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res @@ -30,16 +30,16 @@ let library = [ ("prior", FRTypeDist), ]), ], - ~run=(_, inputs, env, _) => { + ~run=(_, inputs, accessors, _) => { switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) => - runScoring(estimate, Score_Dist(d), Some(prior), env) + runScoring(estimate, Score_Dist(d), Some(prior), accessors.environment) | Ok([ FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d)), FRValueDist(prior), ]) => - runScoring(estimate, Score_Scalar(d), Some(prior), env) + runScoring(estimate, Score_Scalar(d), Some(prior), accessors.environment) | Error(e) => Error(e) | _ => Error(FunctionRegistry_Helpers.impossibleError) } @@ -49,12 +49,12 @@ let library = [ FnDefinition.make( ~name="logScore", ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], - ~run=(_, inputs, env, _) => { + ~run=(_, inputs, accessors, _) => { switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => - runScoring(estimate, Score_Dist(d), None, env) + runScoring(estimate, Score_Dist(d), None, accessors.environment) | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => - runScoring(estimate, Score_Scalar(d), None, env) + runScoring(estimate, Score_Scalar(d), None, accessors.environment) | Error(e) => Error(e) | _ => Error(FunctionRegistry_Helpers.impossibleError) } @@ -74,10 +74,10 @@ let library = [ FnDefinition.make( ~name="klDivergence", ~inputs=[FRTypeDist, FRTypeDist], - ~run=(_, inputs, env, _) => { + ~run=(_, inputs, accessors, _) => { switch inputs { | [FRValueDist(estimate), FRValueDist(d)] => - runScoring(estimate, Score_Dist(d), None, env) + runScoring(estimate, Score_Dist(d), None, accessors.environment) | _ => Error(FunctionRegistry_Helpers.impossibleError) } }, diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res deleted file mode 100644 index bf8c89f9..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ /dev/null @@ -1,35 +0,0 @@ -module ErrorValue = Reducer_ErrorValue -module Expression = Reducer_Expression -module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue -module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Lambda = Reducer_Expression_Lambda - -type environment = ReducerInterface_InternalExpressionValue.environment -type errorValue = Reducer_ErrorValue.errorValue -type expressionValue = ExternalExpressionValue.t -type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings -type lambdaValue = ExternalExpressionValue.lambdaValue - -let evaluate = Expression.evaluate -let evaluateUsingOptions = Expression.evaluateUsingOptions -let evaluatePartialUsingExternalBindings = Expression.evaluatePartialUsingExternalBindings -let parse = Expression.parse - -let foreignFunctionInterface = ( - lambdaValue: ExternalExpressionValue.lambdaValue, - argArray: array, - environment: ExternalExpressionValue.environment, -) => { - let internallambdaValue = InternalExpressionValue.lambdaValueToInternal(lambdaValue) - let internalArgArray = argArray->Js.Array2.map(InternalExpressionValue.toInternal) - Lambda.foreignFunctionInterface( - internallambdaValue, - internalArgArray, - environment, - Expression.reduceExpression, - )->Belt.Result.map(InternalExpressionValue.toExternal) -} - -let defaultEnvironment = ExternalExpressionValue.defaultEnvironment - -let defaultExternalBindings = ReducerInterface_StdLib.externalStdLib diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi deleted file mode 100644 index bd0c43fb..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ /dev/null @@ -1,45 +0,0 @@ -module ErrorValue = Reducer_ErrorValue -module Expression = Reducer_Expression - -@genType -type environment = ReducerInterface_ExternalExpressionValue.environment -@genType -type errorValue = Reducer_ErrorValue.errorValue -@genType -type expressionValue = ReducerInterface_ExternalExpressionValue.t -@genType -type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings -@genType -type lambdaValue = ReducerInterface_ExternalExpressionValue.lambdaValue - -@genType -let evaluateUsingOptions: ( - ~environment: option, - ~externalBindings: option< - QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings, - >, - string, -) => result -@genType -let evaluatePartialUsingExternalBindings: ( - string, - QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings, - QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment, -) => result -@genType -let evaluate: string => result - -let parse: string => result - -@genType -let foreignFunctionInterface: ( - QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.lambdaValue, - array, - QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment, -) => result - -@genType -let defaultEnvironment: environment - -@genType -let defaultExternalBindings: externalBindings diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res index 28175d7a..0f1c2037 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res @@ -74,9 +74,10 @@ let set = (nameSpace: t, id: string, value): t => { let emptyModule: t = NameSpace(emptyMap) let emptyBindings = emptyModule +let emptyNameSpace = emptyModule -let fromTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceFromTypeScriptBindings -let toTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceToTypeScriptBindings +// let fromTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceFromTypeScriptBindings +// let toTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceToTypeScriptBindings let toExpressionValue = (nameSpace: t): internalExpressionValue => IEvBindings(nameSpace) let fromExpressionValue = (aValue: internalExpressionValue): t => 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 a2ca204a..1e8b19d0 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 @@ -1,11 +1,15 @@ +module Bindings = Reducer_Bindings module BindingsReplacer = Reducer_Expression_BindingsReplacer +module Continuation = ReducerInterface_Value_Continuation module ExpressionT = Reducer_Expression_T module ExternalLibrary = ReducerInterface.ExternalLibrary module Lambda = Reducer_Expression_Lambda module MathJs = Reducer_MathJs -module Bindings = Reducer_Bindings +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module Result = Belt.Result module TypeBuilder = Reducer_Type_TypeBuilder + open ReducerInterface_InternalExpressionValue open Reducer_ErrorValue @@ -19,10 +23,11 @@ open Reducer_ErrorValue exception TestRescriptException -let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< - 'b, - errorValue, -> => { +let callInternal = ( + call: functionCall, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, +): result<'b, errorValue> => { let callMathJs = (call: functionCall): result<'b, errorValue> => switch call { | ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests @@ -95,9 +100,17 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce let doExportBindings = (bindings: nameSpace) => bindings->Bindings.toExpressionValue->Ok + let doIdentity = (value: internalExpressionValue) => value->Ok + + let doDumpBindings = (continuation: nameSpace, value: internalExpressionValue) => { + // let _ = Continuation.inspect(continuation, "doDumpBindings") + accessors.states.continuation = continuation + value->Ok + } + module SampleMap = { let doLambdaCall = (aLambdaValue, list) => - switch Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) { + switch Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) { | Ok(IEvNumber(f)) => Ok(f) | _ => Error(Operation.SampleMapNeedsNtoNFunction) } @@ -137,12 +150,14 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce | ("$_constructArray_$", [IEvArray(aValueArray)]) => IEvArray(aValueArray)->Ok | ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) | ("$_exportBindings_$", [IEvBindings(nameSpace)]) => doExportBindings(nameSpace) + | ("$_exportBindings_$", [evValue]) => doIdentity(evValue) | ("$_setBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) => doSetBindings(nameSpace, symbol, value) | ("$_setTypeAliasBindings_$", [IEvBindings(nameSpace), IEvTypeIdentifier(symbol), value]) => doSetTypeAliasBindings(nameSpace, symbol, value) | ("$_setTypeOfBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) => doSetTypeOfBindings(nameSpace, symbol, value) + | ("$_dumpBindings_$", [IEvBindings(nameSpace), _, evValue]) => doDumpBindings(nameSpace, evValue) | ("$_typeModifier_memberOf_$", [IEvTypeIdentifier(typeIdentifier), IEvArray(arr)]) => TypeBuilder.typeModifier_memberOf(IEvTypeIdentifier(typeIdentifier), IEvArray(arr)) | ("$_typeModifier_memberOf_$", [IEvType(typeRecord), IEvArray(arr)]) => @@ -182,15 +197,16 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce /* Reducer uses Result monad while reducing expressions */ -let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< - internalExpressionValue, - errorValue, -> => +let dispatch = ( + call: functionCall, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, +): result => try { let (fn, args) = call // There is a bug that prevents string match in patterns // So we have to recreate a copy of the string - ExternalLibrary.dispatch((Js.String.make(fn), args), environment, reducer, callInternal) + ExternalLibrary.dispatch((Js.String.make(fn), args), accessors, reducer, callInternal) } catch { | Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error | _ => RETodo("unhandled rescript exception")->Error diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index c4c76ce3..978ca399 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -3,17 +3,19 @@ they take expressions as parameters and return a new expression. Macros are used to define language building blocks. They are like Lisp macros. */ +module Bindings = Reducer_Bindings module BindingsReplacer = Reducer_Expression_BindingsReplacer module ErrorValue = Reducer_ErrorValue module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionT = Reducer_Expression_T -module InternalExpressionValue = ReducerInterface_InternalExpressionValue module ExpressionWithContext = Reducer_ExpressionWithContext -module Bindings = Reducer_Bindings +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module Result = Belt.Result + open Reducer_Expression_ExpressionBuilder -type environment = InternalExpressionValue.environment type errorValue = ErrorValue.errorValue type expression = ExpressionT.expression type expressionWithContext = ExpressionWithContext.expressionWithContext @@ -21,11 +23,11 @@ type expressionWithContext = ExpressionWithContext.expressionWithContext let dispatchMacroCall = ( macroExpression: expression, bindings: ExpressionT.bindings, - environment, - reduceExpression: ExpressionT.reducerFn, + accessors: ProjectAccessorsT.t, + reduceExpression: ProjectReducerFnT.t, ): result => { - let useExpressionToSetBindings = (bindingExpr: expression, environment, statement, newCode) => { - let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) + let useExpressionToSetBindings = (bindingExpr: expression, accessors, statement, newCode) => { + let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, accessors) rExternalBindingsValue->Result.flatMap(nameSpaceValue => { let newBindings = Bindings.fromExpressionValue(nameSpaceValue) @@ -45,16 +47,17 @@ let dispatchMacroCall = ( | "$_let_$" => "$_setBindings_$" | "$_typeOf_$" => "$_setTypeOfBindings_$" | "$_typeAlias_$" => "$_setTypeAliasBindings_$" + | "$_endOfOuterBlock_$" => "$_dumpBindings_$" | _ => "" } - let doBindStatement = (bindingExpr: expression, statement: expression, environment) => { + let doBindStatement = (bindingExpr: expression, statement: expression, accessors) => { let defaultStatement = ErrorValue.REAssignmentExpected->Error switch statement { | ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => { let setBindingsFn = correspondingSetBindingsFn(callName) if setBindingsFn !== "" { - useExpressionToSetBindings(bindingExpr, environment, statement, ( + useExpressionToSetBindings(bindingExpr, accessors, statement, ( newBindingsExpr, boundStatement, ) => eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})) @@ -66,12 +69,12 @@ let dispatchMacroCall = ( } } - let doBindExpression = (bindingExpr: expression, statement: expression, environment): result< + let doBindExpression = (bindingExpr: expression, statement: expression, accessors): result< expressionWithContext, errorValue, > => { let defaultStatement = () => - useExpressionToSetBindings(bindingExpr, environment, statement, ( + useExpressionToSetBindings(bindingExpr, accessors, statement, ( _newBindingsExpr, boundStatement, ) => boundStatement) @@ -80,13 +83,13 @@ let dispatchMacroCall = ( | ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => { let setBindingsFn = correspondingSetBindingsFn(callName) if setBindingsFn !== "" { - useExpressionToSetBindings(bindingExpr, environment, statement, ( + useExpressionToSetBindings(bindingExpr, accessors, statement, ( newBindingsExpr, boundStatement, ) => eFunction( "$_exportBindings_$", - list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})}, + list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})}, // expression returning bindings ) ) } else { @@ -97,7 +100,7 @@ let dispatchMacroCall = ( } } - let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< + let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _accessors): result< expressionWithContext, errorValue, > => { @@ -130,10 +133,10 @@ let dispatchMacroCall = ( ifTrue: expression, ifFalse: expression, bindings: ExpressionT.bindings, - environment, + accessors, ): result => { let blockCondition = ExpressionBuilder.eBlock(list{condition}) - let rCondition = reduceExpression(blockCondition, bindings, environment) + let rCondition = reduceExpression(blockCondition, bindings, accessors) rCondition->Result.flatMap(conditionValue => switch conditionValue { | InternalExpressionValue.IEvBool(false) => { @@ -149,7 +152,7 @@ let dispatchMacroCall = ( ) } - let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment): result< + let expandExpressionList = (aList, bindings: ExpressionT.bindings, accessors): result< expressionWithContext, errorValue, > => @@ -159,21 +162,21 @@ let dispatchMacroCall = ( bindingExpr: ExpressionT.expression, statement, } => - doBindStatement(bindingExpr, statement, environment) + doBindStatement(bindingExpr, statement, accessors) | list{ExpressionT.EValue(IEvCall("$$_bindStatement_$$")), statement} => // bindings of the context are used when there is no binding expression - doBindStatement(eModule(bindings), statement, environment) + doBindStatement(eModule(bindings), statement, accessors) | list{ ExpressionT.EValue(IEvCall("$$_bindExpression_$$")), bindingExpr: ExpressionT.expression, expression, } => - doBindExpression(bindingExpr, expression, environment) + doBindExpression(bindingExpr, expression, accessors) | list{ExpressionT.EValue(IEvCall("$$_bindExpression_$$")), expression} => // bindings of the context are used when there is no binding expression - doBindExpression(eModule(bindings), expression, environment) + doBindExpression(eModule(bindings), expression, accessors) | list{ExpressionT.EValue(IEvCall("$$_block_$$")), ...exprs} => - doBlock(exprs, bindings, environment) + doBlock(exprs, bindings, accessors) | list{ ExpressionT.EValue(IEvCall("$$_lambda_$$")), ExpressionT.EValue(IEvArrayString(parameters)), @@ -181,12 +184,12 @@ let dispatchMacroCall = ( } => doLambdaDefinition(bindings, parameters, lambdaDefinition) | list{ExpressionT.EValue(IEvCall("$$_ternary_$$")), condition, ifTrue, ifFalse} => - doTernary(condition, ifTrue, ifFalse, bindings, environment) + doTernary(condition, ifTrue, ifFalse, bindings, accessors) | _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok } switch macroExpression { - | EList(aList) => expandExpressionList(aList, bindings, environment) + | EList(aList) => expandExpressionList(aList, bindings, accessors) | _ => ExpressionWithContext.noContext(macroExpression)->Ok } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_ChainPiece.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_ChainPiece.res index 6cebfef5..310f4879 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_ChainPiece.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_ChainPiece.res @@ -1,17 +1,21 @@ -module TypeChecker = Reducer_Type_TypeChecker +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T module T = Reducer_Dispatch_T +module TypeChecker = Reducer_Type_TypeChecker open ReducerInterface_InternalExpressionValue type errorValue = Reducer_ErrorValue.errorValue let makeFromTypes = jumpTable => { - let dispatchChainPiece: T.dispatchChainPiece = ((fnName, fnArgs): functionCall, environment) => { + let dispatchChainPiece: T.dispatchChainPiece = ( + (fnName, fnArgs): functionCall, + accessors: ProjectAccessorsT.t, + ) => { let jumpTableEntry = jumpTable->Js.Array2.find(elem => { let (candidName, candidType, _) = elem candidName == fnName && TypeChecker.checkITypeArgumentsBool(candidType, fnArgs) }) switch jumpTableEntry { - | Some((_, _, bridgeFn)) => bridgeFn(fnArgs, environment)->Some + | Some((_, _, bridgeFn)) => bridgeFn(fnArgs, accessors)->Some | _ => None } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_T.res index f6234976..68b8f789 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_T.res @@ -1,20 +1,22 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue module ExpressionT = Reducer_Expression_T +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T // Each piece of the dispatch chain computes the result or returns None so that the chain can continue type dispatchChainPiece = ( InternalExpressionValue.functionCall, - InternalExpressionValue.environment, + ProjectAccessorsT.t, ) => option> type dispatchChainPieceWithReducer = ( InternalExpressionValue.functionCall, - InternalExpressionValue.environment, - ExpressionT.reducerFn, + ProjectAccessorsT.t, + ProjectReducerFnT.t, ) => option> // This is a switch statement case implementation: get the arguments and compute the result type genericIEvFunction = ( array, - InternalExpressionValue.environment, + ProjectAccessorsT.t, ) => result diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 211c9f53..55cde709 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -1,9 +1,10 @@ +//TODO: Do not export here but in ForTS__Types @gentype.import("peggy") @genType.as("LocationRange") -type location +type syntaxErrorLocation -@genType +@genType.opaque type errorValue = - | REArityError(option, int, int) //TODO: Binding a lambda to a variable should record the variable name in lambda for error reporting + | REArityError(option, int, int) | REArrayIndexNotFound(string, int) | REAssignmentExpected | REDistributionError(DistributionTypes.error) @@ -17,13 +18,13 @@ type errorValue = | REOperationError(Operation.operationError) | RERecordPropertyNotFound(string, string) | RESymbolNotFound(string) - | RESyntaxError(string, option) + | RESyntaxError(string, option) | RETodo(string) // To do | REUnitNotFound(string) + | RENeedToRun type t = errorValue -@genType let errorToString = err => switch err { | REArityError(_oFnName, arity, usedArity) => @@ -57,4 +58,5 @@ let errorToString = err => | RETodo(msg) => `TODO: ${msg}` | REExpectedType(typeName, valueString) => `Expected type: ${typeName} but got: ${valueString}` | REUnitNotFound(unitName) => `Unit not found: ${unitName}` + | RENeedToRun => "Need to run" } 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 6de4f74a..f2b05036 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 @@ -1,3 +1,4 @@ +module Bindings = Reducer_Bindings module BindingsReplacer = Reducer_Expression_BindingsReplacer module BuiltIn = Reducer_Dispatch_BuiltIn module ExpressionBuilder = Reducer_Expression_ExpressionBuilder @@ -6,30 +7,21 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue module Lambda = Reducer_Expression_Lambda module Macro = Reducer_Expression_Macro module MathJs = Reducer_MathJs -module Bindings = Reducer_Bindings +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T module Result = Belt.Result module T = Reducer_Expression_T -type environment = InternalExpressionValue.environment type errorValue = Reducer_ErrorValue.errorValue -type expression = T.expression -type internalExpressionValue = InternalExpressionValue.t -type externalExpressionValue = ReducerInterface_ExternalExpressionValue.t -type t = expression +type t = T.t /* - Converts a Squigle code to expression + Recursively evaluate/reduce the expression (Lisp AST/Lambda calculus) */ -let parse = (peggyCode: string): result => - peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode) - -/* - Recursively evaluate/reduce the expression (Lisp AST) -*/ -let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< - internalExpressionValue, - 'e, -> => { +let rec reduceExpressionInProject = ( + expression: t, + continuation: T.bindings, + accessors: ProjectAccessorsT.t, +): result => { // Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`) switch expression { | T.EValue(value) => value->Ok @@ -38,41 +30,40 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en | list{EValue(IEvCall(fName)), ..._args} => switch Macro.isMacroName(fName) { // A macro expands then reduces itself - | true => Macro.doMacroCall(expression, bindings, environment, reduceExpression) - | false => reduceExpressionList(list, bindings, environment) + | true => Macro.doMacroCall(expression, continuation, accessors, reduceExpressionInProject) + | false => reduceExpressionList(list, continuation, accessors) } - | _ => reduceExpressionList(list, bindings, environment) + | _ => reduceExpressionList(list, continuation, accessors) } } } - and reduceExpressionList = ( expressions: list, - bindings: T.bindings, - environment: environment, -): result => { + continuation: T.bindings, + accessors: ProjectAccessorsT.t, +): result => { let racc: result< - list, + list, 'e, - > = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => + > = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: t) => racc->Result.flatMap(acc => { each - ->reduceExpression(bindings, environment) + ->reduceExpressionInProject(continuation, accessors) ->Result.map(newNode => { acc->Belt.List.add(newNode) }) }) ) - racc->Result.flatMap(acc => acc->reduceValueList(environment)) + racc->Result.flatMap(acc => acc->reduceValueList(accessors)) } /* After reducing each level of expression(Lisp AST), we have a value list to evaluate */ -and reduceValueList = (valueList: list, environment): result< - internalExpressionValue, - 'e, -> => +and reduceValueList = ( + valueList: list, + accessors: ProjectAccessorsT.t, +): result => switch valueList { | list{IEvCall(fName), ...args} => { let rCheckedArgs = switch fName { @@ -81,7 +72,10 @@ and reduceValueList = (valueList: list, environment): r } rCheckedArgs->Result.flatMap(checkedArgs => - (fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression) + (fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch( + accessors, + reduceExpressionInProject, + ) ) } | list{IEvLambda(_)} => @@ -91,11 +85,11 @@ and reduceValueList = (valueList: list, environment): r ->Result.flatMap(reducedValueList => reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok ) - | list{IEvLambda(lamdaCall), ...args} => + | list{IEvLambda(lambdaCall), ...args} => args ->Lambda.checkIfReduced ->Result.flatMap(checkedArgs => - Lambda.doLambdaCall(lamdaCall, checkedArgs, environment, reduceExpression) + Lambda.doLambdaCall(lambdaCall, checkedArgs, accessors, reduceExpressionInProject) ) | _ => @@ -106,53 +100,27 @@ and reduceValueList = (valueList: list, environment): r ) } -let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result< - internalExpressionValue, - 'e, -> => reduceExpression(aExpression, bindings, environment) - -let evaluateUsingOptions = ( - ~environment: option, - ~externalBindings: option, - code: string, -): result => { - let anEnvironment = Belt.Option.getWithDefault( - environment, - ReducerInterface_ExternalExpressionValue.defaultEnvironment, - ) - - let mergedBindings: InternalExpressionValue.nameSpace = Bindings.merge( - ReducerInterface_StdLib.internalStdLib, - Belt.Option.map(externalBindings, Bindings.fromTypeScriptBindings)->Belt.Option.getWithDefault( - Bindings.emptyModule, - ), - ) - - parse(code) - ->Result.flatMap(expr => evalUsingBindingsExpression_(expr, mergedBindings, anEnvironment)) - ->Result.map(ReducerInterface_InternalExpressionValue.toExternal) +let reduceReturningBindings = ( + expression: t, + continuation: T.bindings, + accessors: ProjectAccessorsT.t, +): (result, T.bindings) => { + let states = accessors.states + let result = reduceExpressionInProject(expression, continuation, accessors) + (result, states.continuation) } -/* - IEvaluates Squiggle code and bindings via Reducer and answers the result -*/ -let evaluate = (code: string): result => { - evaluateUsingOptions(~environment=None, ~externalBindings=None, code) -} -let evaluatePartialUsingExternalBindings = ( - code: string, - externalBindings: ReducerInterface_ExternalExpressionValue.externalBindings, - environment: ReducerInterface_ExternalExpressionValue.environment, -): result => { - let rAnswer = evaluateUsingOptions( - ~environment=Some(environment), - ~externalBindings=Some(externalBindings), - code, - ) - switch rAnswer { - | Ok(EvModule(externalBindings)) => Ok(externalBindings) - | Ok(_) => - Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`, None)) - | Error(err) => err->Error +module BackCompatible = { + // Those methods are used to support the existing tests + // If they are used outside limited testing context, error location reporting will fail + let parse = (peggyCode: string): result => + peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode) + + let evaluate = (expression: t): result => { + let accessors = ProjectAccessorsT.identityAccessors + expression->reduceExpressionInProject(accessors.stdLib, accessors) } + + let evaluateString = (peggyCode: string): result => + parse(peggyCode)->Result.flatMap(evaluate) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res index 44059e2b..808a2dcd 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res @@ -1,9 +1,11 @@ +module Bindings = Reducer_Bindings module BindingsReplacer = Reducer_Expression_BindingsReplacer module ErrorValue = Reducer_ErrorValue module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module Result = Belt.Result -module Bindings = Reducer_Bindings type bindings = ExpressionT.bindings type context = bindings @@ -11,7 +13,6 @@ type environment = InternalExpressionValue.environment type errorValue = Reducer_ErrorValue.errorValue type expression = ExpressionT.expression type internalExpressionValue = InternalExpressionValue.t -type reducerFn = ExpressionT.reducerFn type expressionWithContext = | ExpressionWithContext(expression, context) @@ -20,16 +21,16 @@ type expressionWithContext = let callReducer = ( expressionWithContext: expressionWithContext, bindings: bindings, - environment: environment, - reducer: reducerFn, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, ): result => { switch expressionWithContext { | ExpressionNoContext(expr) => // Js.log(`callReducer: bindings ${Bindings.toString(bindings)} expr ${ExpressionT.toString(expr)}`) - reducer(expr, bindings, environment) + reducer(expr, bindings, accessors) | ExpressionWithContext(expr, context) => // Js.log(`callReducer: context ${Bindings.toString(context)} expr ${ExpressionT.toString(expr)}`) - reducer(expr, context, environment) + reducer(expr, context, accessors) } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_BindingsReplacer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_BindingsReplacer.res index 15ecfe58..6e38f833 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_BindingsReplacer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_BindingsReplacer.res @@ -7,7 +7,6 @@ module Bindings = Reducer_Bindings type errorValue = Reducer_ErrorValue.errorValue type expression = ExpressionT.expression type internalExpressionValue = InternalExpressionValue.t -type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$") diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res index 59779484..5ab7761d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res @@ -1,12 +1,13 @@ +module Bindings = Reducer_Bindings module BindingsReplacer = Reducer_Expression_BindingsReplacer module ErrorValue = Reducer_ErrorValue module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface_InternalExpressionValue -module Bindings = Reducer_Bindings +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module Result = Belt.Result -type environment = ReducerInterface_InternalExpressionValue.environment type expression = ExpressionT.expression type expressionOrFFI = ExpressionT.expressionOrFFI type internalExpressionValue = ReducerInterface_InternalExpressionValue.t @@ -44,7 +45,13 @@ let checkIfReduced = (args: list) => ) ) -let caseNotFFI = (lambdaValue: ExpressionValue.lambdaValue, expr, args, environment, reducer) => { +let caseNotFFI = ( + lambdaValue: ExpressionValue.lambdaValue, + expr, + args, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, +) => { let parameterList = lambdaValue.parameters->Belt.List.fromArray let zippedParameterList = parameterList->Belt.List.zip(args) let bindings = Belt.List.reduce(zippedParameterList, lambdaValue.context, ( @@ -52,39 +59,43 @@ let caseNotFFI = (lambdaValue: ExpressionValue.lambdaValue, expr, args, environm (variable, variableValue), ) => acc->Bindings.set(variable, variableValue)) let newExpression = ExpressionBuilder.eBlock(list{expr}) - reducer(newExpression, bindings, environment) + reducer(newExpression, bindings, accessors) } -let caseFFI = (ffiFn: ExpressionT.ffiFn, args, environment) => { - ffiFn(args->Belt.List.toArray, environment) +let caseFFI = (ffiFn: ExpressionT.ffiFn, args, accessors: ProjectAccessorsT.t) => { + ffiFn(args->Belt.List.toArray, accessors.environment) } let applyParametersToLambda = ( lambdaValue: ExpressionValue.lambdaValue, args, - environment, - reducer: ExpressionT.reducerFn, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, ): result => { checkArity(lambdaValue, args)->Result.flatMap(args => checkIfReduced(args)->Result.flatMap(args => { let exprOrFFI = castInternalCodeToExpression(lambdaValue.body) switch exprOrFFI { - | NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, environment, reducer) - | FFI(ffiFn) => caseFFI(ffiFn, args, environment) + | NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, accessors, reducer) + | FFI(ffiFn) => caseFFI(ffiFn, args, accessors) } }) ) } -let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => - applyParametersToLambda(lambdaValue, args, environment, reducer) +let doLambdaCall = ( + lambdaValue: ExpressionValue.lambdaValue, + args, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, +) => applyParametersToLambda(lambdaValue, args, accessors, reducer) let foreignFunctionInterface = ( lambdaValue: ExpressionValue.lambdaValue, argArray: array, - environment: ExpressionValue.environment, - reducer: ExpressionT.reducerFn, -): result => { + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, +): result => { let args = argArray->Belt.List.fromArray - applyParametersToLambda(lambdaValue, args, environment, reducer) + applyParametersToLambda(lambdaValue, args, accessors, reducer) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res index 2598a9ed..003d3170 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res @@ -2,6 +2,8 @@ module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue module ExpressionWithContext = Reducer_ExpressionWithContext module Result = Belt.Result +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T type environment = InternalExpressionValue.environment type expression = ExpressionT.expression @@ -11,34 +13,29 @@ type expressionWithContext = ExpressionWithContext.expressionWithContext let expandMacroCall = ( macroExpression: expression, bindings: ExpressionT.bindings, - environment: environment, - reduceExpression: ExpressionT.reducerFn, + accessors: ProjectAccessorsT.t, + reduceExpression: ProjectReducerFnT.t, ): result => Reducer_Dispatch_BuiltInMacros.dispatchMacroCall( macroExpression, bindings, - environment, + accessors, reduceExpression, ) let doMacroCall = ( macroExpression: expression, bindings: ExpressionT.bindings, - environment: environment, - reduceExpression: ExpressionT.reducerFn, + accessors: ProjectAccessorsT.t, + reduceExpression: ProjectReducerFnT.t, ): result => expandMacroCall( macroExpression, bindings, - environment, - reduceExpression, + (accessors: ProjectAccessorsT.t), + (reduceExpression: ProjectReducerFnT.t), )->Result.flatMap(expressionWithContext => - ExpressionWithContext.callReducer( - expressionWithContext, - bindings, - environment, - reduceExpression, - ) + ExpressionWithContext.callReducer(expressionWithContext, bindings, accessors, reduceExpression) ) let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$") 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 c9739be3..61f723df 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 @@ -17,6 +17,8 @@ type rec expression = | EValue(internalExpressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible and bindings = InternalExpressionValue.nameSpace +type t = expression + type reducerFn = ( expression, bindings, diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy index 15837da4..ec490c42 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy @@ -9,12 +9,25 @@ start zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda +// { return h.makeFunctionCall('$_typeOf_$', [identifier, typeExpression])} +// {return [h.nodeVoid()];} outerBlock = statements:array_statements finalExpression: (statementSeparator @expression)? - { if (finalExpression != null) { statements.push(finalExpression) } - return h.nodeBlock(statements) } + { if (finalExpression != null) + { + var newFinalExpression = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), finalExpression]); + statements.push(newFinalExpression); + } + else + { + var newFinalStatement = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), h.nodeVoid()]); + statements.push(newFinalStatement); + } + return h.nodeBlock(statements) } / finalExpression: expression - { return h.nodeBlock([finalExpression])} + { + var newFinalExpression = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), finalExpression]); + return h.nodeBlock([newFinalExpression])} innerBlockOrExpression = quotedInnerBlock diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res index 193cb893..8ecff48c 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res @@ -5,13 +5,12 @@ type node = {"type": string} @module("./Reducer_Peggy_GeneratedParser.js") external parse__: string => node = "parse" -type withLocation = {"location": Reducer_ErrorValue.location} +type withLocation = {"location": Reducer_ErrorValue.syntaxErrorLocation} external castWithLocation: Js.Exn.t => withLocation = "%identity" -let syntaxErrorToLocation = (error: Js.Exn.t): Reducer_ErrorValue.location => +let syntaxErrorToLocation = (error: Js.Exn.t): Reducer_ErrorValue.syntaxErrorLocation => castWithLocation(error)["location"] -@genType let parse = (expr: string): result => try { Ok(parse__(expr)) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res index 896f4a12..79153801 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res @@ -1,47 +1,44 @@ +module Bindings = Reducer_Bindings module ErrorValue = Reducer_ErrorValue +module Expression = Reducer_Expression module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Bindings = Reducer_Bindings +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module T = Reducer_Type_T let ievFromTypeExpression = ( typeExpressionSourceCode: string, - reducerFn: ExpressionT.reducerFn, + reducerFn: ProjectReducerFnT.t, ): result => { let sIndex = "compiled" let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}` - Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => { - let rContext = reducerFn( - expr, - Bindings.emptyBindings, - InternalExpressionValue.defaultEnvironment, - ) - Belt.Result.map(rContext, context => - switch context { - | IEvBindings(nameSpace) => - switch Bindings.getType(nameSpace, sIndex) { - | Some(value) => value - | None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none")) - } - | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-raise")) + Reducer_Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => { + let accessors = ProjectAccessorsT.identityAccessors + let result = reducerFn(expr, Bindings.emptyBindings, accessors) + let nameSpace = accessors.states.continuation + + switch result { + | Ok(_) => + switch Bindings.getType(nameSpace, sIndex) { + | Some(value) => value->Ok + | None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none")) } - ) + | err => err + } }) } -let fromTypeExpression = ( - typeExpressionSourceCode: string, - reducerFn: ExpressionT.reducerFn, -): result => { - ievFromTypeExpression( - (typeExpressionSourceCode: string), - (reducerFn: ExpressionT.reducerFn), - )->Belt.Result.map(T.fromIEvValue) +let fromTypeExpression = (typeExpressionSourceCode: string, reducerFn: ProjectReducerFnT.t): result< + T.t, + ErrorValue.t, +> => { + ievFromTypeExpression(typeExpressionSourceCode, reducerFn)->Belt.Result.map(T.fromIEvValue) } let fromTypeExpressionExn = ( typeExpressionSourceCode: string, - reducerFn: ExpressionT.reducerFn, + reducerFn: ProjectReducerFnT.t, ): T.t => switch fromTypeExpression(typeExpressionSourceCode, reducerFn) { | Ok(value) => value diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res index 33cbbeca..c9152e3c 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res @@ -1,5 +1,7 @@ module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T module T = Reducer_Type_T module TypeContracts = Reducer_Type_Contracts open InternalExpressionValue @@ -129,7 +131,7 @@ let rec isITypeOf = (anIType: T.iType, aValue): result = let isTypeOf = ( typeExpressionSourceCode: string, aValue: InternalExpressionValue.t, - reducerFn: ExpressionT.reducerFn, + reducerFn: ProjectReducerFnT.t, ): result => { switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) { | Ok(anIType) => @@ -164,7 +166,7 @@ let checkITypeArgumentsBool = (anIType: T.iType, args: array, - reducerFn: ExpressionT.reducerFn, + reducerFn: ProjectReducerFnT.t, ): result => { switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) { | Ok(anIType) => diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface.res index ef27130b..d19b93b3 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface.res @@ -1,4 +1,3 @@ -module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue module ExternalLibrary = ReducerInterface_ExternalLibrary module InternalExpressionValue = ReducerInterface_InternalExpressionValue module StdLib = ReducerInterface_StdLib diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalExpressionValue.res deleted file mode 100644 index d613ceb8..00000000 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalExpressionValue.res +++ /dev/null @@ -1,99 +0,0 @@ -/* - Irreducible values. Reducer does not know about those. Only used for external calls - This is a configuration to to make external calls of those types -*/ -module Extra_Array = Reducer_Extra_Array -module ErrorValue = Reducer_ErrorValue -@genType.opaque -type internalCode = Object - -@genType.opaque -type hiddenNameSpace = Object - -@genType -type rec externalExpressionValue = - | EvArray(array) - | EvArrayString(array) - | EvBool(bool) - | EvCall(string) // External function call - | EvDistribution(DistributionTypes.genericDist) - | EvLambda(lambdaValue) - | EvNumber(float) - | EvRecord(record) - | EvString(string) - | EvSymbol(string) - | EvDate(Js.Date.t) - | EvTimeDuration(float) - | EvDeclaration(lambdaDeclaration) - | EvTypeIdentifier(string) - | EvModule(record) - | EvType(record) - | EvVoid -and record = Js.Dict.t -and lambdaValue = { - parameters: array, - context: hiddenNameSpace, - body: internalCode, -} -and lambdaDeclaration = Declaration.declaration - -@genType -type externalBindings = record - -@genType -type t = externalExpressionValue - -type functionCall = (string, array) - -let rec toString = aValue => - switch aValue { - | EvArray(anArray) => { - let args = anArray->Js.Array2.map(each => toString(each))->Js.Array2.toString - `[${args}]` - } - | EvArrayString(anArray) => { - let args = anArray->Js.Array2.toString - `[${args}]` - } - | EvBool(aBool) => Js.String.make(aBool) - | EvCall(fName) => `:${fName}` - | EvDate(date) => DateTime.Date.toString(date) - | EvDeclaration(d) => Declaration.toString(d, r => toString(EvLambda(r))) - | EvDistribution(dist) => GenericDist.toString(dist) - | EvLambda(lambdaValue) => `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)` - | EvModule(m) => `@${m->toStringRecord}` - | EvNumber(aNumber) => Js.String.make(aNumber) - | EvRecord(aRecord) => aRecord->toStringRecord - | EvString(aString) => `'${aString}'` - | EvSymbol(aString) => `:${aString}` - | EvTimeDuration(t) => DateTime.Duration.toString(t) - | EvType(t) => `type${t->toStringRecord}` - | EvTypeIdentifier(id) => `#${id}` - | EvVoid => `()` - } -and toStringRecord = aRecord => { - let pairs = - aRecord - ->Js.Dict.entries - ->Js.Array2.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`) - ->Js.Array2.toString - `{${pairs}}` -} - -let argsToString = (args: array): string => { - args->Js.Array2.map(arg => arg->toString)->Js.Array2.toString -} - -let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})` - -let toStringResult = x => - switch x { - | Ok(a) => `Ok(${toString(a)})` - | Error(m) => `Error(${ErrorValue.errorToString(m)})` - } - -@genType -type environment = GenericDist.env - -@genType -let defaultEnvironment: environment = DistributionOperation.defaultEnv diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 7ae6ace9..89528a32 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -1,4 +1,6 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectReducerFnT = ReducerProject_ReducerFn_T type internalExpressionValue = InternalExpressionValue.t /* @@ -6,17 +8,17 @@ type internalExpressionValue = InternalExpressionValue.t */ let dispatch = ( call: InternalExpressionValue.functionCall, - environment, - reducer: Reducer_Expression_T.reducerFn, + accessors: ProjectAccessorsT.t, + reducer: ProjectReducerFnT.t, chain, ): result => { E.A.O.firstSomeFn([ - () => ReducerInterface_GenericDistribution.dispatch(call, environment), - () => ReducerInterface_Date.dispatch(call, environment), - () => ReducerInterface_Duration.dispatch(call, environment), - () => ReducerInterface_Number.dispatch(call, environment), - () => FunctionRegistry_Library.dispatch(call, environment, reducer), - ])->E.O2.defaultFn(() => chain(call, environment, reducer)) + () => ReducerInterface_GenericDistribution.dispatch(call, accessors.environment), + () => ReducerInterface_Date.dispatch(call, accessors.environment), + () => ReducerInterface_Duration.dispatch(call, accessors.environment), + () => ReducerInterface_Number.dispatch(call, accessors.environment), + () => FunctionRegistry_Library.dispatch(call, accessors, reducer), + ])->E.O2.defaultFn(() => chain(call, accessors, reducer)) } /* diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi index 6cccdf17..4cf8a17d 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi @@ -1,4 +1,4 @@ let dispatch: ( ReducerInterface_InternalExpressionValue.functionCall, - ReducerInterface_ExternalExpressionValue.environment, + ReducerInterface_InternalExpressionValue.environment, ) => option> diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res index 86718b64..6a26ecd2 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res @@ -1,11 +1,11 @@ module ErrorValue = Reducer_ErrorValue -module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue module Extra_Array = Reducer_Extra_Array -type internalCode = ExternalExpressionValue.internalCode -type environment = ExternalExpressionValue.environment +type internalCode = Object +type environment = GenericDist.env -let defaultEnvironment = ExternalExpressionValue.defaultEnvironment +let defaultEnvironment: environment = DistributionOperation.defaultEnv +@genType.opaque type rec t = | IEvArray(array) // FIXME: Convert to MapInt | IEvArrayString(array) @@ -24,42 +24,21 @@ type rec t = | IEvType(map) | IEvTypeIdentifier(string) | IEvVoid -and map = Belt.Map.String.t -and nameSpace = NameSpace(Belt.Map.String.t) +@genType.opaque and squiggleArray = array +@genType.opaque and map = Belt.Map.String.t +@genType.opaque and nameSpace = NameSpace(Belt.Map.String.t) +@genType.opaque and lambdaValue = { parameters: array, context: nameSpace, body: internalCode, } -and lambdaDeclaration = Declaration.declaration +@genType.opaque and lambdaDeclaration = Declaration.declaration type internalExpressionValue = t type functionCall = (string, array) -module Internal = { - module NameSpace = { - external castNameSpaceToHidden: nameSpace => ExternalExpressionValue.hiddenNameSpace = - "%identity" - external castHiddenToNameSpace: ExternalExpressionValue.hiddenNameSpace => nameSpace = - "%identity" - } - module Lambda = { - let toInternal = (v: ExternalExpressionValue.lambdaValue): lambdaValue => { - let p = v.parameters - let c = v.context->NameSpace.castHiddenToNameSpace - let b = v.body - {parameters: p, context: c, body: b} - } - and toExternal = (v: lambdaValue): ExternalExpressionValue.lambdaValue => { - let p = v.parameters - let c = v.context->NameSpace.castNameSpaceToHidden - let b = v.body - {parameters: p, context: c, body: b} - } - } -} - let rec toString = aValue => switch aValue { | IEvArray(anArray) => { @@ -132,6 +111,12 @@ let toStringResult = x => | Error(m) => `Error(${ErrorValue.errorToString(m)})` } +let toStringOptionResult = x => + switch x { + | Some(a) => toStringResult(a) + | None => "None" + } + let toStringResultOkless = (codeResult: result): string => switch codeResult { | Ok(a) => toString(a) @@ -140,7 +125,7 @@ let toStringResultOkless = (codeResult: result): strin let toStringResultRecord = x => switch x { - | Ok(a) => `Ok(${ExternalExpressionValue.toStringRecord(a)})` + | Ok(a) => `Ok(${toStringMap(a)})` | Error(m) => `Error(${ErrorValue.errorToString(m)})` } @@ -188,27 +173,6 @@ let valueToValueType = value => | IEvVoid => EvtVoid } -let externalValueToValueType = (value: ExternalExpressionValue.t) => - switch value { - | EvArray(_) => EvtArray - | EvArrayString(_) => EvtArrayString - | EvBool(_) => EvtBool - | EvCall(_) => EvtCall - | EvDate(_) => EvtDate - | EvDeclaration(_) => EvtDeclaration - | EvDistribution(_) => EvtDistribution - | EvLambda(_) => EvtLambda - | EvModule(_) => EvtModule - | EvNumber(_) => EvtNumber - | EvRecord(_) => EvtRecord - | EvString(_) => EvtString - | EvSymbol(_) => EvtSymbol - | EvTimeDuration(_) => EvtTimeDuration - | EvType(_) => EvtType - | EvTypeIdentifier(_) => EvtTypeIdentifier - | EvVoid => EvtVoid - } - let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => { let (fn, args) = functionCall CallSignature(fn, args->Js.Array2.map(valueToValueType)) @@ -240,70 +204,18 @@ let functionCallSignatureToString = (functionCallSignature: functionCallSignatur `${fn}(${args->Js.Array2.map(valueTypeToString)->Js.Array2.toString})` } -let rec toExternal = (iev: t): ExternalExpressionValue.t => { - switch iev { - | IEvArray(v) => v->Belt.Array.map(e => toExternal(e))->EvArray - | IEvArrayString(v) => EvArrayString(v) - | IEvBool(v) => EvBool(v) - | IEvCall(v) => EvCall(v) - | IEvDeclaration(v) => { - let fn = lambdaValueToExternal(v.fn) - let args = v.args - EvDeclaration({fn: fn, args: args}) - } - | IEvDistribution(v) => EvDistribution(v) - | IEvLambda(v) => EvLambda(lambdaValueToExternal(v)) - | IEvNumber(v) => EvNumber(v) - | IEvRecord(v) => v->mapToExternal->EvRecord - | IEvString(v) => EvString(v) - | IEvSymbol(v) => EvSymbol(v) - | IEvDate(v) => EvDate(v) - | IEvTimeDuration(v) => EvTimeDuration(v) - | IEvType(v) => v->mapToExternal->EvType - | IEvTypeIdentifier(v) => EvTypeIdentifier(v) - | IEvBindings(v) => v->nameSpaceToTypeScriptBindings->EvModule - | IEvVoid => EvVoid - } -} -and mapToExternal = v => - v->Belt.Map.String.map(e => toExternal(e))->Belt.Map.String.toArray->Js.Dict.fromArray -and lambdaValueToExternal = Internal.Lambda.toExternal -and nameSpaceToTypeScriptBindings = ( - nameSpace: nameSpace, -): ReducerInterface_ExternalExpressionValue.externalBindings => { - let NameSpace(container) = nameSpace - Belt.Map.String.map(container, e => toExternal(e))->Belt.Map.String.toArray->Js.Dict.fromArray -} +let arrayToValueArray = (arr: array): array => arr -let rec toInternal = (ev: ExternalExpressionValue.t): t => { - switch ev { - | EvArray(v) => v->Belt.Array.map(e => toInternal(e))->IEvArray - | EvArrayString(v) => IEvArrayString(v) - | EvBool(v) => IEvBool(v) - | EvCall(v) => IEvCall(v) - | EvDate(v) => IEvDate(v) - | EvDeclaration(v) => { - let fn = lambdaValueToInternal(v.fn) - let args = v.args - IEvDeclaration({fn: fn, args: args}) - } - | EvDistribution(v) => IEvDistribution(v) - | EvLambda(v) => IEvLambda(lambdaValueToInternal(v)) - | EvModule(v) => v->nameSpaceFromTypeScriptBindings->IEvBindings - | EvNumber(v) => IEvNumber(v) - | EvRecord(v) => v->recordToInternal->IEvRecord - | EvString(v) => IEvString(v) - | EvSymbol(v) => IEvSymbol(v) - | EvTimeDuration(v) => IEvTimeDuration(v) - | EvType(v) => v->recordToInternal->IEvType - | EvTypeIdentifier(v) => IEvTypeIdentifier(v) - | EvVoid => IEvVoid - } +let recordToKeyValuePairs = (record: map): array<(string, t)> => record->Belt.Map.String.toArray + +// let nameSpaceToTypeScriptBindings = ( +// nameSpace: nameSpace, +// ) => { +// let NameSpace(container) = nameSpace +// Belt.Map.String.map(container, e => e->Belt.Map.String.toArray->Js.Dict.fromArray) +// } + +let nameSpaceToKeyValuePairs = (nameSpace: nameSpace): array<(string, t)> => { + let NameSpace(container) = nameSpace + container->Belt.Map.String.toArray } -and recordToInternal = v => - v->Js.Dict.entries->Belt.Map.String.fromArray->Belt.Map.String.map(e => toInternal(e)) -and lambdaValueToInternal = Internal.Lambda.toInternal -and nameSpaceFromTypeScriptBindings = ( - r: ReducerInterface_ExternalExpressionValue.externalBindings, -): nameSpace => - r->Js.Dict.entries->Belt.Map.String.fromArray->Belt.Map.String.map(e => toInternal(e))->NameSpace diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res index ec6c4fd4..a868eeb5 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res @@ -1,7 +1,4 @@ module Bindings = Reducer_Bindings -let internalStdLib = +let internalStdLib: Bindings.t = Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings->SquiggleLibrary_Versions.makeBindings - -@genType -let externalStdLib = internalStdLib->Bindings.toTypeScriptBindings diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res new file mode 100644 index 00000000..af1c16c9 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res @@ -0,0 +1,28 @@ +module InternalExpressionValue = ReducerInterface_InternalExpressionValue + +type t = InternalExpressionValue.nameSpace + +let toValue = nameSpace => InternalExpressionValue.IEvBindings(nameSpace) +let toString = nameSpace => InternalExpressionValue.toString(toValue(nameSpace)) +let toStringResult = rNameSpace => + Belt.Result.map(rNameSpace, toValue(_))->InternalExpressionValue.toStringResult +let toStringOptionResult = orNameSpace => + Belt.Option.map( + orNameSpace, + Belt.Result.map(_, toValue(_)), + )->InternalExpressionValue.toStringOptionResult + +let inspect = (nameSpace, label: string) => Js.log(`${label}: ${toString(nameSpace)}`) + +let inspectOption = (oNameSpace, label: string) => + switch oNameSpace { + | Some(nameSpace) => inspect(nameSpace, label) + | None => Js.log(`${label}: None`) + } + +let minus = (NameSpace(thisContainer): t, NameSpace(thatContainer): t) => { + Belt.Map.String.removeMany( + thisContainer, + Belt.Map.String.keysToArray(thatContainer), + )->InternalExpressionValue.NameSpace +} diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res new file mode 100644 index 00000000..5f2fdce0 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res @@ -0,0 +1,208 @@ +// TODO: Auto clean project based on topology + +module Bindings = Reducer_Bindings +module Continuation = ReducerInterface_Value_Continuation +module ErrorValue = Reducer_ErrorValue +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ProjectItem = ReducerProject_ProjectItem +module T = ReducerProject_T +module Topology = ReducerProject_Topology + +type t = T.t + +module Private = { + type internalProject = T.Private.t + type t = T.Private.t + + let getSourceIds = T.Private.getSourceIds + let getItem = T.Private.getItem + let getDependents = Topology.getDependents + let getDependencies = Topology.getDependencies + let getRunOrder = Topology.getRunOrder + let getRunOrderFor = Topology.getRunOrderFor + + let createProject = () => { + let project: t = { + "tag": "reducerProject", + "items": Belt.Map.String.empty, + "stdLib": ReducerInterface_StdLib.internalStdLib, + "environment": InternalExpressionValue.defaultEnvironment, + } + project + } + + let rec touchSource = (project: t, sourceId: string): unit => { + let item = project->getItem(sourceId) + let newItem = ProjectItem.touchSource(item) + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + touchDependents(project, sourceId) + } + and touchDependents = (project: t, sourceId: string): unit => { + let _ = getDependents(project, sourceId)->Belt.Array.forEach(_, touchSource(project, _)) + } + + let getSource = (project: t, sourceId: string): option => + Belt.Map.String.get(project["items"], sourceId)->Belt.Option.map(ProjectItem.getSource) + + let setSource = (project: t, sourceId: string, value: string): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.setSource(value) + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + touchDependents(project, sourceId) + } + + let clean = (project: t, sourceId: string): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.clean + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + } + + let cleanAll = (project: t): unit => + getSourceIds(project)->Belt.Array.forEach(sourceId => clean(project, sourceId)) + + let cleanResults = (project: t, sourceId: string): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.cleanResults + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + } + + let cleanAllResults = (project: t): unit => + getSourceIds(project)->Belt.Array.forEach(sourceId => cleanResults(project, sourceId)) + + let getIncludes = (project: t, sourceId: string): ProjectItem.T.includesType => + project->getItem(sourceId)->ProjectItem.getIncludes + + let setContinues = (project: t, sourceId: string, continues: array): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.setContinues(continues) + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + touchSource(project, sourceId) + } + let getContinues = (project: t, sourceId: string): array => + ProjectItem.getContinues(project->getItem(sourceId)) + + let removeContinues = (project: t, sourceId: string): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.removeContinues + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + touchSource(project, sourceId) + } + + let getContinuation = (project: t, sourceId: string): ProjectItem.T.continuationArgumentType => + project->getItem(sourceId)->ProjectItem.getContinuation + + let setContinuation = ( + project: t, + sourceId: string, + continuation: ProjectItem.T.continuationArgumentType, + ): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.setContinuation(continuation) + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + } + + let getResultOption = (project: t, sourceId: string): ProjectItem.T.resultType => + project->getItem(sourceId)->ProjectItem.getResult + + let getResult = (project: t, sourceId: string): ProjectItem.T.resultArgumentType => + switch getResultOption(project, sourceId) { + | None => RENeedToRun->Error + | Some(result) => result + } + + let setResult = (project: t, sourceId: string, value: ProjectItem.T.resultArgumentType): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.setResult(value) + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + } + + let parseIncludes = (project: t, sourceId: string): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.parseIncludes + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + } + + let rawParse = (project: t, sourceId): unit => { + let newItem = project->getItem(sourceId)->ProjectItem.rawParse + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + } + + let getStdLib = (project: t): Reducer_Bindings.t => project["stdLib"] + let setStdLib = (project: t, value: Reducer_Bindings.t): unit => + T.Private.setFieldStdLib(project, value) + + let getEnvironment = (project: t): InternalExpressionValue.environment => project["environment"] + let setEnvironment = (project: t, value: InternalExpressionValue.environment): unit => + T.Private.setFieldEnvironment(project, value) + + let getBindings = (project: t, sourceId: string): ProjectItem.T.bindingsArgumentType => { + let those = project->getContinuation(sourceId) + let these = project->getStdLib + let ofUser = Continuation.minus(those, these) + ofUser + } + + let buildProjectAccessors = (project: t): ProjectAccessorsT.t => { + states: {continuation: Bindings.emptyBindings}, + stdLib: getStdLib(project), + environment: getEnvironment(project), + } + + let doRunWithContinuation = ( + project: t, + sourceId: string, + continuation: ProjectItem.T.continuation, + ): unit => { + let accessors = buildProjectAccessors(project) + let states = accessors.states + let newItem = project->getItem(sourceId)->ProjectItem.run(continuation, accessors) + Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) + setContinuation(project, sourceId, states.continuation) + } + + type runState = (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) + + let tryRunWithContinuation = ( + project: t, + sourceId: string, + (rPrevResult: ProjectItem.T.resultArgumentType, continuation: ProjectItem.T.continuation), + ): (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) => { + switch getResultOption(project, sourceId) { + | Some(result) => (result, getContinuation(project, sourceId)) // already ran + | None => + switch rPrevResult { + | Error(error) => { + setResult(project, sourceId, Error(error)) + (Error(error), continuation) + } + | Ok(_prevResult) => { + doRunWithContinuation(project, sourceId, continuation) + ( + getResultOption(project, sourceId)->Belt.Option.getWithDefault(rPrevResult), + getContinuation(project, sourceId), + ) + } + } + } + } + + let runAll = (project: t): unit => { + let runOrder = Topology.getRunOrder(project) + let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project)) + let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) => + tryRunWithContinuation(project, currId, currState) + ) + } + + let run = (project: t, sourceId: string): unit => { + let runOrder = Topology.getRunOrderFor(project, sourceId) + let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project)) + let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) => + tryRunWithContinuation(project, currId, currState) + ) + } + + let evaluate = (sourceCode: string) => { + let project = createProject() + setSource(project, "main", sourceCode) + runAll(project) + let those = project->getContinuation("main") + let these = project->getStdLib + let ofUser = Continuation.minus(those, these) + + (getResultOption(project, "main")->Belt.Option.getWithDefault(IEvVoid->Ok), ofUser) + } +} diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js new file mode 100644 index 00000000..e04b8ba2 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js @@ -0,0 +1,945 @@ +// Generated by Peggy 2.0.1. +// +// https://peggyjs.org/ + +"use strict"; + +function peg$subclass(child, parent) { + function C() { this.constructor = child; } + C.prototype = parent.prototype; + child.prototype = new C(); +} + +function peg$SyntaxError(message, expected, found, location) { + var self = Error.call(this, message); + // istanbul ignore next Check is a necessary evil to support older environments + if (Object.setPrototypeOf) { + Object.setPrototypeOf(self, peg$SyntaxError.prototype); + } + self.expected = expected; + self.found = found; + self.location = location; + self.name = "SyntaxError"; + return self; +} + +peg$subclass(peg$SyntaxError, Error); + +function peg$padEnd(str, targetLength, padString) { + padString = padString || " "; + if (str.length > targetLength) { return str; } + targetLength -= str.length; + padString += padString.repeat(targetLength); + return str + padString.slice(0, targetLength); +} + +peg$SyntaxError.prototype.format = function(sources) { + var str = "Error: " + this.message; + if (this.location) { + var src = null; + var k; + for (k = 0; k < sources.length; k++) { + if (sources[k].source === this.location.source) { + src = sources[k].text.split(/\r\n|\n|\r/g); + break; + } + } + var s = this.location.start; + var loc = this.location.source + ":" + s.line + ":" + s.column; + if (src) { + var e = this.location.end; + var filler = peg$padEnd("", s.line.toString().length, ' '); + var line = src[s.line - 1]; + var last = s.line === e.line ? e.column : line.length + 1; + var hatLen = (last - s.column) || 1; + str += "\n --> " + loc + "\n" + + filler + " |\n" + + s.line + " | " + line + "\n" + + filler + " | " + peg$padEnd("", s.column - 1, ' ') + + peg$padEnd("", hatLen, "^"); + } else { + str += "\n at " + loc; + } + } + return str; +}; + +peg$SyntaxError.buildMessage = function(expected, found) { + var DESCRIBE_EXPECTATION_FNS = { + literal: function(expectation) { + return "\"" + literalEscape(expectation.text) + "\""; + }, + + class: function(expectation) { + var escapedParts = expectation.parts.map(function(part) { + return Array.isArray(part) + ? classEscape(part[0]) + "-" + classEscape(part[1]) + : classEscape(part); + }); + + return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]"; + }, + + any: function() { + return "any character"; + }, + + end: function() { + return "end of input"; + }, + + other: function(expectation) { + return expectation.description; + } + }; + + function hex(ch) { + return ch.charCodeAt(0).toString(16).toUpperCase(); + } + + function literalEscape(s) { + return s + .replace(/\\/g, "\\\\") + .replace(/"/g, "\\\"") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); }); + } + + function classEscape(s) { + return s + .replace(/\\/g, "\\\\") + .replace(/\]/g, "\\]") + .replace(/\^/g, "\\^") + .replace(/-/g, "\\-") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); }); + } + + function describeExpectation(expectation) { + return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); + } + + function describeExpected(expected) { + var descriptions = expected.map(describeExpectation); + var i, j; + + descriptions.sort(); + + if (descriptions.length > 0) { + for (i = 1, j = 1; i < descriptions.length; i++) { + if (descriptions[i - 1] !== descriptions[i]) { + descriptions[j] = descriptions[i]; + j++; + } + } + descriptions.length = j; + } + + switch (descriptions.length) { + case 1: + return descriptions[0]; + + case 2: + return descriptions[0] + " or " + descriptions[1]; + + default: + return descriptions.slice(0, -1).join(", ") + + ", or " + + descriptions[descriptions.length - 1]; + } + } + + function describeFound(found) { + return found ? "\"" + literalEscape(found) + "\"" : "end of input"; + } + + return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; +}; + +function peg$parse(input, options) { + options = options !== undefined ? options : {}; + + var peg$FAILED = {}; + var peg$source = options.grammarSource; + + var peg$startRuleFunctions = { start: peg$parsestart }; + var peg$startRuleFunction = peg$parsestart; + + var peg$c0 = "#include"; + var peg$c1 = "'"; + var peg$c2 = "\""; + var peg$c3 = "//"; + var peg$c4 = "/*"; + var peg$c5 = "*/"; + + var peg$r0 = /^[^']/; + var peg$r1 = /^[^"]/; + var peg$r2 = /^[^*]/; + var peg$r3 = /^[ \t]/; + var peg$r4 = /^[\n\r]/; + var peg$r5 = /^[^\r\n]/; + + var peg$e0 = peg$literalExpectation("#include", false); + var peg$e1 = peg$otherExpectation("string"); + var peg$e2 = peg$literalExpectation("'", false); + var peg$e3 = peg$classExpectation(["'"], true, false); + var peg$e4 = peg$literalExpectation("\"", false); + var peg$e5 = peg$classExpectation(["\""], true, false); + var peg$e6 = peg$literalExpectation("//", false); + var peg$e7 = peg$literalExpectation("/*", false); + var peg$e8 = peg$classExpectation(["*"], true, false); + var peg$e9 = peg$literalExpectation("*/", false); + var peg$e10 = peg$otherExpectation("white space"); + var peg$e11 = peg$classExpectation([" ", "\t"], false, false); + var peg$e12 = peg$otherExpectation("newline"); + var peg$e13 = peg$classExpectation(["\n", "\r"], false, false); + var peg$e14 = peg$classExpectation(["\r", "\n"], true, false); + + var peg$f0 = function(head, tail) {return [head, ...tail].filter( e => e != '');}; + var peg$f1 = function() {return [];}; + var peg$f2 = function(characters) {return characters.join('');}; + var peg$f3 = function(characters) {return characters.join('');}; + var peg$f4 = function() { return '';}; + var peg$f5 = function() { return '';}; + var peg$currPos = 0; + var peg$savedPos = 0; + var peg$posDetailsCache = [{ line: 1, column: 1 }]; + var peg$maxFailPos = 0; + var peg$maxFailExpected = []; + var peg$silentFails = 0; + + var peg$resultsCache = {}; + + var peg$result; + + if ("startRule" in options) { + if (!(options.startRule in peg$startRuleFunctions)) { + throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); + } + + peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; + } + + function text() { + return input.substring(peg$savedPos, peg$currPos); + } + + function offset() { + return peg$savedPos; + } + + function range() { + return { + source: peg$source, + start: peg$savedPos, + end: peg$currPos + }; + } + + function location() { + return peg$computeLocation(peg$savedPos, peg$currPos); + } + + function expected(description, location) { + location = location !== undefined + ? location + : peg$computeLocation(peg$savedPos, peg$currPos); + + throw peg$buildStructuredError( + [peg$otherExpectation(description)], + input.substring(peg$savedPos, peg$currPos), + location + ); + } + + function error(message, location) { + location = location !== undefined + ? location + : peg$computeLocation(peg$savedPos, peg$currPos); + + throw peg$buildSimpleError(message, location); + } + + function peg$literalExpectation(text, ignoreCase) { + return { type: "literal", text: text, ignoreCase: ignoreCase }; + } + + function peg$classExpectation(parts, inverted, ignoreCase) { + return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; + } + + function peg$anyExpectation() { + return { type: "any" }; + } + + function peg$endExpectation() { + return { type: "end" }; + } + + function peg$otherExpectation(description) { + return { type: "other", description: description }; + } + + function peg$computePosDetails(pos) { + var details = peg$posDetailsCache[pos]; + var p; + + if (details) { + return details; + } else { + p = pos - 1; + while (!peg$posDetailsCache[p]) { + p--; + } + + details = peg$posDetailsCache[p]; + details = { + line: details.line, + column: details.column + }; + + while (p < pos) { + if (input.charCodeAt(p) === 10) { + details.line++; + details.column = 1; + } else { + details.column++; + } + + p++; + } + + peg$posDetailsCache[pos] = details; + + return details; + } + } + + function peg$computeLocation(startPos, endPos) { + var startPosDetails = peg$computePosDetails(startPos); + var endPosDetails = peg$computePosDetails(endPos); + + return { + source: peg$source, + start: { + offset: startPos, + line: startPosDetails.line, + column: startPosDetails.column + }, + end: { + offset: endPos, + line: endPosDetails.line, + column: endPosDetails.column + } + }; + } + + function peg$fail(expected) { + if (peg$currPos < peg$maxFailPos) { return; } + + if (peg$currPos > peg$maxFailPos) { + peg$maxFailPos = peg$currPos; + peg$maxFailExpected = []; + } + + peg$maxFailExpected.push(expected); + } + + function peg$buildSimpleError(message, location) { + return new peg$SyntaxError(message, null, null, location); + } + + function peg$buildStructuredError(expected, found, location) { + return new peg$SyntaxError( + peg$SyntaxError.buildMessage(expected, found), + expected, + found, + location + ); + } + + function peg$parsestart() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 10 + 0; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = []; + s2 = peg$parsenewLine(); + if (s2 === peg$FAILED) { + s2 = peg$parse_(); + if (s2 === peg$FAILED) { + s2 = peg$parsecomment(); + if (s2 === peg$FAILED) { + s2 = peg$parsedelimitedComment(); + } + } + } + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = peg$parsenewLine(); + if (s2 === peg$FAILED) { + s2 = peg$parse_(); + if (s2 === peg$FAILED) { + s2 = peg$parsecomment(); + if (s2 === peg$FAILED) { + s2 = peg$parsedelimitedComment(); + } + } + } + } + s2 = peg$parseincludes(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$parsenewLine(); + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$parsenewLine(); + } + s4 = peg$parseignore(); + s0 = s2; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseincludes() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 10 + 1; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseincludeStatement(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = []; + s5 = peg$parsenewLine(); + if (s5 !== peg$FAILED) { + while (s5 !== peg$FAILED) { + s4.push(s5); + s5 = peg$parsenewLine(); + } + } else { + s4 = peg$FAILED; + } + if (s4 !== peg$FAILED) { + s5 = peg$parseincludeStatement(); + if (s5 !== peg$FAILED) { + s3 = s5; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = []; + s5 = peg$parsenewLine(); + if (s5 !== peg$FAILED) { + while (s5 !== peg$FAILED) { + s4.push(s5); + s5 = peg$parsenewLine(); + } + } else { + s4 = peg$FAILED; + } + if (s4 !== peg$FAILED) { + s5 = peg$parseincludeStatement(); + if (s5 !== peg$FAILED) { + s3 = s5; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f0(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parseignore(); + peg$savedPos = s0; + s1 = peg$f1(); + s0 = s1; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseincludeStatement() { + var s0, s1, s2, s3, s4, s5, s6; + + var key = peg$currPos * 10 + 2; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = []; + s2 = peg$parse_(); + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = peg$parse_(); + } + if (input.substr(peg$currPos, 8) === peg$c0) { + s2 = peg$c0; + peg$currPos += 8; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e0); } + } + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$parse_(); + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$parse_(); + } + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = []; + s6 = peg$parse_(); + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = peg$parse_(); + } + s0 = s4; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parsecomment(); + if (s0 === peg$FAILED) { + s0 = peg$parsedelimitedComment(); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsestring() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 10 + 3; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 39) { + s2 = peg$c1; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e2); } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r0.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e3); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r0.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e3); } + } + } + if (input.charCodeAt(peg$currPos) === 39) { + s4 = peg$c1; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e2); } + } + if (s4 !== peg$FAILED) { + s1 = s3; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f2(s1); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 34) { + s2 = peg$c2; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e4); } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r1.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e5); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r1.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e5); } + } + } + if (input.charCodeAt(peg$currPos) === 34) { + s4 = peg$c2; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e4); } + } + if (s4 !== peg$FAILED) { + s1 = s3; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f3(s1); + } + s0 = s1; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e1); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseignore() { + var s0, s1; + + var key = peg$currPos * 10 + 4; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = []; + s1 = peg$parseany(); + if (s1 === peg$FAILED) { + s1 = peg$parsenewLine(); + if (s1 === peg$FAILED) { + s1 = peg$parse_(); + } + } + while (s1 !== peg$FAILED) { + s0.push(s1); + s1 = peg$parseany(); + if (s1 === peg$FAILED) { + s1 = peg$parsenewLine(); + if (s1 === peg$FAILED) { + s1 = peg$parse_(); + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecomment() { + var s0, s1, s2, s3; + + var key = peg$currPos * 10 + 5; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c3) { + s1 = peg$c3; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e6); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parseany(); + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parseany(); + } + peg$savedPos = s0; + s0 = peg$f4(); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsedelimitedComment() { + var s0, s1, s2, s3; + + var key = peg$currPos * 10 + 6; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c4) { + s1 = peg$c4; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e7); } + } + if (s1 !== peg$FAILED) { + s2 = []; + if (peg$r2.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e8); } + } + while (s3 !== peg$FAILED) { + s2.push(s3); + if (peg$r2.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e8); } + } + } + if (input.substr(peg$currPos, 2) === peg$c5) { + s3 = peg$c5; + peg$currPos += 2; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e9); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f5(); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parse_() { + var s0, s1; + + var key = peg$currPos * 10 + 7; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (peg$r3.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e11); } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e10); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsenewLine() { + var s0, s1; + + var key = peg$currPos * 10 + 8; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (peg$r4.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e13); } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e12); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseany() { + var s0; + + var key = peg$currPos * 10 + 9; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (peg$r5.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e14); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + peg$result = peg$startRuleFunction(); + + if (peg$result !== peg$FAILED && peg$currPos === input.length) { + return peg$result; + } else { + if (peg$result !== peg$FAILED && peg$currPos < input.length) { + peg$fail(peg$endExpectation()); + } + + throw peg$buildStructuredError( + peg$maxFailExpected, + peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, + peg$maxFailPos < input.length + ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) + : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) + ); + } +} + +module.exports = { + SyntaxError: peg$SyntaxError, + parse: peg$parse +}; diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy new file mode 100644 index 00000000..dc65fac4 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy @@ -0,0 +1,40 @@ +// Includes are at the start of the file, before any other code. +// There might be some comments before or between the includes. +// #include "string" +// #include "string2" + +start + = (newLine/_/comment/delimitedComment)* @includes newLine* ignore + +includes + = head:includeStatement tail:(newLine+ @includeStatement)* + {return [head, ...tail].filter( e => e != '');} + / ignore + {return [];} + +includeStatement + = _* '#include' _* @string _* + / comment + / delimitedComment + +string 'string' + = characters:("'" @([^'])* "'") {return characters.join('');} + / characters:('"' @([^"])* '"') {return characters.join('');} + +ignore = (any / newLine / _)* + +comment += '//'any* +{ return '';} + +delimitedComment += '/*' ([^*]*) '*/' +{ return '';} + +_ "white space" + = [ \t] + +newLine "newline" + = [\n\r] + +any = [^\r\n] diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res new file mode 100644 index 00000000..f6b17901 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res @@ -0,0 +1,15 @@ +@module("./ReducerProject_IncludeParser.js") external parse__: string => array = "parse" + +let parseIncludes = (expr: string): result, Reducer_ErrorValue.errorValue> => + try { + let answer = parse__(expr) + // let logEntry = answer->Js.Array2.joinWith(",") + // `parseIncludes: ${logEntry} for expr: ${expr}`->Js.log + answer->Ok + } catch { + | Js.Exn.Error(obj) => + RESyntaxError( + Belt.Option.getExn(Js.Exn.message(obj)), + Reducer_Peggy_Parse.syntaxErrorToLocation(obj)->Some, + )->Error + } diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectAccessors_T.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectAccessors_T.res new file mode 100644 index 00000000..9cc06e8f --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectAccessors_T.res @@ -0,0 +1,40 @@ +module ProjectItemT = ReducerProject_ProjectItem_T +module Bindings = Reducer_Bindings +module ExpressionT = Reducer_Expression_T +module InternalExpressionValue = ReducerInterface_InternalExpressionValue + +type states = {mutable continuation: ProjectItemT.continuationArgumentType} + +type projectAccessors = { + stdLib: Reducer_Bindings.t, + environment: ExpressionT.environment, + states: states, +} + +type t = projectAccessors + +let identityAccessors: t = { + // We need the states at the end of the runtime. + // Accessors can be modified but states will stay as the same pointer + states: { + continuation: Bindings.emptyBindings, + }, + stdLib: ReducerInterface_StdLib.internalStdLib, + environment: InternalExpressionValue.defaultEnvironment, +} + +let identityAccessorsWithEnvironment = (environment): t => { + states: { + continuation: Bindings.emptyBindings, + }, + stdLib: ReducerInterface_StdLib.internalStdLib, + environment: environment, +} + +// to support change of environment in runtime +let setEnvironment = (this: t, environment: ExpressionT.environment): t => { + { + ...this, + environment: environment, + } +} diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res new file mode 100644 index 00000000..2608e344 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res @@ -0,0 +1,170 @@ +// TODO: Use actual types instead of aliases in public functions +// TODO: Use topological sorting to prevent unnecessary runs +module Bindings = Reducer_Bindings +module Continuation = ReducerInterface_Value_Continuation +module ExpressionT = Reducer_Expression_T +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T +module ReducerFnT = ReducerProject_ReducerFn_T +module T = ReducerProject_ProjectItem_T + +type projectItem = T.projectItem +type t = T.t + +let emptyItem = T.ProjectItem({ + source: "", + rawParse: None, + expression: None, + continuation: Bindings.emptyBindings, + result: None, + continues: [], + includes: []->Ok, +}) +// source -> rawParse -> includes -> expression -> continuation -> result + +let getSource = (T.ProjectItem(r)): T.sourceType => r.source +let getRawParse = (T.ProjectItem(r)): T.rawParseType => r.rawParse +let getExpression = (T.ProjectItem(r)): T.expressionType => r.expression +let getContinuation = (T.ProjectItem(r)): T.continuationArgumentType => r.continuation +let getResult = (T.ProjectItem(r)): T.resultType => r.result + +let getContinues = (T.ProjectItem(r)): T.continuesType => r.continues +let getIncludes = (T.ProjectItem(r)): T.includesType => r.includes + +let touchSource = (this: t): t => { + let T.ProjectItem(r) = emptyItem + T.ProjectItem({ + ...r, + includes: getIncludes(this), + continues: getContinues(this), + source: getSource(this), + }) +} +let touchRawParse = (this: t): t => { + let T.ProjectItem(r) = emptyItem + T.ProjectItem({ + ...r, + continues: getContinues(this), + source: getSource(this), + rawParse: getRawParse(this), + includes: getIncludes(this), + }) +} +let touchExpression = (this: t): t => { + let T.ProjectItem(r) = emptyItem + T.ProjectItem({ + ...r, + continues: getContinues(this), + source: getSource(this), + rawParse: getRawParse(this), + includes: getIncludes(this), + expression: getExpression(this), + }) +} + +let setSource = (T.ProjectItem(r): t, source: T.sourceArgumentType): t => + T.ProjectItem({...r, source: source})->touchSource + +let setRawParse = (T.ProjectItem(r): t, rawParse: T.rawParseArgumentType): t => + T.ProjectItem({...r, rawParse: Some(rawParse)})->touchRawParse + +let setExpression = (T.ProjectItem(r): t, expression: T.expressionArgumentType): t => + T.ProjectItem({...r, expression: Some(expression)})->touchExpression + +let setContinuation = (T.ProjectItem(r): t, continuation: T.continuationArgumentType): t => { + T.ProjectItem({...r, continuation: continuation}) +} + +let setResult = (T.ProjectItem(r): t, result: T.resultArgumentType): t => T.ProjectItem({ + ...r, + result: Some(result), +}) + +let cleanResults = touchExpression + +let clean = (this: t): t => { + let T.ProjectItem(r) = emptyItem + T.ProjectItem({ + ...r, + source: getSource(this), + continuation: getContinuation(this), + result: getResult(this), + }) +} + +let getImmediateDependencies = (this: t): T.includesType => + getIncludes(this)->Belt.Result.map(Js.Array2.concat(_, getContinues(this))) + +let setContinues = (T.ProjectItem(r): t, continues: array): t => + T.ProjectItem({...r, continues: continues})->touchSource +let removeContinues = (T.ProjectItem(r): t): t => T.ProjectItem({...r, continues: []})->touchSource + +let setIncludes = (T.ProjectItem(r): t, includes: T.includesType): t => T.ProjectItem({ + ...r, + includes: includes, +}) + +//TODO: forward parse errors to the user +let parseIncludes = (this: t): t => + setIncludes(this, getSource(this)->ReducerProject_ParseIncludes.parseIncludes) + +let doRawParse = (this: t): T.rawParseArgumentType => this->getSource->Reducer_Peggy_Parse.parse + +let rawParse = (this: t): t => + this->getRawParse->E.O2.defaultFn(() => doRawParse(this))->setRawParse(this, _) + +let doBuildExpression = (this: t): T.expressionType => + this + ->getRawParse + ->Belt.Option.map(o => o->Belt.Result.map(r => r->Reducer_Peggy_ToExpression.fromNode)) + +let buildExpression = (this: t): t => { + let withRawParse: t = this->rawParse + switch withRawParse->getExpression { + | Some(_) => withRawParse + | None => + withRawParse + ->doBuildExpression + ->Belt.Option.map(setExpression(withRawParse, _)) + ->E.O2.defaultFn(() => withRawParse) + } +} + +let wrappedReducer = ( + rExpression: T.expressionArgumentType, + aContinuation: T.continuation, + accessors: ProjectAccessorsT.t, +): T.resultArgumentType => { + Belt.Result.flatMap( + rExpression, + Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors), + ) +} + +let doBuildResult = ( + this: t, + aContinuation: T.continuation, + accessors: ProjectAccessorsT.t, +): T.resultType => + this + ->getExpression + ->Belt.Option.map( + Belt.Result.flatMap( + _, + Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors), + ), + ) + +let buildResult = (this: t, aContinuation: T.continuation, accessors: ProjectAccessorsT.t): t => { + let withExpression: t = this->buildExpression + switch withExpression->getResult { + | Some(_) => withExpression + | None => + withExpression + ->doBuildResult(aContinuation, accessors) + ->Belt.Option.map(setResult(withExpression, _)) + ->E.O2.defaultFn(() => withExpression) + } +} + +let run = buildResult diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res new file mode 100644 index 00000000..6fe251d2 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res @@ -0,0 +1,36 @@ +module Parse = Reducer_Peggy_Parse +module ExpressionT = Reducer_Expression_T +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +open Reducer_ErrorValue + +type sourceArgumentType = string +type sourceType = string +type rawParseArgumentType = result +type rawParseType = option +type expressionArgumentType = result +type expressionType = option +type continuation = InternalExpressionValue.nameSpace +type continuationArgumentType = InternalExpressionValue.nameSpace +type continuationType = option +type continuationResultType = option> +type bindingsArgumentType = InternalExpressionValue.nameSpace +type bindingsType = option +type resultArgumentType = result +type resultType = option +type continuesArgumentType = array +type continuesType = array +type includesArgumentType = string +type includesType = result, errorValue> + +type projectItem = + | ProjectItem({ + source: sourceType, + rawParse: rawParseType, + expression: expressionType, + continuation: continuationArgumentType, + result: resultType, + continues: continuesType, + includes: includesType, + }) + +type t = projectItem diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ReducerFn_T.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ReducerFn_T.res new file mode 100644 index 00000000..0b401fcb --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ReducerFn_T.res @@ -0,0 +1,9 @@ +module ExpressionT = Reducer_Expression_T +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T + +type t = ( + ExpressionT.t, + ExpressionT.bindings, + ProjectAccessorsT.t, +) => result diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_T.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_T.res new file mode 100644 index 00000000..a9411c43 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_T.res @@ -0,0 +1,34 @@ +module ProjectItem = ReducerProject_ProjectItem +module ExpressionT = Reducer_Expression_T +module ProjectAccessorsT = ReducerProject_ProjectAccessors_T + +@genType.opaque +type project = {"tag": string} +//re-export +@genType +type t = project + +module Private = { + type internalProject = { + "tag": string, + "items": Belt.Map.String.t, + "stdLib": Reducer_Bindings.t, + "environment": ExpressionT.environment, + } + type t = internalProject + + @set + external setFieldItems: (t, Belt.Map.String.t) => unit = "items" + @set + external setFieldStdLib: (t, Reducer_Bindings.t) => unit = "stdLib" + @set + external setFieldEnvironment: (t, ExpressionT.environment) => unit = "stdLib" + + external castFromInternalProject: t => project = "%identity" + external castToInternalProject: project => t = "%identity" + + let getSourceIds = (this: t): array => Belt.Map.String.keysToArray(this["items"]) + + let getItem = (this: t, sourceId: string) => + Belt.Map.String.getWithDefault(this["items"], sourceId, ProjectItem.emptyItem) +} diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_Topology.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_Topology.res new file mode 100644 index 00000000..f23c19c1 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_Topology.res @@ -0,0 +1,72 @@ +module ProjectItem = ReducerProject_ProjectItem +module T = ReducerProject_T +type t = T.Private.t + +let getSourceIds = T.Private.getSourceIds +let getItem = T.Private.getItem + +let getImmediateDependencies = (this: t, sourceId: string): ProjectItem.T.includesType => + getItem(this, sourceId)->ProjectItem.getImmediateDependencies + +type topologicalSortState = (Belt.Map.String.t, list) +let rec topologicalSortUtil = ( + this: t, + sourceId: string, + state: topologicalSortState, +): topologicalSortState => { + let dependencies = getImmediateDependencies(this, sourceId)->Belt.Result.getWithDefault([]) + let (visited, stack) = state + let myVisited = Belt.Map.String.set(visited, sourceId, true) + let (newVisited, newStack) = dependencies->Belt.Array.reduce((myVisited, stack), ( + (currVisited, currStack), + dependency, + ) => { + if !Belt.Map.String.getWithDefault(currVisited, dependency, false) { + topologicalSortUtil(this, dependency, (currVisited, currStack)) + } else { + (currVisited, currStack) + } + }) + (newVisited, list{sourceId, ...newStack}) +} + +let getTopologicalSort = (this: t): array => { + let (_visited, stack) = getSourceIds(this)->Belt.Array.reduce((Belt.Map.String.empty, list{}), ( + (currVisited, currStack), + currId, + ) => + if !Belt.Map.String.getWithDefault(currVisited, currId, false) { + topologicalSortUtil(this, currId, (currVisited, currStack)) + } else { + (currVisited, currStack) + } + ) + Belt.List.reverse(stack)->Belt.List.toArray +} + +let getTopologicalSortFor = (this: t, sourceId) => { + let runOrder = getTopologicalSort(this) + let index = runOrder->Js.Array2.indexOf(sourceId) + let after = Belt.Array.sliceToEnd(runOrder, index + 1) + let before = Js.Array2.slice(runOrder, ~start=0, ~end_=index + 1) + (before, after) +} + +let getRunOrder = getTopologicalSort + +let getRunOrderFor = (this: t, sourceId: string) => { + let (runOrder, _) = getTopologicalSortFor(this, sourceId) + runOrder +} + +let getDependencies = (this: t, sourceId: string): array => { + let runOrder = getRunOrderFor(this, sourceId) + + let _ = Js.Array2.pop(runOrder) + runOrder +} + +let getDependents = (this: t, sourceId: string): array => { + let (_, dependents) = getTopologicalSortFor(this, sourceId) + dependents +} diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index a1f5afe6..428fb0cd 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -1,3 +1,4 @@ +open ForTS__Types /* This is meant as a file to contain @genType declarations as needed for Typescript. I would ultimately want to have all @genType declarations here, vs. other files, but @@ -7,59 +8,32 @@ would be preferable. The below few seem to work fine. In the future there's definitely more work to do here. */ -@genType -type samplingParams = GenericDist.env +// For backwards compatibility: +//Alternatives if one wants to keep the old habits +@genType type samplingParams = environment +@genType type squiggleValue_Dist = squiggleValue_Distribution //alternative +@genType type genericDist = squiggleValue_Distribution //alternative +@genType type sampleSetDist = sampleSetDistribution //alternative +@genType type symbolicDist = symbolicDistribution //alternative +@genType type resultDist = result //alternative +@genType type resultFloat = result //alternative +@genType type resultString = result //alternative @genType -type genericDist = DistributionTypes.genericDist +let makeSampleSetDist: array => result< + sampleSetDist, + SampleSetDist.sampleSetError, +> = SampleSetDist.make +//TODO: ForTS Interface module candid @genType -type sampleSetDist = SampleSetDist.t - -@genType -type symbolicDist = SymbolicDistTypes.symbolicDist - -@genType -type distributionError = DistributionTypes.error - -@genType -type resultDist = result - -@genType -type resultFloat = result - -@genType -type resultString = result - -@genType -let makeSampleSetDist = SampleSetDist.make - -@genType -let evaluate = Reducer.evaluate - -@genType -let evaluateUsingOptions = Reducer.evaluateUsingOptions - -@genType -let parse = Reducer_Peggy_Parse.parse - -@genType -let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings - -@genType -type externalBindings = Reducer.externalBindings - -@genType -type expressionValue = ReducerInterface_ExternalExpressionValue.t - -@genType -type recordEV = ReducerInterface_ExternalExpressionValue.record - -@genType -type errorValue = Reducer_ErrorValue.errorValue - -@genType -let toPointSet = GenericDist.toPointSet +let toPointSet: ( + squiggleValue_Distribution, + ~xyPointLength: int, + ~sampleCount: int, + ~xSelection: DistributionTypes.DistributionOperation.pointsetXSelection=?, + unit, +) => result = GenericDist.toPointSet @genType type mixedShape = PointSetTypes.mixedShape @@ -71,31 +45,14 @@ type discreteShape = PointSetTypes.discreteShape type continuousShape = PointSetTypes.continuousShape @genType -let errorValueToString = Reducer_ErrorValue.errorToString +let distributionErrorToString = ForTS_Distribution_Error.toString @genType -let distributionErrorToString = DistributionTypes.Error.toString +let defaultSamplingEnv = ForTS_Distribution.defaultEnvironment -@genType -type lambdaValue = ReducerInterface_ExternalExpressionValue.lambdaValue +// Umur: opaqe types +// @genType +// type declarationArg = Declaration.arg -@genType -type lambdaDeclaration = ReducerInterface_ExternalExpressionValue.lambdaDeclaration - -@genType -let defaultSamplingEnv = DistributionOperation.defaultEnv - -@genType -type environment = ReducerInterface_ExternalExpressionValue.environment - -@genType -let defaultEnvironment = ReducerInterface_ExternalExpressionValue.defaultEnvironment - -@genType -let foreignFunctionInterface = Reducer.foreignFunctionInterface - -@genType -type declarationArg = Declaration.arg - -@genType -type declaration<'a> = Declaration.declaration<'a> +// @genType +// type declaration<'a> = Declaration.declaration<'a>