fix more tests; FR improvements/refactorings
This commit is contained in:
parent
6aa2280543
commit
271303fb5f
|
@ -31,9 +31,7 @@ describe("Bindings", () => {
|
|||
|
||||
describe("extend", () => {
|
||||
let value2 = Reducer_T.IEvNumber(5.)
|
||||
let extendedBindings = bindings
|
||||
->Bindings.extend
|
||||
->Bindings.set("value", value2)
|
||||
let extendedBindings = bindings->Bindings.extend->Bindings.set("value", value2)
|
||||
|
||||
test("get on extended", () => {
|
||||
expect(extendedBindings->Bindings.get("value")) == Some(value2)
|
||||
|
|
|
@ -144,3 +144,4 @@
|
|||
// let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)})
|
||||
// testMacroEval([("y", IEvNumber(666.))], callLambdaExpression, "Ok(667)")
|
||||
// })
|
||||
|
||||
|
|
|
@ -35,12 +35,8 @@ describe("Namespace", () => {
|
|||
let x2 = makeValue(20.)
|
||||
let x3 = makeValue(30.)
|
||||
let x4 = makeValue(40.)
|
||||
let ns1 = Namespace.make()
|
||||
->Namespace.set("x1", x1)
|
||||
->Namespace.set("x2", x2)
|
||||
let ns2 = Namespace.make()
|
||||
->Namespace.set("x3", x3)
|
||||
->Namespace.set("x4", x4)
|
||||
let ns1 = Namespace.make()->Namespace.set("x1", x1)->Namespace.set("x2", x2)
|
||||
let ns2 = Namespace.make()->Namespace.set("x3", x3)->Namespace.set("x4", x4)
|
||||
|
||||
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", "{(:multiply (:divide 1 2) 3)}")
|
||||
testParse("1 / 2 / 3", "{(:divide (:divide 1 2) 3)}")
|
||||
testParse(
|
||||
"1 * 2 + 3 * 4",
|
||||
"{(:add (:multiply 1 2) (:multiply 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 - 3 * 4",
|
||||
"{(:subtract (:multiply 1 2) (:multiply 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 .+ 3 * 4",
|
||||
"{(:dotAdd (:multiply 1 2) (:multiply 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 .- 3 * 4",
|
||||
"{(:dotSubtract (:multiply 1 2) (:multiply 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 + 3 .* 4",
|
||||
"{(:add (:multiply 1 2) (:dotMultiply 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 + 3 / 4",
|
||||
"{(:add (:multiply 1 2) (:divide 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 + 3 ./ 4",
|
||||
"{(:add (:multiply 1 2) (:dotDivide 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 - 3 .* 4",
|
||||
"{(:subtract (:multiply 1 2) (:dotMultiply 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 - 3 / 4",
|
||||
"{(:subtract (:multiply 1 2) (:divide 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 - 3 ./ 4",
|
||||
"{(:subtract (:multiply 1 2) (:dotDivide 3 4))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 - 3 * 4^5",
|
||||
"{(:subtract (:multiply 1 2) (:multiply 3 (:pow 4 5)))}",
|
||||
)
|
||||
testParse("1 * 2 + 3 * 4", "{(:add (:multiply 1 2) (:multiply 3 4))}")
|
||||
testParse("1 * 2 - 3 * 4", "{(:subtract (:multiply 1 2) (:multiply 3 4))}")
|
||||
testParse("1 * 2 .+ 3 * 4", "{(:dotAdd (:multiply 1 2) (:multiply 3 4))}")
|
||||
testParse("1 * 2 .- 3 * 4", "{(:dotSubtract (:multiply 1 2) (:multiply 3 4))}")
|
||||
testParse("1 * 2 + 3 .* 4", "{(:add (:multiply 1 2) (:dotMultiply 3 4))}")
|
||||
testParse("1 * 2 + 3 / 4", "{(:add (:multiply 1 2) (:divide 3 4))}")
|
||||
testParse("1 * 2 + 3 ./ 4", "{(:add (:multiply 1 2) (:dotDivide 3 4))}")
|
||||
testParse("1 * 2 - 3 .* 4", "{(:subtract (:multiply 1 2) (:dotMultiply 3 4))}")
|
||||
testParse("1 * 2 - 3 / 4", "{(:subtract (:multiply 1 2) (:divide 3 4))}")
|
||||
testParse("1 * 2 - 3 ./ 4", "{(:subtract (:multiply 1 2) (:dotDivide 3 4))}")
|
||||
testParse("1 * 2 - 3 * 4^5", "{(:subtract (:multiply 1 2) (:multiply 3 (:pow 4 5)))}")
|
||||
testParse(
|
||||
"1 * 2 - 3 * 4^5^6",
|
||||
"{(:subtract (:multiply 1 2) (:multiply 3 (:pow (:pow 4 5) 6)))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * -a[-2]",
|
||||
"{(:multiply 1 (:unaryMinus (:$_atIndex_$ :a (:unaryMinus 2))))}",
|
||||
)
|
||||
testParse("1 * -a[-2]", "{(:multiply 1 (:unaryMinus (:$_atIndex_$ :a (:unaryMinus 2))))}")
|
||||
})
|
||||
|
||||
describe("multi-line", () => {
|
||||
|
@ -111,25 +75,13 @@ describe("Peggy parse", () => {
|
|||
describe("arrays", () => {
|
||||
testParse("[]", "{[]}")
|
||||
testParse("[0, 1, 2]", "{[0; 1; 2]}")
|
||||
testParse(
|
||||
"['hello', 'world']",
|
||||
"{['hello'; 'world']}",
|
||||
)
|
||||
testParse(
|
||||
"([0,1,2])[1]",
|
||||
"{(:$_atIndex_$ [0; 1; 2] 1)}",
|
||||
)
|
||||
testParse("['hello', 'world']", "{['hello'; 'world']}")
|
||||
testParse("([0,1,2])[1]", "{(:$_atIndex_$ [0; 1; 2] 1)}")
|
||||
})
|
||||
|
||||
describe("records", () => {
|
||||
testParse(
|
||||
"{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
|
||||
testParse("{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
|
||||
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
|
||||
testParse("a==!b(1)", "{(:equal :a (:not (:b 1)))}")
|
||||
testParse("a==!b[1]", "{(:equal :a (:not (:$_atIndex_$ :b 1)))}")
|
||||
testParse(
|
||||
"a==!b.one",
|
||||
"{(:equal :a (:not (:$_atIndex_$ :b 'one')))}",
|
||||
)
|
||||
testParse("a==!b.one", "{(:equal :a (:not (:$_atIndex_$ :b 'one')))}")
|
||||
})
|
||||
|
||||
describe("comments", () => {
|
||||
|
@ -167,14 +116,8 @@ describe("Peggy parse", () => {
|
|||
})
|
||||
|
||||
describe("if then else", () => {
|
||||
testParse(
|
||||
"if true then 2 else 3",
|
||||
"{(::$$_ternary_$$ true {2} {3})}",
|
||||
)
|
||||
testParse(
|
||||
"if false then {2} else {3}",
|
||||
"{(::$$_ternary_$$ false {2} {3})}",
|
||||
)
|
||||
testParse("if true then 2 else 3", "{(::$$_ternary_$$ true {2} {3})}")
|
||||
testParse("if false then {2} else {3}", "{(::$$_ternary_$$ false {2} {3})}")
|
||||
testParse(
|
||||
"if false then {2} else if false then {4} else {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", "{(:or (:and :a (:not :b)) :c)}")
|
||||
testParse("a && b==c || d", "{(:or (:and :a (:equal :b :c)) :d)}")
|
||||
testParse(
|
||||
"a && b!=c || d",
|
||||
"{(:or (:and :a (:unequal :b :c)) :d)}",
|
||||
)
|
||||
testParse(
|
||||
"a && !(b==c) || d",
|
||||
"{(:or (:and :a (:not (:equal :b :c))) :d)}",
|
||||
)
|
||||
testParse(
|
||||
"a && b>=c || d",
|
||||
"{(:or (:and :a (:largerEq :b :c)) :d)}",
|
||||
)
|
||||
testParse(
|
||||
"a && !(b>=c) || d",
|
||||
"{(:or (:and :a (:not (:largerEq :b :c))) :d)}",
|
||||
)
|
||||
testParse(
|
||||
"a && b<=c || d",
|
||||
"{(:or (:and :a (:smallerEq :b :c)) :d)}",
|
||||
)
|
||||
testParse("a && b!=c || d", "{(:or (:and :a (:unequal :b :c)) :d)}")
|
||||
testParse("a && !(b==c) || d", "{(:or (:and :a (:not (:equal :b :c))) :d)}")
|
||||
testParse("a && b>=c || d", "{(:or (:and :a (:largerEq :b :c)) :d)}")
|
||||
testParse("a && !(b>=c) || d", "{(:or (:and :a (:not (:largerEq :b :c))) :d)}")
|
||||
testParse("a && b<=c || d", "{(:or (:and :a (:smallerEq :b :c)) :d)}")
|
||||
testParse("a && b>c || d", "{(:or (:and :a (:larger :b :c)) :d)}")
|
||||
testParse(
|
||||
"a && b<c || d",
|
||||
"{(: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 (:$_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("a && b<c || 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 (:$_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(
|
||||
"a && b<1+2*-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", () => {
|
||||
testParse("1 -> add(2)", "{(:add 1 2)}")
|
||||
testParse("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}")
|
||||
testParse(
|
||||
"-a[1] -> add(2)",
|
||||
"{(:add (:unaryMinus (:$_atIndex_$ :a 1)) 2)}",
|
||||
)
|
||||
testParse("-a[1] -> add(2)", "{(:add (:unaryMinus (:$_atIndex_$ :a 1)) 2)}")
|
||||
testParse("-f(1) -> add(2)", "{(:add (:unaryMinus (:f 1)) 2)}")
|
||||
testParse("1 + 2 -> add(3)", "{(:add 1 (:add 2 3))}")
|
||||
testParse("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}")
|
||||
testParse("1 -> subtract(2)", "{(:subtract 1 2)}")
|
||||
testParse("-1 -> subtract(2)", "{(:subtract (:unaryMinus 1) 2)}")
|
||||
testParse(
|
||||
"1 -> subtract(2) * 3",
|
||||
"{(:multiply (:subtract 1 2) 3)}",
|
||||
)
|
||||
testParse("1 -> subtract(2) * 3", "{(:multiply (:subtract 1 2) 3)}")
|
||||
})
|
||||
|
||||
describe("elixir pipe", () => {
|
||||
|
@ -269,10 +173,7 @@ describe("Peggy parse", () => {
|
|||
|
||||
describe("to", () => {
|
||||
testParse("1 to 2", "{(:credibleIntervalToDistribution 1 2)}")
|
||||
testParse(
|
||||
"-1 to -2",
|
||||
"{(:credibleIntervalToDistribution (:unaryMinus 1) (:unaryMinus 2))}",
|
||||
) // lower than unary
|
||||
testParse("-1 to -2", "{(:credibleIntervalToDistribution (:unaryMinus 1) (:unaryMinus 2))}") // lower than unary
|
||||
testParse(
|
||||
"a[1] to a[2]",
|
||||
"{(:credibleIntervalToDistribution (:$_atIndex_$ :a 1) (:$_atIndex_$ :a 2))}",
|
||||
|
@ -281,10 +182,7 @@ describe("Peggy parse", () => {
|
|||
"a.p1 to a.p2",
|
||||
"{(:credibleIntervalToDistribution (:$_atIndex_$ :a 'p1') (:$_atIndex_$ :a 'p2'))}",
|
||||
) // lower than post
|
||||
testParse(
|
||||
"1 to 2 + 3",
|
||||
"{(:add (:credibleIntervalToDistribution 1 2) 3)}",
|
||||
) // higher than binary operators
|
||||
testParse("1 to 2 + 3", "{(:add (:credibleIntervalToDistribution 1 2) 3)}") // higher than binary operators
|
||||
testParse(
|
||||
"1->add(2) to 3->add(4) -> add(4)",
|
||||
"{(:credibleIntervalToDistribution (:add 1 2) (:add (:add 3 4) 4))}",
|
||||
|
@ -301,10 +199,7 @@ describe("Peggy parse", () => {
|
|||
testParse("{|x| x}", "{{|:x| :x}}")
|
||||
testParse("f={|x| x}", "{:f = {{|:x| :x}}}")
|
||||
testParse("f(x)=x", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments
|
||||
testParse(
|
||||
"f(x)=x ? 1 : 0",
|
||||
"{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}",
|
||||
) // Function definitions are lambda assignments
|
||||
testParse("f(x)=x ? 1 : 0", "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}") // Function definitions are lambda assignments
|
||||
})
|
||||
|
||||
describe("Using lambda as value", () => {
|
||||
|
@ -321,18 +216,9 @@ describe("Peggy parse", () => {
|
|||
"{:myaddd = {|:x,:y| {(:add :x :y)}}; :z = {{'x': :myaddd}}; :z}",
|
||||
)
|
||||
testParse("f({|x| x+1})", "{(:f {|:x| (:add :x 1)})}")
|
||||
testParse(
|
||||
"map(arr, {|x| x+1})",
|
||||
"{(:map :arr {|:x| (:add :x 1)})}",
|
||||
)
|
||||
testParse(
|
||||
"map([1,2,3], {|x| x+1})",
|
||||
"{(:map [1; 2; 3] {|:x| (:add :x 1)})}",
|
||||
)
|
||||
testParse(
|
||||
"[1,2,3]->map({|x| x+1})",
|
||||
"{(:map [1; 2; 3] {|:x| (:add :x 1)})}",
|
||||
)
|
||||
testParse("map(arr, {|x| x+1})", "{(:map :arr {|:x| (:add :x 1)})}")
|
||||
testParse("map([1,2,3], {|x| x+1})", "{(:map [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", () => {
|
||||
testParse("1m", "{(:fromUnit_m 1)}")
|
||||
|
@ -419,7 +305,7 @@ describe("parsing new line", () => {
|
|||
g=f+4
|
||||
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(
|
||||
`
|
||||
|
@ -441,7 +327,7 @@ describe("parsing new line", () => {
|
|||
p ->
|
||||
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(
|
||||
`
|
||||
|
@ -460,6 +346,6 @@ describe("parsing new line", () => {
|
|||
d +
|
||||
e
|
||||
`,
|
||||
"{(:add (:d (:c (:b :a))) :e)}"
|
||||
"{(:add (:d (:c (:b :a))) :e)}",
|
||||
)
|
||||
})
|
||||
|
|
|
@ -4,20 +4,12 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|||
open Jest
|
||||
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", () => {
|
||||
testToExpression("1", "1", ~v="1", ())
|
||||
testToExpression("x=1", "x = {1}", ~v="()", ())
|
||||
testToExpression(
|
||||
"x=1; y=2",
|
||||
"x = {1}; y = {2}",
|
||||
~v="()",
|
||||
(),
|
||||
)
|
||||
testToExpression("x=1; y=2", "x = {1}; y = {2}", ~v="()", ())
|
||||
testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ())
|
||||
testToExpression(
|
||||
"x={a=1; a}; x",
|
||||
"x = {a = {1}; a}; x",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
testToExpression("x={a=1; a}; x", "x = {a = {1}; a}; x", ~v="1", ())
|
||||
})
|
||||
|
|
|
@ -25,11 +25,7 @@ describe("Peggy to Expression", () => {
|
|||
|
||||
describe("multi-line", () => {
|
||||
testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ())
|
||||
testToExpression(
|
||||
"x=1; y=2",
|
||||
"x = {1}; y = {2}",
|
||||
(),
|
||||
)
|
||||
testToExpression("x=1; y=2", "x = {1}; y = {2}", ())
|
||||
})
|
||||
|
||||
describe("variables", () => {
|
||||
|
@ -39,11 +35,7 @@ describe("Peggy to Expression", () => {
|
|||
})
|
||||
|
||||
describe("functions", () => {
|
||||
testToExpression(
|
||||
"identity(x) = x",
|
||||
"identity = {|x| {x}}",
|
||||
(),
|
||||
) // Function definitions become lambda assignments
|
||||
testToExpression("identity(x) = x", "identity = {|x| {x}}", ()) // Function definitions become lambda assignments
|
||||
testToExpression("identity(x)", "(identity)(x)", ()) // Note value returns error properly
|
||||
testToExpression(
|
||||
"f(x) = x> 2 ? 0 : 1; f(3)",
|
||||
|
@ -55,43 +47,15 @@ describe("Peggy to Expression", () => {
|
|||
|
||||
describe("arrays", () => {
|
||||
testToExpression("[]", "[]", ~v="[]", ())
|
||||
testToExpression(
|
||||
"[0, 1, 2]",
|
||||
"[0, 1, 2]",
|
||||
~v="[0,1,2]",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"['hello', 'world']",
|
||||
"['hello', 'world']",
|
||||
~v="['hello','world']",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"([0,1,2])[1]",
|
||||
"($_atIndex_$)([0, 1, 2], 1)",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
testToExpression("[0, 1, 2]", "[0, 1, 2]", ~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", () => {
|
||||
testToExpression(
|
||||
"{a: 1, b: 2}",
|
||||
"{'a': 1, 'b': 2}",
|
||||
~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("{a: 1, b: 2}", "{'a': 1, 'b': 2}", ~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(
|
||||
"record={property: 1}; record.property",
|
||||
"record = {{'property': 1}}; ($_atIndex_$)(record, 'property')",
|
||||
|
@ -103,45 +67,15 @@ describe("Peggy to Expression", () => {
|
|||
describe("comments", () => {
|
||||
testToExpression("1 # This is a line comment", "1", ~v="1", ())
|
||||
testToExpression("1 // This is a line comment", "1", ~v="1", ())
|
||||
testToExpression(
|
||||
"1 /* This is a multi line comment */",
|
||||
"1",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"/* This is a multi line comment */ 1",
|
||||
"1",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
testToExpression("1 /* This is a multi line comment */", "1", ~v="1", ())
|
||||
testToExpression("/* This is a multi line comment */ 1", "1", ~v="1", ())
|
||||
})
|
||||
|
||||
describe("ternary operator", () => {
|
||||
testToExpression(
|
||||
"true ? 1 : 0",
|
||||
"true ? (1) : (0)",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
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
|
||||
testToExpression("true ? 1 : 0", "true ? (1) : (0)", ~v="1", ())
|
||||
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", () => {
|
||||
testToExpression(
|
||||
// expression binding
|
||||
|
@ -168,16 +102,8 @@ describe("Peggy to Expression", () => {
|
|||
})
|
||||
|
||||
describe("if then else", () => {
|
||||
testToExpression(
|
||||
"if true then 2 else 3",
|
||||
"true ? ({2}) : ({3})",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"if true then {2} else {3}",
|
||||
"true ? ({2}) : ({3})",
|
||||
(),
|
||||
)
|
||||
testToExpression("if true then 2 else 3", "true ? ({2}) : ({3})", ())
|
||||
testToExpression("if true then {2} else {3}", "true ? ({2}) : ({3})", ())
|
||||
testToExpression(
|
||||
"if false then {2} else if false then {4} else {5}",
|
||||
"false ? ({2}) : (false ? ({4}) : ({5}))",
|
||||
|
@ -187,18 +113,8 @@ describe("Peggy to Expression", () => {
|
|||
|
||||
describe("pipe", () => {
|
||||
testToExpression("1 -> add(2)", "(add)(1, 2)", ~v="3", ())
|
||||
testToExpression(
|
||||
"-1 -> add(2)",
|
||||
"(add)((unaryMinus)(1), 2)",
|
||||
~v="1",
|
||||
(),
|
||||
) // note that unary has higher priority naturally
|
||||
testToExpression(
|
||||
"1 -> add(2) * 3",
|
||||
"(multiply)((add)(1, 2), 3)",
|
||||
~v="9",
|
||||
(),
|
||||
)
|
||||
testToExpression("-1 -> add(2)", "(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", () => {
|
||||
|
@ -219,27 +135,10 @@ describe("Peggy to Expression", () => {
|
|||
})
|
||||
|
||||
describe("lambda", () => {
|
||||
testToExpression(
|
||||
"{|x| x}",
|
||||
"{|x| x}",
|
||||
~v="lambda(x=>internal code)",
|
||||
(),
|
||||
)
|
||||
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)}}",
|
||||
(),
|
||||
)
|
||||
testToExpression("{|x| x}", "{|x| x}", ~v="lambda(x=>internal code)", ())
|
||||
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", () => {
|
||||
|
|
|
@ -86,3 +86,4 @@
|
|||
// expectedValue: string,
|
||||
// ) => testMacroEval_(Only.test, bindArray, expr, expectedValue)
|
||||
// }
|
||||
|
||||
|
|
|
@ -50,3 +50,4 @@
|
|||
// "Ok({properties: {age: #number,name: #string},typeTag: 'typeRecord'})",
|
||||
// )
|
||||
// myTypeTest(test, "{age: number, name: string}", "{age: number, name: string}")
|
||||
|
||||
|
|
|
@ -40,3 +40,4 @@
|
|||
// test(aTypeSourceCode, () => myCheckArgumentsExpectEqual(aTypeSourceCode, sourceCode, answer))
|
||||
|
||||
// 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, "any", "0", "Ok")
|
||||
// myTypeCheckTest(test, "any", "'a'", "Ok")
|
||||
|
||||
|
|
|
@ -124,3 +124,4 @@
|
|||
// expect(result)->toEqual(Some(Ok(IEvString("helloworld"))))
|
||||
// })
|
||||
// })
|
||||
|
||||
|
|
|
@ -2,14 +2,8 @@ open Jest
|
|||
open Reducer_TestHelpers
|
||||
|
||||
describe("Parse function assignment", () => {
|
||||
testParseToBe(
|
||||
"f(x)=x",
|
||||
"Ok(f = {|x| {x}})"
|
||||
)
|
||||
testParseToBe(
|
||||
"f(x)=2*x",
|
||||
"Ok(f = {|x| {(multiply)(2, x)}})"
|
||||
)
|
||||
testParseToBe("f(x)=x", "Ok(f = {|x| {x}})")
|
||||
testParseToBe("f(x)=2*x", "Ok(f = {|x| {(multiply)(2, x)}})")
|
||||
//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); z=f(1); z", "Ok(2)")
|
||||
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(0)", "Ok(2)")
|
||||
testParseToBe(
|
||||
"f=99; g(x)=f; g(2)",
|
||||
"Ok(f = {99}; g = {|x| {f}}; (g)(2))",
|
||||
)
|
||||
testParseToBe("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(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)")
|
||||
|
|
|
@ -2,10 +2,7 @@ open Jest
|
|||
open Reducer_TestHelpers
|
||||
|
||||
describe("Parse ternary operator", () => {
|
||||
testParseToBe(
|
||||
"true ? 'YES' : 'NO'",
|
||||
"Ok(true ? ('YES') : ('NO'))",
|
||||
)
|
||||
testParseToBe("true ? 'YES' : 'NO'", "Ok(true ? ('YES') : ('NO'))")
|
||||
})
|
||||
|
||||
describe("Evaluate ternary operator", () => {
|
||||
|
|
|
@ -119,10 +119,7 @@ describe("eval on distribution functions", () => {
|
|||
|
||||
describe("parse on distribution functions", () => {
|
||||
describe("power", () => {
|
||||
testParse(
|
||||
"normal(5,2) ^ normal(5,1)",
|
||||
"Ok((pow)((normal)(5, 2), (normal)(5, 1)))",
|
||||
)
|
||||
testParse("normal(5,2) ^ normal(5,1)", "Ok((pow)((normal)(5, 2), (normal)(5, 1)))")
|
||||
testParse("3 ^ normal(5,1)", "Ok((pow)(3, (normal)(5, 1)))")
|
||||
testParse("normal(5,2) ^ 3", "Ok((pow)((normal)(5, 2), 3))")
|
||||
})
|
||||
|
@ -138,18 +135,9 @@ describe("parse on distribution functions", () => {
|
|||
"Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))",
|
||||
// TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})"
|
||||
)
|
||||
testParse(
|
||||
"normal(5,2) .* normal(5,1)",
|
||||
"Ok((dotMultiply)((normal)(5, 2), (normal)(5, 1)))",
|
||||
)
|
||||
testParse(
|
||||
"normal(5,2) ./ normal(5,1)",
|
||||
"Ok((dotDivide)((normal)(5, 2), (normal)(5, 1)))",
|
||||
)
|
||||
testParse(
|
||||
"normal(5,2) .^ normal(5,1)",
|
||||
"Ok((dotPow)((normal)(5, 2), (normal)(5, 1)))",
|
||||
)
|
||||
testParse("normal(5,2) .* normal(5,1)", "Ok((dotMultiply)((normal)(5, 2), (normal)(5, 1)))")
|
||||
testParse("normal(5,2) ./ normal(5,1)", "Ok((dotDivide)((normal)(5, 2), (normal)(5, 1)))")
|
||||
testParse("normal(5,2) .^ normal(5,1)", "Ok((dotPow)((normal)(5, 2), (normal)(5, 1)))")
|
||||
})
|
||||
describe("equality", () => {
|
||||
testParse("5 == normal(5,2)", "Ok((equal)(5, (normal)(5, 2)))")
|
||||
|
|
|
@ -75,9 +75,7 @@ x=1`,
|
|||
})
|
||||
|
||||
test("include as variables", () => {
|
||||
expect(project->Project.Private.getIncludesAsVariables("main")) == [
|
||||
("myVariable", "myModule"),
|
||||
]
|
||||
expect(project->Project.Private.getIncludesAsVariables("main")) == [("myVariable", "myModule")]
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -110,8 +108,6 @@ x=1`,
|
|||
expect(Project.getPastChain(project, "main")) == ["common", "common2"]
|
||||
})
|
||||
test("include as variables", () => {
|
||||
expect(project->Project.Private.getIncludesAsVariables("main")) == [
|
||||
("myVariable", "myModule"),
|
||||
]
|
||||
expect(project->Project.Private.getIncludesAsVariables("main")) == [("myVariable", "myModule")]
|
||||
})
|
||||
})
|
||||
|
|
|
@ -14,8 +14,7 @@ let runFetchResult = (project, sourceId) => {
|
|||
|
||||
let runFetchFlatBindings = (project, sourceId) => {
|
||||
Project.run(project, sourceId)
|
||||
Project.getBindings(project, sourceId)
|
||||
->InternalExpressionValue.toStringRecord
|
||||
Project.getBindings(project, sourceId)->InternalExpressionValue.toStringRecord
|
||||
}
|
||||
|
||||
test("test result true", () => {
|
||||
|
|
|
@ -24,7 +24,9 @@ module Map: Benchmark_Helpers.BenchmarkTopic = {
|
|||
}
|
||||
|
||||
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("Js.Array2.map", jsArray2)
|
||||
Benchmark_Helpers.measure("Array.map", ocamlArray)
|
||||
|
@ -65,7 +67,9 @@ module Sort: Benchmark_Helpers.BenchmarkTopic = {
|
|||
}
|
||||
|
||||
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 with Ocaml compare", jsArray2withOcamlCompare)
|
||||
Benchmark_Helpers.measure("Array.fast_sort", ocamlArray)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module type BenchmarkTopic = {
|
||||
let runAll: () => unit
|
||||
let runAll: unit => unit
|
||||
}
|
||||
|
||||
let measure = (name: string, f: () => unit) => {
|
||||
let start = Js.Date.make()->Js.Date.valueOf
|
||||
f()
|
||||
let end = Js.Date.make()->Js.Date.valueOf
|
||||
let duration = (end -. start) /. 1000.
|
||||
Js.log2(duration, name)
|
||||
let measure = (name: string, f: unit => unit) => {
|
||||
let start = Js.Date.make()->Js.Date.valueOf
|
||||
f()
|
||||
let end = Js.Date.make()->Js.Date.valueOf
|
||||
let duration = (end -. start) /. 1000.
|
||||
Js.log2(duration, name)
|
||||
}
|
||||
|
|
|
@ -2,63 +2,61 @@ module StringMap: Benchmark_Helpers.BenchmarkTopic = {
|
|||
let size = 1000
|
||||
let iterations = 10_000
|
||||
|
||||
let kv = Belt.Array.range(1, size)->Belt.Array.map(
|
||||
v => ("key" ++ v->Belt.Int.toString, v)
|
||||
)
|
||||
let kv = Belt.Array.range(1, size)->Belt.Array.map(v => ("key" ++ v->Belt.Int.toString, v))
|
||||
|
||||
let beltMap = () => {
|
||||
Belt.Range.forEach(1, iterations, _ => {
|
||||
let m = Belt.Map.String.empty
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => acc->Belt.Map.String.set(k, v))
|
||||
let m = Belt.Map.String.empty
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => acc->Belt.Map.String.set(k, v))
|
||||
})
|
||||
}
|
||||
|
||||
let beltMutableMap = () => {
|
||||
Belt.Range.forEach(1, iterations, _ => {
|
||||
let m = Belt.MutableMap.String.make()
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
|
||||
acc->Belt.MutableMap.String.set(k, v)
|
||||
acc
|
||||
})
|
||||
let m = Belt.MutableMap.String.make()
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
|
||||
acc->Belt.MutableMap.String.set(k, v)
|
||||
acc
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let beltHashMap = () => {
|
||||
Belt.Range.forEach(1, iterations, _ => {
|
||||
let m = Belt.HashMap.String.make(~hintSize=100)
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
|
||||
acc->Belt.HashMap.String.set(k, v)
|
||||
acc
|
||||
})
|
||||
let m = Belt.HashMap.String.make(~hintSize=100)
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
|
||||
acc->Belt.HashMap.String.set(k, v)
|
||||
acc
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let jsDict = () => {
|
||||
Belt.Range.forEach(1, iterations, _ => {
|
||||
let m = Js.Dict.empty()
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
|
||||
acc->Js.Dict.set(k, v)
|
||||
acc
|
||||
})
|
||||
let m = Js.Dict.empty()
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => {
|
||||
acc->Js.Dict.set(k, v)
|
||||
acc
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let jsMap = () => {
|
||||
Belt.Range.forEach(1, iterations, _ => {
|
||||
let m = Js_map.make()
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) =>
|
||||
acc->Js_map.set(k, v)
|
||||
)
|
||||
let m = Js_map.make()
|
||||
let _ = Belt.Array.reduce(kv, m, (acc, (k, v)) => acc->Js_map.set(k, v))
|
||||
})
|
||||
}
|
||||
|
||||
let runAll = () => {
|
||||
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.MutableMap.String", beltMutableMap)
|
||||
Benchmark_Helpers.measure("Belt.HashMap.String", beltHashMap)
|
||||
Benchmark_Helpers.measure("Js.Dict", jsDict)
|
||||
Benchmark_Helpers.measure("Js.Map", jsMap)
|
||||
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.MutableMap.String", beltMutableMap)
|
||||
Benchmark_Helpers.measure("Belt.HashMap.String", beltHashMap)
|
||||
Benchmark_Helpers.measure("Js.Dict", jsDict)
|
||||
Benchmark_Helpers.measure("Js.Map", jsMap)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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 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 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 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 = {
|
||||
let laplace = Function.make(
|
||||
|
@ -77,8 +77,7 @@ module Integration = {
|
|||
| Reducer_T.IEvNumber(x) => Ok(x)
|
||||
| _ =>
|
||||
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"
|
||||
->Reducer_ErrorValue.REOther
|
||||
"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,
|
||||
)
|
||||
}
|
||||
result
|
||||
|
@ -142,11 +141,11 @@ module Integration = {
|
|||
resultWithOuterPoints
|
||||
}
|
||||
| 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." ++
|
||||
"Original error: " ++
|
||||
b->Reducer_ErrorValue.errorToString
|
||||
)->Reducer_ErrorValue.REOther->Error
|
||||
("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: " ++
|
||||
b->Reducer_ErrorValue.errorToString)
|
||||
->Reducer_ErrorValue.REOther
|
||||
->Error
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -169,7 +168,9 @@ module Integration = {
|
|||
~run=(inputs, _, env, reducer) => {
|
||||
let result = switch inputs {
|
||||
| [_, _, _, 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),
|
||||
IEvNumber(min),
|
||||
|
@ -186,7 +187,9 @@ module Integration = {
|
|||
)
|
||||
| _ =>
|
||||
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
|
||||
|
@ -221,8 +224,8 @@ module Integration = {
|
|||
env,
|
||||
reducer,
|
||||
)->E.R2.errMap(b =>
|
||||
("Integration error 7 in Danger.integrate. Something went wrong along the way: " ++ b->Reducer_ErrorValue.errorToString)
|
||||
->Reducer_ErrorValue.REOther
|
||||
("Integration error 7 in Danger.integrate. Something went wrong along the way: " ++
|
||||
b->Reducer_ErrorValue.errorToString)->Reducer_ErrorValue.REOther
|
||||
)
|
||||
| _ =>
|
||||
"Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))"
|
||||
|
@ -287,23 +290,19 @@ module DiminishingReturns = {
|
|||
) {
|
||||
| (false, _, _, _) =>
|
||||
Error(
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, number of functions should be greater than 1."
|
||||
->Reducer_ErrorValue.REOther
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, number of functions should be greater than 1."->Reducer_ErrorValue.REOther,
|
||||
)
|
||||
| (_, false, _, _) =>
|
||||
Error(
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, funds should be greater than 0."
|
||||
->Reducer_ErrorValue.REOther
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, funds should be greater than 0."->Reducer_ErrorValue.REOther,
|
||||
)
|
||||
| (_, _, false, _) =>
|
||||
Error(
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be greater than 0."
|
||||
->Reducer_ErrorValue.REOther
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be greater than 0."->Reducer_ErrorValue.REOther,
|
||||
)
|
||||
| (_, _, _, false) =>
|
||||
Error(
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be smaller than funds amount."
|
||||
->Reducer_ErrorValue.REOther
|
||||
"Error in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions, approximateIncrement should be smaller than funds amount."->Reducer_ErrorValue.REOther,
|
||||
)
|
||||
| (true, true, true, true) => {
|
||||
let applyFunctionAtPoint = (lambda, point: float) => {
|
||||
|
@ -319,8 +318,7 @@ module DiminishingReturns = {
|
|||
| Reducer_T.IEvNumber(x) => Ok(x)
|
||||
| _ =>
|
||||
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"
|
||||
->Reducer_ErrorValue.REOther
|
||||
"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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +431,10 @@ module DiminishingReturns = {
|
|||
}
|
||||
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]))
|
||||
->Wrappers.evArray
|
||||
|
||||
let fromList = (items: array<internalExpressionValue>): result<internalExpressionValue, errorValue> =>
|
||||
let fromList = (items: array<internalExpressionValue>): result<
|
||||
internalExpressionValue,
|
||||
errorValue,
|
||||
> =>
|
||||
items
|
||||
->E.A2.fmap(item => {
|
||||
switch (item: internalExpressionValue) {
|
|
@ -315,10 +315,11 @@ module Old = {
|
|||
|
||||
let dispatch = (call: ReducerInterface_InternalExpressionValue.functionCall, environment) =>
|
||||
switch dispatchToGenericOutput(call, environment) {
|
||||
| Some(o) => genericOutputToReducerValue(o)
|
||||
| None => Reducer_ErrorValue.REOther("Internal error in FR_GenericDist implementation")
|
||||
->Reducer_ErrorValue.ErrorException
|
||||
->raise
|
||||
| Some(o) => genericOutputToReducerValue(o)
|
||||
| None =>
|
||||
Reducer_ErrorValue.REOther("Internal error in FR_GenericDist implementation")
|
||||
->Reducer_ErrorValue.ErrorException
|
||||
->raise
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,24 +341,32 @@ let makeProxyFn = (name: string, inputs: array<frType>) => {
|
|||
}
|
||||
|
||||
let makeOperationFns = (): array<function> => {
|
||||
let ops = ["add", "multiply", "subtract", "divide", "pow", "log", "dotAdd", "dotMultiply", "dotSubtract", "dotDivide", "dotPow"]
|
||||
let twoArgTypes = [
|
||||
// can't use numeric+numeric, since number+number should be delegated to builtin arithmetics
|
||||
[FRTypeDist, FRTypeNumber],
|
||||
[FRTypeNumber, FRTypeDist],
|
||||
[FRTypeDist, FRTypeDist],
|
||||
]
|
||||
let ops = [
|
||||
"add",
|
||||
"multiply",
|
||||
"subtract",
|
||||
"divide",
|
||||
"pow",
|
||||
"log",
|
||||
"dotAdd",
|
||||
"dotMultiply",
|
||||
"dotSubtract",
|
||||
"dotDivide",
|
||||
"dotPow",
|
||||
]
|
||||
let twoArgTypes = [
|
||||
// can't use numeric+numeric, since number+number should be delegated to builtin arithmetics
|
||||
[FRTypeDist, FRTypeNumber],
|
||||
[FRTypeNumber, FRTypeDist],
|
||||
[FRTypeDist, FRTypeDist],
|
||||
]
|
||||
|
||||
ops->E.A2.fmap(
|
||||
op => twoArgTypes->E.A2.fmap(
|
||||
types => makeProxyFn(op, types)
|
||||
)
|
||||
)->E.A.concatMany
|
||||
ops->E.A2.fmap(op => twoArgTypes->E.A2.fmap(types => makeProxyFn(op, types)))->E.A.concatMany
|
||||
}
|
||||
|
||||
// TODO - duplicates the switch above, should rewrite with standard FR APIs
|
||||
let library = E.A.concatMany([
|
||||
[
|
||||
[
|
||||
makeProxyFn("triangular", [FRTypeNumber, FRTypeNumber, FRTypeNumber]),
|
||||
makeProxyFn("sample", [FRTypeDist]),
|
||||
makeProxyFn("sampleN", [FRTypeDist, FRTypeNumber]),
|
||||
|
@ -394,14 +403,14 @@ let library = E.A.concatMany([
|
|||
makeProxyFn("log10", [FRTypeDist]),
|
||||
makeProxyFn("unaryMinus", [FRTypeDist]),
|
||||
makeProxyFn("dotExp", [FRTypeDist]),
|
||||
],
|
||||
makeOperationFns()
|
||||
],
|
||||
makeOperationFns(),
|
||||
])
|
||||
|
||||
// FIXME - impossible to implement with FR due to arbitrary parameters length;
|
||||
let mxLambda = Reducer_Expression_Lambda.makeFFILambda((inputs, env, _) => {
|
||||
switch Old.dispatch(("mx", inputs), env) {
|
||||
| Ok(value) => value
|
||||
| Error(e) => e->Reducer_ErrorValue.ErrorException->raise
|
||||
}
|
||||
switch Old.dispatch(("mx", inputs), env) {
|
||||
| Ok(value) => value
|
||||
| Error(e) => e->Reducer_ErrorValue.ErrorException->raise
|
||||
}
|
||||
})
|
|
@ -66,12 +66,7 @@ module Internals = {
|
|||
reducer: Reducer_T.reducerFn,
|
||||
) => {
|
||||
Js.Array2.filter(aValueArray, elem => {
|
||||
let result = Reducer_Expression_Lambda.doLambdaCall(
|
||||
aLambdaValue,
|
||||
[elem],
|
||||
env,
|
||||
reducer,
|
||||
)
|
||||
let result = Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, [elem], env, reducer)
|
||||
switch result {
|
||||
| IEvBool(true) => true
|
||||
| _ => 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 = [
|
|
@ -111,8 +111,7 @@ let library = [
|
|||
~name="makeContinuous",
|
||||
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
|
||||
~run=(_, inputs, _, _) =>
|
||||
inputsTodist(inputs, r => Continuous(Continuous.make(r)))
|
||||
->E.R2.errMap(wrapError),
|
||||
inputsTodist(inputs, r => Continuous(Continuous.make(r)))->E.R2.errMap(wrapError),
|
||||
(),
|
||||
),
|
||||
],
|
||||
|
@ -136,8 +135,7 @@ let library = [
|
|||
~name="makeDiscrete",
|
||||
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
|
||||
~run=(_, inputs, _, _) =>
|
||||
inputsTodist(inputs, r => Discrete(Discrete.make(r)))
|
||||
->E.R2.errMap(wrapError),
|
||||
inputsTodist(inputs, r => Discrete(Discrete.make(r)))->E.R2.errMap(wrapError),
|
||||
(),
|
||||
),
|
||||
],
|
|
@ -120,7 +120,8 @@ let libaryBase = [
|
|||
Prepare.ToTypedArray.numbers(inputs) |> E.R2.bind(r =>
|
||||
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.errMap(wrapError)
|
||||
},
|
||||
|
@ -291,7 +292,9 @@ module Comparison = {
|
|||
let wrapper = r =>
|
||||
r
|
||||
->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) =>
|
||||
Function.make(
|
|
@ -22,14 +22,13 @@ let makeUnitFn = (name: string, multiplier: float) => {
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
let library = [
|
||||
makeUnitFn("n", 1E-9),
|
||||
makeUnitFn("m", 1E-3),
|
||||
makeUnitFn("k", 1E3),
|
||||
makeUnitFn("M", 1E6),
|
||||
makeUnitFn("B", 1E9),
|
||||
makeUnitFn("G", 1E9),
|
||||
makeUnitFn("T", 1E12),
|
||||
makeUnitFn("P", 1E15),
|
||||
makeUnitFn("n", 1E-9),
|
||||
makeUnitFn("m", 1E-3),
|
||||
makeUnitFn("k", 1E3),
|
||||
makeUnitFn("M", 1E6),
|
||||
makeUnitFn("B", 1E9),
|
||||
makeUnitFn("G", 1E9),
|
||||
makeUnitFn("T", 1E12),
|
||||
makeUnitFn("P", 1E15),
|
||||
]
|
|
@ -212,8 +212,7 @@ let setEnvironment = (project: reducerProject, environment: environment): unit =
|
|||
project->Private.setEnvironment(environment)
|
||||
|
||||
@genType
|
||||
let getEnvironment = (project: reducerProject): environment =>
|
||||
project->Private.getEnvironment
|
||||
let getEnvironment = (project: reducerProject): environment => project->Private.getEnvironment
|
||||
|
||||
/*
|
||||
Foreign function interface is intentionally demolished.
|
||||
|
|
|
@ -225,9 +225,9 @@ module FnDefinition = {
|
|||
}
|
||||
|
||||
let make = (~name, ~inputs, ~run, ()): t => {
|
||||
name,
|
||||
inputs,
|
||||
run,
|
||||
name: name,
|
||||
inputs: inputs,
|
||||
run: run,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,14 +253,14 @@ module Function = {
|
|||
~isExperimental=false,
|
||||
(),
|
||||
): t => {
|
||||
name,
|
||||
nameSpace,
|
||||
definitions,
|
||||
output,
|
||||
name: name,
|
||||
nameSpace: nameSpace,
|
||||
definitions: definitions,
|
||||
output: output,
|
||||
examples: examples |> E.O.default([]),
|
||||
isExperimental,
|
||||
requiresNamespace,
|
||||
description,
|
||||
isExperimental: isExperimental,
|
||||
requiresNamespace: requiresNamespace,
|
||||
description: description,
|
||||
}
|
||||
|
||||
let toJson = (t: t): functionJson => {
|
||||
|
@ -288,12 +288,8 @@ module Registry = {
|
|||
// 1. functions
|
||||
// 2. definitions of each function
|
||||
// 3. name variations of each definition
|
||||
r->Belt.Array.reduce(
|
||||
Belt.Map.String.empty,
|
||||
(acc, fn) =>
|
||||
fn.definitions->Belt.Array.reduce(
|
||||
acc,
|
||||
(acc, def) => {
|
||||
r->Belt.Array.reduce(Belt.Map.String.empty, (acc, fn) =>
|
||||
fn.definitions->Belt.Array.reduce(acc, (acc, def) => {
|
||||
let names =
|
||||
[
|
||||
fn.nameSpace == "" ? [] : [`${fn.nameSpace}.${def.name}`],
|
||||
|
@ -338,8 +334,7 @@ module Registry = {
|
|||
|
||||
let match = definitions->Js.Array2.find(def => def->FnDefinition.isMatch(args))
|
||||
switch match {
|
||||
| Some(def) =>
|
||||
def->FnDefinition.run(args, env, reducer)
|
||||
| Some(def) => def->FnDefinition.run(args, env, reducer)
|
||||
| None => REOther(showNameMatchDefinitions())->Error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,13 +225,11 @@ module DefineFn = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeNumber],
|
||||
~run=(_, inputs, _, _) => {
|
||||
inputs
|
||||
->getOrError(0)
|
||||
->E.R.bind(Prepare.oneNumber)
|
||||
->E.R2.fmap(fn)
|
||||
->E.R2.fmap(Wrappers.evNumber)
|
||||
->E.R2.errMap(e => Reducer_ErrorValue.REOther(e))
|
||||
~run=(inputs, _, _, _) => {
|
||||
switch inputs {
|
||||
| [IEvNumber(x)] => fn(x)->IEvNumber->Ok
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
},
|
||||
(),
|
||||
)
|
||||
|
@ -239,12 +237,11 @@ module DefineFn = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeNumber, FRTypeNumber],
|
||||
~run=(_, inputs, _, _) => {
|
||||
inputs
|
||||
->Prepare.ToValueTuple.twoNumbers
|
||||
->E.R2.fmap(fn)
|
||||
->E.R2.fmap(Wrappers.evNumber)
|
||||
->E.R2.errMap(e => Reducer_ErrorValue.REOther(e))
|
||||
~run=(inputs, _, _, _) => {
|
||||
switch inputs {
|
||||
| [IEvNumber(x), IEvNumber(y)] => fn(x, y)->IEvNumber->Ok
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
},
|
||||
(),
|
||||
)
|
||||
|
@ -252,12 +249,11 @@ module DefineFn = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber],
|
||||
~run=(_, inputs, _, _) => {
|
||||
inputs
|
||||
->Prepare.ToValueTuple.threeNumbers
|
||||
->E.R2.fmap(fn)
|
||||
->E.R2.fmap(Wrappers.evNumber)
|
||||
->E.R2.errMap(e => Reducer_ErrorValue.REOther(e))
|
||||
~run=(inputs, _, _, _) => {
|
||||
switch inputs {
|
||||
| [IEvNumber(x), IEvNumber(y), IEvNumber(z)] => fn(x, y, z)->IEvNumber->Ok
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
},
|
||||
(),
|
||||
)
|
||||
|
|
|
@ -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**
|
||||
A list of all the Functions defined in the Function Registry.
|
||||
|
||||
The definition arrays are stored in `FR_*` modules, by convention.
|
||||
|
||||
**FunctionRegistry_Helpers**
|
||||
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,47 +13,51 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
|||
switch expression {
|
||||
| T.EBlock(statements) => {
|
||||
let innerContext = {...context, bindings: context.bindings->Bindings.extend}
|
||||
let (value, _) = statements->Belt.Array.reduce(
|
||||
(T.IEvVoid, innerContext),
|
||||
((_, currentContext), statement) => statement->evaluate(currentContext)
|
||||
)
|
||||
(value, context) // inner context can be dropped
|
||||
let (value, _) =
|
||||
statements->Belt.Array.reduce((T.IEvVoid, innerContext), ((_, currentContext), statement) =>
|
||||
statement->evaluate(currentContext)
|
||||
)
|
||||
(value, context)
|
||||
}
|
||||
|
||||
| T.EProgram(statements) => {
|
||||
// Js.log(`bindings: ${context.bindings->Bindings.locals->Reducer_Namespace.toString}`)
|
||||
let (value, finalContext) = statements->Belt.Array.reduce(
|
||||
(T.IEvVoid, context),
|
||||
((_, currentContext), statement) => statement->evaluate(currentContext))
|
||||
let (value, finalContext) =
|
||||
statements->Belt.Array.reduce((T.IEvVoid, context), ((_, currentContext), statement) =>
|
||||
statement->evaluate(currentContext)
|
||||
)
|
||||
|
||||
// Js.log(`bindings after: ${finalContext.bindings->Bindings.locals->Reducer_Namespace.toString}`)
|
||||
(value, finalContext)
|
||||
}
|
||||
|
||||
| T.EArray(elements) => {
|
||||
let value = elements->Belt.Array.map(element => {
|
||||
let (value, _) = evaluate(element, context)
|
||||
value
|
||||
})->T.IEvArray
|
||||
(value, context)
|
||||
}
|
||||
let value =
|
||||
elements
|
||||
->Belt.Array.map(element => {
|
||||
let (value, _) = evaluate(element, context)
|
||||
value
|
||||
})
|
||||
->T.IEvArray
|
||||
(value, context)
|
||||
}
|
||||
|
||||
| T.ERecord(pairs) => {
|
||||
let value =
|
||||
pairs
|
||||
->Belt.Array.map(((eKey, eValue)) => {
|
||||
let (key, _) = eKey->evaluate(context)
|
||||
let keyString = switch key {
|
||||
| IEvString(s) => s
|
||||
| _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise
|
||||
}
|
||||
let (value, _) = eValue->evaluate(context)
|
||||
(keyString, value)
|
||||
})
|
||||
->Belt.Map.String.fromArray
|
||||
->T.IEvRecord
|
||||
(value, context)
|
||||
}
|
||||
let value =
|
||||
pairs
|
||||
->Belt.Array.map(((eKey, eValue)) => {
|
||||
let (key, _) = eKey->evaluate(context)
|
||||
let keyString = switch key {
|
||||
| IEvString(s) => s
|
||||
| _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise
|
||||
}
|
||||
let (value, _) = eValue->evaluate(context)
|
||||
(keyString, value)
|
||||
})
|
||||
->Belt.Map.String.fromArray
|
||||
->T.IEvRecord
|
||||
(value, context)
|
||||
}
|
||||
|
||||
| T.EAssign(left, right) => {
|
||||
let (result, _) = right->evaluate(context)
|
||||
|
@ -62,7 +66,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
|||
{
|
||||
...context,
|
||||
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) =>
|
||||
(Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda, context)
|
||||
| T.ELambda(parameters, body) => (
|
||||
Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda,
|
||||
context,
|
||||
)
|
||||
|
||||
| T.ECall(fn, args) => {
|
||||
let (lambda, _) = fn->evaluate(context)
|
||||
|
@ -92,8 +98,14 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
|||
argValue
|
||||
})
|
||||
switch lambda {
|
||||
| T.IEvLambda(lambda) => (Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate), context)
|
||||
| _ => RENotAFunction(lambda->ReducerInterface_InternalExpressionValue.toString)->Reducer_ErrorValue.ErrorException->raise
|
||||
| T.IEvLambda(lambda) => (
|
||||
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 localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex(
|
||||
localBindings,
|
||||
(currentBindings, parameter, index) => {
|
||||
let localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex(localBindings, (
|
||||
currentBindings,
|
||||
parameter,
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -7,17 +7,20 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|||
type t = Reducer_T.expression
|
||||
|
||||
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
|
||||
*/
|
||||
let rec toString = (expression: t) =>
|
||||
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
|
||||
| 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
|
||||
| ETernary(predicate, trueCase, falseCase) =>
|
||||
`${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
|
||||
|
||||
let make = (): t => Belt.Map.String.empty
|
||||
|
||||
let get = (namespace: t, id: string): option<Reducer_T.value> =>
|
||||
namespace->Belt.Map.String.get(id)
|
||||
let get = (namespace: t, id: string): option<Reducer_T.value> => namespace->Belt.Map.String.get(id)
|
||||
|
||||
let set = (namespace: t, id: string, value): t => {
|
||||
namespace->Belt.Map.String.set(id, value)
|
||||
|
@ -16,19 +19,18 @@ let mergeFrom = (from: t, to: t): t => {
|
|||
}
|
||||
|
||||
let mergeMany = (namespaces: array<t>): t =>
|
||||
Belt.Array.reduce(namespaces, make(), (acc, ns) => acc->mergeFrom(ns))
|
||||
Belt.Array.reduce(namespaces, make(), (acc, ns) => acc->mergeFrom(ns))
|
||||
|
||||
let toString = (namespace: t) =>
|
||||
namespace
|
||||
->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
|
||||
|
||||
let fromArray = (a): t =>
|
||||
Belt.Map.String.fromArray(a)
|
||||
let fromArray = (a): t => Belt.Map.String.fromArray(a)
|
||||
|
||||
let toMap = (namespace: t): Reducer_T.map =>
|
||||
namespace
|
||||
let toMap = (namespace: t): Reducer_T.map => namespace
|
||||
|
||||
let toRecord = (namespace: t): Reducer_T.value =>
|
||||
namespace->toMap->IEvRecord
|
||||
let toRecord = (namespace: t): Reducer_T.value => namespace->toMap->IEvRecord
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { LocationRange } from "peggy";
|
||||
|
||||
export const toFunction = {
|
||||
"+": "add",
|
||||
"-": "subtract",
|
||||
"->": "pipe",
|
||||
"!=": "unequal",
|
||||
".-": "dotSubtract",
|
||||
".*": "dotMultiply",
|
||||
|
@ -13,7 +13,6 @@ export const toFunction = {
|
|||
"/": "divide",
|
||||
"&&": "and",
|
||||
"^": "pow", // or xor
|
||||
"+": "add",
|
||||
"<": "smaller",
|
||||
"<=": "smallerEq",
|
||||
"==": "equal",
|
||||
|
|
|
@ -9,12 +9,11 @@ let dispatch = (
|
|||
reducer: Reducer_T.reducerFn,
|
||||
chain,
|
||||
): result<Reducer_T.value, 'e> => {
|
||||
E.A.O.firstSomeFn([
|
||||
// () => ReducerInterface_GenericDistribution.dispatch(call, environment),
|
||||
// () => ReducerInterface_Date.dispatch(call, environment),
|
||||
// () => ReducerInterface_Duration.dispatch(call, environment),
|
||||
// () => ReducerInterface_Number.dispatch(call, environment),
|
||||
// () => FunctionRegistry_Library.dispatch(call, environment, reducer),
|
||||
E.A.O.firstSomeFn([// () => ReducerInterface_GenericDistribution.dispatch(call, environment),
|
||||
// () => ReducerInterface_Date.dispatch(call, environment),
|
||||
// () => ReducerInterface_Duration.dispatch(call, environment),
|
||||
// () => ReducerInterface_Number.dispatch(call, environment),
|
||||
// () => FunctionRegistry_Library.dispatch(call, environment, reducer),
|
||||
])->E.O2.defaultFn(() => chain(call, environment, reducer))
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// (value methods should be moved to Reducer_Value.res)
|
||||
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module Extra_Array = Reducer_Extra_Array
|
||||
type environment = GenericDist.env
|
||||
module T = Reducer_T
|
||||
|
||||
|
|
|
@ -10,49 +10,37 @@ let internalStdLib: Reducer_T.namespace = {
|
|||
"$_atIndex_$",
|
||||
Reducer_Expression_Lambda.makeFFILambda((inputs, _, _) => {
|
||||
switch inputs {
|
||||
| [IEvArray(aValueArray), IEvNumber(fIndex)] => switch Belt.Array.get(
|
||||
aValueArray,
|
||||
Belt.Int.fromFloat(fIndex),
|
||||
) {
|
||||
| [IEvArray(aValueArray), IEvNumber(fIndex)] => {
|
||||
let index = Belt.Int.fromFloat(fIndex) // TODO - fail on non-integer indices?
|
||||
|
||||
switch Belt.Array.get(aValueArray, index) {
|
||||
| Some(value) => value
|
||||
| None =>
|
||||
REArrayIndexNotFound("Array index not found", Belt.Int.fromFloat(fIndex))
|
||||
REArrayIndexNotFound("Array index not found", index)
|
||||
->ErrorException
|
||||
->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
|
||||
| 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
|
||||
}
|
||||
})->Reducer_T.IEvLambda,
|
||||
)
|
||||
|
||||
let res = FunctionRegistry_Library.nonRegistryLambdas->Belt.Array.reduce(
|
||||
res,
|
||||
(cur, (name, lambda)) => {
|
||||
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),
|
||||
let res = FunctionRegistry_Library.nonRegistryLambdas->Belt.Array.reduce(res, (
|
||||
cur,
|
||||
(name, lambda),
|
||||
) => {
|
||||
cur->Reducer_Namespace.set(name, lambda->Reducer_T.IEvLambda)
|
||||
})
|
||||
|
||||
// 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(_)])
|
||||
// [ ] | (_, [IEvNumber(_)])
|
||||
// [ ] | (_, [IEvString(_)])
|
||||
|
@ -60,19 +48,20 @@ let internalStdLib: Reducer_T.namespace = {
|
|||
// [ ] | (_, [IEvNumber(_), IEvNumber(_)])
|
||||
// [ ] | (_, [IEvString(_), IEvString(_)]) => callMathJs(call)
|
||||
|
||||
let res = FunctionRegistry_Library.registry
|
||||
->FunctionRegistry_Core.Registry.allNames
|
||||
->Belt.Array.reduce(res, (cur, name) => {
|
||||
cur->Reducer_Namespace.set(
|
||||
name,
|
||||
Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => {
|
||||
switch FunctionRegistry_Library.call(name, arguments, environment, reducer) {
|
||||
| Ok(value) => value
|
||||
| Error(error) => error->Reducer_ErrorValue.ErrorException->raise
|
||||
}
|
||||
})->Reducer_T.IEvLambda,
|
||||
)
|
||||
})
|
||||
let res =
|
||||
FunctionRegistry_Library.registry
|
||||
->FunctionRegistry_Core.Registry.allNames
|
||||
->Belt.Array.reduce(res, (cur, name) => {
|
||||
cur->Reducer_Namespace.set(
|
||||
name,
|
||||
Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => {
|
||||
switch FunctionRegistry_Library.call(name, arguments, environment, reducer) {
|
||||
| Ok(value) => value
|
||||
| Error(error) => error->Reducer_ErrorValue.ErrorException->raise
|
||||
}
|
||||
})->Reducer_T.IEvLambda,
|
||||
)
|
||||
})
|
||||
|
||||
res
|
||||
}
|
||||
|
|
|
@ -166,23 +166,25 @@ let linkDependencies = (project: t, sourceId: string): Reducer_T.namespace => {
|
|||
Belt.Array.concatMany([
|
||||
[project->getStdLib],
|
||||
pastChain->Belt.Array.map(project->getBindings),
|
||||
pastChain->Belt.Array.map(
|
||||
id => Reducer_Namespace.fromArray([
|
||||
("__result__",
|
||||
switch project->getResult(id) {
|
||||
pastChain->Belt.Array.map(id =>
|
||||
Reducer_Namespace.fromArray([
|
||||
(
|
||||
"__result__",
|
||||
switch project->getResult(id) {
|
||||
| Ok(result) => result
|
||||
| Error(error) => error->Reducer_ErrorValue.ErrorException->raise
|
||||
})
|
||||
},
|
||||
),
|
||||
])
|
||||
),
|
||||
])
|
||||
]),
|
||||
)
|
||||
|
||||
let includesAsVariables = project->getIncludesAsVariables(sourceId)
|
||||
Belt.Array.reduce(includesAsVariables, namespace, (acc, (variable, includeFile)) =>
|
||||
acc->Reducer_Namespace.set(
|
||||
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 context = Reducer_Context.createContext(
|
||||
project->linkDependencies(sourceId),
|
||||
project->getEnvironment
|
||||
project->getEnvironment,
|
||||
)
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.run(context)
|
||||
// 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 =>
|
||||
switch this->getExpression {
|
||||
| Some(expressionResult) => switch expressionResult {
|
||||
| Ok(expression) => try {
|
||||
| Some(expressionResult) =>
|
||||
switch expressionResult {
|
||||
| Ok(expression) =>
|
||||
try {
|
||||
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 {
|
||||
| Reducer_ErrorValue.ErrorException(e) => this->failRun(e)
|
||||
| _ => this->failRun(RETodo("unhandled rescript exception"))
|
||||
|
|
|
@ -12,4 +12,6 @@ let availableNumbers: array<(string, float)> = [
|
|||
]
|
||||
|
||||
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