fix more tests; FR improvements/refactorings

This commit is contained in:
Vyacheslav Matyukhin 2022-09-19 15:00:38 +04:00
parent 6aa2280543
commit 271303fb5f
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
56 changed files with 810 additions and 1260 deletions

View File

@ -31,9 +31,7 @@ describe("Bindings", () => {
describe("extend", () => { describe("extend", () => {
let value2 = Reducer_T.IEvNumber(5.) let value2 = Reducer_T.IEvNumber(5.)
let extendedBindings = bindings let extendedBindings = bindings->Bindings.extend->Bindings.set("value", value2)
->Bindings.extend
->Bindings.set("value", value2)
test("get on extended", () => { test("get on extended", () => {
expect(extendedBindings->Bindings.get("value")) == Some(value2) expect(extendedBindings->Bindings.get("value")) == Some(value2)

View File

@ -144,3 +144,4 @@
// let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)}) // let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)})
// testMacroEval([("y", IEvNumber(666.))], callLambdaExpression, "Ok(667)") // testMacroEval([("y", IEvNumber(666.))], callLambdaExpression, "Ok(667)")
// }) // })

View File

@ -35,13 +35,9 @@ describe("Namespace", () => {
let x2 = makeValue(20.) let x2 = makeValue(20.)
let x3 = makeValue(30.) let x3 = makeValue(30.)
let x4 = makeValue(40.) let x4 = makeValue(40.)
let ns1 = Namespace.make() let ns1 = Namespace.make()->Namespace.set("x1", x1)->Namespace.set("x2", x2)
->Namespace.set("x1", x1) let ns2 = Namespace.make()->Namespace.set("x3", x3)->Namespace.set("x4", x4)
->Namespace.set("x2", x2)
let ns2 = Namespace.make()
->Namespace.set("x3", x3)
->Namespace.set("x4", x4)
let nsMerged = Namespace.mergeMany([ns, ns1, ns2]) let nsMerged = Namespace.mergeMany([ns, ns1, ns2])
test("merge many 1", () => { test("merge many 1", () => {

View File

@ -38,58 +38,22 @@ describe("Peggy parse", () => {
testParse("1 * 2 / 3", "{(:divide (: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", "{(:multiply (:divide 1 2) 3)}")
testParse("1 / 2 / 3", "{(:divide (:divide 1 2) 3)}") testParse("1 / 2 / 3", "{(:divide (:divide 1 2) 3)}")
testParse( testParse("1 * 2 + 3 * 4", "{(:add (:multiply 1 2) (:multiply 3 4))}")
"1 * 2 + 3 * 4", testParse("1 * 2 - 3 * 4", "{(:subtract (:multiply 1 2) (:multiply 3 4))}")
"{(:add (: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( testParse("1 * 2 + 3 .* 4", "{(:add (:multiply 1 2) (:dotMultiply 3 4))}")
"1 * 2 - 3 * 4", testParse("1 * 2 + 3 / 4", "{(:add (:multiply 1 2) (:divide 3 4))}")
"{(:subtract (:multiply 1 2) (:multiply 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( testParse("1 * 2 - 3 / 4", "{(:subtract (:multiply 1 2) (:divide 3 4))}")
"1 * 2 .+ 3 * 4", testParse("1 * 2 - 3 ./ 4", "{(:subtract (:multiply 1 2) (:dotDivide 3 4))}")
"{(:dotAdd (:multiply 1 2) (:multiply 3 4))}", testParse("1 * 2 - 3 * 4^5", "{(:subtract (:multiply 1 2) (:multiply 3 (:pow 4 5)))}")
)
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( testParse(
"1 * 2 - 3 * 4^5^6", "1 * 2 - 3 * 4^5^6",
"{(:subtract (:multiply 1 2) (:multiply 3 (:pow (:pow 4 5) 6)))}", "{(:subtract (:multiply 1 2) (:multiply 3 (:pow (:pow 4 5) 6)))}",
) )
testParse( testParse("1 * -a[-2]", "{(:multiply 1 (:unaryMinus (:$_atIndex_$ :a (:unaryMinus 2))))}")
"1 * -a[-2]",
"{(:multiply 1 (:unaryMinus (:$_atIndex_$ :a (:unaryMinus 2))))}",
)
}) })
describe("multi-line", () => { describe("multi-line", () => {
@ -111,25 +75,13 @@ describe("Peggy parse", () => {
describe("arrays", () => { describe("arrays", () => {
testParse("[]", "{[]}") testParse("[]", "{[]}")
testParse("[0, 1, 2]", "{[0; 1; 2]}") testParse("[0, 1, 2]", "{[0; 1; 2]}")
testParse( testParse("['hello', 'world']", "{['hello'; 'world']}")
"['hello', 'world']", testParse("([0,1,2])[1]", "{(:$_atIndex_$ [0; 1; 2] 1)}")
"{['hello'; 'world']}",
)
testParse(
"([0,1,2])[1]",
"{(:$_atIndex_$ [0; 1; 2] 1)}",
)
}) })
describe("records", () => { describe("records", () => {
testParse( testParse("{a: 1, b: 2}", "{{'a': 1, 'b': 2}}")
"{a: 1, b: 2}", testParse("{1+0: 1, 2+0: 2}", "{{(:add 1 0): 1, (:add 2 0): 2}}") // key can be any expression
"{{'a': 1, 'b': 2}}",
)
testParse(
"{1+0: 1, 2+0: 2}",
"{{(:add 1 0): 1, (:add 2 0): 2}}",
) // key can be any expression
testParse("record.property", "{(:$_atIndex_$ :record 'property')}") testParse("record.property", "{(:$_atIndex_$ :record 'property')}")
}) })
@ -137,10 +89,7 @@ describe("Peggy parse", () => {
//function call, array and record access are post operators with higher priority than unary 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 (:b 1)))}")
testParse("a==!b[1]", "{(:equal :a (:not (:$_atIndex_$ :b 1)))}") testParse("a==!b[1]", "{(:equal :a (:not (:$_atIndex_$ :b 1)))}")
testParse( testParse("a==!b.one", "{(:equal :a (:not (:$_atIndex_$ :b 'one')))}")
"a==!b.one",
"{(:equal :a (:not (:$_atIndex_$ :b 'one')))}",
)
}) })
describe("comments", () => { describe("comments", () => {
@ -167,14 +116,8 @@ describe("Peggy parse", () => {
}) })
describe("if then else", () => { describe("if then else", () => {
testParse( testParse("if true then 2 else 3", "{(::$$_ternary_$$ true {2} {3})}")
"if true then 2 else 3", testParse("if false then {2} else {3}", "{(::$$_ternary_$$ false {2} {3})}")
"{(::$$_ternary_$$ true {2} {3})}",
)
testParse(
"if false then {2} else {3}",
"{(::$$_ternary_$$ false {2} {3})}",
)
testParse( testParse(
"if false then {2} else if false then {4} else {5}", "if false then {2} else if false then {4} else {5}",
"{(::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5}))}", "{(::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5}))}",
@ -189,51 +132,18 @@ describe("Peggy parse", () => {
testParse("a && b || c && d", "{(:or (:and :a :b) (:and :c :d))}") 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", "{(: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 (:equal :b :c)) :d)}")
testParse( testParse("a && b!=c || d", "{(:or (:and :a (:unequal :b :c)) :d)}")
"a && b!=c || d", testParse("a && !(b==c) || d", "{(:or (:and :a (:not (:equal :b :c))) :d)}")
"{(:or (:and :a (:unequal :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( testParse("a && b<=c || d", "{(:or (:and :a (:smallerEq :b :c)) :d)}")
"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", "{(:or (:and :a (:larger :b :c)) :d)}")
testParse( testParse("a && b<c || d", "{(:or (:and :a (:smaller :b :c)) :d)}")
"a && b<c || d", testParse("a && b<c[i] || d", "{(:or (:and :a (:smaller :b (:$_atIndex_$ :c :i))) :d)}")
"{(:or (:and :a (:smaller :b :c)) :d)}", testParse("a && b<c.i || d", "{(:or (:and :a (:smaller :b (:$_atIndex_$ :c 'i'))) :d)}")
) testParse("a && b<c(i) || d", "{(:or (:and :a (:smaller :b (:c :i))) :d)}")
testParse( testParse("a && b<1+2 || d", "{(:or (:and :a (:smaller :b (:add 1 2))) :d)}")
"a && b<c[i] || d", testParse("a && b<1+2*3 || d", "{(:or (:and :a (:smaller :b (:add 1 (:multiply 2 3)))) :d)}")
"{(:or (:and :a (:smaller :b (:$_atIndex_$ :c :i))) :d)}",
)
testParse(
"a && b<c.i || d",
"{(:or (:and :a (:smaller :b (:$_atIndex_$ :c 'i'))) :d)}",
)
testParse(
"a && b<c(i) || d",
"{(:or (:and :a (:smaller :b (:c :i))) :d)}",
)
testParse(
"a && b<1+2 || d",
"{(:or (:and :a (:smaller :b (:add 1 2))) :d)}",
)
testParse(
"a && b<1+2*3 || d",
"{(:or (:and :a (:smaller :b (:add 1 (:multiply 2 3)))) :d)}",
)
testParse( testParse(
"a && b<1+2*-3+4 || d", "a && b<1+2*-3+4 || d",
"{(:or (:and :a (:smaller :b (:add (:add 1 (:multiply 2 (:unaryMinus 3))) 4))) :d)}", "{(:or (:and :a (:smaller :b (:add (:add 1 (:multiply 2 (:unaryMinus 3))) 4))) :d)}",
@ -247,19 +157,13 @@ describe("Peggy parse", () => {
describe("pipe", () => { describe("pipe", () => {
testParse("1 -> add(2)", "{(:add 1 2)}") testParse("1 -> add(2)", "{(:add 1 2)}")
testParse("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}") testParse("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}")
testParse( testParse("-a[1] -> add(2)", "{(:add (:unaryMinus (:$_atIndex_$ :a 1)) 2)}")
"-a[1] -> add(2)",
"{(:add (:unaryMinus (:$_atIndex_$ :a 1)) 2)}",
)
testParse("-f(1) -> add(2)", "{(:add (:unaryMinus (:f 1)) 2)}") testParse("-f(1) -> add(2)", "{(:add (:unaryMinus (:f 1)) 2)}")
testParse("1 + 2 -> add(3)", "{(:add 1 (:add 2 3))}") testParse("1 + 2 -> add(3)", "{(:add 1 (:add 2 3))}")
testParse("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}") testParse("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}")
testParse("1 -> subtract(2)", "{(:subtract 1 2)}") testParse("1 -> subtract(2)", "{(:subtract 1 2)}")
testParse("-1 -> subtract(2)", "{(:subtract (:unaryMinus 1) 2)}") testParse("-1 -> subtract(2)", "{(:subtract (:unaryMinus 1) 2)}")
testParse( testParse("1 -> subtract(2) * 3", "{(:multiply (:subtract 1 2) 3)}")
"1 -> subtract(2) * 3",
"{(:multiply (:subtract 1 2) 3)}",
)
}) })
describe("elixir pipe", () => { describe("elixir pipe", () => {
@ -269,10 +173,7 @@ describe("Peggy parse", () => {
describe("to", () => { describe("to", () => {
testParse("1 to 2", "{(:credibleIntervalToDistribution 1 2)}") testParse("1 to 2", "{(:credibleIntervalToDistribution 1 2)}")
testParse( testParse("-1 to -2", "{(:credibleIntervalToDistribution (:unaryMinus 1) (:unaryMinus 2))}") // lower than unary
"-1 to -2",
"{(:credibleIntervalToDistribution (:unaryMinus 1) (:unaryMinus 2))}",
) // lower than unary
testParse( testParse(
"a[1] to a[2]", "a[1] to a[2]",
"{(:credibleIntervalToDistribution (:$_atIndex_$ :a 1) (:$_atIndex_$ :a 2))}", "{(:credibleIntervalToDistribution (:$_atIndex_$ :a 1) (:$_atIndex_$ :a 2))}",
@ -281,10 +182,7 @@ describe("Peggy parse", () => {
"a.p1 to a.p2", "a.p1 to a.p2",
"{(:credibleIntervalToDistribution (:$_atIndex_$ :a 'p1') (:$_atIndex_$ :a 'p2'))}", "{(:credibleIntervalToDistribution (:$_atIndex_$ :a 'p1') (:$_atIndex_$ :a 'p2'))}",
) // lower than post ) // lower than post
testParse( testParse("1 to 2 + 3", "{(:add (:credibleIntervalToDistribution 1 2) 3)}") // higher than binary operators
"1 to 2 + 3",
"{(:add (:credibleIntervalToDistribution 1 2) 3)}",
) // higher than binary operators
testParse( testParse(
"1->add(2) to 3->add(4) -> add(4)", "1->add(2) to 3->add(4) -> add(4)",
"{(:credibleIntervalToDistribution (:add 1 2) (:add (:add 3 4) 4))}", "{(:credibleIntervalToDistribution (:add 1 2) (:add (:add 3 4) 4))}",
@ -301,10 +199,7 @@ describe("Peggy parse", () => {
testParse("{|x| x}", "{{|:x| :x}}") testParse("{|x| x}", "{{|:x| :x}}")
testParse("f={|x| x}", "{:f = {{|: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", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments
testParse( testParse("f(x)=x ? 1 : 0", "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}") // Function definitions are lambda assignments
"f(x)=x ? 1 : 0",
"{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}",
) // Function definitions are lambda assignments
}) })
describe("Using lambda as value", () => { describe("Using lambda as value", () => {
@ -321,18 +216,9 @@ describe("Peggy parse", () => {
"{:myaddd = {|:x,:y| {(:add :x :y)}}; :z = {{'x': :myaddd}}; :z}", "{:myaddd = {|:x,:y| {(:add :x :y)}}; :z = {{'x': :myaddd}}; :z}",
) )
testParse("f({|x| x+1})", "{(:f {|:x| (:add :x 1)})}") testParse("f({|x| x+1})", "{(:f {|:x| (:add :x 1)})}")
testParse( testParse("map(arr, {|x| x+1})", "{(:map :arr {|:x| (:add :x 1)})}")
"map(arr, {|x| x+1})", testParse("map([1,2,3], {|x| x+1})", "{(:map [1; 2; 3] {|:x| (:add :x 1)})}")
"{(:map :arr {|:x| (:add :x 1)})}", testParse("[1,2,3]->map({|x| x+1})", "{(:map [1; 2; 3] {|:x| (:add :x 1)})}")
)
testParse(
"map([1,2,3], {|x| x+1})",
"{(:map [1; 2; 3] {|:x| (:add :x 1)})}",
)
testParse(
"[1,2,3]->map({|x| x+1})",
"{(:map [1; 2; 3] {|:x| (:add :x 1)})}",
)
}) })
describe("unit", () => { describe("unit", () => {
testParse("1m", "{(:fromUnit_m 1)}") testParse("1m", "{(:fromUnit_m 1)}")
@ -419,7 +305,7 @@ describe("parsing new line", () => {
g=f+4 g=f+4
g g
`, `,
"{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}; :g = {(:add :f 4)}; :g}" "{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}; :g = {(:add :f 4)}; :g}",
) )
testParse( testParse(
` `
@ -441,7 +327,7 @@ describe("parsing new line", () => {
p -> p ->
q q
`, `,
"{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}; :g = {(:add :f 4)}; (:q (:p (:h :g)))}" "{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}; :g = {(:add :f 4)}; (:q (:p (:h :g)))}",
) )
testParse( testParse(
` `
@ -460,6 +346,6 @@ describe("parsing new line", () => {
d + d +
e e
`, `,
"{(:add (:d (:c (:b :a))) :e)}" "{(:add (:d (:c (:b :a))) :e)}",
) )
}) })

View File

@ -4,20 +4,12 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
open Jest open Jest
open Reducer_Peggy_TestHelpers open Reducer_Peggy_TestHelpers
// Note: these tests aren't useful anymore since outer block macro got deleted.
// Probably can be removed or folded into other Peggy tests.
describe("Peggy Outer Block", () => { describe("Peggy Outer Block", () => {
testToExpression("1", "1", ~v="1", ()) testToExpression("1", "1", ~v="1", ())
testToExpression("x=1", "x = {1}", ~v="()", ()) testToExpression("x=1", "x = {1}", ~v="()", ())
testToExpression( testToExpression("x=1; y=2", "x = {1}; y = {2}", ~v="()", ())
"x=1; y=2",
"x = {1}; y = {2}",
~v="()",
(),
)
testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ()) testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ())
testToExpression( testToExpression("x={a=1; a}; x", "x = {a = {1}; a}; x", ~v="1", ())
"x={a=1; a}; x",
"x = {a = {1}; a}; x",
~v="1",
(),
)
}) })

View File

@ -25,11 +25,7 @@ describe("Peggy to Expression", () => {
describe("multi-line", () => { describe("multi-line", () => {
testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ()) testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ())
testToExpression( testToExpression("x=1; y=2", "x = {1}; y = {2}", ())
"x=1; y=2",
"x = {1}; y = {2}",
(),
)
}) })
describe("variables", () => { describe("variables", () => {
@ -39,11 +35,7 @@ describe("Peggy to Expression", () => {
}) })
describe("functions", () => { describe("functions", () => {
testToExpression( testToExpression("identity(x) = x", "identity = {|x| {x}}", ()) // Function definitions become lambda assignments
"identity(x) = x",
"identity = {|x| {x}}",
(),
) // Function definitions become lambda assignments
testToExpression("identity(x)", "(identity)(x)", ()) // Note value returns error properly testToExpression("identity(x)", "(identity)(x)", ()) // Note value returns error properly
testToExpression( testToExpression(
"f(x) = x> 2 ? 0 : 1; f(3)", "f(x) = x> 2 ? 0 : 1; f(3)",
@ -55,43 +47,15 @@ describe("Peggy to Expression", () => {
describe("arrays", () => { describe("arrays", () => {
testToExpression("[]", "[]", ~v="[]", ()) testToExpression("[]", "[]", ~v="[]", ())
testToExpression( testToExpression("[0, 1, 2]", "[0, 1, 2]", ~v="[0,1,2]", ())
"[0, 1, 2]", testToExpression("['hello', 'world']", "['hello', 'world']", ~v="['hello','world']", ())
"[0, 1, 2]", testToExpression("([0,1,2])[1]", "($_atIndex_$)([0, 1, 2], 1)", ~v="1", ())
~v="[0,1,2]",
(),
)
testToExpression(
"['hello', 'world']",
"['hello', 'world']",
~v="['hello','world']",
(),
)
testToExpression(
"([0,1,2])[1]",
"($_atIndex_$)([0, 1, 2], 1)",
~v="1",
(),
)
}) })
describe("records", () => { describe("records", () => {
testToExpression( testToExpression("{a: 1, b: 2}", "{'a': 1, 'b': 2}", ~v="{a: 1,b: 2}", ())
"{a: 1, b: 2}", testToExpression("{1+0: 1, 2+0: 2}", "{(add)(1, 0): 1, (add)(2, 0): 2}", ()) // key can be any expression
"{'a': 1, 'b': 2}", testToExpression("record.property", "($_atIndex_$)(record, 'property')", ())
~v="{a: 1,b: 2}",
(),
)
testToExpression(
"{1+0: 1, 2+0: 2}",
"{(add)(1, 0): 1, (add)(2, 0): 2}",
(),
) // key can be any expression
testToExpression(
"record.property",
"($_atIndex_$)(record, 'property')",
(),
)
testToExpression( testToExpression(
"record={property: 1}; record.property", "record={property: 1}; record.property",
"record = {{'property': 1}}; ($_atIndex_$)(record, 'property')", "record = {{'property': 1}}; ($_atIndex_$)(record, 'property')",
@ -103,45 +67,15 @@ describe("Peggy to Expression", () => {
describe("comments", () => { 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 line comment", "1", ~v="1", ()) testToExpression("1 // This is a line comment", "1", ~v="1", ())
testToExpression( testToExpression("1 /* This is a multi line comment */", "1", ~v="1", ())
"1 /* This is a multi line comment */", testToExpression("/* This is a multi line comment */ 1", "1", ~v="1", ())
"1",
~v="1",
(),
)
testToExpression(
"/* This is a multi line comment */ 1",
"1",
~v="1",
(),
)
}) })
describe("ternary operator", () => { describe("ternary operator", () => {
testToExpression( testToExpression("true ? 1 : 0", "true ? (1) : (0)", ~v="1", ())
"true ? 1 : 0", testToExpression("false ? 1 : 0", "false ? (1) : (0)", ~v="0", ())
"true ? (1) : (0)", testToExpression("true ? 1 : false ? 2 : 0", "true ? (1) : (false ? (2) : (0))", ~v="1", ()) // nested ternary
~v="1", testToExpression("false ? 1 : false ? 2 : 0", "false ? (1) : (false ? (2) : (0))", ~v="0", ()) // nested ternary
(),
)
testToExpression(
"false ? 1 : 0",
"false ? (1) : (0)",
~v="0",
(),
)
testToExpression(
"true ? 1 : false ? 2 : 0",
"true ? (1) : (false ? (2) : (0))",
~v="1",
(),
) // nested ternary
testToExpression(
"false ? 1 : false ? 2 : 0",
"false ? (1) : (false ? (2) : (0))",
~v="0",
(),
) // nested ternary
describe("ternary bindings", () => { describe("ternary bindings", () => {
testToExpression( testToExpression(
// expression binding // expression binding
@ -168,16 +102,8 @@ describe("Peggy to Expression", () => {
}) })
describe("if then else", () => { describe("if then else", () => {
testToExpression( testToExpression("if true then 2 else 3", "true ? ({2}) : ({3})", ())
"if true then 2 else 3", testToExpression("if true then {2} else {3}", "true ? ({2}) : ({3})", ())
"true ? ({2}) : ({3})",
(),
)
testToExpression(
"if true then {2} else {3}",
"true ? ({2}) : ({3})",
(),
)
testToExpression( testToExpression(
"if false then {2} else if false then {4} else {5}", "if false then {2} else if false then {4} else {5}",
"false ? ({2}) : (false ? ({4}) : ({5}))", "false ? ({2}) : (false ? ({4}) : ({5}))",
@ -187,18 +113,8 @@ describe("Peggy to Expression", () => {
describe("pipe", () => { describe("pipe", () => {
testToExpression("1 -> add(2)", "(add)(1, 2)", ~v="3", ()) testToExpression("1 -> add(2)", "(add)(1, 2)", ~v="3", ())
testToExpression( testToExpression("-1 -> add(2)", "(add)((unaryMinus)(1), 2)", ~v="1", ()) // note that unary has higher priority naturally
"-1 -> add(2)", testToExpression("1 -> add(2) * 3", "(multiply)((add)(1, 2), 3)", ~v="9", ())
"(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",
(),
)
}) })
describe("elixir pipe", () => { describe("elixir pipe", () => {
@ -219,27 +135,10 @@ describe("Peggy to Expression", () => {
}) })
describe("lambda", () => { describe("lambda", () => {
testToExpression( testToExpression("{|x| x}", "{|x| x}", ~v="lambda(x=>internal code)", ())
"{|x| x}", testToExpression("f={|x| x}", "f = {{|x| x}}", ())
"{|x| x}", testToExpression("f(x)=x", "f = {|x| {x}}", ()) // Function definitions are lambda assignments
~v="lambda(x=>internal code)", testToExpression("f(x)=x ? 1 : 0", "f = {|x| {x ? (1) : (0)}}", ())
(),
)
testToExpression(
"f={|x| x}",
"f = {{|x| x}}",
(),
)
testToExpression(
"f(x)=x",
"f = {|x| {x}}",
(),
) // Function definitions are lambda assignments
testToExpression(
"f(x)=x ? 1 : 0",
"f = {|x| {x ? (1) : (0)}}",
(),
)
}) })
describe("module", () => { describe("module", () => {

View File

@ -86,3 +86,4 @@
// expectedValue: string, // expectedValue: string,
// ) => testMacroEval_(Only.test, bindArray, expr, expectedValue) // ) => testMacroEval_(Only.test, bindArray, expr, expectedValue)
// } // }

View File

@ -50,3 +50,4 @@
// "Ok({properties: {age: #number,name: #string},typeTag: 'typeRecord'})", // "Ok({properties: {age: #number,name: #string},typeTag: 'typeRecord'})",
// ) // )
// myTypeTest(test, "{age: number, name: string}", "{age: number, name: string}") // myTypeTest(test, "{age: number, name: string}", "{age: number, name: string}")

View File

@ -40,3 +40,4 @@
// test(aTypeSourceCode, () => myCheckArgumentsExpectEqual(aTypeSourceCode, sourceCode, answer)) // test(aTypeSourceCode, () => myCheckArgumentsExpectEqual(aTypeSourceCode, sourceCode, answer))
// myCheckArgumentsTest(test, "number=>number=>number", "[1,2]", "Ok") // myCheckArgumentsTest(test, "number=>number=>number", "[1,2]", "Ok")

View File

@ -71,3 +71,4 @@
// myTypeCheckTest(test, "number<-min(10)", "0", "Expected type: number<-min(10) but got: 0") // myTypeCheckTest(test, "number<-min(10)", "0", "Expected type: number<-min(10) but got: 0")
// myTypeCheckTest(test, "any", "0", "Ok") // myTypeCheckTest(test, "any", "0", "Ok")
// myTypeCheckTest(test, "any", "'a'", "Ok") // myTypeCheckTest(test, "any", "'a'", "Ok")

View File

@ -124,3 +124,4 @@
// expect(result)->toEqual(Some(Ok(IEvString("helloworld")))) // expect(result)->toEqual(Some(Ok(IEvString("helloworld"))))
// }) // })
// }) // })

View File

@ -2,14 +2,8 @@ open Jest
open Reducer_TestHelpers open Reducer_TestHelpers
describe("Parse function assignment", () => { describe("Parse function assignment", () => {
testParseToBe( testParseToBe("f(x)=x", "Ok(f = {|x| {x}})")
"f(x)=x", testParseToBe("f(x)=2*x", "Ok(f = {|x| {(multiply)(2, x)}})")
"Ok(f = {|x| {x}})"
)
testParseToBe(
"f(x)=2*x",
"Ok(f = {|x| {(multiply)(2, x)}})"
)
//MathJs does not allow blocks in function definitions //MathJs does not allow blocks in function definitions
}) })

View File

@ -46,10 +46,7 @@ describe("call and bindings", () => {
testEvalToBe("f(x)=x+1; y=f(1); f(1)", "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); z", "Ok(2)") 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)") testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(0)", "Ok(2)")
testParseToBe( testParseToBe("f=99; g(x)=f; g(2)", "Ok(f = {99}; g = {|x| {f}}; (g)(2))")
"f=99; g(x)=f; g(2)",
"Ok(f = {99}; g = {|x| {f}}; (g)(2))",
)
testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)") 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; g(x)=f(x); g(2)", "Ok(2)")
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; y=g(2); y", "Ok(4)")

View File

@ -2,10 +2,7 @@ open Jest
open Reducer_TestHelpers open Reducer_TestHelpers
describe("Parse ternary operator", () => { describe("Parse ternary operator", () => {
testParseToBe( testParseToBe("true ? 'YES' : 'NO'", "Ok(true ? ('YES') : ('NO'))")
"true ? 'YES' : 'NO'",
"Ok(true ? ('YES') : ('NO'))",
)
}) })
describe("Evaluate ternary operator", () => { describe("Evaluate ternary operator", () => {

View File

@ -119,10 +119,7 @@ describe("eval on distribution functions", () => {
describe("parse on distribution functions", () => { describe("parse on distribution functions", () => {
describe("power", () => { describe("power", () => {
testParse( testParse("normal(5,2) ^ normal(5,1)", "Ok((pow)((normal)(5, 2), (normal)(5, 1)))")
"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("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) ^ 3", "Ok((pow)((normal)(5, 2), 3))")
}) })
@ -138,18 +135,9 @@ describe("parse on distribution functions", () => {
"Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))", "Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))",
// TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})" // TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})"
) )
testParse( testParse("normal(5,2) .* normal(5,1)", "Ok((dotMultiply)((normal)(5, 2), (normal)(5, 1)))")
"normal(5,2) .* normal(5,1)", testParse("normal(5,2) ./ normal(5,1)", "Ok((dotDivide)((normal)(5, 2), (normal)(5, 1)))")
"Ok((dotMultiply)((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((dotDivide)((normal)(5, 2), (normal)(5, 1)))",
)
testParse(
"normal(5,2) .^ normal(5,1)",
"Ok((dotPow)((normal)(5, 2), (normal)(5, 1)))",
)
}) })
describe("equality", () => { describe("equality", () => {
testParse("5 == normal(5,2)", "Ok((equal)(5, (normal)(5, 2)))") testParse("5 == normal(5,2)", "Ok((equal)(5, (normal)(5, 2)))")

View File

@ -75,9 +75,7 @@ x=1`,
}) })
test("include as variables", () => { test("include as variables", () => {
expect(project->Project.Private.getIncludesAsVariables("main")) == [ expect(project->Project.Private.getIncludesAsVariables("main")) == [("myVariable", "myModule")]
("myVariable", "myModule"),
]
}) })
}) })
@ -110,8 +108,6 @@ x=1`,
expect(Project.getPastChain(project, "main")) == ["common", "common2"] expect(Project.getPastChain(project, "main")) == ["common", "common2"]
}) })
test("include as variables", () => { test("include as variables", () => {
expect(project->Project.Private.getIncludesAsVariables("main")) == [ expect(project->Project.Private.getIncludesAsVariables("main")) == [("myVariable", "myModule")]
("myVariable", "myModule"),
]
}) })
}) })

View File

@ -14,8 +14,7 @@ let runFetchResult = (project, sourceId) => {
let runFetchFlatBindings = (project, sourceId) => { let runFetchFlatBindings = (project, sourceId) => {
Project.run(project, sourceId) Project.run(project, sourceId)
Project.getBindings(project, sourceId) Project.getBindings(project, sourceId)->InternalExpressionValue.toStringRecord
->InternalExpressionValue.toStringRecord
} }
test("test result true", () => { test("test result true", () => {

View File

@ -24,7 +24,9 @@ module Map: Benchmark_Helpers.BenchmarkTopic = {
} }
let runAll = () => { let runAll = () => {
Js.log(`Mapping identity function over arrays of size ${arraySize->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`) Js.log(
`Mapping identity function over arrays of size ${arraySize->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`,
)
Benchmark_Helpers.measure("Belt.Array.map", beltArray) Benchmark_Helpers.measure("Belt.Array.map", beltArray)
Benchmark_Helpers.measure("Js.Array2.map", jsArray2) Benchmark_Helpers.measure("Js.Array2.map", jsArray2)
Benchmark_Helpers.measure("Array.map", ocamlArray) Benchmark_Helpers.measure("Array.map", ocamlArray)
@ -65,7 +67,9 @@ module Sort: Benchmark_Helpers.BenchmarkTopic = {
} }
let runAll = () => { let runAll = () => {
Js.log(`Sorting arrays of size ${arraySize->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`) Js.log(
`Sorting arrays of size ${arraySize->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`,
)
Benchmark_Helpers.measure("Js.Array2.sort", jsArray2) Benchmark_Helpers.measure("Js.Array2.sort", jsArray2)
Benchmark_Helpers.measure("Js.Array2.sort with Ocaml compare", jsArray2withOcamlCompare) Benchmark_Helpers.measure("Js.Array2.sort with Ocaml compare", jsArray2withOcamlCompare)
Benchmark_Helpers.measure("Array.fast_sort", ocamlArray) Benchmark_Helpers.measure("Array.fast_sort", ocamlArray)

View File

@ -1,11 +1,11 @@
module type BenchmarkTopic = { module type BenchmarkTopic = {
let runAll: () => unit let runAll: unit => unit
} }
let measure = (name: string, f: () => unit) => { let measure = (name: string, f: unit => unit) => {
let start = Js.Date.make()->Js.Date.valueOf let start = Js.Date.make()->Js.Date.valueOf
f() f()
let end = Js.Date.make()->Js.Date.valueOf let end = Js.Date.make()->Js.Date.valueOf
let duration = (end -. start) /. 1000. let duration = (end -. start) /. 1000.
Js.log2(duration, name) Js.log2(duration, name)
} }

View File

@ -2,63 +2,61 @@ module StringMap: Benchmark_Helpers.BenchmarkTopic = {
let size = 1000 let size = 1000
let iterations = 10_000 let iterations = 10_000
let kv = Belt.Array.range(1, size)->Belt.Array.map( let kv = Belt.Array.range(1, size)->Belt.Array.map(v => ("key" ++ v->Belt.Int.toString, v))
v => ("key" ++ v->Belt.Int.toString, v)
)
let beltMap = () => { let beltMap = () => {
Belt.Range.forEach(1, iterations, _ => { Belt.Range.forEach(1, iterations, _ => {
let m = Belt.Map.String.empty let m = Belt.Map.String.empty
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => acc->Belt.Map.String.set(k, v)) let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => acc->Belt.Map.String.set(k, v))
}) })
} }
let beltMutableMap = () => { let beltMutableMap = () => {
Belt.Range.forEach(1, iterations, _ => { Belt.Range.forEach(1, iterations, _ => {
let m = Belt.MutableMap.String.make() let m = Belt.MutableMap.String.make()
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => { let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
acc->Belt.MutableMap.String.set(k, v) acc->Belt.MutableMap.String.set(k, v)
acc acc
}) })
}) })
} }
let beltHashMap = () => { let beltHashMap = () => {
Belt.Range.forEach(1, iterations, _ => { Belt.Range.forEach(1, iterations, _ => {
let m = Belt.HashMap.String.make(~hintSize=100) let m = Belt.HashMap.String.make(~hintSize=100)
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => { let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
acc->Belt.HashMap.String.set(k, v) acc->Belt.HashMap.String.set(k, v)
acc acc
}) })
}) })
} }
let jsDict = () => { let jsDict = () => {
Belt.Range.forEach(1, iterations, _ => { Belt.Range.forEach(1, iterations, _ => {
let m = Js.Dict.empty() let m = Js.Dict.empty()
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => { let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
acc->Js.Dict.set(k, v) acc->Js.Dict.set(k, v)
acc acc
}) })
}) })
} }
let jsMap = () => { let jsMap = () => {
Belt.Range.forEach(1, iterations, _ => { Belt.Range.forEach(1, iterations, _ => {
let m = Js_map.make() let m = Js_map.make()
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => acc->Js_map.set(k, v))
acc->Js_map.set(k, v)
)
}) })
} }
let runAll = () => { let runAll = () => {
Js.log(`Filling a map with ("key{i}" => "i") key-value pairs, size ${size->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`) Js.log(
Benchmark_Helpers.measure("Belt.Map.String", beltMap) `Filling a map with ("key{i}" => "i") key-value pairs, size ${size->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`,
Benchmark_Helpers.measure("Belt.MutableMap.String", beltMutableMap) )
Benchmark_Helpers.measure("Belt.HashMap.String", beltHashMap) Benchmark_Helpers.measure("Belt.Map.String", beltMap)
Benchmark_Helpers.measure("Js.Dict", jsDict) Benchmark_Helpers.measure("Belt.MutableMap.String", beltMutableMap)
Benchmark_Helpers.measure("Js.Map", jsMap) Benchmark_Helpers.measure("Belt.HashMap.String", beltHashMap)
Benchmark_Helpers.measure("Js.Dict", jsDict)
Benchmark_Helpers.measure("Js.Map", jsMap)
} }
} }

View File

@ -0,0 +1,123 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let nameSpace = "" // no namespaced versions
type simpleDefinition = {
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>,
}
let makeFnMany = (name: string, definitions: array<simpleDefinition>) =>
Function.make(
~name,
~nameSpace,
~requiresNamespace=false,
~definitions=definitions->Js.Array2.map(({inputs, fn}) =>
FnDefinition.make(~name, ~inputs, ~run=(inputs, _, _, _) => fn(inputs), ())
),
(),
)
let makeFn = (
name: string,
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>,
) => makeFnMany(name, [{inputs: inputs, fn: fn}])
let makeFF2F = (name: string, fn: (float, float) => float) => {
makeFn(name, [FRTypeNumber, FRTypeNumber], inputs => {
switch inputs {
| [IEvNumber(x), IEvNumber(y)] => fn(x, y)->IEvNumber->Ok
| _ => Error(impossibleError)
}
})
}
let makeFF2B = (name: string, fn: (float, float) => bool) => {
makeFn(name, [FRTypeNumber, FRTypeNumber], inputs => {
switch inputs {
| [IEvNumber(x), IEvNumber(y)] => fn(x, y)->IEvBool->Ok
| _ => Error(impossibleError)
}
})
}
let makeBB2B = (name: string, fn: (bool, bool) => bool) => {
makeFn(name, [FRTypeBool, FRTypeBool], inputs => {
switch inputs {
| [IEvBool(x), IEvBool(y)] => fn(x, y)->IEvBool->Ok
| _ => Error(impossibleError)
}
})
}
let library = [
makeFF2F("add", (x, y) => x +. y), // infix + (see Reducer/Reducer_Peggy/helpers.ts)
makeFF2F("subtract", (x, y) => x -. y), // infix -
makeFF2F("multiply", (x, y) => x *. y), // infix *
makeFF2F("divide", (x, y) => x /. y), // infix /
makeFF2F("pow", (x, y) => Js.Math.pow_float(~base=x, ~exp=y)), // infix ^
makeFF2B("equal", (x, y) => x == y), // infix ==
makeFF2B("smaller", (x, y) => x < y), // infix <
makeFF2B("smallerEq", (x, y) => x <= y), // infix <=
makeFF2B("larger", (x, y) => x > y), // infix >
makeFF2B("largerEq", (x, y) => x >= y), // infix >=
makeBB2B("or", (x, y) => x || y), // infix ||
makeBB2B("and", (x, y) => x && y), // infix &&
makeFn("unaryMinus", [FRTypeNumber], inputs => { // unary prefix -
switch inputs {
| [IEvNumber(x)] => IEvNumber(-.x)->Ok
| _ => Error(impossibleError)
}
}),
makeFn("not", [FRTypeNumber], inputs => { // unary prefix !
switch inputs {
| [IEvNumber(x)] => IEvBool(x != 0.)->Ok
| _ => Error(impossibleError)
}
}),
makeFn("not", [FRTypeBool], inputs => { // unary prefix !
switch inputs {
| [IEvBool(x)] => IEvBool(!x)->Ok
| _ => Error(impossibleError)
}
}),
makeFn("concat", [FRTypeString, FRTypeString], inputs => {
switch inputs {
| [IEvString(a), IEvString(b)] => {
let answer = Js.String2.concat(a, b)
answer->Reducer_T.IEvString->Ok
}
| _ => Error(impossibleError)
}
}),
makeFn("concat", [FRTypeArray(FRTypeAny), FRTypeArray(FRTypeAny)], inputs => {
switch inputs {
| [IEvArray(originalA), IEvArray(b)] => {
let a = originalA->Js.Array2.copy
let _ = Js.Array2.pushMany(a, b)
a->Reducer_T.IEvArray->Ok
}
| _ => Error(impossibleError)
}
}),
makeFn("inspect", [FRTypeAny], inputs => {
switch inputs {
| [value] => {
Js.log(value->ReducerInterface_InternalExpressionValue.toString)
value->Ok
}
| _ => Error(impossibleError)
}
}),
makeFn("inspect", [FRTypeAny, FRTypeString], inputs => {
switch inputs {
| [value, IEvString(label)] => {
Js.log(`${label}: ${value->ReducerInterface_InternalExpressionValue.toString}`)
value->Ok
}
| _ => Error(impossibleError)
}
}),
]

View File

@ -8,11 +8,11 @@ let requiresNamespace = true
module Combinatorics = { module Combinatorics = {
module Helpers = { module Helpers = {
let laplace = ((successes, trials)) => (successes +. 1.0) /. (trials +. 2.0) let laplace = (successes, trials) => (successes +. 1.0) /. (trials +. 2.0)
let factorial = Stdlib.Math.factorial let factorial = Stdlib.Math.factorial
let choose = ((n, k)) => factorial(n) /. (factorial(n -. k) *. factorial(k)) let choose = (n, k) => factorial(n) /. (factorial(n -. k) *. factorial(k))
let pow = (base, exp) => Js.Math.pow_float(~base, ~exp) let pow = (base, exp) => Js.Math.pow_float(~base, ~exp)
let binomial = ((n, k, p)) => choose((n, k)) *. pow(p, k) *. pow(1.0 -. p, n -. k) let binomial = (n, k, p) => choose(n, k) *. pow(p, k) *. pow(1.0 -. p, n -. k)
} }
module Lib = { module Lib = {
let laplace = Function.make( let laplace = Function.make(
@ -77,8 +77,7 @@ module Integration = {
| Reducer_T.IEvNumber(x) => Ok(x) | Reducer_T.IEvNumber(x) => Ok(x)
| _ => | _ =>
Error( Error(
"Error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead" "Error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead"->Reducer_ErrorValue.REOther,
->Reducer_ErrorValue.REOther
) )
} }
result result
@ -142,11 +141,11 @@ module Integration = {
resultWithOuterPoints resultWithOuterPoints
} }
| Error(b) => | Error(b) =>
( ("Integration error 2 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
"Integration error 2 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++ "Original error: " ++
"Original error: " ++ b->Reducer_ErrorValue.errorToString)
b->Reducer_ErrorValue.errorToString ->Reducer_ErrorValue.REOther
)->Reducer_ErrorValue.REOther->Error ->Error
} }
result result
} }
@ -169,7 +168,9 @@ module Integration = {
~run=(inputs, _, env, reducer) => { ~run=(inputs, _, env, reducer) => {
let result = switch inputs { let result = switch inputs {
| [_, _, _, IEvNumber(0.0)] => | [_, _, _, IEvNumber(0.0)] =>
"Integration error 4 in Danger.integrate: Increment can't be 0."->Reducer_ErrorValue.REOther->Error "Integration error 4 in Danger.integrate: Increment can't be 0."
->Reducer_ErrorValue.REOther
->Error
| [ | [
IEvLambda(aLambda), IEvLambda(aLambda),
IEvNumber(min), IEvNumber(min),
@ -186,7 +187,9 @@ module Integration = {
) )
| _ => | _ =>
Error( Error(
Reducer_ErrorValue.REOther("Integration error 5 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))") Reducer_ErrorValue.REOther(
"Integration error 5 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))",
),
) )
} }
result result
@ -221,8 +224,8 @@ module Integration = {
env, env,
reducer, reducer,
)->E.R2.errMap(b => )->E.R2.errMap(b =>
("Integration error 7 in Danger.integrate. Something went wrong along the way: " ++ b->Reducer_ErrorValue.errorToString) ("Integration error 7 in Danger.integrate. Something went wrong along the way: " ++
->Reducer_ErrorValue.REOther b->Reducer_ErrorValue.errorToString)->Reducer_ErrorValue.REOther
) )
| _ => | _ =>
"Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))" "Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))"
@ -287,23 +290,19 @@ module DiminishingReturns = {
) { ) {
| (false, _, _, _) => | (false, _, _, _) =>
Error( Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, number of functions should be greater than 1." "Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, number of functions should be greater than 1."->Reducer_ErrorValue.REOther,
->Reducer_ErrorValue.REOther
) )
| (_, false, _, _) => | (_, false, _, _) =>
Error( Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, funds should be greater than 0." "Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, funds should be greater than 0."->Reducer_ErrorValue.REOther,
->Reducer_ErrorValue.REOther
) )
| (_, _, false, _) => | (_, _, false, _) =>
Error( Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be greater than 0." "Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be greater than 0."->Reducer_ErrorValue.REOther,
->Reducer_ErrorValue.REOther
) )
| (_, _, _, false) => | (_, _, _, false) =>
Error( Error(
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be smaller than funds amount." "Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be smaller than funds amount."->Reducer_ErrorValue.REOther,
->Reducer_ErrorValue.REOther
) )
| (true, true, true, true) => { | (true, true, true, true) => {
let applyFunctionAtPoint = (lambda, point: float) => { let applyFunctionAtPoint = (lambda, point: float) => {
@ -319,8 +318,7 @@ module DiminishingReturns = {
| Reducer_T.IEvNumber(x) => Ok(x) | Reducer_T.IEvNumber(x) => Ok(x)
| _ => | _ =>
Error( Error(
"Error 1 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead" "Error 1 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead"->Reducer_ErrorValue.REOther,
->Reducer_ErrorValue.REOther
) )
} }
} }
@ -433,7 +431,10 @@ module DiminishingReturns = {
} }
result result
} }
| _ => "Error in Danger.diminishingMarginalReturnsForTwoFunctions"->Reducer_ErrorValue.REOther->Error | _ =>
"Error in Danger.diminishingMarginalReturnsForTwoFunctions"
->Reducer_ErrorValue.REOther
->Error
}, },
(), (),
), ),

View File

@ -0,0 +1,159 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let makeFn = (
name: string,
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>,
) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[FnDefinition.make(~name, ~inputs, ~run=(inputs, _, _, _) => fn(inputs), ())],
(),
)
let makeNumberToDurationFn = (name: string, fn: float => DateTime.Duration.t) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[
FnDefinition.make(
~name,
~inputs=[FRTypeNumber],
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvNumber(t)] => IEvTimeDuration(fn(t))->Ok
| _ => Error(impossibleError)
},
(),
),
],
(),
)
let makeDurationToNumberFn = (name: string, fn: DateTime.Duration.t => float) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[
FnDefinition.make(
~name,
~inputs=[FRTypeTimeDuration],
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvTimeDuration(t)] => IEvNumber(fn(t))->Ok
| _ => Error(impossibleError)
},
(),
),
],
(),
)
let library = [
makeFn("toString", [FRTypeDate], inputs =>
switch inputs {
| [IEvDate(t)] => IEvString(DateTime.Date.toString(t))->Ok
| _ => Error(impossibleError)
}
),
makeFn("makeDateFromYear", [FRTypeNumber], inputs =>
switch inputs {
| [IEvNumber(year)] =>
switch DateTime.Date.makeFromYear(year) {
| Ok(t) => IEvDate(t)->Ok
| Error(e) => Reducer_ErrorValue.RETodo(e)->Error
}
| _ => Error(impossibleError)
}
),
makeFn("dateFromNumber", [FRTypeNumber], inputs =>
switch inputs {
| [IEvNumber(f)] => IEvDate(DateTime.Date.fromFloat(f))->Ok
| _ => Error(impossibleError)
}
),
makeFn("toNumber", [FRTypeDate], inputs =>
switch inputs {
| [IEvDate(f)] => IEvNumber(DateTime.Date.toFloat(f))->Ok
| _ => Error(impossibleError)
}
),
makeFn("subtract", [FRTypeDate, FRTypeDate], inputs =>
switch inputs {
| [IEvDate(d1), IEvDate(d2)] =>
switch DateTime.Date.subtract(d1, d2) {
| Ok(d) => IEvTimeDuration(d)->Ok
| Error(e) => Error(RETodo(e))
}
| _ => Error(impossibleError)
}
),
makeFn("subtract", [FRTypeDate, FRTypeTimeDuration], inputs =>
switch inputs {
| [IEvDate(d1), IEvTimeDuration(d2)] => IEvDate(DateTime.Date.subtractDuration(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("add", [FRTypeDate, FRTypeTimeDuration], inputs =>
switch inputs {
| [IEvDate(d1), IEvTimeDuration(d2)] => IEvDate(DateTime.Date.addDuration(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("toString", [FRTypeTimeDuration], inputs =>
switch inputs {
| [IEvTimeDuration(t)] => IEvString(DateTime.Duration.toString(t))->Ok
| _ => Error(impossibleError)
}
),
makeNumberToDurationFn("minutes", DateTime.Duration.fromMinutes),
makeNumberToDurationFn("fromUnit_minutes", DateTime.Duration.fromMinutes),
makeNumberToDurationFn("hours", DateTime.Duration.fromHours),
makeNumberToDurationFn("fromUnit_hours", DateTime.Duration.fromHours),
makeNumberToDurationFn("days", DateTime.Duration.fromDays),
makeNumberToDurationFn("fromUnit_days", DateTime.Duration.fromDays),
makeNumberToDurationFn("years", DateTime.Duration.fromYears),
makeNumberToDurationFn("fromUnit_years", DateTime.Duration.fromYears),
makeDurationToNumberFn("toMinutes", DateTime.Duration.toMinutes),
makeDurationToNumberFn("toHours", DateTime.Duration.toHours),
makeDurationToNumberFn("toDays", DateTime.Duration.toDays),
makeDurationToNumberFn("toYears", DateTime.Duration.toYears),
makeFn("add", [FRTypeTimeDuration, FRTypeTimeDuration], inputs =>
switch inputs {
| [IEvTimeDuration(d1), IEvTimeDuration(d2)] =>
IEvTimeDuration(DateTime.Duration.add(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("subtract", [FRTypeTimeDuration, FRTypeTimeDuration], inputs =>
switch inputs {
| [IEvTimeDuration(d1), IEvTimeDuration(d2)] =>
IEvTimeDuration(DateTime.Duration.subtract(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("multiply", [FRTypeTimeDuration, FRTypeNumber], inputs =>
switch inputs {
| [IEvTimeDuration(d1), IEvNumber(d2)] =>
IEvTimeDuration(DateTime.Duration.multiply(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("divide", [FRTypeTimeDuration, FRTypeNumber], inputs =>
switch inputs {
| [IEvTimeDuration(d1), IEvNumber(d2)] => IEvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("divide", [FRTypeTimeDuration, FRTypeTimeDuration], inputs =>
switch inputs {
| [IEvTimeDuration(d1), IEvTimeDuration(d2)] => IEvNumber(d1 /. d2)->Ok
| _ => Error(impossibleError)
}
),
]

View File

@ -17,7 +17,10 @@ module Internals = {
->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value]))
->Wrappers.evArray ->Wrappers.evArray
let fromList = (items: array<internalExpressionValue>): result<internalExpressionValue, errorValue> => let fromList = (items: array<internalExpressionValue>): result<
internalExpressionValue,
errorValue,
> =>
items items
->E.A2.fmap(item => { ->E.A2.fmap(item => {
switch (item: internalExpressionValue) { switch (item: internalExpressionValue) {

View File

@ -315,10 +315,11 @@ module Old = {
let dispatch = (call: ReducerInterface_InternalExpressionValue.functionCall, environment) => let dispatch = (call: ReducerInterface_InternalExpressionValue.functionCall, environment) =>
switch dispatchToGenericOutput(call, environment) { switch dispatchToGenericOutput(call, environment) {
| Some(o) => genericOutputToReducerValue(o) | Some(o) => genericOutputToReducerValue(o)
| None => Reducer_ErrorValue.REOther("Internal error in FR_GenericDist implementation") | None =>
->Reducer_ErrorValue.ErrorException Reducer_ErrorValue.REOther("Internal error in FR_GenericDist implementation")
->raise ->Reducer_ErrorValue.ErrorException
->raise
} }
} }
@ -340,24 +341,32 @@ let makeProxyFn = (name: string, inputs: array<frType>) => {
} }
let makeOperationFns = (): array<function> => { let makeOperationFns = (): array<function> => {
let ops = ["add", "multiply", "subtract", "divide", "pow", "log", "dotAdd", "dotMultiply", "dotSubtract", "dotDivide", "dotPow"] let ops = [
let twoArgTypes = [ "add",
// can't use numeric+numeric, since number+number should be delegated to builtin arithmetics "multiply",
[FRTypeDist, FRTypeNumber], "subtract",
[FRTypeNumber, FRTypeDist], "divide",
[FRTypeDist, FRTypeDist], "pow",
] "log",
"dotAdd",
"dotMultiply",
"dotSubtract",
"dotDivide",
"dotPow",
]
let twoArgTypes = [
// can't use numeric+numeric, since number+number should be delegated to builtin arithmetics
[FRTypeDist, FRTypeNumber],
[FRTypeNumber, FRTypeDist],
[FRTypeDist, FRTypeDist],
]
ops->E.A2.fmap( ops->E.A2.fmap(op => twoArgTypes->E.A2.fmap(types => makeProxyFn(op, types)))->E.A.concatMany
op => twoArgTypes->E.A2.fmap(
types => makeProxyFn(op, types)
)
)->E.A.concatMany
} }
// TODO - duplicates the switch above, should rewrite with standard FR APIs // TODO - duplicates the switch above, should rewrite with standard FR APIs
let library = E.A.concatMany([ let library = E.A.concatMany([
[ [
makeProxyFn("triangular", [FRTypeNumber, FRTypeNumber, FRTypeNumber]), makeProxyFn("triangular", [FRTypeNumber, FRTypeNumber, FRTypeNumber]),
makeProxyFn("sample", [FRTypeDist]), makeProxyFn("sample", [FRTypeDist]),
makeProxyFn("sampleN", [FRTypeDist, FRTypeNumber]), makeProxyFn("sampleN", [FRTypeDist, FRTypeNumber]),
@ -394,14 +403,14 @@ let library = E.A.concatMany([
makeProxyFn("log10", [FRTypeDist]), makeProxyFn("log10", [FRTypeDist]),
makeProxyFn("unaryMinus", [FRTypeDist]), makeProxyFn("unaryMinus", [FRTypeDist]),
makeProxyFn("dotExp", [FRTypeDist]), makeProxyFn("dotExp", [FRTypeDist]),
], ],
makeOperationFns() makeOperationFns(),
]) ])
// FIXME - impossible to implement with FR due to arbitrary parameters length; // FIXME - impossible to implement with FR due to arbitrary parameters length;
let mxLambda = Reducer_Expression_Lambda.makeFFILambda((inputs, env, _) => { let mxLambda = Reducer_Expression_Lambda.makeFFILambda((inputs, env, _) => {
switch Old.dispatch(("mx", inputs), env) { switch Old.dispatch(("mx", inputs), env) {
| Ok(value) => value | Ok(value) => value
| Error(e) => e->Reducer_ErrorValue.ErrorException->raise | Error(e) => e->Reducer_ErrorValue.ErrorException->raise
} }
}) })

View File

@ -66,12 +66,7 @@ module Internals = {
reducer: Reducer_T.reducerFn, reducer: Reducer_T.reducerFn,
) => { ) => {
Js.Array2.filter(aValueArray, elem => { Js.Array2.filter(aValueArray, elem => {
let result = Reducer_Expression_Lambda.doLambdaCall( let result = Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, [elem], env, reducer)
aLambdaValue,
[elem],
env,
reducer,
)
switch result { switch result {
| IEvBool(true) => true | IEvBool(true) => true
| _ => false | _ => false

View File

@ -0,0 +1,70 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
// FIXME - copy-pasted (see FR_Date.res and others)
let makeFn = (
name: string,
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>,
) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[FnDefinition.make(~name, ~inputs, ~run=(inputs, _, _, _) => fn(inputs), ())],
(),
)
@module("mathjs") external dummy_: string => unit = "evaluate"
let dummy1_ = dummy_ //Deceive the compiler to make the import although we wont make a call from rescript. Otherwise the optimizer deletes the import
let mathjsCall1: (string, float) => 'a = %raw(`function (name, arg) { return Mathjs[name](arg); }`)
let mathjsCall2: (string, float, float) => 'a = %raw(`function (name, arg1, arg2) { return Mathjs[name](arg1, arg2); }`)
let makeMathjsFn1 = (
name: string
) => {
makeFn(name, [FRTypeNumber], inputs => {
switch inputs {
| [IEvNumber(x)] => mathjsCall1(name, x)->Reducer_Js_Gate.jsToIEv
| _ => Error(impossibleError)
}
})
}
let makeMathjsFn2 = (
name: string
) => {
makeFn(name, [FRTypeNumber, FRTypeNumber], inputs => {
switch inputs {
| [IEvNumber(x), IEvNumber(y)] => mathjsCall2(name, x, y)->Reducer_Js_Gate.jsToIEv
| _ => Error(impossibleError)
}
})
}
let library = [
// TODO - other MathJS
// https://mathjs.org/docs/reference/functions.html
// Arithmetic functions
makeMathjsFn1("abs"),
makeMathjsFn1("cbrt"),
makeMathjsFn1("ceil"),
makeMathjsFn1("cube"),
makeMathjsFn1("exp"),
makeMathjsFn1("fix"),
makeMathjsFn1("floor"),
makeMathjsFn2("gcd"),
makeMathjsFn2("hypot"),
makeMathjsFn2("invmod"),
makeMathjsFn2("lcm"),
makeMathjsFn1("log"), // Do we need makeMathjsFn2 for `log` too?
makeMathjsFn1("log10"),
makeMathjsFn1("log2"),
makeMathjsFn1("factorial"),
makeMathjsFn1("cos"),
]

View File

@ -17,18 +17,6 @@ module ArrayNumberDist = {
(), (),
) )
} }
let make2 = (name, fn) => {
FnDefinition.make(
~name,
~inputs=[FRTypeArray(FRTypeAny)],
~run=(_, inputs, _, _) =>
Prepare.ToTypedArray.numbers(inputs)
->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r))
->E.R.bind(fn)
->E.R2.errMap(wrapError),
(),
)
}
} }
let library = [ let library = [

View File

@ -111,8 +111,7 @@ let library = [
~name="makeContinuous", ~name="makeContinuous",
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
~run=(_, inputs, _, _) => ~run=(_, inputs, _, _) =>
inputsTodist(inputs, r => Continuous(Continuous.make(r))) inputsTodist(inputs, r => Continuous(Continuous.make(r)))->E.R2.errMap(wrapError),
->E.R2.errMap(wrapError),
(), (),
), ),
], ],
@ -136,8 +135,7 @@ let library = [
~name="makeDiscrete", ~name="makeDiscrete",
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
~run=(_, inputs, _, _) => ~run=(_, inputs, _, _) =>
inputsTodist(inputs, r => Discrete(Discrete.make(r))) inputsTodist(inputs, r => Discrete(Discrete.make(r)))->E.R2.errMap(wrapError),
->E.R2.errMap(wrapError),
(), (),
), ),
], ],

View File

@ -120,7 +120,8 @@ let libaryBase = [
Prepare.ToTypedArray.numbers(inputs) |> E.R2.bind(r => Prepare.ToTypedArray.numbers(inputs) |> E.R2.bind(r =>
SampleSetDist.make(r)->E.R2.errMap(_ => "AM I HERE? WHYERE AMI??") SampleSetDist.make(r)->E.R2.errMap(_ => "AM I HERE? WHYERE AMI??")
) )
sampleSet->E.R2.fmap(Wrappers.sampleSet) sampleSet
->E.R2.fmap(Wrappers.sampleSet)
->E.R2.fmap(Wrappers.evDistribution) ->E.R2.fmap(Wrappers.evDistribution)
->E.R2.errMap(wrapError) ->E.R2.errMap(wrapError)
}, },
@ -291,7 +292,9 @@ module Comparison = {
let wrapper = r => let wrapper = r =>
r r
->E.R2.fmap(r => r->Wrappers.sampleSet->Wrappers.evDistribution) ->E.R2.fmap(r => r->Wrappers.sampleSet->Wrappers.evDistribution)
->E.R2.errMap(e => e->DistributionTypes.Error.sampleErrorToDistErr->Reducer_ErrorValue.REDistributionError) ->E.R2.errMap(e =>
e->DistributionTypes.Error.sampleErrorToDistErr->Reducer_ErrorValue.REDistributionError
)
let mkBig = (name, withDist, withFloat) => let mkBig = (name, withDist, withFloat) =>
Function.make( Function.make(

View File

@ -22,14 +22,13 @@ let makeUnitFn = (name: string, multiplier: float) => {
) )
} }
let library = [ let library = [
makeUnitFn("n", 1E-9), makeUnitFn("n", 1E-9),
makeUnitFn("m", 1E-3), makeUnitFn("m", 1E-3),
makeUnitFn("k", 1E3), makeUnitFn("k", 1E3),
makeUnitFn("M", 1E6), makeUnitFn("M", 1E6),
makeUnitFn("B", 1E9), makeUnitFn("B", 1E9),
makeUnitFn("G", 1E9), makeUnitFn("G", 1E9),
makeUnitFn("T", 1E12), makeUnitFn("T", 1E12),
makeUnitFn("P", 1E15), makeUnitFn("P", 1E15),
] ]

View File

@ -212,8 +212,7 @@ let setEnvironment = (project: reducerProject, environment: environment): unit =
project->Private.setEnvironment(environment) project->Private.setEnvironment(environment)
@genType @genType
let getEnvironment = (project: reducerProject): environment => let getEnvironment = (project: reducerProject): environment => project->Private.getEnvironment
project->Private.getEnvironment
/* /*
Foreign function interface is intentionally demolished. Foreign function interface is intentionally demolished.

View File

@ -225,9 +225,9 @@ module FnDefinition = {
} }
let make = (~name, ~inputs, ~run, ()): t => { let make = (~name, ~inputs, ~run, ()): t => {
name, name: name,
inputs, inputs: inputs,
run, run: run,
} }
} }
@ -253,14 +253,14 @@ module Function = {
~isExperimental=false, ~isExperimental=false,
(), (),
): t => { ): t => {
name, name: name,
nameSpace, nameSpace: nameSpace,
definitions, definitions: definitions,
output, output: output,
examples: examples |> E.O.default([]), examples: examples |> E.O.default([]),
isExperimental, isExperimental: isExperimental,
requiresNamespace, requiresNamespace: requiresNamespace,
description, description: description,
} }
let toJson = (t: t): functionJson => { let toJson = (t: t): functionJson => {
@ -288,12 +288,8 @@ module Registry = {
// 1. functions // 1. functions
// 2. definitions of each function // 2. definitions of each function
// 3. name variations of each definition // 3. name variations of each definition
r->Belt.Array.reduce( r->Belt.Array.reduce(Belt.Map.String.empty, (acc, fn) =>
Belt.Map.String.empty, fn.definitions->Belt.Array.reduce(acc, (acc, def) => {
(acc, fn) =>
fn.definitions->Belt.Array.reduce(
acc,
(acc, def) => {
let names = let names =
[ [
fn.nameSpace == "" ? [] : [`${fn.nameSpace}.${def.name}`], fn.nameSpace == "" ? [] : [`${fn.nameSpace}.${def.name}`],
@ -338,8 +334,7 @@ module Registry = {
let match = definitions->Js.Array2.find(def => def->FnDefinition.isMatch(args)) let match = definitions->Js.Array2.find(def => def->FnDefinition.isMatch(args))
switch match { switch match {
| Some(def) => | Some(def) => def->FnDefinition.run(args, env, reducer)
def->FnDefinition.run(args, env, reducer)
| None => REOther(showNameMatchDefinitions())->Error | None => REOther(showNameMatchDefinitions())->Error
} }
} }

View File

@ -225,13 +225,11 @@ module DefineFn = {
FnDefinition.make( FnDefinition.make(
~name, ~name,
~inputs=[FRTypeNumber], ~inputs=[FRTypeNumber],
~run=(_, inputs, _, _) => { ~run=(inputs, _, _, _) => {
inputs switch inputs {
->getOrError(0) | [IEvNumber(x)] => fn(x)->IEvNumber->Ok
->E.R.bind(Prepare.oneNumber) | _ => Error(impossibleError)
->E.R2.fmap(fn) }
->E.R2.fmap(Wrappers.evNumber)
->E.R2.errMap(e => Reducer_ErrorValue.REOther(e))
}, },
(), (),
) )
@ -239,12 +237,11 @@ module DefineFn = {
FnDefinition.make( FnDefinition.make(
~name, ~name,
~inputs=[FRTypeNumber, FRTypeNumber], ~inputs=[FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _, _) => { ~run=(inputs, _, _, _) => {
inputs switch inputs {
->Prepare.ToValueTuple.twoNumbers | [IEvNumber(x), IEvNumber(y)] => fn(x, y)->IEvNumber->Ok
->E.R2.fmap(fn) | _ => Error(impossibleError)
->E.R2.fmap(Wrappers.evNumber) }
->E.R2.errMap(e => Reducer_ErrorValue.REOther(e))
}, },
(), (),
) )
@ -252,12 +249,11 @@ module DefineFn = {
FnDefinition.make( FnDefinition.make(
~name, ~name,
~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _, _) => { ~run=(inputs, _, _, _) => {
inputs switch inputs {
->Prepare.ToValueTuple.threeNumbers | [IEvNumber(x), IEvNumber(y), IEvNumber(z)] => fn(x, y, z)->IEvNumber->Ok
->E.R2.fmap(fn) | _ => Error(impossibleError)
->E.R2.fmap(Wrappers.evNumber) }
->E.R2.errMap(e => Reducer_ErrorValue.REOther(e))
}, },
(), (),
) )

View File

@ -1,163 +0,0 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let nameSpace = "" // no namespaced versions
type simpleDefinition = {
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>,
}
let makeFnMany = (name: string, definitions: array<simpleDefinition>) =>
Function.make(
~name,
~nameSpace,
~requiresNamespace=false,
~definitions=definitions->Js.Array2.map(({inputs, fn}) =>
FnDefinition.make(~name, ~inputs, ~run=(inputs, _, _, _) => fn(inputs), ())
),
(),
)
let makeFn = (
name: string,
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>,
) => makeFnMany(name, [{ inputs, fn }])
let makeBinaryFn = (name: string, fn: (float, float) => float) => {
makeFn(
name,
[FRTypeNumber, FRTypeNumber],
inputs => {
switch inputs {
| [IEvNumber(x), IEvNumber(y)] => fn(x, y)->IEvNumber->Ok
| _ => Error(impossibleError)
}
}
)
}
let makeBinaryCmpFn = (name: string, fn: (float, float) => bool) => {
makeFn(
name,
[FRTypeNumber, FRTypeNumber],
inputs => {
switch inputs {
| [IEvNumber(x), IEvNumber(y)] => fn(x, y)->IEvBool->Ok
| _ => Error(impossibleError)
}
}
)
}
let makeBinaryBooleanFn = (name: string, fn: (bool, bool) => bool) => {
makeFn(
name,
[FRTypeBool, FRTypeBool],
inputs => {
switch inputs {
| [IEvBool(x), IEvBool(y)] => fn(x, y)->IEvBool->Ok
| _ => Error(impossibleError)
}
}
)
}
let library = [
makeBinaryFn("add", (x, y) => x +. y),
makeBinaryFn("subtract", (x, y) => x -. y),
makeBinaryFn("multiply", (x, y) => x *. y),
makeBinaryFn("divide", (x, y) => x /. y),
makeBinaryFn("pow", (x, y) => Js.Math.pow_float(~base=x, ~exp=y)),
makeBinaryCmpFn("equal", (x, y) => x == y),
makeBinaryCmpFn("smaller", (x, y) => x < y),
makeBinaryCmpFn("smallerEq", (x, y) => x <= y),
makeBinaryCmpFn("larger", (x, y) => x > y),
makeBinaryCmpFn("largerEq", (x, y) => x >= y),
makeBinaryBooleanFn("or", (x, y) => x || y),
makeBinaryBooleanFn("and", (x, y) => x && y),
makeFn(
"unaryMinus",
[FRTypeNumber],
inputs => {
switch inputs {
| [IEvNumber(x)] => IEvNumber(-.x)->Ok
| _ => Error(impossibleError)
}
}
),
makeFn(
"not",
[FRTypeNumber],
inputs => {
switch inputs {
| [IEvNumber(x)] => IEvBool(x != 0.)->Ok
| _ => Error(impossibleError)
}
}
),
makeFn(
"not",
[FRTypeBool],
inputs => {
switch inputs {
| [IEvBool(x)] => IEvBool(!x)->Ok
| _ => Error(impossibleError)
}
}
),
makeFn(
"concat",
[FRTypeString, FRTypeString],
inputs => {
switch inputs {
| [IEvString(a), IEvString(b)] => {
let answer = Js.String2.concat(a, b)
answer->Reducer_T.IEvString->Ok
}
| _ => Error(impossibleError)
}
}
),
makeFn(
"concat",
[FRTypeArray(FRTypeAny), FRTypeArray(FRTypeAny)],
inputs => {
switch inputs {
| [IEvArray(originalA), IEvArray(b)] => {
let a = originalA->Js.Array2.copy
let _ = Js.Array2.pushMany(a, b)
a->Reducer_T.IEvArray->Ok
}
| _ => Error(impossibleError)
}
}
),
makeFn(
"inspect",
[FRTypeAny],
inputs => {
switch inputs {
| [value] => {
Js.log(value->ReducerInterface_InternalExpressionValue.toString)
value->Ok
}
| _ => Error(impossibleError)
}
}
),
makeFn(
"inspect",
[FRTypeAny, FRTypeString],
inputs => {
switch inputs {
| [value, IEvString(label)] => {
Js.log(`${label}: ${value->ReducerInterface_InternalExpressionValue.toString}`)
value->Ok
}
| _ => Error(impossibleError)
}
}
),
]

View File

@ -1,155 +0,0 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let makeFn = (
name: string,
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>
) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[
FnDefinition.make(~name, ~inputs, ~run=(inputs, _, _, _) => fn(inputs), ())
],
()
)
let makeNumberToDurationFn = (
name: string,
fn: float => DateTime.Duration.t,
) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[
FnDefinition.make(~name, ~inputs=[FRTypeNumber], ~run=(inputs, _, _, _) =>
switch inputs {
| [IEvNumber(t)] => IEvTimeDuration(fn(t))->Ok
| _ => Error(impossibleError)
}, ())
],
()
)
let makeDurationToNumberFn = (
name: string,
fn: DateTime.Duration.t => float,
) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[
FnDefinition.make(~name, ~inputs=[FRTypeTimeDuration], ~run=(inputs, _, _, _) =>
switch inputs {
| [IEvTimeDuration(t)] => IEvNumber(fn(t))->Ok
| _ => Error(impossibleError)
}, ())
],
()
)
let library = [
makeFn("toString", [FRTypeDate], (inputs) =>
switch inputs {
| [IEvDate(t)] => IEvString(DateTime.Date.toString(t))->Ok
| _ => Error(impossibleError)
}
),
makeFn("makeDateFromYear", [FRTypeNumber], (inputs) =>
switch inputs {
| [IEvNumber(year)] =>
switch DateTime.Date.makeFromYear(year) {
| Ok(t) => IEvDate(t)->Ok
| Error(e) => Reducer_ErrorValue.RETodo(e)->Error
}
| _ => Error(impossibleError)
}
),
makeFn("dateFromNumber", [FRTypeNumber], (inputs) =>
switch inputs {
| [IEvNumber(f)] => IEvDate(DateTime.Date.fromFloat(f))->Ok
| _ => Error(impossibleError)
}
),
makeFn("toNumber", [FRTypeDate], (inputs) =>
switch inputs {
| [IEvDate(f)] => IEvNumber(DateTime.Date.toFloat(f))->Ok
| _ => Error(impossibleError)
}
),
makeFn("subtract", [FRTypeDate, FRTypeDate], (inputs) =>
switch inputs {
| [IEvDate(d1), IEvDate(d2)] => switch DateTime.Date.subtract(d1, d2) {
| Ok(d) => IEvTimeDuration(d)->Ok
| Error(e) => Error(RETodo(e))
}
| _ => Error(impossibleError)
}
),
makeFn("subtract", [FRTypeDate, FRTypeTimeDuration], (inputs) =>
switch inputs {
| [IEvDate(d1), IEvTimeDuration(d2)] =>
IEvDate(DateTime.Date.subtractDuration(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("add", [FRTypeDate, FRTypeTimeDuration], (inputs) =>
switch inputs {
| [IEvDate(d1), IEvTimeDuration(d2)] =>
IEvDate(DateTime.Date.addDuration(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("toString", [FRTypeTimeDuration], (inputs) =>
switch inputs {
| [IEvTimeDuration(t)] => IEvString(DateTime.Duration.toString(t))->Ok
| _ => Error(impossibleError)
}
),
makeNumberToDurationFn("minutes", DateTime.Duration.fromMinutes),
makeNumberToDurationFn("fromUnit_minutes", DateTime.Duration.fromMinutes),
makeNumberToDurationFn("hours", DateTime.Duration.fromHours),
makeNumberToDurationFn("fromUnit_hours", DateTime.Duration.fromHours),
makeNumberToDurationFn("days", DateTime.Duration.fromDays),
makeNumberToDurationFn("fromUnit_days", DateTime.Duration.fromDays),
makeNumberToDurationFn("years", DateTime.Duration.fromYears),
makeNumberToDurationFn("fromUnit_years", DateTime.Duration.fromYears),
makeDurationToNumberFn("toMinutes", DateTime.Duration.toMinutes),
makeDurationToNumberFn("toHours", DateTime.Duration.toHours),
makeDurationToNumberFn("toDays", DateTime.Duration.toDays),
makeDurationToNumberFn("toYears", DateTime.Duration.toYears),
makeFn("add", [FRTypeTimeDuration, FRTypeTimeDuration], (inputs) =>
switch inputs {
| [IEvTimeDuration(d1), IEvTimeDuration(d2)] => IEvTimeDuration(DateTime.Duration.add(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("subtract", [FRTypeTimeDuration, FRTypeTimeDuration], (inputs) =>
switch inputs {
| [IEvTimeDuration(d1), IEvTimeDuration(d2)] => IEvTimeDuration(DateTime.Duration.subtract(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("multiply", [FRTypeTimeDuration, FRTypeNumber], (inputs) =>
switch inputs {
| [IEvTimeDuration(d1), IEvNumber(d2)] => IEvTimeDuration(DateTime.Duration.multiply(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("divide", [FRTypeTimeDuration, FRTypeNumber], (inputs) =>
switch inputs {
| [IEvTimeDuration(d1), IEvNumber(d2)] => IEvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok
| _ => Error(impossibleError)
}
),
makeFn("divide", [FRTypeTimeDuration, FRTypeTimeDuration], (inputs) =>
switch inputs {
| [IEvTimeDuration(d1), IEvTimeDuration(d2)] => IEvNumber(d1 /. d2)->Ok
| _ => Error(impossibleError)
}
),
]

View File

@ -1,38 +0,0 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
// FIXME - copy-pasted (see FR_Date.res and others)
let makeFn = (
name: string,
inputs: array<frType>,
fn: array<internalExpressionValue> => result<internalExpressionValue, errorValue>
) =>
Function.make(
~name,
~nameSpace="",
~requiresNamespace=false,
~definitions=[
FnDefinition.make(~name, ~inputs, ~run=(inputs, _, _, _) => fn(inputs), ())
],
()
)
@module("mathjs") external dummy_: string => unit = "evaluate"
let dummy1_ = dummy_ //Deceive the compiler to make the import although we wont make a call from rescript. Otherwise the optimizer deletes the import
let mathjsFactorial: float => 'a = %raw(`function (expr) { return Mathjs.factorial(expr); }`)
let library = [
// TODO - other MathJS
// https://mathjs.org/docs/reference/functions.html
makeFn(
"factorial",
[FRTypeNumber],
inputs => {
switch inputs {
| [IEvNumber(x)] => mathjsFactorial(x)->Reducer_Js_Gate.jsToIEv
| _ => Error(impossibleError)
}
}
),
]

View File

@ -42,5 +42,7 @@ Key types, internal functionality, and a `Registry` module with a `matchAndRun`
**FunctionRegistry_Library** **FunctionRegistry_Library**
A list of all the Functions defined in the Function Registry. A list of all the Functions defined in the Function Registry.
The definition arrays are stored in `FR_*` modules, by convention.
**FunctionRegistry_Helpers** **FunctionRegistry_Helpers**
A list of helper functions for the FunctionRegistry_Library. A list of helper functions for the FunctionRegistry_Library.

View File

@ -0,0 +1,89 @@
/*
Bindings describe the entire set of bound variables accessible to the squiggle code.
Bindings objects are stored as linked lists of scopes:
{ localX: ..., localY: ... } <- { globalZ: ..., ... } <- { importedT: ..., ... } <- { stdlibFunction: ..., ... }
*/
type t = Reducer_T.bindings
type internalExpressionValue = Reducer_T.value
let rec get = ({namespace, parent}: t, id: string) => {
switch namespace->Reducer_Namespace.get(id) {
| Some(v) => Some(v)
| None =>
switch parent {
| Some(p) => p->get(id)
| None => None
}
}
}
let set = ({namespace} as bindings: t, id: string, value): t => {
{
...bindings,
namespace: namespace->Reducer_Namespace.set(id, value),
}
}
let rec toString = ({namespace, parent}: t) => {
let pairs = namespace->Reducer_Namespace.toString
switch parent {
| Some(p) => `{${pairs}} / ${toString(p)}`
| None => `{${pairs}}`
}
}
let extend = (bindings: t): t => {namespace: Reducer_Namespace.make(), parent: bindings->Some}
let make = (): t => {namespace: Reducer_Namespace.make(), parent: None}
let removeResult = ({namespace} as bindings: t): t => {
...bindings,
namespace: namespace->Belt.Map.String.remove("__result__"),
}
let locals = ({namespace}: t): Reducer_T.namespace => namespace
let fromNamespace = (namespace: Reducer_Namespace.t): t => {namespace: namespace, parent: None}
// let typeAliasesKey = "_typeAliases_"
// let typeReferencesKey = "_typeReferences_"
// let getType = (NameSpace(container): t, id: string) => {
// Belt.Map.String.get(container, typeAliasesKey)->Belt.Option.flatMap(aliases =>
// switch aliases {
// | IEvRecord(r) => Belt.Map.String.get(r, id)
// | _ => None
// }
// )
// }
// let getTypeOf = (NameSpace(container): t, id: string) => {
// Belt.Map.String.get(container, typeReferencesKey)->Belt.Option.flatMap(defs =>
// switch defs {
// | IEvRecord(r) => Belt.Map.String.get(r, id)
// | _ => None
// }
// )
// }
// let setTypeAlias = (NameSpace(container): t, id: string, value): t => {
// let rValue = Belt.Map.String.getWithDefault(container, typeAliasesKey, IEvRecord(emptyMap))
// let r = switch rValue {
// | IEvRecord(r) => r
// | _ => emptyMap
// }
// let r2 = Belt.Map.String.set(r, id, value)->IEvRecord
// NameSpace(Belt.Map.String.set(container, typeAliasesKey, r2))
// }
// let setTypeOf = (NameSpace(container): t, id: string, value): t => {
// let rValue = Belt.Map.String.getWithDefault(container, typeReferencesKey, IEvRecord(emptyMap))
// let r = switch rValue {
// | IEvRecord(r) => r
// | _ => emptyMap
// }
// let r2 = Belt.Map.String.set(r, id, value)->IEvRecord
// NameSpace(Belt.Map.String.set(container, typeReferencesKey, r2))
// }

View File

@ -1,141 +0,0 @@
// Only Bindings as the global module is supported
// Other module operations such as import export will be preprocessed jobs
module ExpressionT = Reducer_Expression_T
module T = Reducer_T
type t = Reducer_T.bindings
type internalExpressionValue = Reducer_T.value
let rec get = ({ namespace, parent }: t, id: string) => {
switch namespace->Reducer_Namespace.get(id) {
| Some(v) => Some(v)
| None =>
switch parent {
| Some(p) => get(p, id)
| None => None
}
}
}
let set = ({ namespace } as bindings: t, id: string, value): t => {
{
...bindings,
namespace: namespace->Reducer_Namespace.set(id, value),
}
}
let rec toString = ({ namespace, parent }: t) => {
let pairs = namespace->Reducer_Namespace.toString
switch parent {
| Some(p) => `{${pairs}} / ${toString(p)}`
| None => `{${pairs}}`
}
}
let extend = (bindings: t): t => { namespace: Reducer_Namespace.make(), parent: bindings->Some }
let make = (): t => { namespace: Reducer_Namespace.make(), parent: None }
let removeResult = ({ namespace } as bindings: t): t => {
...bindings,
namespace: namespace->Belt.Map.String.remove("__result__"),
}
let locals = ({ namespace }: t): Reducer_T.namespace => namespace
let fromNamespace = (namespace: Reducer_Namespace.t): t => { namespace, parent: None }
// let typeAliasesKey = "_typeAliases_"
// let typeReferencesKey = "_typeReferences_"
// let getType = (NameSpace(container): t, id: string) => {
// Belt.Map.String.get(container, typeAliasesKey)->Belt.Option.flatMap(aliases =>
// switch aliases {
// | IEvRecord(r) => Belt.Map.String.get(r, id)
// | _ => None
// }
// )
// }
// let getTypeOf = (NameSpace(container): t, id: string) => {
// Belt.Map.String.get(container, typeReferencesKey)->Belt.Option.flatMap(defs =>
// switch defs {
// | IEvRecord(r) => Belt.Map.String.get(r, id)
// | _ => None
// }
// )
// }
// let setTypeAlias = (NameSpace(container): t, id: string, value): t => {
// let rValue = Belt.Map.String.getWithDefault(container, typeAliasesKey, IEvRecord(emptyMap))
// let r = switch rValue {
// | IEvRecord(r) => r
// | _ => emptyMap
// }
// let r2 = Belt.Map.String.set(r, id, value)->IEvRecord
// NameSpace(Belt.Map.String.set(container, typeAliasesKey, r2))
// }
// let setTypeOf = (NameSpace(container): t, id: string, value): t => {
// let rValue = Belt.Map.String.getWithDefault(container, typeReferencesKey, IEvRecord(emptyMap))
// let r = switch rValue {
// | IEvRecord(r) => r
// | _ => emptyMap
// }
// let r2 = Belt.Map.String.set(r, id, value)->IEvRecord
// NameSpace(Belt.Map.String.set(container, typeReferencesKey, r2))
// }
// let functionNotFoundError = (call: functionCall) =>
// REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)->Error
// let functionNotFoundErrorFFIFn = (functionName: string): ExpressionT.ffiFn => {
// (args: array<internalExpressionValue>, _environment: environment): result<
// internalExpressionValue,
// errorValue,
// > => {
// let call = (functionName, args)
// functionNotFoundError(call)
// }
// }
// let convertOptionToFfiFnReturningResult = (
// myFunctionName: string,
// myFunction: ExpressionT.optionFfiFnReturningResult,
// ): ExpressionT.ffiFn => {
// (args: array<InternalExpressionValue.t>, environment) => {
// myFunction(args, environment)->Belt.Option.getWithDefault(
// functionNotFoundErrorFFIFn(myFunctionName)(args, environment),
// )
// }
// }
// let convertOptionToFfiFn = (
// myFunctionName: string,
// myFunction: ExpressionT.optionFfiFn,
// ): ExpressionT.ffiFn => {
// (args: array<InternalExpressionValue.t>, environment) => {
// myFunction(args, environment)
// ->Belt.Option.map(v => v->Ok)
// ->Belt.Option.getWithDefault(functionNotFoundErrorFFIFn(myFunctionName)(args, environment))
// }
// }
// -- Module definition
// let define = (NameSpace(container): t, identifier: string, ev: internalExpressionValue): t => {
// NameSpace(Belt.Map.String.set(container, identifier, ev))
// }
// let defineNumber = (nameSpace: t, identifier: string, value: float): t =>
// nameSpace->define(identifier, IEvNumber(value))
// let defineString = (nameSpace: t, identifier: string, value: string): t =>
// nameSpace->define(identifier, IEvString(value))
// let defineBool = (nameSpace: t, identifier: string, value: bool): t =>
// nameSpace->define(identifier, IEvBool(value))
// let defineModule = (nameSpace: t, identifier: string, value: t): t =>
// nameSpace->define(identifier, toExpressionValue(value))

View File

@ -1,148 +0,0 @@
module Bindings = Reducer_Bindings
// module Continuation = ReducerInterface_Value_Continuation
module ExpressionT = Reducer_Expression_T
module ExternalLibrary = ReducerInterface.ExternalLibrary
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
module Lambda = Reducer_Expression_Lambda
module MathJs = Reducer_MathJs
module Result = Belt.Result
module TypeBuilder = Reducer_Type_TypeBuilder
module IEV = ReducerInterface_InternalExpressionValue
open Reducer_ErrorValue
/*
MathJs provides default implementations for built-ins
This is where all the expected built-ins like + = * / sin cos log ln etc are handled
DO NOT try to add external function mapping here!
*/
//TODO: pow to xor
exception TestRescriptException
let callInternal = (
call: IEV.functionCall,
_: Reducer_T.environment,
_: Reducer_T.reducerFn,
): result<'b, errorValue> => {
let callMathJs = (call: IEV.functionCall): result<'b, errorValue> =>
switch call {
| ("javascriptraise", [msg]) => Js.Exn.raiseError(IEV.toString(msg)) // For Tests
| ("rescriptraise", _) => raise(TestRescriptException) // For Tests
| call => call->IEV.toStringFunctionCall->MathJs.Eval.eval
}
// let doAddArray = (originalA, b) => {
// let a = originalA->Js.Array2.copy
// let _ = Js.Array2.pushMany(a, b)
// a->Reducer_T.IEvArray->Ok
// }
// let doAddString = (a, b) => {
// let answer = Js.String2.concat(a, b)
// answer->Reducer_T.IEvString->Ok
// }
let inspect = (value: Reducer_T.value) => {
Js.log(value->IEV.toString)
value->Ok
}
let inspectLabel = (value: Reducer_T.value, label: string) => {
Js.log(`${label}: ${value->IEV.toString}`)
value->Ok
}
// let doSetTypeAliasBindings = (
// bindings: nameSpace,
// symbol: string,
// value: internalExpressionValue,
// ) => Bindings.setTypeAlias(bindings, symbol, value)->IEvBindings->Ok
// let doSetTypeOfBindings = (bindings: nameSpace, symbol: string, value: internalExpressionValue) =>
// Bindings.setTypeOf(bindings, symbol, value)->IEvBindings->Ok
// let doExportBindings = (bindings: nameSpace) => bindings->Bindings.toExpressionValue->Ok
// let doIdentity = (value: Reducer_T.value) => value->Ok
// let doDumpBindings = (continuation: Reducer_T.nameSpace, value: Reducer_T.value) => {
// // let _ = Continuation.inspect(continuation, "doDumpBindings")
// accessors.states.continuation = continuation->Bindings.set("__result__", value)
// value->Ok
// }
switch call {
// | ("$_atIndex_$", [IEvArray(aValueArray), IEvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
// | ("$_atIndex_$", [IEvBindings(dict), IEvString(sIndex)]) => moduleAtIndex(dict, sIndex)
// | ("$_atIndex_$", [IEvRecord(dict), IEvString(sIndex)]) => recordAtIndex(dict, sIndex)
// | ("$_constructArray_$", args) => IEvArray(args)->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)]) =>
// TypeBuilder.typeModifier_memberOf_update(typeRecord, IEvArray(arr))
// | ("$_typeModifier_min_$", [IEvTypeIdentifier(typeIdentifier), value]) =>
// TypeBuilder.typeModifier_min(IEvTypeIdentifier(typeIdentifier), value)
// | ("$_typeModifier_min_$", [IEvType(typeRecord), value]) =>
// TypeBuilder.typeModifier_min_update(typeRecord, value)
// | ("$_typeModifier_max_$", [IEvTypeIdentifier(typeIdentifier), value]) =>
// TypeBuilder.typeModifier_max(IEvTypeIdentifier(typeIdentifier), value)
// | ("$_typeModifier_max_$", [IEvType(typeRecord), value]) =>
// TypeBuilder.typeModifier_max_update(typeRecord, value)
// | ("$_typeModifier_opaque_$", [IEvType(typeRecord)]) =>
// TypeBuilder.typeModifier_opaque_update(typeRecord)
// | ("$_typeOr_$", [IEvArray(arr)]) => TypeBuilder.typeOr(IEvArray(arr))
// | ("$_typeFunction_$", [IEvArray(arr)]) => TypeBuilder.typeFunction(arr)
// | ("$_typeTuple_$", [IEvArray(elems)]) => TypeBuilder.typeTuple(elems)
// | ("$_typeArray_$", [elem]) => TypeBuilder.typeArray(elem)
// | ("$_typeRecord_$", [IEvRecord(propertyMap)]) => TypeBuilder.typeRecord(propertyMap)
// | ("concat", [IEvArray(aValueArray), IEvArray(bValueArray)]) =>
// doAddArray(aValueArray, bValueArray)
// | ("concat", [IEvString(aValueString), IEvString(bValueString)]) =>
// doAddString(aValueString, bValueString)
| ("inspect", [value, IEvString(label)]) => inspectLabel(value, label)
| ("inspect", [value]) => inspect(value)
| (_, [IEvBool(_)])
| (_, [IEvNumber(_)])
| (_, [IEvString(_)])
| (_, [IEvBool(_), IEvBool(_)])
| (_, [IEvNumber(_), IEvNumber(_)])
| (_, [IEvString(_), IEvString(_)]) =>
callMathJs(call)
| call =>
Error(
REFunctionNotFound(call->IEV.functionCallToCallSignature->IEV.functionCallSignatureToString),
) // Report full type signature as error
}
}
/*
Reducer uses Result monad while reducing expressions
*/
let dispatch = (
call: IEV.functionCall,
env: Reducer_T.environment,
reducer: Reducer_T.reducerFn,
): Reducer_T.value =>
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
switch ExternalLibrary.dispatch((Js.String.make(fn), args), env, reducer, callInternal) {
| Ok(v) => v
| Error(e) => raise(ErrorException(e))
}
} catch {
| exn => Reducer_ErrorValue.fromException(exn)->Reducer_ErrorValue.toException
}

View File

@ -13,47 +13,51 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
switch expression { switch expression {
| T.EBlock(statements) => { | T.EBlock(statements) => {
let innerContext = {...context, bindings: context.bindings->Bindings.extend} let innerContext = {...context, bindings: context.bindings->Bindings.extend}
let (value, _) = statements->Belt.Array.reduce( let (value, _) =
(T.IEvVoid, innerContext), statements->Belt.Array.reduce((T.IEvVoid, innerContext), ((_, currentContext), statement) =>
((_, currentContext), statement) => statement->evaluate(currentContext) statement->evaluate(currentContext)
) )
(value, context) // inner context can be dropped (value, context)
} }
| T.EProgram(statements) => { | T.EProgram(statements) => {
// Js.log(`bindings: ${context.bindings->Bindings.locals->Reducer_Namespace.toString}`) // Js.log(`bindings: ${context.bindings->Bindings.locals->Reducer_Namespace.toString}`)
let (value, finalContext) = statements->Belt.Array.reduce( let (value, finalContext) =
(T.IEvVoid, context), statements->Belt.Array.reduce((T.IEvVoid, context), ((_, currentContext), statement) =>
((_, currentContext), statement) => statement->evaluate(currentContext)) statement->evaluate(currentContext)
)
// Js.log(`bindings after: ${finalContext.bindings->Bindings.locals->Reducer_Namespace.toString}`) // Js.log(`bindings after: ${finalContext.bindings->Bindings.locals->Reducer_Namespace.toString}`)
(value, finalContext) (value, finalContext)
} }
| T.EArray(elements) => { | T.EArray(elements) => {
let value = elements->Belt.Array.map(element => { let value =
let (value, _) = evaluate(element, context) elements
value ->Belt.Array.map(element => {
})->T.IEvArray let (value, _) = evaluate(element, context)
(value, context) value
} })
->T.IEvArray
(value, context)
}
| T.ERecord(pairs) => { | T.ERecord(pairs) => {
let value = let value =
pairs pairs
->Belt.Array.map(((eKey, eValue)) => { ->Belt.Array.map(((eKey, eValue)) => {
let (key, _) = eKey->evaluate(context) let (key, _) = eKey->evaluate(context)
let keyString = switch key { let keyString = switch key {
| IEvString(s) => s | IEvString(s) => s
| _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise | _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise
} }
let (value, _) = eValue->evaluate(context) let (value, _) = eValue->evaluate(context)
(keyString, value) (keyString, value)
}) })
->Belt.Map.String.fromArray ->Belt.Map.String.fromArray
->T.IEvRecord ->T.IEvRecord
(value, context) (value, context)
} }
| T.EAssign(left, right) => { | T.EAssign(left, right) => {
let (result, _) = right->evaluate(context) let (result, _) = right->evaluate(context)
@ -62,7 +66,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
{ {
...context, ...context,
bindings: context.bindings->Bindings.set(left, result), bindings: context.bindings->Bindings.set(left, result),
} },
) )
} }
@ -82,8 +86,10 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
} }
} }
| T.ELambda(parameters, body) => | T.ELambda(parameters, body) => (
(Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda, context) Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda,
context,
)
| T.ECall(fn, args) => { | T.ECall(fn, args) => {
let (lambda, _) = fn->evaluate(context) let (lambda, _) = fn->evaluate(context)
@ -92,8 +98,14 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
argValue argValue
}) })
switch lambda { switch lambda {
| T.IEvLambda(lambda) => (Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate), context) | T.IEvLambda(lambda) => (
| _ => RENotAFunction(lambda->ReducerInterface_InternalExpressionValue.toString)->Reducer_ErrorValue.ErrorException->raise Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate),
context,
)
| _ =>
RENotAFunction(lambda->ReducerInterface_InternalExpressionValue.toString)
->Reducer_ErrorValue.ErrorException
->raise
} }
} }
} }

View File

@ -34,13 +34,18 @@ let makeLambda = (
} }
let localBindings = bindings->Reducer_Bindings.extend let localBindings = bindings->Reducer_Bindings.extend
let localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex( let localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex(localBindings, (
localBindings, currentBindings,
(currentBindings, parameter, index) => { parameter,
index,
) => {
currentBindings->Reducer_Bindings.set(parameter, arguments[index]) currentBindings->Reducer_Bindings.set(parameter, arguments[index])
}) })
let (value, _) = reducer(body, {bindings: localBindingsWithParameters, environment: environment}) let (value, _) = reducer(
body,
{bindings: localBindingsWithParameters, environment: environment},
)
value value
} }

View File

@ -7,17 +7,20 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
type t = Reducer_T.expression type t = Reducer_T.expression
let commaJoin = values => values->Reducer_Extra_Array.intersperse(", ")->Js.String.concatMany("") let commaJoin = values => values->Reducer_Extra_Array.intersperse(", ")->Js.String.concatMany("")
let semicolonJoin = values => values->Reducer_Extra_Array.intersperse("; ")->Js.String.concatMany("") let semicolonJoin = values =>
values->Reducer_Extra_Array.intersperse("; ")->Js.String.concatMany("")
/* /*
Converts the expression to String Converts the expression to String
*/ */
let rec toString = (expression: t) => let rec toString = (expression: t) =>
switch expression { switch expression {
| EBlock(statements) => `{${Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin}}` | EBlock(statements) =>
`{${Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin}}`
| EProgram(statements) => Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin | EProgram(statements) => Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin
| EArray(aList) => `[${Js.Array2.map(aList, aValue => toString(aValue))->commaJoin}]` | EArray(aList) => `[${Js.Array2.map(aList, aValue => toString(aValue))->commaJoin}]`
| ERecord(map) => `{${map->Belt.Array.map(((key, value)) => `${key->toString}: ${value->toString}`)->commaJoin}}` | ERecord(map) =>
`{${map->Belt.Array.map(((key, value)) => `${key->toString}: ${value->toString}`)->commaJoin}}`
| ESymbol(name) => name | ESymbol(name) => name
| ETernary(predicate, trueCase, falseCase) => | ETernary(predicate, trueCase, falseCase) =>
`${predicate->toString} ? (${trueCase->toString}) : (${falseCase->toString})` `${predicate->toString} ? (${trueCase->toString}) : (${falseCase->toString})`

View File

@ -1,9 +1,12 @@
/*
Namespace is a flat mapping of names to Squiggle values.
The full context of variables accessible to Squiggle is called "bindings"; see Reducer_Bindings module for details on it.
*/
type t = Reducer_T.namespace type t = Reducer_T.namespace
let make = (): t => Belt.Map.String.empty let make = (): t => Belt.Map.String.empty
let get = (namespace: t, id: string): option<Reducer_T.value> => let get = (namespace: t, id: string): option<Reducer_T.value> => namespace->Belt.Map.String.get(id)
namespace->Belt.Map.String.get(id)
let set = (namespace: t, id: string, value): t => { let set = (namespace: t, id: string, value): t => {
namespace->Belt.Map.String.set(id, value) namespace->Belt.Map.String.set(id, value)
@ -16,19 +19,18 @@ let mergeFrom = (from: t, to: t): t => {
} }
let mergeMany = (namespaces: array<t>): t => let mergeMany = (namespaces: array<t>): t =>
Belt.Array.reduce(namespaces, make(), (acc, ns) => acc->mergeFrom(ns)) Belt.Array.reduce(namespaces, make(), (acc, ns) => acc->mergeFrom(ns))
let toString = (namespace: t) => let toString = (namespace: t) =>
namespace namespace
->Belt.Map.String.toArray ->Belt.Map.String.toArray
->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${eachValue->ReducerInterface_InternalExpressionValue.toString}`) ->Belt.Array.map(((eachKey, eachValue)) =>
`${eachKey}: ${eachValue->ReducerInterface_InternalExpressionValue.toString}`
)
->Js.Array2.toString ->Js.Array2.toString
let fromArray = (a): t => let fromArray = (a): t => Belt.Map.String.fromArray(a)
Belt.Map.String.fromArray(a)
let toMap = (namespace: t): Reducer_T.map => let toMap = (namespace: t): Reducer_T.map => namespace
namespace
let toRecord = (namespace: t): Reducer_T.value => let toRecord = (namespace: t): Reducer_T.value => namespace->toMap->IEvRecord
namespace->toMap->IEvRecord

View File

@ -11,7 +11,7 @@ zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
outerBlock outerBlock
= statements:array_statements finalExpression: (statementSeparator @expression)? = statements:array_statements finalExpression: (statementSeparator @expression)?
{ if (finalExpression) statements.push(finalExpression) { if (finalExpression) statements.push(finalExpression)
return h.nodeProgram(statements) } return h.nodeProgram(statements) }
/ finalExpression: expression / finalExpression: expression
{ return h.nodeProgram([finalExpression]) } { return h.nodeProgram([finalExpression]) }
@ -23,7 +23,7 @@ innerBlockOrExpression
quotedInnerBlock quotedInnerBlock
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}' = '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
{ if (finalExpression) statements.push(finalExpression) { if (finalExpression) statements.push(finalExpression)
return h.nodeBlock(statements) } return h.nodeBlock(statements) }
/ '{' _nl finalExpression: expression _nl '}' / '{' _nl finalExpression: expression _nl '}'
{ return h.nodeBlock([finalExpression]) } { return h.nodeBlock([finalExpression]) }

View File

@ -1,8 +1,8 @@
import { LocationRange } from "peggy"; import { LocationRange } from "peggy";
export const toFunction = { export const toFunction = {
"+": "add",
"-": "subtract", "-": "subtract",
"->": "pipe",
"!=": "unequal", "!=": "unequal",
".-": "dotSubtract", ".-": "dotSubtract",
".*": "dotMultiply", ".*": "dotMultiply",
@ -13,7 +13,6 @@ export const toFunction = {
"/": "divide", "/": "divide",
"&&": "and", "&&": "and",
"^": "pow", // or xor "^": "pow", // or xor
"+": "add",
"<": "smaller", "<": "smaller",
"<=": "smallerEq", "<=": "smallerEq",
"==": "equal", "==": "equal",

View File

@ -9,12 +9,11 @@ let dispatch = (
reducer: Reducer_T.reducerFn, reducer: Reducer_T.reducerFn,
chain, chain,
): result<Reducer_T.value, 'e> => { ): result<Reducer_T.value, 'e> => {
E.A.O.firstSomeFn([ E.A.O.firstSomeFn([// () => ReducerInterface_GenericDistribution.dispatch(call, environment),
// () => ReducerInterface_GenericDistribution.dispatch(call, environment), // () => ReducerInterface_Date.dispatch(call, environment),
// () => ReducerInterface_Date.dispatch(call, environment), // () => ReducerInterface_Duration.dispatch(call, environment),
// () => ReducerInterface_Duration.dispatch(call, environment), // () => ReducerInterface_Number.dispatch(call, environment),
// () => ReducerInterface_Number.dispatch(call, environment), // () => FunctionRegistry_Library.dispatch(call, environment, reducer),
// () => FunctionRegistry_Library.dispatch(call, environment, reducer),
])->E.O2.defaultFn(() => chain(call, environment, reducer)) ])->E.O2.defaultFn(() => chain(call, environment, reducer))
} }

View File

@ -2,7 +2,6 @@
// (value methods should be moved to Reducer_Value.res) // (value methods should be moved to Reducer_Value.res)
module ErrorValue = Reducer_ErrorValue module ErrorValue = Reducer_ErrorValue
module Extra_Array = Reducer_Extra_Array
type environment = GenericDist.env type environment = GenericDist.env
module T = Reducer_T module T = Reducer_T

View File

@ -10,49 +10,37 @@ let internalStdLib: Reducer_T.namespace = {
"$_atIndex_$", "$_atIndex_$",
Reducer_Expression_Lambda.makeFFILambda((inputs, _, _) => { Reducer_Expression_Lambda.makeFFILambda((inputs, _, _) => {
switch inputs { switch inputs {
| [IEvArray(aValueArray), IEvNumber(fIndex)] => switch Belt.Array.get( | [IEvArray(aValueArray), IEvNumber(fIndex)] => {
aValueArray, let index = Belt.Int.fromFloat(fIndex) // TODO - fail on non-integer indices?
Belt.Int.fromFloat(fIndex),
) { switch Belt.Array.get(aValueArray, index) {
| Some(value) => value | Some(value) => value
| None => | None =>
REArrayIndexNotFound("Array index not found", Belt.Int.fromFloat(fIndex)) REArrayIndexNotFound("Array index not found", index)
->ErrorException ->ErrorException
->raise ->raise
} }
| [IEvRecord(dict), IEvString(sIndex)] => switch Belt.Map.String.get(dict, sIndex) { }
| [IEvRecord(dict), IEvString(sIndex)] =>
switch Belt.Map.String.get(dict, sIndex) {
| Some(value) => value | Some(value) => value
| None => RERecordPropertyNotFound("Record property not found", sIndex)->ErrorException->raise | None =>
RERecordPropertyNotFound("Record property not found", sIndex)->ErrorException->raise
} }
| _ => REOther("Trying to access key on wrong value")->ErrorException->raise | _ => REOther("Trying to access key on wrong value")->ErrorException->raise
} }
})->Reducer_T.IEvLambda, })->Reducer_T.IEvLambda,
) )
let res = FunctionRegistry_Library.nonRegistryLambdas->Belt.Array.reduce( let res = FunctionRegistry_Library.nonRegistryLambdas->Belt.Array.reduce(res, (
res, cur,
(cur, (name, lambda)) => { (name, lambda),
cur->Reducer_Namespace.set(name, lambda->Reducer_T.IEvLambda) ) => {
} cur->Reducer_Namespace.set(name, lambda->Reducer_T.IEvLambda)
) })
// TODO:
// () => ReducerInterface_GenericDistribution.dispatch(call, environment),
// () => ReducerInterface_Date.dispatch(call, environment),
// () => ReducerInterface_Duration.dispatch(call, environment),
// () => ReducerInterface_Number.dispatch(call, environment),
// Reducer_Dispatch_BuiltIn: // Reducer_Dispatch_BuiltIn:
// [x] | ("$_atIndex_$", [IEvArray(aValueArray), IEvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
// [ ] | ("$_atIndex_$", [IEvBindings(dict), IEvString(sIndex)]) => moduleAtIndex(dict, sIndex)
// [x] | ("$_atIndex_$", [IEvRecord(dict), IEvString(sIndex)]) => recordAtIndex(dict, sIndex)
// [x] | ("$_constructArray_$", args) => IEvArray(args)->Ok
// [x] | ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
// [ ] | ("concat", [IEvArray(aValueArray), IEvArray(bValueArray)]) => doAddArray(aValueArray, bValueArray)
// [ ] | ("concat", [IEvString(aValueString), IEvString(bValueString)]) => doAddString(aValueString, bValueString)
// [ ] | ("inspect", [value, IEvString(label)]) => inspectLabel(value, label)
// [ ] | ("inspect", [value]) => inspect(value)
// [ ] | (_, [IEvBool(_)]) // [ ] | (_, [IEvBool(_)])
// [ ] | (_, [IEvNumber(_)]) // [ ] | (_, [IEvNumber(_)])
// [ ] | (_, [IEvString(_)]) // [ ] | (_, [IEvString(_)])
@ -60,19 +48,20 @@ let internalStdLib: Reducer_T.namespace = {
// [ ] | (_, [IEvNumber(_), IEvNumber(_)]) // [ ] | (_, [IEvNumber(_), IEvNumber(_)])
// [ ] | (_, [IEvString(_), IEvString(_)]) => callMathJs(call) // [ ] | (_, [IEvString(_), IEvString(_)]) => callMathJs(call)
let res = FunctionRegistry_Library.registry let res =
->FunctionRegistry_Core.Registry.allNames FunctionRegistry_Library.registry
->Belt.Array.reduce(res, (cur, name) => { ->FunctionRegistry_Core.Registry.allNames
cur->Reducer_Namespace.set( ->Belt.Array.reduce(res, (cur, name) => {
name, cur->Reducer_Namespace.set(
Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => { name,
switch FunctionRegistry_Library.call(name, arguments, environment, reducer) { Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => {
| Ok(value) => value switch FunctionRegistry_Library.call(name, arguments, environment, reducer) {
| Error(error) => error->Reducer_ErrorValue.ErrorException->raise | Ok(value) => value
} | Error(error) => error->Reducer_ErrorValue.ErrorException->raise
})->Reducer_T.IEvLambda, }
) })->Reducer_T.IEvLambda,
}) )
})
res res
} }

View File

@ -166,23 +166,25 @@ let linkDependencies = (project: t, sourceId: string): Reducer_T.namespace => {
Belt.Array.concatMany([ Belt.Array.concatMany([
[project->getStdLib], [project->getStdLib],
pastChain->Belt.Array.map(project->getBindings), pastChain->Belt.Array.map(project->getBindings),
pastChain->Belt.Array.map( pastChain->Belt.Array.map(id =>
id => Reducer_Namespace.fromArray([ Reducer_Namespace.fromArray([
("__result__", (
switch project->getResult(id) { "__result__",
switch project->getResult(id) {
| Ok(result) => result | Ok(result) => result
| Error(error) => error->Reducer_ErrorValue.ErrorException->raise | Error(error) => error->Reducer_ErrorValue.ErrorException->raise
}) },
),
]) ])
), ),
]) ]),
) )
let includesAsVariables = project->getIncludesAsVariables(sourceId) let includesAsVariables = project->getIncludesAsVariables(sourceId)
Belt.Array.reduce(includesAsVariables, namespace, (acc, (variable, includeFile)) => Belt.Array.reduce(includesAsVariables, namespace, (acc, (variable, includeFile)) =>
acc->Reducer_Namespace.set( acc->Reducer_Namespace.set(
variable, variable,
project->getBindings(includeFile)->Reducer_Namespace.toRecord project->getBindings(includeFile)->Reducer_Namespace.toRecord,
) )
) )
} }
@ -190,7 +192,7 @@ let linkDependencies = (project: t, sourceId: string): Reducer_T.namespace => {
let doLinkAndRun = (project: t, sourceId: string): unit => { let doLinkAndRun = (project: t, sourceId: string): unit => {
let context = Reducer_Context.createContext( let context = Reducer_Context.createContext(
project->linkDependencies(sourceId), project->linkDependencies(sourceId),
project->getEnvironment project->getEnvironment,
) )
let newItem = project->getItem(sourceId)->ProjectItem.run(context) let newItem = project->getItem(sourceId)->ProjectItem.run(context)
// Js.log("after run " ++ newItem.continuation->Reducer_Bindings.toString) // Js.log("after run " ++ newItem.continuation->Reducer_Bindings.toString)

View File

@ -172,10 +172,14 @@ let failRun = (this: t, e: Reducer_ErrorValue.errorValue): t =>
let doRun = (this: t, context: Reducer_T.context): t => let doRun = (this: t, context: Reducer_T.context): t =>
switch this->getExpression { switch this->getExpression {
| Some(expressionResult) => switch expressionResult { | Some(expressionResult) =>
| Ok(expression) => try { switch expressionResult {
| Ok(expression) =>
try {
let (result, contextAfterEvaluation) = Reducer_Expression.evaluate(expression, context) let (result, contextAfterEvaluation) = Reducer_Expression.evaluate(expression, context)
this->setResult(result->Ok)->setContinuation(contextAfterEvaluation.bindings->Reducer_Bindings.locals) this
->setResult(result->Ok)
->setContinuation(contextAfterEvaluation.bindings->Reducer_Bindings.locals)
} catch { } catch {
| Reducer_ErrorValue.ErrorException(e) => this->failRun(e) | Reducer_ErrorValue.ErrorException(e) => this->failRun(e)
| _ => this->failRun(RETodo("unhandled rescript exception")) | _ => this->failRun(RETodo("unhandled rescript exception"))

View File

@ -12,4 +12,6 @@ let availableNumbers: array<(string, float)> = [
] ]
let make = (): Reducer_Namespace.t => let make = (): Reducer_Namespace.t =>
availableNumbers->E.A2.fmap(((name, v)) => (name, Reducer_T.IEvNumber(v)))->Reducer_Namespace.fromArray availableNumbers
->E.A2.fmap(((name, v)) => (name, Reducer_T.IEvNumber(v)))
->Reducer_Namespace.fromArray