fix more tests; FR improvements/refactorings

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

View File

@ -31,9 +31,7 @@ describe("Bindings", () => {
describe("extend", () => {
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)

View File

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

View File

@ -35,13 +35,9 @@ 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])
test("merge many 1", () => {

View File

@ -38,58 +38,22 @@ describe("Peggy parse", () => {
testParse("1 * 2 / 3", "{(:divide (:multiply 1 2) 3)}")
testParse("1 / 2 * 3", "{(: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)}",
)
})

View File

@ -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", ())
})

View File

@ -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", () => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
})

View File

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

View File

@ -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", () => {

View File

@ -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)))")

View File

@ -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")]
})
})

View File

@ -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", () => {

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}
}

View File

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

View File

@ -8,11 +8,11 @@ let requiresNamespace = true
module Combinatorics = {
module 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
},
(),
),

View File

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

View File

@ -17,7 +17,10 @@ module Internals = {
->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value]))
->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) {

View File

@ -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
}
})

View File

@ -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

View File

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

View File

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

View File

@ -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),
(),
),
],

View File

@ -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(

View File

@ -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),
]

View File

@ -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.

View File

@ -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
}
}

View File

@ -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)
}
},
(),
)

View File

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

View File

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

View File

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

View File

@ -42,5 +42,7 @@ Key types, internal functionality, and a `Registry` module with a `matchAndRun`
**FunctionRegistry_Library**
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.

View File

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

View File

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

View File

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

View File

@ -13,47 +13,51 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
switch expression {
| 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
}
}
}

View File

@ -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
}

View File

@ -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})`

View File

@ -1,9 +1,12 @@
/*
Namespace is a flat mapping of names to Squiggle values.
The full context of variables accessible to Squiggle is called "bindings"; see Reducer_Bindings module for details on it.
*/
type t = Reducer_T.namespace
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

View File

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

View File

@ -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",

View File

@ -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))
}

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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"))

View File

@ -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