fix more tests; FR improvements/refactorings
This commit is contained in:
parent
6aa2280543
commit
271303fb5f
|
@ -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)
|
||||||
|
|
|
@ -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)")
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,8 @@ 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])
|
||||||
|
|
||||||
|
|
|
@ -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)}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -86,3 +86,4 @@
|
||||||
// expectedValue: string,
|
// expectedValue: string,
|
||||||
// ) => testMacroEval_(Only.test, bindArray, expr, expectedValue)
|
// ) => testMacroEval_(Only.test, bindArray, expr, expectedValue)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
|
@ -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}")
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -124,3 +124,4 @@
|
||||||
// expect(result)->toEqual(Some(Ok(IEvString("helloworld"))))
|
// expect(result)->toEqual(Some(Ok(IEvString("helloworld"))))
|
||||||
// })
|
// })
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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)")
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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)))")
|
||||||
|
|
|
@ -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"),
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
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
|
||||||
|
|
|
@ -2,9 +2,7 @@ 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, _ => {
|
||||||
|
@ -46,14 +44,14 @@ module StringMap: Benchmark_Helpers.BenchmarkTopic = {
|
||||||
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(
|
||||||
|
`Filling a map with ("key{i}" => "i") key-value pairs, size ${size->Js.Int.toString} (${iterations->Js.Int.toString} iterations)`,
|
||||||
|
)
|
||||||
Benchmark_Helpers.measure("Belt.Map.String", beltMap)
|
Benchmark_Helpers.measure("Belt.Map.String", beltMap)
|
||||||
Benchmark_Helpers.measure("Belt.MutableMap.String", beltMutableMap)
|
Benchmark_Helpers.measure("Belt.MutableMap.String", beltMutableMap)
|
||||||
Benchmark_Helpers.measure("Belt.HashMap.String", beltHashMap)
|
Benchmark_Helpers.measure("Belt.HashMap.String", beltHashMap)
|
||||||
|
|
123
packages/squiggle-lang/src/rescript/FR/FR_Builtin.res
Normal file
123
packages/squiggle-lang/src/rescript/FR/FR_Builtin.res
Normal 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)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]
|
|
@ -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->Error
|
->Reducer_ErrorValue.REOther
|
||||||
|
->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
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
),
|
),
|
159
packages/squiggle-lang/src/rescript/FR/FR_Date.res
Normal file
159
packages/squiggle-lang/src/rescript/FR/FR_Date.res
Normal 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)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
|
@ -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) {
|
|
@ -316,7 +316,8 @@ 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.REOther("Internal error in FR_GenericDist implementation")
|
||||||
->Reducer_ErrorValue.ErrorException
|
->Reducer_ErrorValue.ErrorException
|
||||||
->raise
|
->raise
|
||||||
}
|
}
|
||||||
|
@ -340,7 +341,19 @@ 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 = [
|
||||||
|
"add",
|
||||||
|
"multiply",
|
||||||
|
"subtract",
|
||||||
|
"divide",
|
||||||
|
"pow",
|
||||||
|
"log",
|
||||||
|
"dotAdd",
|
||||||
|
"dotMultiply",
|
||||||
|
"dotSubtract",
|
||||||
|
"dotDivide",
|
||||||
|
"dotPow",
|
||||||
|
]
|
||||||
let twoArgTypes = [
|
let twoArgTypes = [
|
||||||
// can't use numeric+numeric, since number+number should be delegated to builtin arithmetics
|
// can't use numeric+numeric, since number+number should be delegated to builtin arithmetics
|
||||||
[FRTypeDist, FRTypeNumber],
|
[FRTypeDist, FRTypeNumber],
|
||||||
|
@ -348,11 +361,7 @@ let makeOperationFns = (): array<function> => {
|
||||||
[FRTypeDist, 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
|
||||||
|
@ -395,7 +404,7 @@ let library = E.A.concatMany([
|
||||||
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;
|
|
@ -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
|
70
packages/squiggle-lang/src/rescript/FR/FR_Mathjs.res
Normal file
70
packages/squiggle-lang/src/rescript/FR/FR_Mathjs.res
Normal 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"),
|
||||||
|
|
||||||
|
]
|
|
@ -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 = [
|
|
@ -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),
|
|
||||||
(),
|
(),
|
||||||
),
|
),
|
||||||
],
|
],
|
|
@ -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(
|
|
@ -22,7 +22,6 @@ 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),
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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.
|
||||||
|
|
|
@ -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))
|
||||||
|
// }
|
|
@ -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))
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -13,28 +13,32 @@ 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 =
|
||||||
|
elements
|
||||||
|
->Belt.Array.map(element => {
|
||||||
let (value, _) = evaluate(element, context)
|
let (value, _) = evaluate(element, context)
|
||||||
value
|
value
|
||||||
})->T.IEvArray
|
})
|
||||||
|
->T.IEvArray
|
||||||
(value, context)
|
(value, 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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})`
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -21,14 +24,13 @@ let mergeMany = (namespaces: array<t>): t =>
|
||||||
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
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -9,8 +9,7 @@ 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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,7 +48,8 @@ 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_Library.registry
|
||||||
->FunctionRegistry_Core.Registry.allNames
|
->FunctionRegistry_Core.Registry.allNames
|
||||||
->Belt.Array.reduce(res, (cur, name) => {
|
->Belt.Array.reduce(res, (cur, name) => {
|
||||||
cur->Reducer_Namespace.set(
|
cur->Reducer_Namespace.set(
|
||||||
|
|
|
@ -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__",
|
(
|
||||||
|
"__result__",
|
||||||
switch project->getResult(id) {
|
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)
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user