project
test remove setResult parse end of outerblock test end of outer block compiles testing bindings tested todo chain bindings topological sort
This commit is contained in:
parent
f1f274127b
commit
2e8e71bbd0
|
@ -1,10 +1,14 @@
|
||||||
module ExpressionValue = ReducerInterface.ExternalExpressionValue
|
module ExpressionValue = ReducerInterface.InternalExpressionValue
|
||||||
|
module Expression = Reducer_Expression
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
let expectEvalToBe = (expr: string, answer: string) =>
|
let expectEvalToBe = (sourceCode: string, answer: string) =>
|
||||||
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
Expression.BackCompatible.evaluateString(sourceCode)
|
||||||
|
->ExpressionValue.toStringResult
|
||||||
|
->expect
|
||||||
|
->toBe(answer)
|
||||||
|
|
||||||
let testEval = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
|
let testEval = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
|
||||||
|
|
||||||
|
|
|
@ -3,359 +3,464 @@ open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
describe("Peggy parse", () => {
|
describe("Peggy parse", () => {
|
||||||
describe("float", () => {
|
describe("float", () => {
|
||||||
testParse("1.", "{1}")
|
testParse("1.", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("1.1", "{1.1}")
|
testParse("1.1", "{(::$_endOfOuterBlock_$ () 1.1)}")
|
||||||
testParse(".1", "{0.1}")
|
testParse(".1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
||||||
testParse("0.1", "{0.1}")
|
testParse("0.1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
||||||
testParse("1e1", "{10}")
|
testParse("1e1", "{(::$_endOfOuterBlock_$ () 10)}")
|
||||||
testParse("1e-1", "{0.1}")
|
testParse("1e-1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
||||||
testParse(".1e1", "{1}")
|
testParse(".1e1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("0.1e1", "{1}")
|
testParse("0.1e1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("literals operators parenthesis", () => {
|
describe("literals operators parenthesis", () => {
|
||||||
// Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement
|
// Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement
|
||||||
testParse("1", "{1}")
|
testParse("1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("'hello'", "{'hello'}")
|
testParse("'hello'", "{(::$_endOfOuterBlock_$ () 'hello')}")
|
||||||
testParse("true", "{true}")
|
testParse("true", "{(::$_endOfOuterBlock_$ () true)}")
|
||||||
testParse("1+2", "{(::add 1 2)}")
|
testParse("1+2", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||||
testParse("add(1,2)", "{(::add 1 2)}")
|
testParse("add(1,2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||||
testParse("(1)", "{1}")
|
testParse("(1)", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("(1+2)", "{(::add 1 2)}")
|
testParse("(1+2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("unary", () => {
|
describe("unary", () => {
|
||||||
testParse("-1", "{(::unaryMinus 1)}")
|
testParse("-1", "{(::$_endOfOuterBlock_$ () (::unaryMinus 1))}")
|
||||||
testParse("!true", "{(::not true)}")
|
testParse("!true", "{(::$_endOfOuterBlock_$ () (::not true))}")
|
||||||
testParse("1 + -1", "{(::add 1 (::unaryMinus 1))}")
|
testParse("1 + -1", "{(::$_endOfOuterBlock_$ () (::add 1 (::unaryMinus 1)))}")
|
||||||
testParse("-a[0]", "{(::unaryMinus (::$_atIndex_$ :a 0))}")
|
testParse("-a[0]", "{(::$_endOfOuterBlock_$ () (::unaryMinus (::$_atIndex_$ :a 0)))}")
|
||||||
testParse("!a[0]", "{(::not (::$_atIndex_$ :a 0))}")
|
testParse("!a[0]", "{(::$_endOfOuterBlock_$ () (::not (::$_atIndex_$ :a 0)))}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("multiplicative", () => {
|
describe("multiplicative", () => {
|
||||||
testParse("1 * 2", "{(::multiply 1 2)}")
|
testParse("1 * 2", "{(::$_endOfOuterBlock_$ () (::multiply 1 2))}")
|
||||||
testParse("1 / 2", "{(::divide 1 2)}")
|
testParse("1 / 2", "{(::$_endOfOuterBlock_$ () (::divide 1 2))}")
|
||||||
testParse("1 * 2 * 3", "{(::multiply (::multiply 1 2) 3)}")
|
testParse("1 * 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::multiply 1 2) 3))}")
|
||||||
testParse("1 * 2 / 3", "{(::divide (::multiply 1 2) 3)}")
|
testParse("1 * 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::multiply 1 2) 3))}")
|
||||||
testParse("1 / 2 * 3", "{(::multiply (::divide 1 2) 3)}")
|
testParse("1 / 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::divide 1 2) 3))}")
|
||||||
testParse("1 / 2 / 3", "{(::divide (::divide 1 2) 3)}")
|
testParse("1 / 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::divide 1 2) 3))}")
|
||||||
testParse("1 * 2 + 3 * 4", "{(::add (::multiply 1 2) (::multiply 3 4))}")
|
testParse(
|
||||||
testParse("1 * 2 - 3 * 4", "{(::subtract (::multiply 1 2) (::multiply 3 4))}")
|
"1 * 2 + 3 * 4",
|
||||||
testParse("1 * 2 .+ 3 * 4", "{(::dotAdd (::multiply 1 2) (::multiply 3 4))}")
|
"{(::$_endOfOuterBlock_$ () (::add (::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(
|
||||||
testParse("1 * 2 + 3 / 4", "{(::add (::multiply 1 2) (::divide 3 4))}")
|
"1 * 2 - 3 * 4",
|
||||||
testParse("1 * 2 + 3 ./ 4", "{(::add (::multiply 1 2) (::dotDivide 3 4))}")
|
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 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(
|
||||||
testParse("1 * 2 - 3 ./ 4", "{(::subtract (::multiply 1 2) (::dotDivide 3 4))}")
|
"1 * 2 .+ 3 * 4",
|
||||||
testParse("1 * 2 - 3 * 4^5", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5)))}")
|
"{(::$_endOfOuterBlock_$ () (::dotAdd (::multiply 1 2) (::multiply 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 .- 3 * 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::dotSubtract (::multiply 1 2) (::multiply 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 + 3 .* 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::dotMultiply 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 + 3 / 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::divide 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 + 3 ./ 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::dotDivide 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 - 3 .* 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::dotMultiply 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 - 3 / 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::divide 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 - 3 ./ 4",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::dotDivide 3 4)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * 2 - 3 * 4^5",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5))))}",
|
||||||
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 * 4^5^6",
|
"1 * 2 - 3 * 4^5^6",
|
||||||
"{(::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6)))}",
|
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6))))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"1 * -a[-2]",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::multiply 1 (::unaryMinus (::$_atIndex_$ :a (::unaryMinus 2)))))}",
|
||||||
)
|
)
|
||||||
testParse("1 * -a[-2]", "{(::multiply 1 (::unaryMinus (::$_atIndex_$ :a (::unaryMinus 2))))}")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("multi-line", () => {
|
describe("multi-line", () => {
|
||||||
testParse("x=1; 2", "{:x = {1}; 2}")
|
testParse("x=1; 2", "{:x = {1}; (::$_endOfOuterBlock_$ () 2)}")
|
||||||
testParse("x=1; y=2", "{:x = {1}; :y = {2}}")
|
testParse("x=1; y=2", "{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("variables", () => {
|
describe("variables", () => {
|
||||||
testParse("x = 1", "{:x = {1}}")
|
testParse("x = 1", "{:x = {1}; (::$_endOfOuterBlock_$ () ())}")
|
||||||
testParse("x", "{:x}")
|
testParse("x", "{(::$_endOfOuterBlock_$ () :x)}")
|
||||||
testParse("x = 1; x", "{:x = {1}; :x}")
|
testParse("x = 1; x", "{:x = {1}; (::$_endOfOuterBlock_$ () :x)}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("functions", () => {
|
describe("functions", () => {
|
||||||
testParse("identity(x) = x", "{:identity = {|:x| {:x}}}") // Function definitions become lambda assignments
|
testParse("identity(x) = x", "{:identity = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions become lambda assignments
|
||||||
testParse("identity(x)", "{(::identity :x)}")
|
testParse("identity(x)", "{(::$_endOfOuterBlock_$ () (::identity :x))}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
testParse("[]", "{(::$_constructArray_$ ())}")
|
testParse("[]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ ()))}")
|
||||||
testParse("[0, 1, 2]", "{(::$_constructArray_$ (0 1 2))}")
|
testParse("[0, 1, 2]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ (0 1 2)))}")
|
||||||
testParse("['hello', 'world']", "{(::$_constructArray_$ ('hello' 'world'))}")
|
testParse(
|
||||||
testParse("([0,1,2])[1]", "{(::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1)}")
|
"['hello', 'world']",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::$_constructArray_$ ('hello' 'world')))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"([0,1,2])[1]",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1))}",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
testParse("{a: 1, b: 2}", "{(::$_constructRecord_$ ('a': 1 'b': 2))}")
|
testParse(
|
||||||
testParse("{1+0: 1, 2+0: 2}", "{(::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2))}") // key can be any expression
|
"{a: 1, b: 2}",
|
||||||
testParse("record.property", "{(::$_atIndex_$ :record 'property')}")
|
"{(::$_endOfOuterBlock_$ () (::$_constructRecord_$ ('a': 1 'b': 2)))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"{1+0: 1, 2+0: 2}",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2)))}",
|
||||||
|
) // key can be any expression
|
||||||
|
testParse("record.property", "{(::$_endOfOuterBlock_$ () (::$_atIndex_$ :record 'property'))}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("post operators", () => {
|
describe("post operators", () => {
|
||||||
//function call, array and record access are post operators with higher priority than unary operators
|
//function call, array and record access are post operators with higher priority than unary operators
|
||||||
testParse("a==!b(1)", "{(::equal :a (::not (::b 1)))}")
|
testParse("a==!b(1)", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::b 1))))}")
|
||||||
testParse("a==!b[1]", "{(::equal :a (::not (::$_atIndex_$ :b 1)))}")
|
testParse("a==!b[1]", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 1))))}")
|
||||||
testParse("a==!b.one", "{(::equal :a (::not (::$_atIndex_$ :b 'one')))}")
|
testParse(
|
||||||
|
"a==!b.one",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 'one'))))}",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("comments", () => {
|
describe("comments", () => {
|
||||||
testParse("1 # This is a line comment", "{1}")
|
testParse("1 # This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("1 // This is a line comment", "{1}")
|
testParse("1 // This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("1 /* This is a multi line comment */", "{1}")
|
testParse("1 /* This is a multi line comment */", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse("/* This is a multi line comment */ 1", "{1}")
|
testParse("/* This is a multi line comment */ 1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
/* This is
|
/* This is
|
||||||
a multi line
|
a multi line
|
||||||
comment */
|
comment */
|
||||||
1`,
|
1`,
|
||||||
"{1}",
|
"{(::$_endOfOuterBlock_$ () 1)}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("ternary operator", () => {
|
describe("ternary operator", () => {
|
||||||
testParse("true ? 2 : 3", "{(::$$_ternary_$$ true 2 3)}")
|
testParse("true ? 2 : 3", "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true 2 3))}")
|
||||||
testParse(
|
testParse(
|
||||||
"false ? 2 : false ? 4 : 5",
|
"false ? 2 : false ? 4 : 5",
|
||||||
"{(::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5))}",
|
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5)))}",
|
||||||
) // nested ternary
|
) // nested ternary
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("if then else", () => {
|
describe("if then else", () => {
|
||||||
testParse("if true then 2 else 3", "{(::$$_ternary_$$ true {2} {3})}")
|
testParse(
|
||||||
testParse("if false then {2} else {3}", "{(::$$_ternary_$$ false {2} {3})}")
|
"if true then 2 else 3",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true {2} {3}))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"if false then {2} else {3}",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} {3}))}",
|
||||||
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"if false then {2} else if false then {4} else {5}",
|
"if false then {2} else if false then {4} else {5}",
|
||||||
"{(::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5}))}",
|
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5})))}",
|
||||||
) //nested if
|
) //nested if
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("logical", () => {
|
describe("logical", () => {
|
||||||
testParse("true || false", "{(::or true false)}")
|
testParse("true || false", "{(::$_endOfOuterBlock_$ () (::or true false))}")
|
||||||
testParse("true && false", "{(::and true false)}")
|
testParse("true && false", "{(::$_endOfOuterBlock_$ () (::and true false))}")
|
||||||
testParse("a * b + c", "{(::add (::multiply :a :b) :c)}") // for comparison
|
testParse("a * b + c", "{(::$_endOfOuterBlock_$ () (::add (::multiply :a :b) :c))}") // for comparison
|
||||||
testParse("a && b || c", "{(::or (::and :a :b) :c)}")
|
testParse("a && b || c", "{(::$_endOfOuterBlock_$ () (::or (::and :a :b) :c))}")
|
||||||
testParse("a && b || c && d", "{(::or (::and :a :b) (::and :c :d))}")
|
testParse("a && b || c && d", "{(::$_endOfOuterBlock_$ () (::or (::and :a :b) (::and :c :d)))}")
|
||||||
testParse("a && !b || c", "{(::or (::and :a (::not :b)) :c)}")
|
testParse("a && !b || c", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::not :b)) :c))}")
|
||||||
testParse("a && b==c || d", "{(::or (::and :a (::equal :b :c)) :d)}")
|
testParse("a && b==c || d", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::equal :b :c)) :d))}")
|
||||||
testParse("a && b!=c || d", "{(::or (::and :a (::unequal :b :c)) :d)}")
|
testParse(
|
||||||
testParse("a && !(b==c) || d", "{(::or (::and :a (::not (::equal :b :c))) :d)}")
|
"a && b!=c || d",
|
||||||
testParse("a && b>=c || d", "{(::or (::and :a (::largerEq :b :c)) :d)}")
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::unequal :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(
|
||||||
testParse("a && b>c || d", "{(::or (::and :a (::larger :b :c)) :d)}")
|
"a && !(b==c) || d",
|
||||||
testParse("a && b<c || d", "{(::or (::and :a (::smaller :b :c)) :d)}")
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::not (::equal :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(
|
||||||
testParse("a && b<c(i) || d", "{(::or (::and :a (::smaller :b (::c :i))) :d)}")
|
"a && b>=c || d",
|
||||||
testParse("a && b<1+2 || d", "{(::or (::and :a (::smaller :b (::add 1 2))) :d)}")
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::largerEq :b :c)) :d))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"a && !(b>=c) || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::not (::largerEq :b :c))) :d))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"a && b<=c || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smallerEq :b :c)) :d))}",
|
||||||
|
)
|
||||||
|
testParse("a && b>c || d", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::larger :b :c)) :d))}")
|
||||||
|
testParse(
|
||||||
|
"a && b<c || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b :c)) :d))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"a && b<c[i] || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::$_atIndex_$ :c :i))) :d))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"a && b<c.i || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::$_atIndex_$ :c 'i'))) :d))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"a && b<c(i) || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::c :i))) :d))}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"a && b<1+2 || d",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::add 1 2))) :d))}",
|
||||||
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2*3 || d",
|
"a && b<1+2*3 || d",
|
||||||
"{(::or (::and :a (::smaller :b (::add 1 (::multiply 2 3)))) :d)}",
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::add 1 (::multiply 2 3)))) :d))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2*-3+4 || d",
|
"a && b<1+2*-3+4 || d",
|
||||||
"{(::or (::and :a (::smaller :b (::add (::add 1 (::multiply 2 (::unaryMinus 3))) 4))) :d)}",
|
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::add (::add 1 (::multiply 2 (::unaryMinus 3))) 4))) :d))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2*3 || d ? true : false",
|
"a && b<1+2*3 || d ? true : false",
|
||||||
"{(::$$_ternary_$$ (::or (::and :a (::smaller :b (::add 1 (::multiply 2 3)))) :d) true false)}",
|
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ (::or (::and :a (::smaller :b (::add 1 (::multiply 2 3)))) :d) true false))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("pipe", () => {
|
describe("pipe", () => {
|
||||||
testParse("1 -> add(2)", "{(::add 1 2)}")
|
testParse("1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||||
testParse("-1 -> add(2)", "{(::add (::unaryMinus 1) 2)}")
|
testParse("-1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus 1) 2))}")
|
||||||
testParse("-a[1] -> add(2)", "{(::add (::unaryMinus (::$_atIndex_$ :a 1)) 2)}")
|
testParse(
|
||||||
testParse("-f(1) -> add(2)", "{(::add (::unaryMinus (::f 1)) 2)}")
|
"-a[1] -> add(2)",
|
||||||
testParse("1 + 2 -> add(3)", "{(::add 1 (::add 2 3))}")
|
"{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::$_atIndex_$ :a 1)) 2))}",
|
||||||
testParse("1 -> add(2) * 3", "{(::multiply (::add 1 2) 3)}")
|
)
|
||||||
testParse("1 -> subtract(2)", "{(::subtract 1 2)}")
|
testParse("-f(1) -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::f 1)) 2))}")
|
||||||
testParse("-1 -> subtract(2)", "{(::subtract (::unaryMinus 1) 2)}")
|
testParse("1 + 2 -> add(3)", "{(::$_endOfOuterBlock_$ () (::add 1 (::add 2 3)))}")
|
||||||
testParse("1 -> subtract(2) * 3", "{(::multiply (::subtract 1 2) 3)}")
|
testParse("1 -> add(2) * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::add 1 2) 3))}")
|
||||||
|
testParse("1 -> subtract(2)", "{(::$_endOfOuterBlock_$ () (::subtract 1 2))}")
|
||||||
|
testParse("-1 -> subtract(2)", "{(::$_endOfOuterBlock_$ () (::subtract (::unaryMinus 1) 2))}")
|
||||||
|
testParse(
|
||||||
|
"1 -> subtract(2) * 3",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::multiply (::subtract 1 2) 3))}",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("elixir pipe", () => {
|
describe("elixir pipe", () => {
|
||||||
//handled together with -> so there is no need for seperate tests
|
//handled together with -> so there is no need for seperate tests
|
||||||
testParse("1 |> add(2)", "{(::add 1 2)}")
|
testParse("1 |> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("to", () => {
|
describe("to", () => {
|
||||||
testParse("1 to 2", "{(::credibleIntervalToDistribution 1 2)}")
|
testParse("1 to 2", "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution 1 2))}")
|
||||||
testParse("-1 to -2", "{(::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2))}") // lower than unary
|
testParse(
|
||||||
|
"-1 to -2",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2)))}",
|
||||||
|
) // lower than unary
|
||||||
testParse(
|
testParse(
|
||||||
"a[1] to a[2]",
|
"a[1] to a[2]",
|
||||||
"{(::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2))}",
|
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2)))}",
|
||||||
) // lower than post
|
) // lower than post
|
||||||
testParse(
|
testParse(
|
||||||
"a.p1 to a.p2",
|
"a.p1 to a.p2",
|
||||||
"{(::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2'))}",
|
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2')))}",
|
||||||
) // lower than post
|
) // lower than post
|
||||||
testParse("1 to 2 + 3", "{(::add (::credibleIntervalToDistribution 1 2) 3)}") // higher than binary operators
|
testParse(
|
||||||
|
"1 to 2 + 3",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::add (::credibleIntervalToDistribution 1 2) 3))}",
|
||||||
|
) // higher than binary operators
|
||||||
testParse(
|
testParse(
|
||||||
"1->add(2) to 3->add(4) -> add(4)",
|
"1->add(2) to 3->add(4) -> add(4)",
|
||||||
"{(::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4))}",
|
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4)))}",
|
||||||
) // lower than chain
|
) // lower than chain
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("inner block", () => {
|
describe("inner block", () => {
|
||||||
// inner blocks are 0 argument lambdas. They can be used whenever a value is required.
|
// inner blocks are 0 argument lambdas. They can be used whenever a value is required.
|
||||||
// Like lambdas they have a local scope.
|
// Like lambdas they have a local scope.
|
||||||
testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; :x}")
|
testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; (::$_endOfOuterBlock_$ () :x)}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("lambda", () => {
|
describe("lambda", () => {
|
||||||
testParse("{|x| x}", "{{|:x| {:x}}}")
|
testParse("{|x| x}", "{(::$_endOfOuterBlock_$ () {|:x| {:x}})}")
|
||||||
testParse("f={|x| x}", "{:f = {{|:x| {:x}}}}")
|
testParse("f={|x| x}", "{:f = {{|:x| {:x}}}; (::$_endOfOuterBlock_$ () ())}")
|
||||||
testParse("f(x)=x", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments
|
testParse("f(x)=x", "{:f = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions are lambda assignments
|
||||||
testParse("f(x)=x ? 1 : 0", "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}") // Function definitions are lambda assignments
|
testParse(
|
||||||
|
"f(x)=x ? 1 : 0",
|
||||||
|
"{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}; (::$_endOfOuterBlock_$ () ())}",
|
||||||
|
) // Function definitions are lambda assignments
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Using lambda as value", () => {
|
describe("Using lambda as value", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"myadd(x,y)=x+y; z=myadd; z",
|
"myadd(x,y)=x+y; z=myadd; z",
|
||||||
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; :z}",
|
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; (::$_endOfOuterBlock_$ () :z)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"myadd(x,y)=x+y; z=[myadd]; z",
|
"myadd(x,y)=x+y; z=[myadd]; z",
|
||||||
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructArray_$ (:myadd))}; :z}",
|
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructArray_$ (:myadd))}; (::$_endOfOuterBlock_$ () :z)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"myaddd(x,y)=x+y; z={x: myaddd}; z",
|
"myaddd(x,y)=x+y; z={x: myaddd}; z",
|
||||||
"{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructRecord_$ ('x': :myaddd))}; :z}",
|
"{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructRecord_$ ('x': :myaddd))}; (::$_endOfOuterBlock_$ () :z)}",
|
||||||
|
)
|
||||||
|
testParse("f({|x| x+1})", "{(::$_endOfOuterBlock_$ () (::f {|:x| {(::add :x 1)}}))}")
|
||||||
|
testParse(
|
||||||
|
"map(arr, {|x| x+1})",
|
||||||
|
"{(::$_endOfOuterBlock_$ () (::map :arr {|:x| {(::add :x 1)}}))}",
|
||||||
)
|
)
|
||||||
testParse("f({|x| x+1})", "{(::f {|:x| {(::add :x 1)}})}")
|
|
||||||
testParse("map(arr, {|x| x+1})", "{(::map :arr {|:x| {(::add :x 1)}})}")
|
|
||||||
testParse(
|
testParse(
|
||||||
"map([1,2,3], {|x| x+1})",
|
"map([1,2,3], {|x| x+1})",
|
||||||
"{(::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}})}",
|
"{(::$_endOfOuterBlock_$ () (::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}}))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"[1,2,3]->map({|x| x+1})",
|
"[1,2,3]->map({|x| x+1})",
|
||||||
"{(::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}})}",
|
"{(::$_endOfOuterBlock_$ () (::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}}))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("unit", () => {
|
describe("unit", () => {
|
||||||
testParse("1m", "{(::fromUnit_m 1)}")
|
testParse("1m", "{(::$_endOfOuterBlock_$ () (::fromUnit_m 1))}")
|
||||||
testParse("1M", "{(::fromUnit_M 1)}")
|
testParse("1M", "{(::$_endOfOuterBlock_$ () (::fromUnit_M 1))}")
|
||||||
testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}")
|
testParse("1m+2cm", "{(::$_endOfOuterBlock_$ () (::add (::fromUnit_m 1) (::fromUnit_cm 2)))}")
|
||||||
})
|
})
|
||||||
describe("Module", () => {
|
describe("Module", () => {
|
||||||
testParse("x", "{:x}")
|
testParse("x", "{(::$_endOfOuterBlock_$ () :x)}")
|
||||||
testParse("Math.pi", "{:Math.pi}")
|
testParse("Math.pi", "{(::$_endOfOuterBlock_$ () :Math.pi)}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("parsing new line", () => {
|
describe("parsing new line", () => {
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
a +
|
a +
|
||||||
b`,
|
b`,
|
||||||
"{(::add :a :b)}",
|
"{(::$_endOfOuterBlock_$ () (::add :a :b))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x=
|
x=
|
||||||
1`,
|
1`,
|
||||||
"{:x = {1}}",
|
"{:x = {1}; (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x=1
|
x=1
|
||||||
y=2`,
|
y=2`,
|
||||||
"{:x = {1}; :y = {2}}",
|
"{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x={
|
x={
|
||||||
y=2;
|
y=2;
|
||||||
y }
|
y }
|
||||||
x`,
|
x`,
|
||||||
"{:x = {:y = {2}; :y}; :x}",
|
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x={
|
x={
|
||||||
y=2
|
y=2
|
||||||
y }
|
y }
|
||||||
x`,
|
x`,
|
||||||
"{:x = {:y = {2}; :y}; :x}",
|
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x={
|
x={
|
||||||
y=2
|
y=2
|
||||||
y
|
y
|
||||||
}
|
}
|
||||||
x`,
|
x`,
|
||||||
"{:x = {:y = {2}; :y}; :x}",
|
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
x=1
|
||||||
|
y=2
|
||||||
|
z=3
|
||||||
|
`,
|
||||||
|
"{:x = {1}; :y = {2}; :z = {3}; (::$_endOfOuterBlock_$ () ())}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
`
|
||||||
|
f={
|
||||||
x=1
|
x=1
|
||||||
y=2
|
y=2
|
||||||
z=3
|
z=3
|
||||||
`,
|
x+y+z
|
||||||
"{:x = {1}; :y = {2}; :z = {3}}",
|
}
|
||||||
|
`,
|
||||||
|
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
f={
|
f={
|
||||||
x=1
|
x=1
|
||||||
y=2
|
y=2
|
||||||
z=3
|
z=3
|
||||||
x+y+z
|
x+y+z
|
||||||
|
}
|
||||||
|
g=f+4
|
||||||
|
g
|
||||||
|
`,
|
||||||
|
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () :g)}",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
`
|
||||||
|
f =
|
||||||
|
{
|
||||||
|
x=1; //x
|
||||||
|
y=2 //y
|
||||||
|
z=
|
||||||
|
3
|
||||||
|
x+
|
||||||
|
y+
|
||||||
|
z
|
||||||
}
|
}
|
||||||
`,
|
g =
|
||||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}}",
|
f +
|
||||||
|
4
|
||||||
|
g ->
|
||||||
|
h ->
|
||||||
|
p ->
|
||||||
|
q
|
||||||
|
`,
|
||||||
|
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () (::q (::p (::h :g))))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
f={
|
a |>
|
||||||
x=1
|
b |>
|
||||||
y=2
|
c |>
|
||||||
z=3
|
d
|
||||||
x+y+z
|
`,
|
||||||
}
|
"{(::$_endOfOuterBlock_$ () (::d (::c (::b :a))))}",
|
||||||
g=f+4
|
|
||||||
g
|
|
||||||
`,
|
|
||||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; :g}",
|
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
f =
|
a |>
|
||||||
{
|
b |>
|
||||||
x=1; //x
|
c |>
|
||||||
y=2 //y
|
d +
|
||||||
z=
|
e
|
||||||
3
|
`,
|
||||||
x+
|
"{(::$_endOfOuterBlock_$ () (::add (::d (::c (::b :a))) :e))}",
|
||||||
y+
|
|
||||||
z
|
|
||||||
}
|
|
||||||
g =
|
|
||||||
f +
|
|
||||||
4
|
|
||||||
g ->
|
|
||||||
h ->
|
|
||||||
p ->
|
|
||||||
q
|
|
||||||
`,
|
|
||||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::q (::p (::h :g)))}",
|
|
||||||
)
|
|
||||||
testParse(
|
|
||||||
`
|
|
||||||
a |>
|
|
||||||
b |>
|
|
||||||
c |>
|
|
||||||
d
|
|
||||||
`,
|
|
||||||
"{(::d (::c (::b :a)))}",
|
|
||||||
)
|
|
||||||
testParse(
|
|
||||||
`
|
|
||||||
a |>
|
|
||||||
b |>
|
|
||||||
c |>
|
|
||||||
d +
|
|
||||||
e
|
|
||||||
`,
|
|
||||||
"{(::add (::d (::c (::b :a))) :e)}",
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,77 +3,83 @@ open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
describe("Peggy parse type", () => {
|
describe("Peggy parse type", () => {
|
||||||
describe("type of", () => {
|
describe("type of", () => {
|
||||||
testParse("p: number", "{(::$_typeOf_$ :p #number)}")
|
testParse("p: number", "{(::$_typeOf_$ :p #number); (::$_endOfOuterBlock_$ () ())}")
|
||||||
})
|
})
|
||||||
describe("type alias", () => {
|
describe("type alias", () => {
|
||||||
testParse("type index=number", "{(::$_typeAlias_$ #index #number)}")
|
testParse(
|
||||||
|
"type index=number",
|
||||||
|
"{(::$_typeAlias_$ #index #number); (::$_endOfOuterBlock_$ () ())}",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
describe("type or", () => {
|
describe("type or", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: number|string",
|
"answer: number|string",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string))))}",
|
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type function", () => {
|
describe("type function", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"f: number=>number=>number",
|
"f: number=>number=>number",
|
||||||
"{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}",
|
"{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("high priority contract", () => {
|
describe("high priority contract", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: number<-min<-max(100)|string",
|
"answer: number<-min<-max(100)|string",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string))))}",
|
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"answer: number<-memberOf([1,3,5])",
|
"answer: number<-memberOf([1,3,5])",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5))))}",
|
"{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("low priority contract", () => {
|
describe("low priority contract", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: number | string $ opaque",
|
"answer: number | string $ opaque",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string))))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type array", () => {
|
describe("type array", () => {
|
||||||
testParse("answer: [number]", "{(::$_typeOf_$ :answer (::$_typeArray_$ #number))}")
|
testParse(
|
||||||
|
"answer: [number]",
|
||||||
|
"{(::$_typeOf_$ :answer (::$_typeArray_$ #number)); (::$_endOfOuterBlock_$ () ())}",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
describe("type record", () => {
|
describe("type record", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: {a: number, b: string}",
|
"answer: {a: number, b: string}",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeRecord_$ (::$_constructRecord_$ ('a': #number 'b': #string))))}",
|
"{(::$_typeOf_$ :answer (::$_typeRecord_$ (::$_constructRecord_$ ('a': #number 'b': #string)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type constructor", () => {
|
describe("type constructor", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: Age(number)",
|
"answer: Age(number)",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number))))}",
|
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"answer: Complex(number, number)",
|
"answer: Complex(number, number)",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number))))}",
|
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number)))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"answer: Person({age: number, name: string})",
|
"answer: Person({age: number, name: string})",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Person (::$_constructArray_$ ((::$_typeRecord_$ (::$_constructRecord_$ ('age': #number 'name': #string)))))))}",
|
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Person (::$_constructArray_$ ((::$_typeRecord_$ (::$_constructRecord_$ ('age': #number 'name': #string))))))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"weekend: Saturday | Sunday",
|
"weekend: Saturday | Sunday",
|
||||||
"{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ()))))))}",
|
"{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ())))))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type parenthesis", () => {
|
describe("type parenthesis", () => {
|
||||||
//$ is introduced to avoid parenthesis
|
//$ is introduced to avoid parenthesis
|
||||||
testParse(
|
testParse(
|
||||||
"answer: (number|string)<-opaque",
|
"answer: (number|string)<-opaque",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string))))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("squiggle expressions in type contracts", () => {
|
describe("squiggle expressions in type contracts", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
||||||
"{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2)))}",
|
"{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2))); (::$_endOfOuterBlock_$ () ())}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -23,13 +23,7 @@ let expectToExpressionToBe = (expr, answer, ~v="_", ()) => {
|
||||||
} else {
|
} else {
|
||||||
let a2 =
|
let a2 =
|
||||||
rExpr
|
rExpr
|
||||||
->Result.flatMap(expr =>
|
->Result.flatMap(expr => Expression.BackCompatible.evaluate(expr))
|
||||||
Expression.reduceExpression(
|
|
||||||
expr,
|
|
||||||
ReducerInterface_StdLib.internalStdLib,
|
|
||||||
ExpressionValue.defaultEnvironment,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
->Reducer_Helpers.rRemoveDefaultsInternal
|
->Reducer_Helpers.rRemoveDefaultsInternal
|
||||||
->ExpressionValue.toStringResultOkless
|
->ExpressionValue.toStringResultOkless
|
||||||
(a1, a2)->expect->toEqual((answer, v))
|
(a1, a2)->expect->toEqual((answer, v))
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
|
||||||
|
open Jest
|
||||||
|
open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
|
describe("Peggy Outer Block", () => {
|
||||||
|
testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||||
|
testToExpression("x=1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ~v="()", ())
|
||||||
|
testToExpression(
|
||||||
|
"x=1; y=2",
|
||||||
|
"{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}",
|
||||||
|
~v="()",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ())
|
||||||
|
testToExpression(
|
||||||
|
"x={a=1; a}; x",
|
||||||
|
"{(:$_let_$ :x {(:$_let_$ :a {1}); :a}); (:$_endOfOuterBlock_$ () :x)}",
|
||||||
|
~v="1",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
})
|
|
@ -7,101 +7,138 @@ open Reducer_Peggy_TestHelpers
|
||||||
describe("Peggy to Expression", () => {
|
describe("Peggy to Expression", () => {
|
||||||
describe("literals operators parenthesis", () => {
|
describe("literals operators parenthesis", () => {
|
||||||
// Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement
|
// Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement
|
||||||
testToExpression("1", "{1}", ~v="1", ())
|
testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||||
testToExpression("'hello'", "{'hello'}", ~v="'hello'", ())
|
testToExpression("'hello'", "{(:$_endOfOuterBlock_$ () 'hello')}", ~v="'hello'", ())
|
||||||
testToExpression("true", "{true}", ~v="true", ())
|
testToExpression("true", "{(:$_endOfOuterBlock_$ () true)}", ~v="true", ())
|
||||||
testToExpression("1+2", "{(:add 1 2)}", ~v="3", ())
|
testToExpression("1+2", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||||
testToExpression("add(1,2)", "{(:add 1 2)}", ~v="3", ())
|
testToExpression("add(1,2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||||
testToExpression("(1)", "{1}", ())
|
testToExpression("(1)", "{(:$_endOfOuterBlock_$ () 1)}", ())
|
||||||
testToExpression("(1+2)", "{(:add 1 2)}", ())
|
testToExpression("(1+2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("unary", () => {
|
describe("unary", () => {
|
||||||
testToExpression("-1", "{(:unaryMinus 1)}", ~v="-1", ())
|
testToExpression("-1", "{(:$_endOfOuterBlock_$ () (:unaryMinus 1))}", ~v="-1", ())
|
||||||
testToExpression("!true", "{(:not true)}", ~v="false", ())
|
testToExpression("!true", "{(:$_endOfOuterBlock_$ () (:not true))}", ~v="false", ())
|
||||||
testToExpression("1 + -1", "{(:add 1 (:unaryMinus 1))}", ~v="0", ())
|
testToExpression("1 + -1", "{(:$_endOfOuterBlock_$ () (:add 1 (:unaryMinus 1)))}", ~v="0", ())
|
||||||
testToExpression("-a[0]", "{(:unaryMinus (:$_atIndex_$ :a 0))}", ())
|
testToExpression("-a[0]", "{(:$_endOfOuterBlock_$ () (:unaryMinus (:$_atIndex_$ :a 0)))}", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("multi-line", () => {
|
describe("multi-line", () => {
|
||||||
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); 2}", ~v="2", ())
|
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ())
|
||||||
testToExpression("x=1; y=2", "{(:$_let_$ :x {1}); (:$_let_$ :y {2})}", ~v="@{x: 1,y: 2}", ())
|
testToExpression(
|
||||||
|
"x=1; y=2",
|
||||||
|
"{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}",
|
||||||
|
(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("variables", () => {
|
describe("variables", () => {
|
||||||
testToExpression("x = 1", "{(:$_let_$ :x {1})}", ~v="@{x: 1}", ())
|
testToExpression("x = 1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ())
|
||||||
testToExpression("x", "{:x}", ~v=":x", ()) //TODO: value should return error
|
testToExpression("x", "{(:$_endOfOuterBlock_$ () :x)}", ~v="Error(x is not defined)", ()) //TODO: value should return error
|
||||||
testToExpression("x = 1; x", "{(:$_let_$ :x {1}); :x}", ~v="1", ())
|
testToExpression("x = 1; x", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () :x)}", ~v="1", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("functions", () => {
|
describe("functions", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"identity(x) = x",
|
"identity(x) = x",
|
||||||
"{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x}))}",
|
"{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{identity: lambda(x=>internal code)}",
|
|
||||||
(),
|
(),
|
||||||
) // Function definitions become lambda assignments
|
) // Function definitions become lambda assignments
|
||||||
testToExpression("identity(x)", "{(:identity :x)}", ()) // Note value returns error properly
|
testToExpression("identity(x)", "{(:$_endOfOuterBlock_$ () (:identity :x))}", ()) // Note value returns error properly
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x) = x> 2 ? 0 : 1; f(3)",
|
"f(x) = x> 2 ? 0 : 1; f(3)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ (:larger :x 2) 0 1)})); (:f 3)}",
|
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ (:larger :x 2) 0 1)})); (:$_endOfOuterBlock_$ () (:f 3))}",
|
||||||
~v="0",
|
~v="0",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
testToExpression("[]", "{(:$_constructArray_$ ())}", ~v="[]", ())
|
testToExpression("[]", "{(:$_endOfOuterBlock_$ () (:$_constructArray_$ ()))}", ~v="[]", ())
|
||||||
testToExpression("[0, 1, 2]", "{(:$_constructArray_$ (0 1 2))}", ~v="[0,1,2]", ())
|
testToExpression(
|
||||||
|
"[0, 1, 2]",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$_constructArray_$ (0 1 2)))}",
|
||||||
|
~v="[0,1,2]",
|
||||||
|
(),
|
||||||
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"['hello', 'world']",
|
"['hello', 'world']",
|
||||||
"{(:$_constructArray_$ ('hello' 'world'))}",
|
"{(:$_endOfOuterBlock_$ () (:$_constructArray_$ ('hello' 'world')))}",
|
||||||
~v="['hello','world']",
|
~v="['hello','world']",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression("([0,1,2])[1]", "{(:$_atIndex_$ (:$_constructArray_$ (0 1 2)) 1)}", ~v="1", ())
|
testToExpression(
|
||||||
|
"([0,1,2])[1]",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$_atIndex_$ (:$_constructArray_$ (0 1 2)) 1))}",
|
||||||
|
~v="1",
|
||||||
|
(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"{a: 1, b: 2}",
|
"{a: 1, b: 2}",
|
||||||
"{(:$_constructRecord_$ (('a' 1) ('b' 2)))}",
|
"{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (('a' 1) ('b' 2))))}",
|
||||||
~v="{a: 1,b: 2}",
|
~v="{a: 1,b: 2}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"{1+0: 1, 2+0: 2}",
|
"{1+0: 1, 2+0: 2}",
|
||||||
"{(:$_constructRecord_$ (((:add 1 0) 1) ((:add 2 0) 2)))}",
|
"{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (((:add 1 0) 1) ((:add 2 0) 2))))}",
|
||||||
(),
|
(),
|
||||||
) // key can be any expression
|
) // key can be any expression
|
||||||
testToExpression("record.property", "{(:$_atIndex_$ :record 'property')}", ())
|
testToExpression(
|
||||||
|
"record.property",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}",
|
||||||
|
(),
|
||||||
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"record={property: 1}; record.property",
|
"record={property: 1}; record.property",
|
||||||
"{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_atIndex_$ :record 'property')}",
|
"{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("comments", () => {
|
describe("comments", () => {
|
||||||
testToExpression("1 # This is a line comment", "{1}", ~v="1", ())
|
testToExpression("1 # This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||||
testToExpression("1 // This is a line comment", "{1}", ~v="1", ())
|
testToExpression("1 // This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||||
testToExpression("1 /* This is a multi line comment */", "{1}", ~v="1", ())
|
testToExpression(
|
||||||
testToExpression("/* This is a multi line comment */ 1", "{1}", ~v="1", ())
|
"1 /* This is a multi line comment */",
|
||||||
|
"{(:$_endOfOuterBlock_$ () 1)}",
|
||||||
|
~v="1",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
testToExpression(
|
||||||
|
"/* This is a multi line comment */ 1",
|
||||||
|
"{(:$_endOfOuterBlock_$ () 1)}",
|
||||||
|
~v="1",
|
||||||
|
(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("ternary operator", () => {
|
describe("ternary operator", () => {
|
||||||
testToExpression("true ? 1 : 0", "{(:$$_ternary_$$ true 1 0)}", ~v="1", ())
|
testToExpression(
|
||||||
testToExpression("false ? 1 : 0", "{(:$$_ternary_$$ false 1 0)}", ~v="0", ())
|
"true ? 1 : 0",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 0))}",
|
||||||
|
~v="1",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
testToExpression(
|
||||||
|
"false ? 1 : 0",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 0))}",
|
||||||
|
~v="0",
|
||||||
|
(),
|
||||||
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"true ? 1 : false ? 2 : 0",
|
"true ? 1 : false ? 2 : 0",
|
||||||
"{(:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0))}",
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0)))}",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
) // nested ternary
|
) // nested ternary
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"false ? 1 : false ? 2 : 0",
|
"false ? 1 : false ? 2 : 0",
|
||||||
"{(:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0))}",
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0)))}",
|
||||||
~v="0",
|
~v="0",
|
||||||
(),
|
(),
|
||||||
) // nested ternary
|
) // nested ternary
|
||||||
|
@ -109,21 +146,21 @@ describe("Peggy to Expression", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
// expression binding
|
// expression binding
|
||||||
"f(a) = a > 5 ? 1 : 0; f(6)",
|
"f(a) = a > 5 ? 1 : 0; f(6)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) 1 0)})); (:f 6)}",
|
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) 1 0)})); (:$_endOfOuterBlock_$ () (:f 6))}",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
// when true binding
|
// when true binding
|
||||||
"f(a) = a > 5 ? a : 0; f(6)",
|
"f(a) = a > 5 ? a : 0; f(6)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) :a 0)})); (:f 6)}",
|
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) :a 0)})); (:$_endOfOuterBlock_$ () (:f 6))}",
|
||||||
~v="6",
|
~v="6",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
// when false binding
|
// when false binding
|
||||||
"f(a) = a < 5 ? 1 : a; f(6)",
|
"f(a) = a < 5 ? 1 : a; f(6)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:smaller :a 5) 1 :a)})); (:f 6)}",
|
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:smaller :a 5) 1 :a)})); (:$_endOfOuterBlock_$ () (:f 6))}",
|
||||||
~v="6",
|
~v="6",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
@ -131,23 +168,41 @@ describe("Peggy to Expression", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("if then else", () => {
|
describe("if then else", () => {
|
||||||
testToExpression("if true then 2 else 3", "{(:$$_ternary_$$ true {2} {3})}", ())
|
testToExpression(
|
||||||
testToExpression("if true then {2} else {3}", "{(:$$_ternary_$$ true {2} {3})}", ())
|
"if true then 2 else 3",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
testToExpression(
|
||||||
|
"if true then {2} else {3}",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}",
|
||||||
|
(),
|
||||||
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"if false then {2} else if false then {4} else {5}",
|
"if false then {2} else if false then {4} else {5}",
|
||||||
"{(:$$_ternary_$$ false {2} (:$$_ternary_$$ false {4} {5}))}",
|
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false {2} (:$$_ternary_$$ false {4} {5})))}",
|
||||||
(),
|
(),
|
||||||
) //nested if
|
) //nested if
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("pipe", () => {
|
describe("pipe", () => {
|
||||||
testToExpression("1 -> add(2)", "{(:add 1 2)}", ~v="3", ())
|
testToExpression("1 -> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||||
testToExpression("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}", ~v="1", ()) // note that unary has higher priority naturally
|
testToExpression(
|
||||||
testToExpression("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}", ~v="9", ())
|
"-1 -> add(2)",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:add (:unaryMinus 1) 2))}",
|
||||||
|
~v="1",
|
||||||
|
(),
|
||||||
|
) // note that unary has higher priority naturally
|
||||||
|
testToExpression(
|
||||||
|
"1 -> add(2) * 3",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:multiply (:add 1 2) 3))}",
|
||||||
|
~v="9",
|
||||||
|
(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("elixir pipe", () => {
|
describe("elixir pipe", () => {
|
||||||
testToExpression("1 |> add(2)", "{(:add 1 2)}", ~v="3", ())
|
testToExpression("1 |> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
// see testParse for priorities of to and credibleIntervalToDistribution
|
// see testParse for priorities of to and credibleIntervalToDistribution
|
||||||
|
@ -157,30 +212,31 @@ describe("Peggy to Expression", () => {
|
||||||
// Like lambdas they have a local scope.
|
// Like lambdas they have a local scope.
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"y=99; x={y=1; y}",
|
"y=99; x={y=1; y}",
|
||||||
"{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y})}",
|
"{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y}); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{x: 1,y: 99}",
|
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("lambda", () => {
|
describe("lambda", () => {
|
||||||
testToExpression("{|x| x}", "{(:$$_lambda_$$ [x] {:x})}", ~v="lambda(x=>internal code)", ())
|
testToExpression(
|
||||||
|
"{|x| x}",
|
||||||
|
"{(:$_endOfOuterBlock_$ () (:$$_lambda_$$ [x] {:x}))}",
|
||||||
|
~v="lambda(x=>internal code)",
|
||||||
|
(),
|
||||||
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f={|x| x}",
|
"f={|x| x}",
|
||||||
"{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})})}",
|
"{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})}); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{f: lambda(x=>internal code)}",
|
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x)=x",
|
"f(x)=x",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {:x}))}",
|
"{(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{f: lambda(x=>internal code)}",
|
|
||||||
(),
|
(),
|
||||||
) // Function definitions are lambda assignments
|
) // Function definitions are lambda assignments
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x)=x ? 1 : 0",
|
"f(x)=x ? 1 : 0",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)}))}",
|
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)})); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{f: lambda(x=>internal code)}",
|
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -188,12 +244,12 @@ describe("Peggy to Expression", () => {
|
||||||
describe("module", () => {
|
describe("module", () => {
|
||||||
// testToExpression("Math.pi", "{:Math.pi}", ~v="3.141592653589793", ())
|
// testToExpression("Math.pi", "{:Math.pi}", ~v="3.141592653589793", ())
|
||||||
// Only.test("stdlibrary", () => {
|
// Only.test("stdlibrary", () => {
|
||||||
// ReducerInterface_StdLib.internalStdLib
|
// ReducerInterface_StdLib.internalStdLib
|
||||||
// ->IEvBindings
|
// ->IEvBindings
|
||||||
// ->InternalExpressionValue.toString
|
// ->InternalExpressionValue.toString
|
||||||
// ->expect
|
// ->expect
|
||||||
// ->toBe("")
|
// ->toBe("")
|
||||||
// })
|
// })
|
||||||
testToExpression("Math.pi", "{:Math.pi}", ~v="3.141592653589793", ())
|
testToExpression("Math.pi", "{(:$_endOfOuterBlock_$ () :Math.pi)}", ~v="3.141592653589793", ())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,92 +5,92 @@ describe("Peggy Types to Expression", () => {
|
||||||
describe("type of", () => {
|
describe("type of", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"p: number",
|
"p: number",
|
||||||
"{(:$_typeOf_$ :p #number)}",
|
"{(:$_typeOf_$ :p #number); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {p: #number}}",
|
// ~v="@{_typeReferences_: {p: #number}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type alias", () => {
|
describe("type alias", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"type index=number",
|
"type index=number",
|
||||||
"{(:$_typeAlias_$ #index #number)}",
|
"{(:$_typeAlias_$ #index #number); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeAliases_: {index: #number}}",
|
// ~v="@{_typeAliases_: {index: #number}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type or", () => {
|
describe("type or", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number|string|distribution",
|
"answer: number|string|distribution",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution))))}",
|
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution)))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {typeOr: [#number,#string,#distribution],typeTag: 'typeOr'}}}",
|
// ~v="@{_typeReferences_: {answer: {typeOr: [#number,#string,#distribution],typeTag: 'typeOr'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type function", () => {
|
describe("type function", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f: number=>number=>number",
|
"f: number=>number=>number",
|
||||||
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number))))}",
|
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number)))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {f: {inputs: [#number,#number],output: #number,typeTag: 'typeFunction'}}}",
|
// ~v="@{_typeReferences_: {f: {inputs: [#number,#number],output: #number,typeTag: 'typeFunction'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f: number=>number",
|
"f: number=>number",
|
||||||
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number))))}",
|
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number)))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {f: {inputs: [#number],output: #number,typeTag: 'typeFunction'}}}",
|
// ~v="@{_typeReferences_: {f: {inputs: [#number],output: #number,typeTag: 'typeFunction'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("high priority contract", () => {
|
describe("high priority contract", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-min(1)<-max(100)|string",
|
"answer: number<-min(1)<-max(100)|string",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}",
|
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string)))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {typeOr: [{max: 100,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'},#string],typeTag: 'typeOr'}}}",
|
// ~v="@{_typeReferences_: {answer: {typeOr: [{max: 100,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'},#string],typeTag: 'typeOr'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-memberOf([1,3,5])",
|
"answer: number<-memberOf([1,3,5])",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5))))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5)))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {memberOf: [1,3,5],typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
// ~v="@{_typeReferences_: {answer: {memberOf: [1,3,5],typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-min(1)",
|
"answer: number<-min(1)",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1)); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
// ~v="@{_typeReferences_: {answer: {min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-max(10)",
|
"answer: number<-max(10)",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10)); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {max: 10,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
// ~v="@{_typeReferences_: {answer: {max: 10,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-min(1)<-max(10)",
|
"answer: number<-min(1)<-max(10)",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10)); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
// ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-max(10)<-min(1)",
|
"answer: number<-max(10)<-min(1)",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1)); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
// ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("low priority contract", () => {
|
describe("low priority contract", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number | string $ opaque",
|
"answer: number | string $ opaque",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string))))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeReferences_: {answer: {opaque: true,typeOr: [#number,#string],typeTag: 'typeOr'}}}",
|
// ~v="@{_typeReferences_: {answer: {opaque: true,typeOr: [#number,#string],typeTag: 'typeOr'}}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("squiggle expressions in type contracts", () => {
|
describe("squiggle expressions in type contracts", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
||||||
"{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2)))}",
|
"{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2))); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_typeAliases_: {odds: {memberOf: [1,3,5,7,9],typeIdentifier: #number,typeTag: 'typeIdentifier'}},odds1: [1,3,5],odds2: [7,9]}",
|
// ~v="@{_typeAliases_: {odds: {memberOf: [1,3,5,7,9],typeIdentifier: #number,typeTag: 'typeIdentifier'}},odds1: [1,3,5],odds2: [7,9]}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,18 +3,23 @@ open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
describe("Peggy void", () => {
|
describe("Peggy void", () => {
|
||||||
//literal
|
//literal
|
||||||
testToExpression("()", "{()}", ~v="()", ())
|
testToExpression("()", "{(:$_endOfOuterBlock_$ () ())}", ~v="()", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"fn()=1",
|
"fn()=1",
|
||||||
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1}))}",
|
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{fn: lambda(_=>internal code)}",
|
// ~v="@{fn: lambda(_=>internal code)}",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
testToExpression(
|
||||||
|
"fn()=1; fn()",
|
||||||
|
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:$_endOfOuterBlock_$ () (:fn ()))}",
|
||||||
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression("fn()=1; fn()", "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:fn ())}", ~v="1", ())
|
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"fn(a)=(); call fn(1)",
|
"fn(a)=(); call fn(1)",
|
||||||
"{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)})}",
|
"{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)}); (:$_endOfOuterBlock_$ () ())}",
|
||||||
~v="@{_: (),fn: lambda(a=>internal code)}",
|
// ~v="@{_: (),fn: lambda(a=>internal code)}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module Expression = Reducer_Expression
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExternalExpressionValue = ReducerInterface.ExternalExpressionValue
|
module ExternalExpressionValue = ReducerInterface.ExternalExpressionValue
|
||||||
module ErrorValue = Reducer_ErrorValue
|
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
@ -13,25 +14,21 @@ let unwrapRecord = rValue =>
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let expectParseToBe = (expr: string, answer: string) =>
|
let expectParseToBe = (code: string, answer: string) =>
|
||||||
Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer)
|
Expression.BackCompatible.parse(code)->ExpressionT.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let expectEvalToBe = (expr: string, answer: string) =>
|
let expectEvalToBe = (code: string, answer: string) =>
|
||||||
Reducer.evaluate(expr)
|
Expression.BackCompatible.evaluateStringAsExternal(code)
|
||||||
->Reducer_Helpers.rRemoveDefaultsExternal
|
->Reducer_Helpers.rRemoveDefaultsExternal
|
||||||
->ExternalExpressionValue.toStringResult
|
->ExternalExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
->toBe(answer)
|
->toBe(answer)
|
||||||
|
|
||||||
let expectEvalError = (expr: string) =>
|
let expectEvalError = (code: string) =>
|
||||||
Reducer.evaluate(expr)->ExternalExpressionValue.toStringResult->expect->toMatch("Error\(")
|
Expression.BackCompatible.evaluateStringAsExternal(code)
|
||||||
|
|
||||||
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
|
||||||
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None)
|
|
||||||
->Reducer_Helpers.rRemoveDefaultsExternal
|
|
||||||
->ExternalExpressionValue.toStringResult
|
->ExternalExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
->toBe(answer)
|
->toMatch("Error\(")
|
||||||
|
|
||||||
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testDescriptionParseToBe = (desc, expr, answer) =>
|
let testDescriptionParseToBe = (desc, expr, answer) =>
|
||||||
|
@ -40,18 +37,12 @@ let testDescriptionParseToBe = (desc, expr, answer) =>
|
||||||
let testEvalError = expr => test(expr, () => expectEvalError(expr))
|
let testEvalError = expr => test(expr, () => expectEvalError(expr))
|
||||||
let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
|
let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
|
||||||
|
|
||||||
module MySkip = {
|
module MySkip = {
|
||||||
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
|
||||||
}
|
}
|
||||||
module MyOnly = {
|
module MyOnly = {
|
||||||
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
module Expression = Reducer_Expression
|
module Expression = Reducer_Expression
|
||||||
// module ExpressionValue = ReducerInterface.ExpressionValue
|
|
||||||
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
|
||||||
module ExpressionWithContext = Reducer_ExpressionWithContext
|
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
|
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
||||||
module Macro = Reducer_Expression_Macro
|
module Macro = Reducer_Expression_Macro
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
module T = Reducer_Expression_T
|
module T = Reducer_Expression_T
|
||||||
module Bindings = Reducer_Bindings
|
|
||||||
|
|
||||||
let testMacro_ = (
|
let testMacro_ = (
|
||||||
tester,
|
tester,
|
||||||
|
@ -21,8 +21,8 @@ let testMacro_ = (
|
||||||
expr
|
expr
|
||||||
->Macro.expandMacroCall(
|
->Macro.expandMacroCall(
|
||||||
bindings,
|
bindings,
|
||||||
InternalExpressionValue.defaultEnvironment,
|
ProjectAccessorsT.identityAccessors,
|
||||||
Expression.reduceExpression,
|
Expression.reduceExpressionInProject,
|
||||||
)
|
)
|
||||||
->ExpressionWithContext.toStringResult
|
->ExpressionWithContext.toStringResult
|
||||||
->expect
|
->expect
|
||||||
|
@ -41,8 +41,8 @@ let testMacroEval_ = (
|
||||||
expr
|
expr
|
||||||
->Macro.doMacroCall(
|
->Macro.doMacroCall(
|
||||||
bindings,
|
bindings,
|
||||||
InternalExpressionValue.defaultEnvironment,
|
ProjectAccessorsT.identityAccessors,
|
||||||
Expression.reduceExpression,
|
Expression.reduceExpressionInProject,
|
||||||
)
|
)
|
||||||
->InternalExpressionValue.toStringResult
|
->InternalExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
|
|
|
@ -8,7 +8,7 @@ open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
let myIevEval = (aTypeSourceCode: string) =>
|
let myIevEval = (aTypeSourceCode: string) =>
|
||||||
TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpression)
|
TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpressionInProject)
|
||||||
let myIevEvalToString = (aTypeSourceCode: string) =>
|
let myIevEvalToString = (aTypeSourceCode: string) =>
|
||||||
myIevEval(aTypeSourceCode)->InternalExpressionValue.toStringResult
|
myIevEval(aTypeSourceCode)->InternalExpressionValue.toStringResult
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ let myIevTest = (test, aTypeSourceCode, answer) =>
|
||||||
test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer))
|
test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer))
|
||||||
|
|
||||||
let myTypeEval = (aTypeSourceCode: string) =>
|
let myTypeEval = (aTypeSourceCode: string) =>
|
||||||
TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpression)
|
TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpressionInProject)
|
||||||
let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode)->T.toStringResult
|
let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode)->T.toStringResult
|
||||||
|
|
||||||
let myTypeExpectEqual = (aTypeSourceCode, answer) =>
|
let myTypeExpectEqual = (aTypeSourceCode, answer) =>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module Expression = Reducer_Expression
|
module Expression = Reducer_Expression
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ErrorValue = Reducer_ErrorValue
|
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Bindings = Reducer_Bindings
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
module T = Reducer_Type_T
|
module T = Reducer_Type_T
|
||||||
module TypeChecker = Reducer_Type_TypeChecker
|
module TypeChecker = Reducer_Type_TypeChecker
|
||||||
|
|
||||||
|
@ -13,10 +14,10 @@ let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): re
|
||||||
'v,
|
'v,
|
||||||
ErrorValue.t,
|
ErrorValue.t,
|
||||||
> => {
|
> => {
|
||||||
let reducerFn = Expression.reduceExpression
|
let reducerFn = Expression.reduceExpressionInProject
|
||||||
let rResult =
|
let rResult =
|
||||||
Reducer.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||||
reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment)
|
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
||||||
)
|
)
|
||||||
rResult->Belt.Result.flatMap(result =>
|
rResult->Belt.Result.flatMap(result =>
|
||||||
switch result {
|
switch result {
|
||||||
|
|
|
@ -5,6 +5,7 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Bindings = Reducer_Bindings
|
module Bindings = Reducer_Bindings
|
||||||
module T = Reducer_Type_T
|
module T = Reducer_Type_T
|
||||||
module TypeChecker = Reducer_Type_TypeChecker
|
module TypeChecker = Reducer_Type_TypeChecker
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
@ -16,10 +17,10 @@ let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result<
|
||||||
'v,
|
'v,
|
||||||
ErrorValue.t,
|
ErrorValue.t,
|
||||||
> => {
|
> => {
|
||||||
let reducerFn = Expression.reduceExpression
|
let reducerFn = Expression.reduceExpressionInProject
|
||||||
let rResult =
|
let rResult =
|
||||||
Reducer.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||||
reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment)
|
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
||||||
)
|
)
|
||||||
rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn))
|
rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
open Jest
|
|
||||||
open Reducer_TestHelpers
|
|
||||||
|
|
||||||
describe("Eval with Bindings", () => {
|
|
||||||
testEvalBindingsToBe("x", list{("x", ExternalExpressionValue.EvNumber(1.))}, "Ok(1)")
|
|
||||||
testEvalBindingsToBe("x+1", list{("x", ExternalExpressionValue.EvNumber(1.))}, "Ok(2)")
|
|
||||||
testParseToBe("y = x+1; y", "Ok({(:$_let_$ :y {(:add :x 1)}); :y})")
|
|
||||||
testEvalBindingsToBe("y = x+1; y", list{("x", ExternalExpressionValue.EvNumber(1.))}, "Ok(2)")
|
|
||||||
testEvalBindingsToBe(
|
|
||||||
"y = x+1",
|
|
||||||
list{("x", ExternalExpressionValue.EvNumber(1.))},
|
|
||||||
"Ok(@{x: 1,y: 2})",
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -2,8 +2,14 @@ open Jest
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
describe("Parse function assignment", () => {
|
describe("Parse function assignment", () => {
|
||||||
testParseToBe("f(x)=x", "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {:x}))})")
|
testParseToBe(
|
||||||
testParseToBe("f(x)=2*x", "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {(:multiply 2 :x)}))})")
|
"f(x)=x",
|
||||||
|
"Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())})",
|
||||||
|
)
|
||||||
|
testParseToBe(
|
||||||
|
"f(x)=2*x",
|
||||||
|
"Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {(:multiply 2 :x)})); (:$_endOfOuterBlock_$ () ())})",
|
||||||
|
)
|
||||||
//MathJs does not allow blocks in function definitions
|
//MathJs does not allow blocks in function definitions
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -39,33 +39,27 @@ describe("symbol not defined", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("call and bindings", () => {
|
describe("call and bindings", () => {
|
||||||
testEvalToBe("f(x)=x+1", "Ok(@{f: lambda(x=>internal code)})")
|
testEvalToBe("f(x)=x+1; f(0)", "Ok(1)")
|
||||||
testEvalToBe("f(x)=x+1; f(1)", "Ok(2)")
|
testEvalToBe("f(x)=x+1; f(1)", "Ok(2)")
|
||||||
testEvalToBe("f=1;y=2", "Ok(@{f: 1,y: 2})")
|
testEvalToBe("f=1;y=2", "Ok(())")
|
||||||
testEvalToBe("f(x)=x+1; y=f(1)", "Ok(@{f: lambda(x=>internal code),y: 2})")
|
testEvalToBe("f(x)=x+1; y=f(1); y", "Ok(2)")
|
||||||
testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)")
|
testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)")
|
||||||
testEvalToBe("f(x)=x+1; y=f(1); z=f(1)", "Ok(@{f: lambda(x=>internal code),y: 2,z: 2})")
|
testEvalToBe("f(x)=x+1; y=f(1); z=f(1); z", "Ok(2)")
|
||||||
testEvalToBe(
|
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(0)", "Ok(2)")
|
||||||
"f(x)=x+1; g(x)=f(x)+1",
|
|
||||||
"Ok(@{f: lambda(x=>internal code),g: lambda(x=>internal code)})",
|
|
||||||
)
|
|
||||||
testParseToBe(
|
testParseToBe(
|
||||||
"f=99; g(x)=f; g(2)",
|
"f=99; g(x)=f; g(2)",
|
||||||
"Ok({(:$_let_$ :f {99}); (:$_let_$ :g (:$$_lambda_$$ [x] {:f})); (:g 2)})",
|
"Ok({(:$_let_$ :f {99}); (:$_let_$ :g (:$$_lambda_$$ [x] {:f})); (:$_endOfOuterBlock_$ () (:g 2))})",
|
||||||
)
|
)
|
||||||
testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)")
|
testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)")
|
||||||
testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)")
|
testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)")
|
||||||
testEvalToBe(
|
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; y=g(2); y", "Ok(4)")
|
||||||
"f(x)=x+1; g(x)=f(x)+1; y=g(2)",
|
|
||||||
"Ok(@{f: lambda(x=>internal code),g: lambda(x=>internal code),y: 4})",
|
|
||||||
)
|
|
||||||
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)")
|
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("function tricks", () => {
|
describe("function tricks", () => {
|
||||||
testEvalError("f(x)=f(y)=2; f(2)") //Error because chain assignment is not allowed
|
testEvalError("f(x)=f(y)=2; f(2)") //Error because chain assignment is not allowed
|
||||||
testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)")
|
testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)")
|
||||||
testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok(@{g: lambda(x=>internal code),y: 2})")
|
testEvalToBe("y=2;g(x)=inspect(y)+1;y", "Ok(2)")
|
||||||
MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout?
|
MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout?
|
||||||
MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters
|
MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters
|
||||||
testEvalToBe("myadd(x,y)=x+y; z=myadd; z", "Ok(lambda(x,y=>internal code))")
|
testEvalToBe("myadd(x,y)=x+y; z=myadd; z", "Ok(lambda(x,y=>internal code))")
|
||||||
|
@ -73,10 +67,7 @@ describe("function tricks", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("lambda in structures", () => {
|
describe("lambda in structures", () => {
|
||||||
testEvalToBe(
|
testEvalToBe("myadd(x,y)=x+y; z=[myadd]", "Ok(())")
|
||||||
"myadd(x,y)=x+y; z=[myadd]",
|
|
||||||
"Ok(@{myadd: lambda(x,y=>internal code),z: [lambda(x,y=>internal code)]})",
|
|
||||||
)
|
|
||||||
testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0]", "Ok(lambda(x,y=>internal code))")
|
testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0]", "Ok(lambda(x,y=>internal code))")
|
||||||
testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0](3,2)", "Ok(5)")
|
testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0](3,2)", "Ok(5)")
|
||||||
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z", "Ok({x: lambda(x,y=>internal code)})")
|
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z", "Ok({x: lambda(x,y=>internal code)})")
|
||||||
|
|
|
@ -2,7 +2,10 @@ open Jest
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
describe("Parse ternary operator", () => {
|
describe("Parse ternary operator", () => {
|
||||||
testParseToBe("true ? 'YES' : 'NO'", "Ok({(:$$_ternary_$$ true 'YES' 'NO')})")
|
testParseToBe(
|
||||||
|
"true ? 'YES' : 'NO'",
|
||||||
|
"Ok({(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 'YES' 'NO'))})",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Evaluate ternary operator", () => {
|
describe("Evaluate ternary operator", () => {
|
||||||
|
|
|
@ -48,7 +48,7 @@ describe("eval", () => {
|
||||||
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
||||||
testEvalError("1; x=1")
|
testEvalError("1; x=1")
|
||||||
testEvalError("1; 1")
|
testEvalError("1; 1")
|
||||||
testEvalToBe("x=1; x=1", "Ok(@{x: 1})")
|
testEvalToBe("x=1; x=1; x", "Ok(1)")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -118,28 +118,40 @@ describe("eval on distribution functions", () => {
|
||||||
|
|
||||||
describe("parse on distribution functions", () => {
|
describe("parse on distribution functions", () => {
|
||||||
describe("power", () => {
|
describe("power", () => {
|
||||||
testParse("normal(5,2) ^ normal(5,1)", "Ok({(:pow (:normal 5 2) (:normal 5 1))})")
|
testParse(
|
||||||
testParse("3 ^ normal(5,1)", "Ok({(:pow 3 (:normal 5 1))})")
|
"normal(5,2) ^ normal(5,1)",
|
||||||
testParse("normal(5,2) ^ 3", "Ok({(:pow (:normal 5 2) 3)})")
|
"Ok({(:$_endOfOuterBlock_$ () (:pow (:normal 5 2) (:normal 5 1)))})",
|
||||||
|
)
|
||||||
|
testParse("3 ^ normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:pow 3 (:normal 5 1)))})")
|
||||||
|
testParse("normal(5,2) ^ 3", "Ok({(:$_endOfOuterBlock_$ () (:pow (:normal 5 2) 3))})")
|
||||||
})
|
})
|
||||||
describe("subtraction", () => {
|
describe("subtraction", () => {
|
||||||
testParse("10 - normal(5,1)", "Ok({(:subtract 10 (:normal 5 1))})")
|
testParse("10 - normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:subtract 10 (:normal 5 1)))})")
|
||||||
testParse("normal(5,1) - 10", "Ok({(:subtract (:normal 5 1) 10)})")
|
testParse("normal(5,1) - 10", "Ok({(:$_endOfOuterBlock_$ () (:subtract (:normal 5 1) 10))})")
|
||||||
})
|
})
|
||||||
describe("pointwise arithmetic expressions", () => {
|
describe("pointwise arithmetic expressions", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
testParse(
|
testParse(
|
||||||
~skip=true,
|
~skip=true,
|
||||||
"normal(5,2) .- normal(5,1)",
|
"normal(5,2) .- normal(5,1)",
|
||||||
"Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))",
|
"Ok((:$_endOfOuterBlock_$ () (:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1)))))",
|
||||||
// TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})"
|
// 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(
|
||||||
testParse("normal(5,2) ./ normal(5,1)", "Ok({(:dotDivide (:normal 5 2) (:normal 5 1))})")
|
"normal(5,2) .* normal(5,1)",
|
||||||
testParse("normal(5,2) .^ normal(5,1)", "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})")
|
"Ok({(:$_endOfOuterBlock_$ () (:dotMultiply (:normal 5 2) (:normal 5 1)))})",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"normal(5,2) ./ normal(5,1)",
|
||||||
|
"Ok({(:$_endOfOuterBlock_$ () (:dotDivide (:normal 5 2) (:normal 5 1)))})",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"normal(5,2) .^ normal(5,1)",
|
||||||
|
"Ok({(:$_endOfOuterBlock_$ () (:dotPow (:normal 5 2) (:normal 5 1)))})",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
describe("equality", () => {
|
describe("equality", () => {
|
||||||
testParse("5 == normal(5,2)", "Ok({(:equal 5 (:normal 5 2))})")
|
testParse("5 == normal(5,2)", "Ok({(:$_endOfOuterBlock_$ () (:equal 5 (:normal 5 2)))})")
|
||||||
})
|
})
|
||||||
describe("pointwise adding two normals", () => {
|
describe("pointwise adding two normals", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
@@warning("-44")
|
||||||
|
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||||
|
module Project = ReducerProject
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module Continuation = ReducerInterface_Value_Continuation
|
||||||
|
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
open Expect.Operators
|
||||||
|
|
||||||
|
// test("", () => expect(1)->toBe(1))
|
||||||
|
|
||||||
|
let runFetchResult = (project, sourceId) => {
|
||||||
|
Project.run(project, sourceId)
|
||||||
|
Project.getExternalResult(project, sourceId)->ExternalExpressionValue.toStringOptionResult
|
||||||
|
}
|
||||||
|
|
||||||
|
let runFetchBindings = (project, sourceId) => {
|
||||||
|
Project.run(project, sourceId)
|
||||||
|
Project.getExternalBindings(project, sourceId)
|
||||||
|
->ExternalExpressionValue.EvModule
|
||||||
|
->ExternalExpressionValue.toString
|
||||||
|
}
|
||||||
|
|
||||||
|
test("setting continuation", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
let privateProject = project->Project.T.Private.castToInternalProject
|
||||||
|
let sampleBindings = Bindings.emptyBindings->Bindings.set("test", IEvVoid)
|
||||||
|
Project.Private.setContinuation(privateProject, "main", sampleBindings)
|
||||||
|
let answer = Project.Private.getContinuation(privateProject, "main")
|
||||||
|
expect(answer)->toBe(sampleBindings)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("test result true", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setSource(project, "main", "true")
|
||||||
|
runFetchResult(project, "main")->expect->toBe("Ok(true)")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("test result false", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setSource(project, "main", "false")
|
||||||
|
runFetchResult(project, "main")->expect->toBe("Ok(false)")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("test library", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setSource(project, "main", "x=Math.pi; x")
|
||||||
|
runFetchResult(project, "main")->expect->toBe("Ok(3.141592653589793)")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("test bindings", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setSource(project, "variables", "myVariable=666")
|
||||||
|
runFetchBindings(project, "variables")->expect->toBe("@{myVariable: 666}")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("project1", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setSource(project, "first", "x=1")
|
||||||
|
Project.setSource(project, "main", "x")
|
||||||
|
Project.setContinues(project, "main", ["first"])
|
||||||
|
|
||||||
|
test("runOrder", () => {
|
||||||
|
expect(Project.getRunOrder(project)) == ["first", "main"]
|
||||||
|
})
|
||||||
|
test("dependents first", () => {
|
||||||
|
expect(Project.getDependents(project, "first")) == ["main"]
|
||||||
|
})
|
||||||
|
test("dependencies first", () => {
|
||||||
|
expect(Project.getDependencies(project, "first")) == []
|
||||||
|
})
|
||||||
|
test("dependents main", () => {
|
||||||
|
expect(Project.getDependents(project, "main")) == []
|
||||||
|
})
|
||||||
|
test("dependencies main", () => {
|
||||||
|
expect(Project.getDependencies(project, "main")) == ["first"]
|
||||||
|
})
|
||||||
|
test("test result", () => {
|
||||||
|
runFetchResult(project, "main")->expect->toBe("Ok(1)")
|
||||||
|
})
|
||||||
|
test("test bindings", () => {
|
||||||
|
runFetchBindings(project, "main")->expect->toBe("@{x: 1}")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("project2", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setContinues(project, "main", ["second"])
|
||||||
|
Project.setContinues(project, "second", ["first"])
|
||||||
|
Project.setSource(project, "first", "x=1")
|
||||||
|
Project.setSource(project, "second", "y=2")
|
||||||
|
Project.setSource(project, "main", "y")
|
||||||
|
|
||||||
|
test("runOrder", () => {
|
||||||
|
expect(Project.getRunOrder(project)) == ["first", "second", "main"]
|
||||||
|
})
|
||||||
|
test("runOrderFor", () => {
|
||||||
|
expect(Project.getRunOrderFor(project, "first")) == ["first"]
|
||||||
|
})
|
||||||
|
test("dependencies first", () => {
|
||||||
|
expect(Project.getDependencies(project, "first")) == []
|
||||||
|
})
|
||||||
|
test("dependents first", () => {
|
||||||
|
expect(Project.getDependents(project, "first")) == ["second", "main"]
|
||||||
|
})
|
||||||
|
test("dependents main", () => {
|
||||||
|
expect(Project.getDependents(project, "main")) == []
|
||||||
|
})
|
||||||
|
test("dependencies main", () => {
|
||||||
|
expect(Project.getDependencies(project, "main")) == ["first", "second"]
|
||||||
|
})
|
||||||
|
test("test result", () => {
|
||||||
|
runFetchResult(project, "main")->expect->toBe("Ok(2)")
|
||||||
|
})
|
||||||
|
test("test bindings", () => {
|
||||||
|
runFetchBindings(project, "main")->expect->toBe("@{x: 1,y: 2}")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("project with include", () => {
|
||||||
|
let project = Project.createProject()
|
||||||
|
Project.setContinues(project, "main", ["second"])
|
||||||
|
Project.setContinues(project, "second", ["first"])
|
||||||
|
|
||||||
|
Project.setSource(
|
||||||
|
project,
|
||||||
|
"first",
|
||||||
|
`
|
||||||
|
#include 'common'
|
||||||
|
x=1`,
|
||||||
|
)
|
||||||
|
Project.parseIncludes(project, "first")
|
||||||
|
Project.parseIncludes(project, "first") //The only way of setting includes
|
||||||
|
//Don't forget to parse includes after changing the source
|
||||||
|
|
||||||
|
Project.setSource(project, "common", "common=0")
|
||||||
|
Project.setSource(
|
||||||
|
project,
|
||||||
|
"second",
|
||||||
|
`
|
||||||
|
#include 'common'
|
||||||
|
y=2`,
|
||||||
|
)
|
||||||
|
Project.parseIncludes(project, "second") //The only way of setting includes
|
||||||
|
|
||||||
|
Project.setSource(project, "main", "y")
|
||||||
|
|
||||||
|
test("runOrder", () => {
|
||||||
|
expect(Project.getRunOrder(project)) == ["common", "first", "second", "main"]
|
||||||
|
})
|
||||||
|
|
||||||
|
test("runOrderFor", () => {
|
||||||
|
expect(Project.getRunOrderFor(project, "first")) == ["common", "first"]
|
||||||
|
})
|
||||||
|
|
||||||
|
test("dependencies first", () => {
|
||||||
|
expect(Project.getDependencies(project, "first")) == ["common"]
|
||||||
|
})
|
||||||
|
test("dependents first", () => {
|
||||||
|
expect(Project.getDependents(project, "first")) == ["second", "main"]
|
||||||
|
})
|
||||||
|
test("dependents main", () => {
|
||||||
|
expect(Project.getDependents(project, "main")) == []
|
||||||
|
})
|
||||||
|
test("dependencies main", () => {
|
||||||
|
expect(Project.getDependencies(project, "main")) == ["common", "first", "second"]
|
||||||
|
})
|
||||||
|
test("test result", () => {
|
||||||
|
runFetchResult(project, "main")->expect->toBe("Ok(2)")
|
||||||
|
})
|
||||||
|
test("test bindings", () => {
|
||||||
|
runFetchBindings(project, "main")->expect->toBe("@{common: 0,x: 1,y: 2}")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// test bindings
|
||||||
|
//TODO: test continues
|
||||||
|
//TODO: test include
|
|
@ -2,8 +2,12 @@ open Jest
|
||||||
open Expect
|
open Expect
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
let expectEvalToBeOk = (expr: string) =>
|
let expectEvalToBeOk = (code: string) =>
|
||||||
Reducer.evaluate(expr)->Reducer_Helpers.rRemoveDefaultsExternal->E.R.isOk->expect->toBe(true)
|
Reducer_Expression.BackCompatible.evaluateStringAsExternal(code)
|
||||||
|
->Reducer_Helpers.rRemoveDefaultsExternal
|
||||||
|
->E.R.isOk
|
||||||
|
->expect
|
||||||
|
->toBe(true)
|
||||||
|
|
||||||
let registry = FunctionRegistry_Library.registry
|
let registry = FunctionRegistry_Library.registry
|
||||||
let examples = E.A.to_list(FunctionRegistry_Core.Registry.allExamples(registry))
|
let examples = E.A.to_list(FunctionRegistry_Core.Registry.allExamples(registry))
|
||||||
|
@ -88,7 +92,7 @@ describe("FunctionRegistry Library", () => {
|
||||||
((fn, example)) => {
|
((fn, example)) => {
|
||||||
let responseType =
|
let responseType =
|
||||||
example
|
example
|
||||||
->Reducer.evaluate
|
->Reducer_Expression.BackCompatible.evaluateStringAsExternal
|
||||||
->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType)
|
->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType)
|
||||||
let expectedOutputType = fn.output |> E.O.toExn("")
|
let expectedOutputType = fn.output |> E.O.toExn("")
|
||||||
expect(responseType)->toEqual(Ok(expectedOutputType))
|
expect(responseType)->toEqual(Ok(expectedOutputType))
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
type internalExpressionValue = ReducerInterface_InternalExpressionValue.t
|
type internalExpressionValue = ReducerInterface_InternalExpressionValue.t
|
||||||
type internalExpressionValueType = ReducerInterface_InternalExpressionValue.internalExpressionValueType
|
type internalExpressionValueType = ReducerInterface_InternalExpressionValue.internalExpressionValueType
|
||||||
|
|
||||||
|
@ -46,8 +48,8 @@ type fnDefinition = {
|
||||||
run: (
|
run: (
|
||||||
array<internalExpressionValue>,
|
array<internalExpressionValue>,
|
||||||
array<frValue>,
|
array<frValue>,
|
||||||
GenericDist.env,
|
ProjectAccessorsT.t,
|
||||||
Reducer_Expression_T.reducerFn,
|
ProjectReducerFnT.t,
|
||||||
) => result<internalExpressionValue, string>,
|
) => result<internalExpressionValue, string>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,12 +384,12 @@ module FnDefinition = {
|
||||||
let run = (
|
let run = (
|
||||||
t: t,
|
t: t,
|
||||||
args: array<internalExpressionValue>,
|
args: array<internalExpressionValue>,
|
||||||
env: GenericDist.env,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: Reducer_Expression_T.reducerFn,
|
reducer: ProjectReducerFnT.t,
|
||||||
) => {
|
) => {
|
||||||
let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
|
let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
|
||||||
switch argValues {
|
switch argValues {
|
||||||
| Some(values) => t.run(args, values, env, reducer)
|
| Some(values) => t.run(args, values, accessors, reducer)
|
||||||
| None => Error("Incorrect Types")
|
| None => Error("Incorrect Types")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,8 +495,8 @@ module Registry = {
|
||||||
~registry: registry,
|
~registry: registry,
|
||||||
~fnName: string,
|
~fnName: string,
|
||||||
~args: array<internalExpressionValue>,
|
~args: array<internalExpressionValue>,
|
||||||
~env: GenericDist.env,
|
~accessors: ProjectAccessorsT.t,
|
||||||
~reducer: Reducer_Expression_T.reducerFn,
|
~reducer: ProjectReducerFnT.t,
|
||||||
) => {
|
) => {
|
||||||
let relevantFunctions = Js.Dict.get(registry.fnNameDict, fnName) |> E.O.default([])
|
let relevantFunctions = Js.Dict.get(registry.fnNameDict, fnName) |> E.O.default([])
|
||||||
let modified = {functions: relevantFunctions, fnNameDict: registry.fnNameDict}
|
let modified = {functions: relevantFunctions, fnNameDict: registry.fnNameDict}
|
||||||
|
@ -512,7 +514,7 @@ module Registry = {
|
||||||
|
|
||||||
switch Matcher.Registry.findMatches(modified, fnName, args) {
|
switch Matcher.Registry.findMatches(modified, fnName, args) {
|
||||||
| Matcher.Match.FullMatch(match) =>
|
| Matcher.Match.FullMatch(match) =>
|
||||||
match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, env, reducer))
|
match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, accessors, reducer))
|
||||||
| SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m)))
|
| SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m)))
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
|
@ -521,10 +523,10 @@ module Registry = {
|
||||||
let dispatch = (
|
let dispatch = (
|
||||||
registry,
|
registry,
|
||||||
(fnName, args): ReducerInterface_InternalExpressionValue.functionCall,
|
(fnName, args): ReducerInterface_InternalExpressionValue.functionCall,
|
||||||
env,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: Reducer_Expression_T.reducerFn,
|
reducer: ProjectReducerFnT.t,
|
||||||
) => {
|
) => {
|
||||||
_matchAndRun(~registry, ~fnName, ~args, ~env, ~reducer)->E.O2.fmap(
|
_matchAndRun(~registry, ~fnName, ~args, ~accessors, ~reducer)->E.O2.fmap(
|
||||||
E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)),
|
E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber],
|
~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber],
|
||||||
~run=(_, inputs, env, _) =>
|
~run=(_, inputs, accessors, _) =>
|
||||||
inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env),
|
inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env=accessors.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
|
~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
|
||||||
~run=(_, inputs, env, _) =>
|
~run=(_, inputs, accessors, _) =>
|
||||||
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env),
|
inputs
|
||||||
|
->Prepare.ToValueTuple.Record.twoDistOrNumber
|
||||||
|
->process(~fn, ~env=accessors.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -41,8 +43,10 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
|
~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
|
||||||
~run=(_, inputs, env, _) =>
|
~run=(_, inputs, accessors, _) =>
|
||||||
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env),
|
inputs
|
||||||
|
->Prepare.ToValueTuple.Record.twoDistOrNumber
|
||||||
|
->process(~fn, ~env=accessors.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -58,8 +62,8 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeDistOrNumber],
|
~inputs=[FRTypeDistOrNumber],
|
||||||
~run=(_, inputs, env, _) =>
|
~run=(_, inputs, accessors, _) =>
|
||||||
inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env),
|
inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env=accessors.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
// module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
|
|
||||||
open FunctionRegistry_Core
|
open FunctionRegistry_Core
|
||||||
open FunctionRegistry_Helpers
|
open FunctionRegistry_Helpers
|
||||||
|
|
||||||
|
@ -24,17 +27,19 @@ module Internals = {
|
||||||
Belt.Array.reverse(array),
|
Belt.Array.reverse(array),
|
||||||
)
|
)
|
||||||
|
|
||||||
let map = (array: array<internalExpressionValue>, environment, eLambdaValue, reducer): result<
|
let map = (
|
||||||
ReducerInterface_InternalExpressionValue.t,
|
array: array<internalExpressionValue>,
|
||||||
Reducer_ErrorValue.errorValue,
|
accessors: ProjectAccessorsT.t,
|
||||||
> => {
|
eLambdaValue,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
): result<ReducerInterface_InternalExpressionValue.t, Reducer_ErrorValue.errorValue> => {
|
||||||
let rMappedList = array->E.A.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
let rMappedList = array->E.A.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
||||||
rAcc->E.R.bind(_, acc => {
|
rAcc->E.R.bind(_, acc => {
|
||||||
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
||||||
eLambdaValue,
|
eLambdaValue,
|
||||||
list{elem},
|
list{elem},
|
||||||
environment,
|
(accessors: ProjectAccessorsT.t),
|
||||||
reducer,
|
(reducer: ProjectReducerFnT.t),
|
||||||
)
|
)
|
||||||
rNewElem->E.R2.fmap(newElem => list{newElem, ...acc})
|
rNewElem->E.R2.fmap(newElem => list{newElem, ...acc})
|
||||||
})
|
})
|
||||||
|
@ -42,29 +47,46 @@ module Internals = {
|
||||||
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
|
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
let reduce = (aValueArray, initialValue, aLambdaValue, environment, reducer) => {
|
let reduce = (
|
||||||
|
aValueArray,
|
||||||
|
initialValue,
|
||||||
|
aLambdaValue,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
) => {
|
||||||
aValueArray->E.A.reduce(Ok(initialValue), (rAcc, elem) =>
|
aValueArray->E.A.reduce(Ok(initialValue), (rAcc, elem) =>
|
||||||
rAcc->E.R.bind(_, acc =>
|
rAcc->E.R.bind(_, acc =>
|
||||||
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer)
|
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let reduceReverse = (aValueArray, initialValue, aLambdaValue, environment, reducer) => {
|
let reduceReverse = (
|
||||||
|
aValueArray,
|
||||||
|
initialValue,
|
||||||
|
aLambdaValue,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
) => {
|
||||||
aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) =>
|
aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) =>
|
||||||
rAcc->Belt.Result.flatMap(acc =>
|
rAcc->Belt.Result.flatMap(acc =>
|
||||||
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer)
|
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter = (aValueArray, aLambdaValue, environment, reducer) => {
|
let filter = (
|
||||||
|
aValueArray,
|
||||||
|
aLambdaValue,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
) => {
|
||||||
let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
||||||
rAcc->E.R.bind(_, acc => {
|
rAcc->E.R.bind(_, acc => {
|
||||||
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
list{elem},
|
list{elem},
|
||||||
environment,
|
accessors,
|
||||||
reducer,
|
reducer,
|
||||||
)
|
)
|
||||||
rNewElem->E.R2.fmap(newElem => {
|
rNewElem->E.R2.fmap(newElem => {
|
||||||
|
@ -189,10 +211,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="map",
|
~name="map",
|
||||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
|
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), IEvLambda(lambda)] =>
|
| [IEvArray(array), IEvLambda(lambda)] =>
|
||||||
Internals.map(array, env, lambda, reducer)->E.R2.errMap(_ => "Error!")
|
Internals.map(array, accessors, lambda, reducer)->E.R2.errMap(_ => "Error!")
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -209,10 +231,12 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="reduce",
|
~name="reduce",
|
||||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
|
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
||||||
Internals.reduce(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ => "Error!")
|
Internals.reduce(array, initialValue, lambda, accessors, reducer)->E.R2.errMap(_ =>
|
||||||
|
"Error!"
|
||||||
|
)
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -229,12 +253,16 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="reduceReverse",
|
~name="reduceReverse",
|
||||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
|
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
||||||
Internals.reduceReverse(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ =>
|
Internals.reduceReverse(
|
||||||
"Error!"
|
array,
|
||||||
)
|
initialValue,
|
||||||
|
lambda,
|
||||||
|
accessors,
|
||||||
|
reducer,
|
||||||
|
)->E.R2.errMap(_ => "Error!")
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -251,10 +279,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="filter",
|
~name="filter",
|
||||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
|
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), IEvLambda(lambda)] =>
|
| [IEvArray(array), IEvLambda(lambda)] =>
|
||||||
Internals.filter(array, lambda, env, reducer)->E.R2.errMap(_ => "Error!")
|
Internals.filter(array, lambda, accessors, reducer)->E.R2.errMap(_ => "Error!")
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
|
|
@ -34,13 +34,13 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="fromDist",
|
~name="fromDist",
|
||||||
~inputs=[FRTypeDist],
|
~inputs=[FRTypeDist],
|
||||||
~run=(_, inputs, env, _) =>
|
~run=(_, inputs, accessors, _) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [FRValueDist(dist)] =>
|
| [FRValueDist(dist)] =>
|
||||||
GenericDist.toPointSet(
|
GenericDist.toPointSet(
|
||||||
dist,
|
dist,
|
||||||
~xyPointLength=env.xyPointLength,
|
~xyPointLength=accessors.environment.xyPointLength,
|
||||||
~sampleCount=env.sampleCount,
|
~sampleCount=accessors.environment.sampleCount,
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
->E.R2.fmap(Wrappers.pointSet)
|
->E.R2.fmap(Wrappers.pointSet)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
// module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
open FunctionRegistry_Core
|
open FunctionRegistry_Core
|
||||||
open FunctionRegistry_Helpers
|
open FunctionRegistry_Helpers
|
||||||
|
|
||||||
|
@ -6,8 +8,14 @@ let requiresNamespace = true
|
||||||
|
|
||||||
module Internal = {
|
module Internal = {
|
||||||
type t = SampleSetDist.t
|
type t = SampleSetDist.t
|
||||||
let doLambdaCall = (aLambdaValue, list, environment, reducer) =>
|
|
||||||
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
|
let doLambdaCall = (
|
||||||
|
aLambdaValue,
|
||||||
|
list,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
) =>
|
||||||
|
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
||||||
| Ok(IEvNumber(f)) => Ok(f)
|
| Ok(IEvNumber(f)) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
@ -22,29 +30,26 @@ module Internal = {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: I don't know why this seems to need at least one input
|
//TODO: I don't know why this seems to need at least one input
|
||||||
let fromFn = (
|
let fromFn = (aLambdaValue, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) => {
|
||||||
aLambdaValue,
|
let sampleCount = accessors.environment.sampleCount
|
||||||
env: ReducerInterface_InternalExpressionValue.environment,
|
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, accessors, reducer)
|
||||||
reducer,
|
|
||||||
) => {
|
|
||||||
let sampleCount = env.sampleCount
|
|
||||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
|
|
||||||
Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen
|
Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
let map1 = (sampleSetDist: t, aLambdaValue, env, reducer) => {
|
let map1 = (sampleSetDist: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => {
|
||||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
|
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, accessors, reducer)
|
||||||
SampleSetDist.samplesMap(~fn, sampleSetDist)->toType
|
SampleSetDist.samplesMap(~fn, sampleSetDist)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
let map2 = (t1: t, t2: t, aLambdaValue, env, reducer) => {
|
let map2 = (t1: t, t2: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => {
|
||||||
let fn = (a, b) => doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, env, reducer)
|
let fn = (a, b) =>
|
||||||
|
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, accessors, reducer)
|
||||||
SampleSetDist.map2(~fn, ~t1, ~t2)->toType
|
SampleSetDist.map2(~fn, ~t1, ~t2)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
let map3 = (t1: t, t2: t, t3: t, aLambdaValue, env, reducer) => {
|
let map3 = (t1: t, t2: t, t3: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => {
|
||||||
let fn = (a, b, c) =>
|
let fn = (a, b, c) =>
|
||||||
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)}, env, reducer)
|
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)}, accessors, reducer)
|
||||||
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
|
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,14 +64,19 @@ module Internal = {
|
||||||
E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr))
|
E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapN = (aValueArray: array<internalExpressionValue>, aLambdaValue, env, reducer) => {
|
let mapN = (
|
||||||
|
aValueArray: array<internalExpressionValue>,
|
||||||
|
aLambdaValue,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer,
|
||||||
|
) => {
|
||||||
switch parseSampleSetArray(aValueArray) {
|
switch parseSampleSetArray(aValueArray) {
|
||||||
| Some(t1) =>
|
| Some(t1) =>
|
||||||
let fn = a =>
|
let fn = a =>
|
||||||
doLambdaCall(
|
doLambdaCall(
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
list{IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))},
|
list{IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))},
|
||||||
env,
|
accessors,
|
||||||
reducer,
|
reducer,
|
||||||
)
|
)
|
||||||
SampleSetDist.mapN(~fn, ~t1)->toType
|
SampleSetDist.mapN(~fn, ~t1)->toType
|
||||||
|
@ -86,10 +96,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="fromDist",
|
~name="fromDist",
|
||||||
~inputs=[FRTypeDist],
|
~inputs=[FRTypeDist],
|
||||||
~run=(_, inputs, env, _) =>
|
~run=(_, inputs, accessors: ProjectAccessorsT.t, _) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [FRValueDist(dist)] =>
|
| [FRValueDist(dist)] =>
|
||||||
GenericDist.toSampleSetDist(dist, env.sampleCount)
|
GenericDist.toSampleSetDist(dist, accessors.environment.sampleCount)
|
||||||
->E.R2.fmap(Wrappers.sampleSet)
|
->E.R2.fmap(Wrappers.sampleSet)
|
||||||
->E.R2.fmap(Wrappers.evDistribution)
|
->E.R2.fmap(Wrappers.evDistribution)
|
||||||
->E.R2.errMap(_ => "")
|
->E.R2.errMap(_ => "")
|
||||||
|
@ -153,10 +163,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="fromFn",
|
~name="fromFn",
|
||||||
~inputs=[FRTypeLambda],
|
~inputs=[FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvLambda(lambda)] =>
|
| [IEvLambda(lambda)] =>
|
||||||
switch Internal.fromFn(lambda, env, reducer) {
|
switch Internal.fromFn(lambda, accessors, reducer) {
|
||||||
| Ok(r) => Ok(r->Wrappers.sampleSet->Wrappers.evDistribution)
|
| Ok(r) => Ok(r->Wrappers.sampleSet->Wrappers.evDistribution)
|
||||||
| Error(_) => Error("issue")
|
| Error(_) => Error("issue")
|
||||||
}
|
}
|
||||||
|
@ -177,10 +187,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="map",
|
~name="map",
|
||||||
~inputs=[FRTypeDist, FRTypeLambda],
|
~inputs=[FRTypeDist, FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvDistribution(SampleSet(dist)), IEvLambda(lambda)] =>
|
| [IEvDistribution(SampleSet(dist)), IEvLambda(lambda)] =>
|
||||||
Internal.map1(dist, lambda, env, reducer)->E.R2.errMap(_ => "")
|
Internal.map1(dist, lambda, accessors, reducer)->E.R2.errMap(_ => "")
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -200,14 +210,14 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="map2",
|
~name="map2",
|
||||||
~inputs=[FRTypeDist, FRTypeDist, FRTypeLambda],
|
~inputs=[FRTypeDist, FRTypeDist, FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) => {
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => {
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [
|
| [
|
||||||
IEvDistribution(SampleSet(dist1)),
|
IEvDistribution(SampleSet(dist1)),
|
||||||
IEvDistribution(SampleSet(dist2)),
|
IEvDistribution(SampleSet(dist2)),
|
||||||
IEvLambda(lambda),
|
IEvLambda(lambda),
|
||||||
] =>
|
] =>
|
||||||
Internal.map2(dist1, dist2, lambda, env, reducer)->E.R2.errMap(_ => "")
|
Internal.map2(dist1, dist2, lambda, accessors, reducer)->E.R2.errMap(_ => "")
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -228,7 +238,7 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="map3",
|
~name="map3",
|
||||||
~inputs=[FRTypeDist, FRTypeDist, FRTypeDist, FRTypeLambda],
|
~inputs=[FRTypeDist, FRTypeDist, FRTypeDist, FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [
|
| [
|
||||||
IEvDistribution(SampleSet(dist1)),
|
IEvDistribution(SampleSet(dist1)),
|
||||||
|
@ -236,7 +246,7 @@ let library = [
|
||||||
IEvDistribution(SampleSet(dist3)),
|
IEvDistribution(SampleSet(dist3)),
|
||||||
IEvLambda(lambda),
|
IEvLambda(lambda),
|
||||||
] =>
|
] =>
|
||||||
Internal.map3(dist1, dist2, dist3, lambda, env, reducer)->E.R2.errMap(_ => "")
|
Internal.map3(dist1, dist2, dist3, lambda, accessors, reducer)->E.R2.errMap(_ => "")
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -256,10 +266,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="mapN",
|
~name="mapN",
|
||||||
~inputs=[FRTypeArray(FRTypeDist), FRTypeLambda],
|
~inputs=[FRTypeArray(FRTypeDist), FRTypeLambda],
|
||||||
~run=(inputs, _, env, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(dists), IEvLambda(lambda)] =>
|
| [IEvArray(dists), IEvLambda(lambda)] =>
|
||||||
Internal.mapN(dists, lambda, env, reducer)->E.R2.errMap(_e => {
|
Internal.mapN(dists, lambda, accessors, reducer)->E.R2.errMap(_e => {
|
||||||
"AHHH doesn't work"
|
"AHHH doesn't work"
|
||||||
})
|
})
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
|
|
|
@ -30,16 +30,16 @@ let library = [
|
||||||
("prior", FRTypeDist),
|
("prior", FRTypeDist),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
~run=(_, inputs, env, _) => {
|
~run=(_, inputs, accessors, _) => {
|
||||||
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) {
|
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) {
|
||||||
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) =>
|
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) =>
|
||||||
runScoring(estimate, Score_Dist(d), Some(prior), env)
|
runScoring(estimate, Score_Dist(d), Some(prior), accessors.environment)
|
||||||
| Ok([
|
| Ok([
|
||||||
FRValueDist(estimate),
|
FRValueDist(estimate),
|
||||||
FRValueDistOrNumber(FRValueNumber(d)),
|
FRValueDistOrNumber(FRValueNumber(d)),
|
||||||
FRValueDist(prior),
|
FRValueDist(prior),
|
||||||
]) =>
|
]) =>
|
||||||
runScoring(estimate, Score_Scalar(d), Some(prior), env)
|
runScoring(estimate, Score_Scalar(d), Some(prior), accessors.environment)
|
||||||
| Error(e) => Error(e)
|
| Error(e) => Error(e)
|
||||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||||
}
|
}
|
||||||
|
@ -49,12 +49,12 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="logScore",
|
~name="logScore",
|
||||||
~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])],
|
~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])],
|
||||||
~run=(_, inputs, env, _) => {
|
~run=(_, inputs, accessors, _) => {
|
||||||
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) {
|
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) {
|
||||||
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) =>
|
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) =>
|
||||||
runScoring(estimate, Score_Dist(d), None, env)
|
runScoring(estimate, Score_Dist(d), None, accessors.environment)
|
||||||
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) =>
|
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) =>
|
||||||
runScoring(estimate, Score_Scalar(d), None, env)
|
runScoring(estimate, Score_Scalar(d), None, accessors.environment)
|
||||||
| Error(e) => Error(e)
|
| Error(e) => Error(e)
|
||||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="klDivergence",
|
~name="klDivergence",
|
||||||
~inputs=[FRTypeDist, FRTypeDist],
|
~inputs=[FRTypeDist, FRTypeDist],
|
||||||
~run=(_, inputs, env, _) => {
|
~run=(_, inputs, accessors, _) => {
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [FRValueDist(estimate), FRValueDist(d)] =>
|
| [FRValueDist(estimate), FRValueDist(d)] =>
|
||||||
runScoring(estimate, Score_Dist(d), None, env)
|
runScoring(estimate, Score_Dist(d), None, accessors.environment)
|
||||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module Expression = Reducer_Expression
|
module Expression = Reducer_Expression
|
||||||
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|
||||||
module Lambda = Reducer_Expression_Lambda
|
|
||||||
|
|
||||||
type environment = ReducerInterface_InternalExpressionValue.environment
|
type environment = ReducerInterface_InternalExpressionValue.environment
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
@ -10,26 +8,10 @@ type expressionValue = ExternalExpressionValue.t
|
||||||
type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings
|
type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings
|
||||||
type lambdaValue = ExternalExpressionValue.lambdaValue
|
type lambdaValue = ExternalExpressionValue.lambdaValue
|
||||||
|
|
||||||
let evaluate = Expression.evaluate
|
/*
|
||||||
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
Use Reducer_Project instead
|
||||||
let evaluatePartialUsingExternalBindings = Expression.evaluatePartialUsingExternalBindings
|
*/
|
||||||
let parse = Expression.parse
|
|
||||||
|
|
||||||
let foreignFunctionInterface = (
|
|
||||||
lambdaValue: ExternalExpressionValue.lambdaValue,
|
|
||||||
argArray: array<expressionValue>,
|
|
||||||
environment: ExternalExpressionValue.environment,
|
|
||||||
) => {
|
|
||||||
let internallambdaValue = InternalExpressionValue.lambdaValueToInternal(lambdaValue)
|
|
||||||
let internalArgArray = argArray->Js.Array2.map(InternalExpressionValue.toInternal)
|
|
||||||
Lambda.foreignFunctionInterface(
|
|
||||||
internallambdaValue,
|
|
||||||
internalArgArray,
|
|
||||||
environment,
|
|
||||||
Expression.reduceExpression,
|
|
||||||
)->Belt.Result.map(InternalExpressionValue.toExternal)
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultEnvironment = ExternalExpressionValue.defaultEnvironment
|
let defaultEnvironment = ExternalExpressionValue.defaultEnvironment
|
||||||
|
|
||||||
let defaultExternalBindings = ReducerInterface_StdLib.externalStdLib
|
// let defaultExternalBindings = ReducerInterface_StdLib.externalStdLib
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module Expression = Reducer_Expression
|
module Expression = Reducer_Expression
|
||||||
|
|
||||||
@genType
|
@genType0
|
||||||
type environment = ReducerInterface_ExternalExpressionValue.environment
|
type environment = ReducerInterface_ExternalExpressionValue.environment
|
||||||
@genType
|
@genType
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
@ -12,34 +12,34 @@ type externalBindings = ReducerInterface_ExternalExpressionValue.externalBinding
|
||||||
@genType
|
@genType
|
||||||
type lambdaValue = ReducerInterface_ExternalExpressionValue.lambdaValue
|
type lambdaValue = ReducerInterface_ExternalExpressionValue.lambdaValue
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let evaluateUsingOptions: (
|
// let evaluateUsingOptions: (
|
||||||
~environment: option<QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment>,
|
// ~environment: option<QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment>,
|
||||||
~externalBindings: option<
|
// ~externalBindings: option<
|
||||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings,
|
// QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings,
|
||||||
>,
|
// >,
|
||||||
string,
|
// string,
|
||||||
) => result<expressionValue, errorValue>
|
// ) => result<expressionValue, errorValue>
|
||||||
@genType
|
// @genType
|
||||||
let evaluatePartialUsingExternalBindings: (
|
// let evaluatePartialUsingExternalBindings: (
|
||||||
string,
|
// string,
|
||||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings,
|
// QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings,
|
||||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment,
|
// QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment,
|
||||||
) => result<externalBindings, errorValue>
|
// ) => result<externalBindings, errorValue>
|
||||||
@genType
|
// @genType
|
||||||
let evaluate: string => result<expressionValue, errorValue>
|
// let evaluate: string => result<expressionValue, errorValue>
|
||||||
|
|
||||||
let parse: string => result<Expression.expression, errorValue>
|
// let parse: string => result<Expression.t, errorValue>
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let foreignFunctionInterface: (
|
// let foreignFunctionInterface: (
|
||||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.lambdaValue,
|
// QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.lambdaValue,
|
||||||
array<QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.t>,
|
// array<QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.t>,
|
||||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment,
|
// QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment,
|
||||||
) => result<expressionValue, errorValue>
|
// ) => result<expressionValue, errorValue>
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let defaultEnvironment: environment
|
let defaultEnvironment: environment
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let defaultExternalBindings: externalBindings
|
// let defaultExternalBindings: externalBindings
|
||||||
|
|
|
@ -74,6 +74,7 @@ let set = (nameSpace: t, id: string, value): t => {
|
||||||
|
|
||||||
let emptyModule: t = NameSpace(emptyMap)
|
let emptyModule: t = NameSpace(emptyMap)
|
||||||
let emptyBindings = emptyModule
|
let emptyBindings = emptyModule
|
||||||
|
let emptyNameSpace = emptyModule
|
||||||
|
|
||||||
let fromTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceFromTypeScriptBindings
|
let fromTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceFromTypeScriptBindings
|
||||||
let toTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceToTypeScriptBindings
|
let toTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceToTypeScriptBindings
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
|
module Continuation = ReducerInterface_Value_Continuation
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
||||||
module Lambda = Reducer_Expression_Lambda
|
module Lambda = Reducer_Expression_Lambda
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
module Bindings = Reducer_Bindings
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
module TypeBuilder = Reducer_Type_TypeBuilder
|
module TypeBuilder = Reducer_Type_TypeBuilder
|
||||||
|
|
||||||
open ReducerInterface_InternalExpressionValue
|
open ReducerInterface_InternalExpressionValue
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
|
@ -19,10 +23,11 @@ open Reducer_ErrorValue
|
||||||
|
|
||||||
exception TestRescriptException
|
exception TestRescriptException
|
||||||
|
|
||||||
let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result<
|
let callInternal = (
|
||||||
'b,
|
call: functionCall,
|
||||||
errorValue,
|
accessors: ProjectAccessorsT.t,
|
||||||
> => {
|
reducer: ProjectReducerFnT.t,
|
||||||
|
): result<'b, errorValue> => {
|
||||||
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
||||||
switch call {
|
switch call {
|
||||||
| ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
|
| ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
|
||||||
|
@ -95,9 +100,17 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
|
|
||||||
let doExportBindings = (bindings: nameSpace) => bindings->Bindings.toExpressionValue->Ok
|
let doExportBindings = (bindings: nameSpace) => bindings->Bindings.toExpressionValue->Ok
|
||||||
|
|
||||||
|
let doIdentity = (value: internalExpressionValue) => value->Ok
|
||||||
|
|
||||||
|
let doDumpBindings = (continuation: nameSpace, value: internalExpressionValue) => {
|
||||||
|
// let _ = Continuation.inspect(continuation, "doDumpBindings")
|
||||||
|
accessors.continuation = continuation
|
||||||
|
value->Ok
|
||||||
|
}
|
||||||
|
|
||||||
module SampleMap = {
|
module SampleMap = {
|
||||||
let doLambdaCall = (aLambdaValue, list) =>
|
let doLambdaCall = (aLambdaValue, list) =>
|
||||||
switch Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
|
switch Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
||||||
| Ok(IEvNumber(f)) => Ok(f)
|
| Ok(IEvNumber(f)) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
@ -137,12 +150,14 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
| ("$_constructArray_$", [IEvArray(aValueArray)]) => IEvArray(aValueArray)->Ok
|
| ("$_constructArray_$", [IEvArray(aValueArray)]) => IEvArray(aValueArray)->Ok
|
||||||
| ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
| ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
||||||
| ("$_exportBindings_$", [IEvBindings(nameSpace)]) => doExportBindings(nameSpace)
|
| ("$_exportBindings_$", [IEvBindings(nameSpace)]) => doExportBindings(nameSpace)
|
||||||
|
| ("$_exportBindings_$", [evValue]) => doIdentity(evValue)
|
||||||
| ("$_setBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) =>
|
| ("$_setBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) =>
|
||||||
doSetBindings(nameSpace, symbol, value)
|
doSetBindings(nameSpace, symbol, value)
|
||||||
| ("$_setTypeAliasBindings_$", [IEvBindings(nameSpace), IEvTypeIdentifier(symbol), value]) =>
|
| ("$_setTypeAliasBindings_$", [IEvBindings(nameSpace), IEvTypeIdentifier(symbol), value]) =>
|
||||||
doSetTypeAliasBindings(nameSpace, symbol, value)
|
doSetTypeAliasBindings(nameSpace, symbol, value)
|
||||||
| ("$_setTypeOfBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) =>
|
| ("$_setTypeOfBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) =>
|
||||||
doSetTypeOfBindings(nameSpace, symbol, value)
|
doSetTypeOfBindings(nameSpace, symbol, value)
|
||||||
|
| ("$_dumpBindings_$", [IEvBindings(nameSpace), _, evValue]) => doDumpBindings(nameSpace, evValue)
|
||||||
| ("$_typeModifier_memberOf_$", [IEvTypeIdentifier(typeIdentifier), IEvArray(arr)]) =>
|
| ("$_typeModifier_memberOf_$", [IEvTypeIdentifier(typeIdentifier), IEvArray(arr)]) =>
|
||||||
TypeBuilder.typeModifier_memberOf(IEvTypeIdentifier(typeIdentifier), IEvArray(arr))
|
TypeBuilder.typeModifier_memberOf(IEvTypeIdentifier(typeIdentifier), IEvArray(arr))
|
||||||
| ("$_typeModifier_memberOf_$", [IEvType(typeRecord), IEvArray(arr)]) =>
|
| ("$_typeModifier_memberOf_$", [IEvType(typeRecord), IEvArray(arr)]) =>
|
||||||
|
@ -182,15 +197,16 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
/*
|
/*
|
||||||
Reducer uses Result monad while reducing expressions
|
Reducer uses Result monad while reducing expressions
|
||||||
*/
|
*/
|
||||||
let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result<
|
let dispatch = (
|
||||||
internalExpressionValue,
|
call: functionCall,
|
||||||
errorValue,
|
accessors: ProjectAccessorsT.t,
|
||||||
> =>
|
reducer: ProjectReducerFnT.t,
|
||||||
|
): result<internalExpressionValue, errorValue> =>
|
||||||
try {
|
try {
|
||||||
let (fn, args) = call
|
let (fn, args) = call
|
||||||
// There is a bug that prevents string match in patterns
|
// There is a bug that prevents string match in patterns
|
||||||
// So we have to recreate a copy of the string
|
// So we have to recreate a copy of the string
|
||||||
ExternalLibrary.dispatch((Js.String.make(fn), args), environment, reducer, callInternal)
|
ExternalLibrary.dispatch((Js.String.make(fn), args), accessors, reducer, callInternal)
|
||||||
} catch {
|
} catch {
|
||||||
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
||||||
| _ => RETodo("unhandled rescript exception")->Error
|
| _ => RETodo("unhandled rescript exception")->Error
|
||||||
|
|
|
@ -3,17 +3,19 @@
|
||||||
they take expressions as parameters and return a new expression.
|
they take expressions as parameters and return a new expression.
|
||||||
Macros are used to define language building blocks. They are like Lisp macros.
|
Macros are used to define language building blocks. They are like Lisp macros.
|
||||||
*/
|
*/
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|
||||||
module ExpressionWithContext = Reducer_ExpressionWithContext
|
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
module Bindings = Reducer_Bindings
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
|
||||||
open Reducer_Expression_ExpressionBuilder
|
open Reducer_Expression_ExpressionBuilder
|
||||||
|
|
||||||
type environment = InternalExpressionValue.environment
|
|
||||||
type errorValue = ErrorValue.errorValue
|
type errorValue = ErrorValue.errorValue
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
|
@ -21,11 +23,11 @@ type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
let dispatchMacroCall = (
|
let dispatchMacroCall = (
|
||||||
macroExpression: expression,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reduceExpression: ExpressionT.reducerFn,
|
reduceExpression: ProjectReducerFnT.t,
|
||||||
): result<expressionWithContext, errorValue> => {
|
): result<expressionWithContext, errorValue> => {
|
||||||
let useExpressionToSetBindings = (bindingExpr: expression, environment, statement, newCode) => {
|
let useExpressionToSetBindings = (bindingExpr: expression, accessors, statement, newCode) => {
|
||||||
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, accessors)
|
||||||
|
|
||||||
rExternalBindingsValue->Result.flatMap(nameSpaceValue => {
|
rExternalBindingsValue->Result.flatMap(nameSpaceValue => {
|
||||||
let newBindings = Bindings.fromExpressionValue(nameSpaceValue)
|
let newBindings = Bindings.fromExpressionValue(nameSpaceValue)
|
||||||
|
@ -45,16 +47,17 @@ let dispatchMacroCall = (
|
||||||
| "$_let_$" => "$_setBindings_$"
|
| "$_let_$" => "$_setBindings_$"
|
||||||
| "$_typeOf_$" => "$_setTypeOfBindings_$"
|
| "$_typeOf_$" => "$_setTypeOfBindings_$"
|
||||||
| "$_typeAlias_$" => "$_setTypeAliasBindings_$"
|
| "$_typeAlias_$" => "$_setTypeAliasBindings_$"
|
||||||
|
| "$_endOfOuterBlock_$" => "$_dumpBindings_$"
|
||||||
| _ => ""
|
| _ => ""
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBindStatement = (bindingExpr: expression, statement: expression, environment) => {
|
let doBindStatement = (bindingExpr: expression, statement: expression, accessors) => {
|
||||||
let defaultStatement = ErrorValue.REAssignmentExpected->Error
|
let defaultStatement = ErrorValue.REAssignmentExpected->Error
|
||||||
switch statement {
|
switch statement {
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
||||||
let setBindingsFn = correspondingSetBindingsFn(callName)
|
let setBindingsFn = correspondingSetBindingsFn(callName)
|
||||||
if setBindingsFn !== "" {
|
if setBindingsFn !== "" {
|
||||||
useExpressionToSetBindings(bindingExpr, environment, statement, (
|
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||||
newBindingsExpr,
|
newBindingsExpr,
|
||||||
boundStatement,
|
boundStatement,
|
||||||
) => eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement}))
|
) => eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement}))
|
||||||
|
@ -66,12 +69,12 @@ let dispatchMacroCall = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBindExpression = (bindingExpr: expression, statement: expression, environment): result<
|
let doBindExpression = (bindingExpr: expression, statement: expression, accessors): result<
|
||||||
expressionWithContext,
|
expressionWithContext,
|
||||||
errorValue,
|
errorValue,
|
||||||
> => {
|
> => {
|
||||||
let defaultStatement = () =>
|
let defaultStatement = () =>
|
||||||
useExpressionToSetBindings(bindingExpr, environment, statement, (
|
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||||
_newBindingsExpr,
|
_newBindingsExpr,
|
||||||
boundStatement,
|
boundStatement,
|
||||||
) => boundStatement)
|
) => boundStatement)
|
||||||
|
@ -80,13 +83,13 @@ let dispatchMacroCall = (
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
||||||
let setBindingsFn = correspondingSetBindingsFn(callName)
|
let setBindingsFn = correspondingSetBindingsFn(callName)
|
||||||
if setBindingsFn !== "" {
|
if setBindingsFn !== "" {
|
||||||
useExpressionToSetBindings(bindingExpr, environment, statement, (
|
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||||
newBindingsExpr,
|
newBindingsExpr,
|
||||||
boundStatement,
|
boundStatement,
|
||||||
) =>
|
) =>
|
||||||
eFunction(
|
eFunction(
|
||||||
"$_exportBindings_$",
|
"$_exportBindings_$",
|
||||||
list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})},
|
list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})}, // expression returning bindings
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,7 +100,7 @@ let dispatchMacroCall = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _environment): result<
|
let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _accessors): result<
|
||||||
expressionWithContext,
|
expressionWithContext,
|
||||||
errorValue,
|
errorValue,
|
||||||
> => {
|
> => {
|
||||||
|
@ -130,10 +133,10 @@ let dispatchMacroCall = (
|
||||||
ifTrue: expression,
|
ifTrue: expression,
|
||||||
ifFalse: expression,
|
ifFalse: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
environment,
|
accessors,
|
||||||
): result<expressionWithContext, errorValue> => {
|
): result<expressionWithContext, errorValue> => {
|
||||||
let blockCondition = ExpressionBuilder.eBlock(list{condition})
|
let blockCondition = ExpressionBuilder.eBlock(list{condition})
|
||||||
let rCondition = reduceExpression(blockCondition, bindings, environment)
|
let rCondition = reduceExpression(blockCondition, bindings, accessors)
|
||||||
rCondition->Result.flatMap(conditionValue =>
|
rCondition->Result.flatMap(conditionValue =>
|
||||||
switch conditionValue {
|
switch conditionValue {
|
||||||
| InternalExpressionValue.IEvBool(false) => {
|
| InternalExpressionValue.IEvBool(false) => {
|
||||||
|
@ -149,7 +152,7 @@ let dispatchMacroCall = (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment): result<
|
let expandExpressionList = (aList, bindings: ExpressionT.bindings, accessors): result<
|
||||||
expressionWithContext,
|
expressionWithContext,
|
||||||
errorValue,
|
errorValue,
|
||||||
> =>
|
> =>
|
||||||
|
@ -159,21 +162,21 @@ let dispatchMacroCall = (
|
||||||
bindingExpr: ExpressionT.expression,
|
bindingExpr: ExpressionT.expression,
|
||||||
statement,
|
statement,
|
||||||
} =>
|
} =>
|
||||||
doBindStatement(bindingExpr, statement, environment)
|
doBindStatement(bindingExpr, statement, accessors)
|
||||||
| list{ExpressionT.EValue(IEvCall("$$_bindStatement_$$")), statement} =>
|
| list{ExpressionT.EValue(IEvCall("$$_bindStatement_$$")), statement} =>
|
||||||
// bindings of the context are used when there is no binding expression
|
// bindings of the context are used when there is no binding expression
|
||||||
doBindStatement(eModule(bindings), statement, environment)
|
doBindStatement(eModule(bindings), statement, accessors)
|
||||||
| list{
|
| list{
|
||||||
ExpressionT.EValue(IEvCall("$$_bindExpression_$$")),
|
ExpressionT.EValue(IEvCall("$$_bindExpression_$$")),
|
||||||
bindingExpr: ExpressionT.expression,
|
bindingExpr: ExpressionT.expression,
|
||||||
expression,
|
expression,
|
||||||
} =>
|
} =>
|
||||||
doBindExpression(bindingExpr, expression, environment)
|
doBindExpression(bindingExpr, expression, accessors)
|
||||||
| list{ExpressionT.EValue(IEvCall("$$_bindExpression_$$")), expression} =>
|
| list{ExpressionT.EValue(IEvCall("$$_bindExpression_$$")), expression} =>
|
||||||
// bindings of the context are used when there is no binding expression
|
// bindings of the context are used when there is no binding expression
|
||||||
doBindExpression(eModule(bindings), expression, environment)
|
doBindExpression(eModule(bindings), expression, accessors)
|
||||||
| list{ExpressionT.EValue(IEvCall("$$_block_$$")), ...exprs} =>
|
| list{ExpressionT.EValue(IEvCall("$$_block_$$")), ...exprs} =>
|
||||||
doBlock(exprs, bindings, environment)
|
doBlock(exprs, bindings, accessors)
|
||||||
| list{
|
| list{
|
||||||
ExpressionT.EValue(IEvCall("$$_lambda_$$")),
|
ExpressionT.EValue(IEvCall("$$_lambda_$$")),
|
||||||
ExpressionT.EValue(IEvArrayString(parameters)),
|
ExpressionT.EValue(IEvArrayString(parameters)),
|
||||||
|
@ -181,12 +184,12 @@ let dispatchMacroCall = (
|
||||||
} =>
|
} =>
|
||||||
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
||||||
| list{ExpressionT.EValue(IEvCall("$$_ternary_$$")), condition, ifTrue, ifFalse} =>
|
| list{ExpressionT.EValue(IEvCall("$$_ternary_$$")), condition, ifTrue, ifFalse} =>
|
||||||
doTernary(condition, ifTrue, ifFalse, bindings, environment)
|
doTernary(condition, ifTrue, ifFalse, bindings, accessors)
|
||||||
| _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok
|
| _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
switch macroExpression {
|
switch macroExpression {
|
||||||
| EList(aList) => expandExpressionList(aList, bindings, environment)
|
| EList(aList) => expandExpressionList(aList, bindings, accessors)
|
||||||
| _ => ExpressionWithContext.noContext(macroExpression)->Ok
|
| _ => ExpressionWithContext.noContext(macroExpression)->Ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ type location
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type errorValue =
|
type errorValue =
|
||||||
| REArityError(option<string>, int, int) //TODO: Binding a lambda to a variable should record the variable name in lambda for error reporting
|
| REArityError(option<string>, int, int)
|
||||||
| REArrayIndexNotFound(string, int)
|
| REArrayIndexNotFound(string, int)
|
||||||
| REAssignmentExpected
|
| REAssignmentExpected
|
||||||
| REDistributionError(DistributionTypes.error)
|
| REDistributionError(DistributionTypes.error)
|
||||||
|
|
|
@ -1,35 +1,29 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
module BuiltIn = Reducer_Dispatch_BuiltIn
|
module BuiltIn = Reducer_Dispatch_BuiltIn
|
||||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
|
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||||
module Extra = Reducer_Extra
|
module Extra = Reducer_Extra
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Lambda = Reducer_Expression_Lambda
|
module Lambda = Reducer_Expression_Lambda
|
||||||
module Macro = Reducer_Expression_Macro
|
module Macro = Reducer_Expression_Macro
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
module Bindings = Reducer_Bindings
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
module T = Reducer_Expression_T
|
module T = Reducer_Expression_T
|
||||||
|
|
||||||
type environment = InternalExpressionValue.environment
|
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expression = T.expression
|
|
||||||
type internalExpressionValue = InternalExpressionValue.t
|
|
||||||
type externalExpressionValue = ReducerInterface_ExternalExpressionValue.t
|
type externalExpressionValue = ReducerInterface_ExternalExpressionValue.t
|
||||||
type t = expression
|
type t = T.t
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Converts a Squigle code to expression
|
Recursively evaluate/reduce the expression (Lisp AST/Lambda calculus)
|
||||||
*/
|
*/
|
||||||
let parse = (peggyCode: string): result<t, errorValue> =>
|
let rec reduceExpressionInProject = (
|
||||||
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
expression: t,
|
||||||
|
continuation: T.bindings,
|
||||||
/*
|
accessors: ProjectAccessorsT.t,
|
||||||
Recursively evaluate/reduce the expression (Lisp AST)
|
): result<InternalExpressionValue.t, 'e> => {
|
||||||
*/
|
|
||||||
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
|
|
||||||
internalExpressionValue,
|
|
||||||
'e,
|
|
||||||
> => {
|
|
||||||
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
||||||
switch expression {
|
switch expression {
|
||||||
| T.EValue(value) => value->Ok
|
| T.EValue(value) => value->Ok
|
||||||
|
@ -38,41 +32,40 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en
|
||||||
| list{EValue(IEvCall(fName)), ..._args} =>
|
| list{EValue(IEvCall(fName)), ..._args} =>
|
||||||
switch Macro.isMacroName(fName) {
|
switch Macro.isMacroName(fName) {
|
||||||
// A macro expands then reduces itself
|
// A macro expands then reduces itself
|
||||||
| true => Macro.doMacroCall(expression, bindings, environment, reduceExpression)
|
| true => Macro.doMacroCall(expression, continuation, accessors, reduceExpressionInProject)
|
||||||
| false => reduceExpressionList(list, bindings, environment)
|
| false => reduceExpressionList(list, continuation, accessors)
|
||||||
}
|
}
|
||||||
| _ => reduceExpressionList(list, bindings, environment)
|
| _ => reduceExpressionList(list, continuation, accessors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
and reduceExpressionList = (
|
and reduceExpressionList = (
|
||||||
expressions: list<t>,
|
expressions: list<t>,
|
||||||
bindings: T.bindings,
|
continuation: T.bindings,
|
||||||
environment: environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
): result<internalExpressionValue, 'e> => {
|
): result<InternalExpressionValue.t, 'e> => {
|
||||||
let racc: result<
|
let racc: result<
|
||||||
list<internalExpressionValue>,
|
list<InternalExpressionValue.t>,
|
||||||
'e,
|
'e,
|
||||||
> = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
> = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: t) =>
|
||||||
racc->Result.flatMap(acc => {
|
racc->Result.flatMap(acc => {
|
||||||
each
|
each
|
||||||
->reduceExpression(bindings, environment)
|
->reduceExpressionInProject(continuation, accessors)
|
||||||
->Result.map(newNode => {
|
->Result.map(newNode => {
|
||||||
acc->Belt.List.add(newNode)
|
acc->Belt.List.add(newNode)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
racc->Result.flatMap(acc => acc->reduceValueList(environment))
|
racc->Result.flatMap(acc => acc->reduceValueList(accessors))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
||||||
*/
|
*/
|
||||||
and reduceValueList = (valueList: list<internalExpressionValue>, environment): result<
|
and reduceValueList = (
|
||||||
internalExpressionValue,
|
valueList: list<InternalExpressionValue.t>,
|
||||||
'e,
|
accessors: ProjectAccessorsT.t,
|
||||||
> =>
|
): result<InternalExpressionValue.t, 'e> =>
|
||||||
switch valueList {
|
switch valueList {
|
||||||
| list{IEvCall(fName), ...args} => {
|
| list{IEvCall(fName), ...args} => {
|
||||||
let rCheckedArgs = switch fName {
|
let rCheckedArgs = switch fName {
|
||||||
|
@ -81,7 +74,10 @@ and reduceValueList = (valueList: list<internalExpressionValue>, environment): r
|
||||||
}
|
}
|
||||||
|
|
||||||
rCheckedArgs->Result.flatMap(checkedArgs =>
|
rCheckedArgs->Result.flatMap(checkedArgs =>
|
||||||
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression)
|
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(
|
||||||
|
accessors,
|
||||||
|
reduceExpressionInProject,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
| list{IEvLambda(_)} =>
|
| list{IEvLambda(_)} =>
|
||||||
|
@ -91,11 +87,11 @@ and reduceValueList = (valueList: list<internalExpressionValue>, environment): r
|
||||||
->Result.flatMap(reducedValueList =>
|
->Result.flatMap(reducedValueList =>
|
||||||
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
|
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
|
||||||
)
|
)
|
||||||
| list{IEvLambda(lamdaCall), ...args} =>
|
| list{IEvLambda(lambdaCall), ...args} =>
|
||||||
args
|
args
|
||||||
->Lambda.checkIfReduced
|
->Lambda.checkIfReduced
|
||||||
->Result.flatMap(checkedArgs =>
|
->Result.flatMap(checkedArgs =>
|
||||||
Lambda.doLambdaCall(lamdaCall, checkedArgs, environment, reduceExpression)
|
Lambda.doLambdaCall(lambdaCall, checkedArgs, accessors, reduceExpressionInProject)
|
||||||
)
|
)
|
||||||
|
|
||||||
| _ =>
|
| _ =>
|
||||||
|
@ -106,53 +102,37 @@ and reduceValueList = (valueList: list<internalExpressionValue>, environment): r
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result<
|
let reduceReturningBindings = (
|
||||||
internalExpressionValue,
|
expression: t,
|
||||||
'e,
|
continuation: T.bindings,
|
||||||
> => reduceExpression(aExpression, bindings, environment)
|
accessors: ProjectAccessorsT.t,
|
||||||
|
): (result<InternalExpressionValue.t, 'e>, T.bindings) => {
|
||||||
let evaluateUsingOptions = (
|
let result = reduceExpressionInProject(expression, continuation, accessors)
|
||||||
~environment: option<ReducerInterface_ExternalExpressionValue.environment>,
|
(result, accessors.continuation)
|
||||||
~externalBindings: option<ReducerInterface_ExternalExpressionValue.externalBindings>,
|
|
||||||
code: string,
|
|
||||||
): result<externalExpressionValue, errorValue> => {
|
|
||||||
let anEnvironment = Belt.Option.getWithDefault(
|
|
||||||
environment,
|
|
||||||
ReducerInterface_ExternalExpressionValue.defaultEnvironment,
|
|
||||||
)
|
|
||||||
|
|
||||||
let mergedBindings: InternalExpressionValue.nameSpace = Bindings.merge(
|
|
||||||
ReducerInterface_StdLib.internalStdLib,
|
|
||||||
Belt.Option.map(externalBindings, Bindings.fromTypeScriptBindings)->Belt.Option.getWithDefault(
|
|
||||||
Bindings.emptyModule,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
parse(code)
|
|
||||||
->Result.flatMap(expr => evalUsingBindingsExpression_(expr, mergedBindings, anEnvironment))
|
|
||||||
->Result.map(ReducerInterface_InternalExpressionValue.toExternal)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
module BackCompatible = {
|
||||||
IEvaluates Squiggle code and bindings via Reducer and answers the result
|
// Those methods are used to support the existing tests
|
||||||
*/
|
// If they are used outside limited testing context, error location reporting will fail
|
||||||
let evaluate = (code: string): result<externalExpressionValue, errorValue> => {
|
let parse = (peggyCode: string): result<t, errorValue> =>
|
||||||
evaluateUsingOptions(~environment=None, ~externalBindings=None, code)
|
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
||||||
}
|
|
||||||
let evaluatePartialUsingExternalBindings = (
|
let evaluate = (expression: t): result<InternalExpressionValue.t, errorValue> => {
|
||||||
code: string,
|
let accessors = ProjectAccessorsT.identityAccessors
|
||||||
externalBindings: ReducerInterface_ExternalExpressionValue.externalBindings,
|
expression->reduceExpressionInProject(accessors.stdLib, accessors)
|
||||||
environment: ReducerInterface_ExternalExpressionValue.environment,
|
|
||||||
): result<ReducerInterface_ExternalExpressionValue.externalBindings, errorValue> => {
|
|
||||||
let rAnswer = evaluateUsingOptions(
|
|
||||||
~environment=Some(environment),
|
|
||||||
~externalBindings=Some(externalBindings),
|
|
||||||
code,
|
|
||||||
)
|
|
||||||
switch rAnswer {
|
|
||||||
| Ok(EvModule(externalBindings)) => Ok(externalBindings)
|
|
||||||
| Ok(_) =>
|
|
||||||
Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`, None))
|
|
||||||
| Error(err) => err->Error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let evaluateString = (peggyCode: string): result<InternalExpressionValue.t, errorValue> =>
|
||||||
|
parse(peggyCode)->Result.flatMap(evaluate)
|
||||||
|
|
||||||
|
let evaluateAsExternal = (expression: t): result<ExternalExpressionValue.t, errorValue> =>
|
||||||
|
{
|
||||||
|
let accessors = ProjectAccessorsT.identityAccessors
|
||||||
|
expression->reduceExpressionInProject(accessors.stdLib, accessors)
|
||||||
|
}->Result.map(InternalExpressionValue.toExternal)
|
||||||
|
|
||||||
|
let evaluateStringAsExternal = (peggyCode: string): result<
|
||||||
|
ExternalExpressionValue.t,
|
||||||
|
errorValue,
|
||||||
|
> => parse(peggyCode)->Result.flatMap(evaluateAsExternal)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
module Bindings = Reducer_Bindings
|
|
||||||
|
|
||||||
type bindings = ExpressionT.bindings
|
type bindings = ExpressionT.bindings
|
||||||
type context = bindings
|
type context = bindings
|
||||||
|
@ -11,7 +13,6 @@ type environment = InternalExpressionValue.environment
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type internalExpressionValue = InternalExpressionValue.t
|
type internalExpressionValue = InternalExpressionValue.t
|
||||||
type reducerFn = ExpressionT.reducerFn
|
|
||||||
|
|
||||||
type expressionWithContext =
|
type expressionWithContext =
|
||||||
| ExpressionWithContext(expression, context)
|
| ExpressionWithContext(expression, context)
|
||||||
|
@ -20,16 +21,16 @@ type expressionWithContext =
|
||||||
let callReducer = (
|
let callReducer = (
|
||||||
expressionWithContext: expressionWithContext,
|
expressionWithContext: expressionWithContext,
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
environment: environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: reducerFn,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, errorValue> => {
|
): result<internalExpressionValue, errorValue> => {
|
||||||
switch expressionWithContext {
|
switch expressionWithContext {
|
||||||
| ExpressionNoContext(expr) =>
|
| ExpressionNoContext(expr) =>
|
||||||
// Js.log(`callReducer: bindings ${Bindings.toString(bindings)} expr ${ExpressionT.toString(expr)}`)
|
// Js.log(`callReducer: bindings ${Bindings.toString(bindings)} expr ${ExpressionT.toString(expr)}`)
|
||||||
reducer(expr, bindings, environment)
|
reducer(expr, bindings, accessors)
|
||||||
| ExpressionWithContext(expr, context) =>
|
| ExpressionWithContext(expr, context) =>
|
||||||
// Js.log(`callReducer: context ${Bindings.toString(context)} expr ${ExpressionT.toString(expr)}`)
|
// Js.log(`callReducer: context ${Bindings.toString(context)} expr ${ExpressionT.toString(expr)}`)
|
||||||
reducer(expr, context, environment)
|
reducer(expr, context, accessors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface_InternalExpressionValue
|
module ExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Bindings = Reducer_Bindings
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
|
||||||
type environment = ReducerInterface_InternalExpressionValue.environment
|
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type expressionOrFFI = ExpressionT.expressionOrFFI
|
type expressionOrFFI = ExpressionT.expressionOrFFI
|
||||||
type internalExpressionValue = ReducerInterface_InternalExpressionValue.t
|
type internalExpressionValue = ReducerInterface_InternalExpressionValue.t
|
||||||
|
@ -44,7 +45,13 @@ let checkIfReduced = (args: list<internalExpressionValue>) =>
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let caseNotFFI = (lambdaValue: ExpressionValue.lambdaValue, expr, args, environment, reducer) => {
|
let caseNotFFI = (
|
||||||
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
|
expr,
|
||||||
|
args,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
) => {
|
||||||
let parameterList = lambdaValue.parameters->Belt.List.fromArray
|
let parameterList = lambdaValue.parameters->Belt.List.fromArray
|
||||||
let zippedParameterList = parameterList->Belt.List.zip(args)
|
let zippedParameterList = parameterList->Belt.List.zip(args)
|
||||||
let bindings = Belt.List.reduce(zippedParameterList, lambdaValue.context, (
|
let bindings = Belt.List.reduce(zippedParameterList, lambdaValue.context, (
|
||||||
|
@ -52,39 +59,43 @@ let caseNotFFI = (lambdaValue: ExpressionValue.lambdaValue, expr, args, environm
|
||||||
(variable, variableValue),
|
(variable, variableValue),
|
||||||
) => acc->Bindings.set(variable, variableValue))
|
) => acc->Bindings.set(variable, variableValue))
|
||||||
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||||
reducer(newExpression, bindings, environment)
|
reducer(newExpression, bindings, accessors)
|
||||||
}
|
}
|
||||||
|
|
||||||
let caseFFI = (ffiFn: ExpressionT.ffiFn, args, environment) => {
|
let caseFFI = (ffiFn: ExpressionT.ffiFn, args, accessors: ProjectAccessorsT.t) => {
|
||||||
ffiFn(args->Belt.List.toArray, environment)
|
ffiFn(args->Belt.List.toArray, accessors.environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
let applyParametersToLambda = (
|
let applyParametersToLambda = (
|
||||||
lambdaValue: ExpressionValue.lambdaValue,
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
args,
|
args,
|
||||||
environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ExpressionT.reducerFn,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, 'e> => {
|
): result<internalExpressionValue, 'e> => {
|
||||||
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
||||||
checkIfReduced(args)->Result.flatMap(args => {
|
checkIfReduced(args)->Result.flatMap(args => {
|
||||||
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
||||||
switch exprOrFFI {
|
switch exprOrFFI {
|
||||||
| NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, environment, reducer)
|
| NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, accessors, reducer)
|
||||||
| FFI(ffiFn) => caseFFI(ffiFn, args, environment)
|
| FFI(ffiFn) => caseFFI(ffiFn, args, accessors)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) =>
|
let doLambdaCall = (
|
||||||
applyParametersToLambda(lambdaValue, args, environment, reducer)
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
|
args,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
reducer: ProjectReducerFnT.t,
|
||||||
|
) => applyParametersToLambda(lambdaValue, args, accessors, reducer)
|
||||||
|
|
||||||
let foreignFunctionInterface = (
|
let foreignFunctionInterface = (
|
||||||
lambdaValue: ExpressionValue.lambdaValue,
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
argArray: array<internalExpressionValue>,
|
argArray: array<internalExpressionValue>,
|
||||||
environment: ExpressionValue.environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ExpressionT.reducerFn,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, 'e> => {
|
): result<internalExpressionValue, 'e> => {
|
||||||
let args = argArray->Belt.List.fromArray
|
let args = argArray->Belt.List.fromArray
|
||||||
applyParametersToLambda(lambdaValue, args, environment, reducer)
|
applyParametersToLambda(lambdaValue, args, accessors, reducer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module ExpressionWithContext = Reducer_ExpressionWithContext
|
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
|
|
||||||
type environment = InternalExpressionValue.environment
|
type environment = InternalExpressionValue.environment
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
|
@ -11,34 +13,29 @@ type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
let expandMacroCall = (
|
let expandMacroCall = (
|
||||||
macroExpression: expression,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
environment: environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reduceExpression: ExpressionT.reducerFn,
|
reduceExpression: ProjectReducerFnT.t,
|
||||||
): result<expressionWithContext, 'e> =>
|
): result<expressionWithContext, 'e> =>
|
||||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
||||||
macroExpression,
|
macroExpression,
|
||||||
bindings,
|
bindings,
|
||||||
environment,
|
accessors,
|
||||||
reduceExpression,
|
reduceExpression,
|
||||||
)
|
)
|
||||||
|
|
||||||
let doMacroCall = (
|
let doMacroCall = (
|
||||||
macroExpression: expression,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
environment: environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reduceExpression: ExpressionT.reducerFn,
|
reduceExpression: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, 'e> =>
|
): result<internalExpressionValue, 'e> =>
|
||||||
expandMacroCall(
|
expandMacroCall(
|
||||||
macroExpression,
|
macroExpression,
|
||||||
bindings,
|
bindings,
|
||||||
environment,
|
(accessors: ProjectAccessorsT.t),
|
||||||
reduceExpression,
|
(reduceExpression: ProjectReducerFnT.t),
|
||||||
)->Result.flatMap(expressionWithContext =>
|
)->Result.flatMap(expressionWithContext =>
|
||||||
ExpressionWithContext.callReducer(
|
ExpressionWithContext.callReducer(expressionWithContext, bindings, accessors, reduceExpression)
|
||||||
expressionWithContext,
|
|
||||||
bindings,
|
|
||||||
environment,
|
|
||||||
reduceExpression,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
||||||
|
|
|
@ -17,6 +17,8 @@ type rec expression =
|
||||||
| EValue(internalExpressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
|
| EValue(internalExpressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
|
||||||
and bindings = InternalExpressionValue.nameSpace
|
and bindings = InternalExpressionValue.nameSpace
|
||||||
|
|
||||||
|
type t = expression
|
||||||
|
|
||||||
type reducerFn = (
|
type reducerFn = (
|
||||||
expression,
|
expression,
|
||||||
bindings,
|
bindings,
|
||||||
|
|
|
@ -9,12 +9,25 @@ start
|
||||||
|
|
||||||
zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
|
zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
|
||||||
|
|
||||||
|
// { return h.makeFunctionCall('$_typeOf_$', [identifier, typeExpression])}
|
||||||
|
// {return [h.nodeVoid()];}
|
||||||
outerBlock
|
outerBlock
|
||||||
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
||||||
{ if (finalExpression != null) { statements.push(finalExpression) }
|
{ if (finalExpression != null)
|
||||||
return h.nodeBlock(statements) }
|
{
|
||||||
|
var newFinalExpression = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), finalExpression]);
|
||||||
|
statements.push(newFinalExpression);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newFinalStatement = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), h.nodeVoid()]);
|
||||||
|
statements.push(newFinalStatement);
|
||||||
|
}
|
||||||
|
return h.nodeBlock(statements) }
|
||||||
/ finalExpression: expression
|
/ finalExpression: expression
|
||||||
{ return h.nodeBlock([finalExpression])}
|
{
|
||||||
|
var newFinalExpression = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), finalExpression]);
|
||||||
|
return h.nodeBlock([newFinalExpression])}
|
||||||
|
|
||||||
innerBlockOrExpression
|
innerBlockOrExpression
|
||||||
= quotedInnerBlock
|
= quotedInnerBlock
|
||||||
|
|
|
@ -1,40 +1,37 @@
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module Expression = Reducer_Expression
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Bindings = Reducer_Bindings
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module T = Reducer_Type_T
|
module T = Reducer_Type_T
|
||||||
|
|
||||||
let ievFromTypeExpression = (
|
let ievFromTypeExpression = (
|
||||||
typeExpressionSourceCode: string,
|
typeExpressionSourceCode: string,
|
||||||
reducerFn: ExpressionT.reducerFn,
|
reducerFn: ProjectReducerFnT.t,
|
||||||
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||||
let sIndex = "compiled"
|
let sIndex = "compiled"
|
||||||
let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}`
|
let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}`
|
||||||
Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
Reducer_Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
||||||
let rContext = reducerFn(
|
let accessors = ProjectAccessorsT.identityAccessors
|
||||||
expr,
|
let result = reducerFn(expr, Bindings.emptyBindings, accessors)
|
||||||
Bindings.emptyBindings,
|
let nameSpace = accessors.continuation
|
||||||
InternalExpressionValue.defaultEnvironment,
|
|
||||||
)
|
switch result {
|
||||||
Belt.Result.map(rContext, context =>
|
| Ok(_) =>
|
||||||
switch context {
|
switch Bindings.getType(nameSpace, sIndex) {
|
||||||
| IEvBindings(nameSpace) =>
|
| Some(value) => value->Ok
|
||||||
switch Bindings.getType(nameSpace, sIndex) {
|
| None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none"))
|
||||||
| Some(value) => value
|
|
||||||
| None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none"))
|
|
||||||
}
|
|
||||||
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-raise"))
|
|
||||||
}
|
}
|
||||||
)
|
| err => err
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let fromTypeExpression = (
|
let fromTypeExpression = (typeExpressionSourceCode: string, reducerFn: ProjectReducerFnT.t): result<
|
||||||
typeExpressionSourceCode: string,
|
T.t,
|
||||||
reducerFn: ExpressionT.reducerFn,
|
ErrorValue.t,
|
||||||
): result<T.t, ErrorValue.t> => {
|
> => {
|
||||||
ievFromTypeExpression(
|
ievFromTypeExpression(typeExpressionSourceCode, reducerFn)->Belt.Result.map(T.fromIEvValue)
|
||||||
(typeExpressionSourceCode: string),
|
|
||||||
(reducerFn: ExpressionT.reducerFn),
|
|
||||||
)->Belt.Result.map(T.fromIEvValue)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module T = Reducer_Type_T
|
module T = Reducer_Type_T
|
||||||
module TypeContracts = Reducer_Type_Contracts
|
module TypeContracts = Reducer_Type_Contracts
|
||||||
open InternalExpressionValue
|
open InternalExpressionValue
|
||||||
|
@ -124,7 +126,7 @@ let rec isITypeOf = (anIType: T.iType, aValue): result<bool, T.typeErrorValue> =
|
||||||
let isTypeOf = (
|
let isTypeOf = (
|
||||||
typeExpressionSourceCode: string,
|
typeExpressionSourceCode: string,
|
||||||
aValue: InternalExpressionValue.t,
|
aValue: InternalExpressionValue.t,
|
||||||
reducerFn: ExpressionT.reducerFn,
|
reducerFn: ProjectReducerFnT.t,
|
||||||
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||||
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
||||||
| Ok(anIType) =>
|
| Ok(anIType) =>
|
||||||
|
@ -152,7 +154,7 @@ let checkITypeArguments = (anIType: T.iType, args: array<InternalExpressionValue
|
||||||
let checkArguments = (
|
let checkArguments = (
|
||||||
typeExpressionSourceCode: string,
|
typeExpressionSourceCode: string,
|
||||||
args: array<InternalExpressionValue.t>,
|
args: array<InternalExpressionValue.t>,
|
||||||
reducerFn: ExpressionT.reducerFn,
|
reducerFn: ProjectReducerFnT.t,
|
||||||
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||||
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
||||||
| Ok(anIType) =>
|
| Ok(anIType) =>
|
||||||
|
|
|
@ -92,6 +92,18 @@ let toStringResult = x =>
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let toStringOptionResult = x =>
|
||||||
|
switch x {
|
||||||
|
| Some(a) => toStringResult(a)
|
||||||
|
| None => `None`
|
||||||
|
}
|
||||||
|
|
||||||
|
let toStringOption = x =>
|
||||||
|
switch x {
|
||||||
|
| Some(a) => toString(a)
|
||||||
|
| None => `None`
|
||||||
|
}
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type environment = GenericDist.env
|
type environment = GenericDist.env
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
type internalExpressionValue = InternalExpressionValue.t
|
type internalExpressionValue = InternalExpressionValue.t
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6,17 +8,17 @@ type internalExpressionValue = InternalExpressionValue.t
|
||||||
*/
|
*/
|
||||||
let dispatch = (
|
let dispatch = (
|
||||||
call: InternalExpressionValue.functionCall,
|
call: InternalExpressionValue.functionCall,
|
||||||
environment,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: Reducer_Expression_T.reducerFn,
|
reducer: ProjectReducerFnT.t,
|
||||||
chain,
|
chain,
|
||||||
): result<internalExpressionValue, 'e> => {
|
): result<internalExpressionValue, 'e> => {
|
||||||
E.A.O.firstSomeFn([
|
E.A.O.firstSomeFn([
|
||||||
() => ReducerInterface_GenericDistribution.dispatch(call, environment),
|
() => ReducerInterface_GenericDistribution.dispatch(call, accessors.environment),
|
||||||
() => ReducerInterface_Date.dispatch(call, environment),
|
() => ReducerInterface_Date.dispatch(call, accessors.environment),
|
||||||
() => ReducerInterface_Duration.dispatch(call, environment),
|
() => ReducerInterface_Duration.dispatch(call, accessors.environment),
|
||||||
() => ReducerInterface_Number.dispatch(call, environment),
|
() => ReducerInterface_Number.dispatch(call, accessors.environment),
|
||||||
() => FunctionRegistry_Library.dispatch(call, environment, reducer),
|
() => FunctionRegistry_Library.dispatch(call, accessors, reducer),
|
||||||
])->E.O2.defaultFn(() => chain(call, environment, reducer))
|
])->E.O2.defaultFn(() => chain(call, accessors, reducer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -132,6 +132,12 @@ let toStringResult = x =>
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let toStringOptionResult = x =>
|
||||||
|
switch x {
|
||||||
|
| Some(a) => `${toStringResult(a)})`
|
||||||
|
| None => "None"
|
||||||
|
}
|
||||||
|
|
||||||
let toStringResultOkless = (codeResult: result<t, ErrorValue.errorValue>): string =>
|
let toStringResultOkless = (codeResult: result<t, ErrorValue.errorValue>): string =>
|
||||||
switch codeResult {
|
switch codeResult {
|
||||||
| Ok(a) => toString(a)
|
| Ok(a) => toString(a)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
module Bindings = Reducer_Bindings
|
module Bindings = Reducer_Bindings
|
||||||
|
|
||||||
let internalStdLib =
|
let internalStdLib: Bindings.t =
|
||||||
Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings->SquiggleLibrary_Versions.makeBindings
|
Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings->SquiggleLibrary_Versions.makeBindings
|
||||||
|
|
||||||
@genType
|
|
||||||
let externalStdLib = internalStdLib->Bindings.toTypeScriptBindings
|
let externalStdLib = internalStdLib->Bindings.toTypeScriptBindings
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
|
||||||
|
type t = InternalExpressionValue.nameSpace
|
||||||
|
|
||||||
|
let toValue = nameSpace => InternalExpressionValue.IEvBindings(nameSpace)
|
||||||
|
let toString = nameSpace => InternalExpressionValue.toString(toValue(nameSpace))
|
||||||
|
let toStringResult = rNameSpace =>
|
||||||
|
Belt.Result.map(rNameSpace, toValue(_))->InternalExpressionValue.toStringResult
|
||||||
|
let toStringOptionResult = orNameSpace =>
|
||||||
|
Belt.Option.map(
|
||||||
|
orNameSpace,
|
||||||
|
Belt.Result.map(_, toValue(_)),
|
||||||
|
)->InternalExpressionValue.toStringOptionResult
|
||||||
|
|
||||||
|
let inspect = (nameSpace, label: string) => Js.log(`${label}: ${toString(nameSpace)}`)
|
||||||
|
|
||||||
|
let inspectOption = (oNameSpace, label: string) =>
|
||||||
|
switch oNameSpace {
|
||||||
|
| Some(nameSpace) => inspect(nameSpace, label)
|
||||||
|
| None => Js.log(`${label}: None`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let minus = (NameSpace(thisContainer): t, NameSpace(thatContainer): t) => {
|
||||||
|
Belt.Map.String.removeMany(
|
||||||
|
thisContainer,
|
||||||
|
Belt.Map.String.keysToArray(thatContainer),
|
||||||
|
)->InternalExpressionValue.NameSpace
|
||||||
|
}
|
|
@ -0,0 +1,396 @@
|
||||||
|
// TODO: Restore run FFI?
|
||||||
|
// TODO: Auto clean project based on topology
|
||||||
|
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module Continuation = ReducerInterface_Value_Continuation
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ProjectItem = ReducerProject_ProjectItem
|
||||||
|
module T = ReducerProject_T
|
||||||
|
|
||||||
|
@genType.opaque
|
||||||
|
type project = T.t
|
||||||
|
type t = T.t
|
||||||
|
|
||||||
|
module Private = {
|
||||||
|
type internalProject = T.Private.t
|
||||||
|
type t = T.Private.t
|
||||||
|
|
||||||
|
let getSourceIds = (this: t): array<string> => Belt.Map.String.keysToArray(this["items"])
|
||||||
|
|
||||||
|
let getItem = (this: t, sourceId: string) =>
|
||||||
|
Belt.Map.String.getWithDefault(this["items"], sourceId, ProjectItem.emptyItem)
|
||||||
|
|
||||||
|
let getImmediateDependencies = (this: t, sourceId: string): ProjectItem.T.includesType =>
|
||||||
|
getItem(this, sourceId)->ProjectItem.getImmediateDependencies
|
||||||
|
|
||||||
|
type topologicalSortState = (Belt.Map.String.t<bool>, list<string>)
|
||||||
|
let rec topologicalSortUtil = (
|
||||||
|
this: t,
|
||||||
|
sourceId: string,
|
||||||
|
state: topologicalSortState,
|
||||||
|
): topologicalSortState => {
|
||||||
|
let dependencies = getImmediateDependencies(this, sourceId)->Belt.Result.getWithDefault([])
|
||||||
|
let (visited, stack) = state
|
||||||
|
let myVisited = Belt.Map.String.set(visited, sourceId, true)
|
||||||
|
let (newVisited, newStack) = dependencies->Belt.Array.reduce((myVisited, stack), (
|
||||||
|
(currVisited, currStack),
|
||||||
|
dependency,
|
||||||
|
) => {
|
||||||
|
if !Belt.Map.String.getWithDefault(currVisited, dependency, false) {
|
||||||
|
topologicalSortUtil(this, dependency, (currVisited, currStack))
|
||||||
|
} else {
|
||||||
|
(currVisited, currStack)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
(newVisited, list{sourceId, ...newStack})
|
||||||
|
}
|
||||||
|
|
||||||
|
let getTopologicalSort = (this: t): array<string> => {
|
||||||
|
let (_visited, stack) = getSourceIds(this)->Belt.Array.reduce((Belt.Map.String.empty, list{}), (
|
||||||
|
(currVisited, currStack),
|
||||||
|
currId,
|
||||||
|
) =>
|
||||||
|
if !Belt.Map.String.getWithDefault(currVisited, currId, false) {
|
||||||
|
topologicalSortUtil(this, currId, (currVisited, currStack))
|
||||||
|
} else {
|
||||||
|
(currVisited, currStack)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Belt.List.reverse(stack)->Belt.List.toArray
|
||||||
|
}
|
||||||
|
|
||||||
|
let getTopologicalSortFor = (this: t, sourceId) => {
|
||||||
|
let runOrder = getTopologicalSort(this)
|
||||||
|
let index = runOrder->Js.Array2.indexOf(sourceId)
|
||||||
|
let after = Belt.Array.sliceToEnd(runOrder, index + 1)
|
||||||
|
let before = Js.Array2.slice(runOrder, ~start=0, ~end_=index + 1)
|
||||||
|
(before, after)
|
||||||
|
}
|
||||||
|
|
||||||
|
let getRunOrder = getTopologicalSort
|
||||||
|
|
||||||
|
let createProject = () => {
|
||||||
|
let this: t = {
|
||||||
|
"items": Belt.Map.String.empty,
|
||||||
|
"stdLib": ReducerInterface_StdLib.internalStdLib,
|
||||||
|
"environment": InternalExpressionValue.defaultEnvironment,
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
let getRunOrderFor = (this: t, sourceId: string) => {
|
||||||
|
let (runOrder, _) = getTopologicalSortFor(this, sourceId)
|
||||||
|
runOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
let getDependencies = (this: t, sourceId: string): array<string> => {
|
||||||
|
let runOrder = getRunOrderFor(this, sourceId)
|
||||||
|
|
||||||
|
let _ = Js.Array2.pop(runOrder)
|
||||||
|
runOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
let getDependents = (this: t, sourceId: string): array<string> => {
|
||||||
|
let (_, dependents) = getTopologicalSortFor(this, sourceId)
|
||||||
|
dependents
|
||||||
|
}
|
||||||
|
|
||||||
|
let rec touchSource = (this: t, sourceId: string): unit => {
|
||||||
|
let item = this->getItem(sourceId)
|
||||||
|
let newItem = ProjectItem.touchSource(item)
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
touchDependents(this, sourceId)
|
||||||
|
}
|
||||||
|
and touchDependents = (this: t, sourceId: string): unit => {
|
||||||
|
let _ = getDependents(this, sourceId)->Belt.Array.forEach(_, touchSource(this, _))
|
||||||
|
}
|
||||||
|
|
||||||
|
let getSource = (this: t, sourceId: string): option<string> =>
|
||||||
|
Belt.Map.String.get(this["items"], sourceId)->Belt.Option.map(ProjectItem.getSource)
|
||||||
|
|
||||||
|
let setSource = (this: t, sourceId: string, value: string): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.setSource(value)
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
touchDependents(this, sourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
let clean = (this: t, sourceId: string): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.clean
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cleanAll = (this: t): unit =>
|
||||||
|
getSourceIds(this)->Belt.Array.forEach(sourceId => clean(this, sourceId))
|
||||||
|
|
||||||
|
let cleanResults = (this: t, sourceId: string): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.cleanResults
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cleanAllResults = (this: t): unit =>
|
||||||
|
getSourceIds(this)->Belt.Array.forEach(sourceId => cleanResults(this, sourceId))
|
||||||
|
|
||||||
|
let getIncludes = (this: t, sourceId: string): ProjectItem.T.includesType =>
|
||||||
|
this->getItem(sourceId)->ProjectItem.getIncludes
|
||||||
|
|
||||||
|
let setContinues = (this: t, sourceId: string, continues: array<string>): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.setContinues(continues)
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
touchSource(this, sourceId)
|
||||||
|
}
|
||||||
|
let getContinues = (this: t, sourceId: string): array<string> =>
|
||||||
|
ProjectItem.getContinues(this->getItem(sourceId))
|
||||||
|
|
||||||
|
let removeContinues = (this: t, sourceId: string): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.removeContinues
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
touchSource(this, sourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
let getContinuation = (this: t, sourceId: string): ProjectItem.T.continuationArgumentType =>
|
||||||
|
this->getItem(sourceId)->ProjectItem.getContinuation
|
||||||
|
|
||||||
|
let setContinuation = (
|
||||||
|
this: t,
|
||||||
|
sourceId: string,
|
||||||
|
continuation: ProjectItem.T.continuationArgumentType,
|
||||||
|
): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.setContinuation(continuation)
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
let getResult = (this: t, sourceId: string): ProjectItem.T.resultType =>
|
||||||
|
this->getItem(sourceId)->ProjectItem.getResult
|
||||||
|
|
||||||
|
let setResult = (this: t, sourceId: string, value: ProjectItem.T.resultArgumentType): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.setResult(value)
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
let getExternalResult = (this: t, sourceId: string): ProjectItem.T.externalResultType =>
|
||||||
|
this->getItem(sourceId)->ProjectItem.getExternalResult
|
||||||
|
|
||||||
|
let parseIncludes = (this: t, sourceId: string): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.parseIncludes
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
let rawParse = (this: t, sourceId): unit => {
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.rawParse
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
let getStdLib = (this: t): Reducer_Bindings.t => this["stdLib"]
|
||||||
|
let setStdLib = (this: t, value: Reducer_Bindings.t): unit =>
|
||||||
|
T.Private.setFieldStdLib(this, value)
|
||||||
|
|
||||||
|
let getEnvironment = (this: t): InternalExpressionValue.environment => this["environment"]
|
||||||
|
let setEnvironment = (this: t, value: InternalExpressionValue.environment): unit =>
|
||||||
|
T.Private.setFieldEnvironment(this, value)
|
||||||
|
|
||||||
|
let getExternalBindings = (
|
||||||
|
this: t,
|
||||||
|
sourceId: string,
|
||||||
|
): ProjectItem.T.externalBindingsArgumentType => {
|
||||||
|
let those = this->getContinuation(sourceId)
|
||||||
|
let these = this->getStdLib
|
||||||
|
let ofUser = Continuation.minus(those, these)
|
||||||
|
ofUser->InternalExpressionValue.nameSpaceToTypeScriptBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
let buildProjectAccessors = (this: t): ProjectAccessorsT.t => {
|
||||||
|
continuation: Bindings.emptyBindings,
|
||||||
|
stdLib: getStdLib(this),
|
||||||
|
environment: getEnvironment(this),
|
||||||
|
}
|
||||||
|
|
||||||
|
let doRunWithContinuation = (
|
||||||
|
this: t,
|
||||||
|
sourceId: string,
|
||||||
|
continuation: ProjectItem.T.continuation,
|
||||||
|
): unit => {
|
||||||
|
let accessors = buildProjectAccessors(this)
|
||||||
|
let newItem = this->getItem(sourceId)->ProjectItem.run(continuation, accessors)
|
||||||
|
Belt.Map.String.set(this["items"], sourceId, newItem)->T.Private.setFieldItems(this, _)
|
||||||
|
setContinuation(this, sourceId, accessors.continuation)
|
||||||
|
}
|
||||||
|
|
||||||
|
type runState = (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation)
|
||||||
|
|
||||||
|
let tryRunWithContinuation = (
|
||||||
|
this: t,
|
||||||
|
sourceId: string,
|
||||||
|
(rPrevResult: ProjectItem.T.resultArgumentType, continuation: ProjectItem.T.continuation),
|
||||||
|
): (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) => {
|
||||||
|
switch getResult(this, sourceId) {
|
||||||
|
| Some(result) => (result, getContinuation(this, sourceId)) // already ran
|
||||||
|
| None =>
|
||||||
|
switch rPrevResult {
|
||||||
|
| Error(error) => {
|
||||||
|
setResult(this, sourceId, Error(error))
|
||||||
|
(Error(error), continuation)
|
||||||
|
}
|
||||||
|
| Ok(_prevResult) => {
|
||||||
|
doRunWithContinuation(this, sourceId, continuation)
|
||||||
|
(
|
||||||
|
getResult(this, sourceId)->Belt.Option.getWithDefault(rPrevResult),
|
||||||
|
getContinuation(this, sourceId),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let runAll = (this: t): unit => {
|
||||||
|
let runOrder = getTopologicalSort(this)
|
||||||
|
let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(this))
|
||||||
|
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
||||||
|
tryRunWithContinuation(this, currId, currState)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let run = (this: t, sourceId: string): unit => {
|
||||||
|
let runOrder = getRunOrderFor(this, sourceId)
|
||||||
|
let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(this))
|
||||||
|
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
||||||
|
tryRunWithContinuation(this, currId, currState)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let evaluate = (sourceCode: string) => {
|
||||||
|
let project = createProject()
|
||||||
|
setSource(project, "main", sourceCode)
|
||||||
|
runAll(project)
|
||||||
|
(
|
||||||
|
getResult(project, "main")->Belt.Option.getWithDefault(IEvVoid->Ok),
|
||||||
|
getContinuation(project, "main"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
PUBLIC FUNCTIONS
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Create a new this to hold the sources, executables, bindings and other data.
|
||||||
|
// The this is a mutable object for use in TypeScript.
|
||||||
|
let createProject = (): t => Private.createProject()->T.Private.castFromInternalProject
|
||||||
|
|
||||||
|
// Answers the array of existing source ids to enumerate over.
|
||||||
|
let getSourceIds = (this: t): array<string> =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getSourceIds
|
||||||
|
|
||||||
|
// Sets the source for a given source id.
|
||||||
|
let setSource = (this: t, sourceId: string, value: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.setSource(sourceId, value)
|
||||||
|
|
||||||
|
// Gets the source for a given source id.
|
||||||
|
let getSource = (this: t, sourceId: string): option<string> =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getSource(sourceId)
|
||||||
|
|
||||||
|
// Touches the source for a given source id. This forces the dependency graph to be re-evaluated.
|
||||||
|
// Touching source code clears the includes so that they can be reevaluated.
|
||||||
|
let touchSource = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.touchSource(sourceId)
|
||||||
|
|
||||||
|
// Cleans the compilation artifacts for a given source id. The results stay untouched.
|
||||||
|
let clean = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.clean(sourceId)
|
||||||
|
|
||||||
|
// Cleans all compilation artifacts for all the this. The results stay untouched.
|
||||||
|
let cleanAll = (this: t): unit => this->T.Private.castToInternalProject->Private.cleanAll
|
||||||
|
|
||||||
|
// Cleans results. Compilation stays untouched to rerun the source.
|
||||||
|
let cleanResults = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.cleanResults(sourceId)
|
||||||
|
|
||||||
|
// Cleans all results. Compilations stays untouched to rerun the source.
|
||||||
|
let cleanAllResults = (this: t): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.cleanAllResults
|
||||||
|
|
||||||
|
let getIncludes = (this: t, sourceId: string): ProjectItem.T.includesType =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getIncludes(sourceId)
|
||||||
|
|
||||||
|
let getContinues = (this: t, sourceId: string): array<string> =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getContinues(sourceId)
|
||||||
|
|
||||||
|
// setContinues acts like an include hidden in the source. It is used to define a continuation.
|
||||||
|
let setContinues = (this: t, sourceId: string, continues: array<string>): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.setContinues(sourceId, continues)
|
||||||
|
|
||||||
|
// This source is not continuing any other source. It is a standalone source.
|
||||||
|
// Touches this source also.
|
||||||
|
let removeContinues = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.removeContinues(sourceId)
|
||||||
|
|
||||||
|
// Gets includes and continues for a given source id. SourceId is depending on them
|
||||||
|
let getDependencies = (this: t, sourceId: string): array<string> =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getDependencies(sourceId)
|
||||||
|
|
||||||
|
// Get source ids depending on a given source id.
|
||||||
|
let getDependents = (this: t, sourceId: string): array<string> =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getDependents(sourceId)
|
||||||
|
|
||||||
|
// Get run order for all sources. It is a topological sort of the dependency graph.
|
||||||
|
let getRunOrder = (this: t) => this->T.Private.castToInternalProject->Private.getRunOrder
|
||||||
|
|
||||||
|
// Get run order for a given source id. It is a topological sort of the dependency graph.
|
||||||
|
let getRunOrderFor = (this: t, sourceId: string) =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getRunOrderFor(sourceId)
|
||||||
|
|
||||||
|
// Parse includes so that you can load them before running. Use getIncludes to get the includes.
|
||||||
|
// It is your responsibility to load the includes before running.
|
||||||
|
let parseIncludes = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.parseIncludes(sourceId)
|
||||||
|
|
||||||
|
// Parse the source code if it is not done already. Use getRawParse to get the parse tree
|
||||||
|
let rawParse = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.rawParse(sourceId)
|
||||||
|
|
||||||
|
// Runs the source code.
|
||||||
|
// The code is parsed if it is not already done.
|
||||||
|
// If it continues/includes another source then it will run that source also if is not already done.
|
||||||
|
let run = (this: t, sourceId: string): unit =>
|
||||||
|
this->T.Private.castToInternalProject->Private.run(sourceId)
|
||||||
|
|
||||||
|
// Runs all the sources.
|
||||||
|
let runAll = (this: t): unit => this->T.Private.castToInternalProject->Private.runAll
|
||||||
|
|
||||||
|
// WARNING" getExternalBindings will be deprecated. Cyclic directed graph problems
|
||||||
|
// Get the bindings after running the source code.
|
||||||
|
let getExternalBindings = (this: t, sourceId: string): ExternalExpressionValue.record =>
|
||||||
|
this->T.Private.castToInternalProject->Private.getExternalBindings(sourceId)
|
||||||
|
|
||||||
|
//WARNING: externalResult will be deprecated. Cyclic directed graph problems
|
||||||
|
let getExternalResult = (this: t, sourceId: string): option<
|
||||||
|
result<ExternalExpressionValue.t, Reducer_ErrorValue.errorValue>,
|
||||||
|
> => this->T.Private.castToInternalProject->Private.getExternalResult(sourceId)
|
||||||
|
|
||||||
|
// This is a convenience function to get the result of a single source.
|
||||||
|
// You cannot use includes
|
||||||
|
let evaluate = (sourceCode: string): ('r, 'b) => {
|
||||||
|
let (result, continuation) = Private.evaluate(sourceCode)
|
||||||
|
(
|
||||||
|
result->Belt.Result.map(InternalExpressionValue.toExternal),
|
||||||
|
continuation->InternalExpressionValue.nameSpaceToTypeScriptBindings,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let foreignFunctionInterface = (
|
||||||
|
lambdaValue: ExternalExpressionValue.lambdaValue,
|
||||||
|
argArray: array<ExternalExpressionValue.t>,
|
||||||
|
environment: ExternalExpressionValue.environment,
|
||||||
|
) => {
|
||||||
|
let internallambdaValue = InternalExpressionValue.lambdaValueToInternal(lambdaValue)
|
||||||
|
let internalArgArray = argArray->Js.Array2.map(InternalExpressionValue.toInternal)
|
||||||
|
let accessors = ProjectAccessorsT.identityAccessorsWithEnvironment(environment)
|
||||||
|
Reducer_Expression_Lambda.foreignFunctionInterface(
|
||||||
|
internallambdaValue,
|
||||||
|
internalArgArray,
|
||||||
|
accessors,
|
||||||
|
Reducer_Expression.reduceExpressionInProject,
|
||||||
|
)->Belt.Result.map(InternalExpressionValue.toExternal)
|
||||||
|
}
|
|
@ -0,0 +1,915 @@
|
||||||
|
// Generated by Peggy 2.0.1.
|
||||||
|
//
|
||||||
|
// https://peggyjs.org/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function peg$subclass(child, parent) {
|
||||||
|
function C() { this.constructor = child; }
|
||||||
|
C.prototype = parent.prototype;
|
||||||
|
child.prototype = new C();
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$SyntaxError(message, expected, found, location) {
|
||||||
|
var self = Error.call(this, message);
|
||||||
|
// istanbul ignore next Check is a necessary evil to support older environments
|
||||||
|
if (Object.setPrototypeOf) {
|
||||||
|
Object.setPrototypeOf(self, peg$SyntaxError.prototype);
|
||||||
|
}
|
||||||
|
self.expected = expected;
|
||||||
|
self.found = found;
|
||||||
|
self.location = location;
|
||||||
|
self.name = "SyntaxError";
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$subclass(peg$SyntaxError, Error);
|
||||||
|
|
||||||
|
function peg$padEnd(str, targetLength, padString) {
|
||||||
|
padString = padString || " ";
|
||||||
|
if (str.length > targetLength) { return str; }
|
||||||
|
targetLength -= str.length;
|
||||||
|
padString += padString.repeat(targetLength);
|
||||||
|
return str + padString.slice(0, targetLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$SyntaxError.prototype.format = function(sources) {
|
||||||
|
var str = "Error: " + this.message;
|
||||||
|
if (this.location) {
|
||||||
|
var src = null;
|
||||||
|
var k;
|
||||||
|
for (k = 0; k < sources.length; k++) {
|
||||||
|
if (sources[k].source === this.location.source) {
|
||||||
|
src = sources[k].text.split(/\r\n|\n|\r/g);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var s = this.location.start;
|
||||||
|
var loc = this.location.source + ":" + s.line + ":" + s.column;
|
||||||
|
if (src) {
|
||||||
|
var e = this.location.end;
|
||||||
|
var filler = peg$padEnd("", s.line.toString().length, ' ');
|
||||||
|
var line = src[s.line - 1];
|
||||||
|
var last = s.line === e.line ? e.column : line.length + 1;
|
||||||
|
var hatLen = (last - s.column) || 1;
|
||||||
|
str += "\n --> " + loc + "\n"
|
||||||
|
+ filler + " |\n"
|
||||||
|
+ s.line + " | " + line + "\n"
|
||||||
|
+ filler + " | " + peg$padEnd("", s.column - 1, ' ')
|
||||||
|
+ peg$padEnd("", hatLen, "^");
|
||||||
|
} else {
|
||||||
|
str += "\n at " + loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
peg$SyntaxError.buildMessage = function(expected, found) {
|
||||||
|
var DESCRIBE_EXPECTATION_FNS = {
|
||||||
|
literal: function(expectation) {
|
||||||
|
return "\"" + literalEscape(expectation.text) + "\"";
|
||||||
|
},
|
||||||
|
|
||||||
|
class: function(expectation) {
|
||||||
|
var escapedParts = expectation.parts.map(function(part) {
|
||||||
|
return Array.isArray(part)
|
||||||
|
? classEscape(part[0]) + "-" + classEscape(part[1])
|
||||||
|
: classEscape(part);
|
||||||
|
});
|
||||||
|
|
||||||
|
return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
|
||||||
|
},
|
||||||
|
|
||||||
|
any: function() {
|
||||||
|
return "any character";
|
||||||
|
},
|
||||||
|
|
||||||
|
end: function() {
|
||||||
|
return "end of input";
|
||||||
|
},
|
||||||
|
|
||||||
|
other: function(expectation) {
|
||||||
|
return expectation.description;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function hex(ch) {
|
||||||
|
return ch.charCodeAt(0).toString(16).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function literalEscape(s) {
|
||||||
|
return s
|
||||||
|
.replace(/\\/g, "\\\\")
|
||||||
|
.replace(/"/g, "\\\"")
|
||||||
|
.replace(/\0/g, "\\0")
|
||||||
|
.replace(/\t/g, "\\t")
|
||||||
|
.replace(/\n/g, "\\n")
|
||||||
|
.replace(/\r/g, "\\r")
|
||||||
|
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
|
||||||
|
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
|
||||||
|
}
|
||||||
|
|
||||||
|
function classEscape(s) {
|
||||||
|
return s
|
||||||
|
.replace(/\\/g, "\\\\")
|
||||||
|
.replace(/\]/g, "\\]")
|
||||||
|
.replace(/\^/g, "\\^")
|
||||||
|
.replace(/-/g, "\\-")
|
||||||
|
.replace(/\0/g, "\\0")
|
||||||
|
.replace(/\t/g, "\\t")
|
||||||
|
.replace(/\n/g, "\\n")
|
||||||
|
.replace(/\r/g, "\\r")
|
||||||
|
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
|
||||||
|
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
|
||||||
|
}
|
||||||
|
|
||||||
|
function describeExpectation(expectation) {
|
||||||
|
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function describeExpected(expected) {
|
||||||
|
var descriptions = expected.map(describeExpectation);
|
||||||
|
var i, j;
|
||||||
|
|
||||||
|
descriptions.sort();
|
||||||
|
|
||||||
|
if (descriptions.length > 0) {
|
||||||
|
for (i = 1, j = 1; i < descriptions.length; i++) {
|
||||||
|
if (descriptions[i - 1] !== descriptions[i]) {
|
||||||
|
descriptions[j] = descriptions[i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptions.length = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (descriptions.length) {
|
||||||
|
case 1:
|
||||||
|
return descriptions[0];
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return descriptions[0] + " or " + descriptions[1];
|
||||||
|
|
||||||
|
default:
|
||||||
|
return descriptions.slice(0, -1).join(", ")
|
||||||
|
+ ", or "
|
||||||
|
+ descriptions[descriptions.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function describeFound(found) {
|
||||||
|
return found ? "\"" + literalEscape(found) + "\"" : "end of input";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
|
||||||
|
};
|
||||||
|
|
||||||
|
function peg$parse(input, options) {
|
||||||
|
options = options !== undefined ? options : {};
|
||||||
|
|
||||||
|
var peg$FAILED = {};
|
||||||
|
var peg$source = options.grammarSource;
|
||||||
|
|
||||||
|
var peg$startRuleFunctions = { start: peg$parsestart };
|
||||||
|
var peg$startRuleFunction = peg$parsestart;
|
||||||
|
|
||||||
|
var peg$c0 = "#include";
|
||||||
|
var peg$c1 = "'";
|
||||||
|
var peg$c2 = "\"";
|
||||||
|
var peg$c3 = "//";
|
||||||
|
var peg$c4 = "/*";
|
||||||
|
var peg$c5 = "*/";
|
||||||
|
|
||||||
|
var peg$r0 = /^[^']/;
|
||||||
|
var peg$r1 = /^[^"]/;
|
||||||
|
var peg$r2 = /^[^*]/;
|
||||||
|
var peg$r3 = /^[ \t]/;
|
||||||
|
var peg$r4 = /^[\n\r]/;
|
||||||
|
var peg$r5 = /^[^\r\n]/;
|
||||||
|
|
||||||
|
var peg$e0 = peg$literalExpectation("#include", false);
|
||||||
|
var peg$e1 = peg$otherExpectation("string");
|
||||||
|
var peg$e2 = peg$literalExpectation("'", false);
|
||||||
|
var peg$e3 = peg$classExpectation(["'"], true, false);
|
||||||
|
var peg$e4 = peg$literalExpectation("\"", false);
|
||||||
|
var peg$e5 = peg$classExpectation(["\""], true, false);
|
||||||
|
var peg$e6 = peg$literalExpectation("//", false);
|
||||||
|
var peg$e7 = peg$literalExpectation("/*", false);
|
||||||
|
var peg$e8 = peg$classExpectation(["*"], true, false);
|
||||||
|
var peg$e9 = peg$literalExpectation("*/", false);
|
||||||
|
var peg$e10 = peg$otherExpectation("white space");
|
||||||
|
var peg$e11 = peg$classExpectation([" ", "\t"], false, false);
|
||||||
|
var peg$e12 = peg$otherExpectation("newline");
|
||||||
|
var peg$e13 = peg$classExpectation(["\n", "\r"], false, false);
|
||||||
|
var peg$e14 = peg$classExpectation(["\r", "\n"], true, false);
|
||||||
|
|
||||||
|
var peg$f0 = function(head, tail) {return [head, ...tail].filter( e => e != '');};
|
||||||
|
var peg$f1 = function() {return [];};
|
||||||
|
var peg$f2 = function(characters) {return characters.join('');};
|
||||||
|
var peg$f3 = function(characters) {return characters.join('');};
|
||||||
|
var peg$f4 = function() { return '';};
|
||||||
|
var peg$f5 = function() { return '';};
|
||||||
|
var peg$currPos = 0;
|
||||||
|
var peg$savedPos = 0;
|
||||||
|
var peg$posDetailsCache = [{ line: 1, column: 1 }];
|
||||||
|
var peg$maxFailPos = 0;
|
||||||
|
var peg$maxFailExpected = [];
|
||||||
|
var peg$silentFails = 0;
|
||||||
|
|
||||||
|
var peg$resultsCache = {};
|
||||||
|
|
||||||
|
var peg$result;
|
||||||
|
|
||||||
|
if ("startRule" in options) {
|
||||||
|
if (!(options.startRule in peg$startRuleFunctions)) {
|
||||||
|
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
|
||||||
|
}
|
||||||
|
|
||||||
|
function text() {
|
||||||
|
return input.substring(peg$savedPos, peg$currPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
function offset() {
|
||||||
|
return peg$savedPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function range() {
|
||||||
|
return {
|
||||||
|
source: peg$source,
|
||||||
|
start: peg$savedPos,
|
||||||
|
end: peg$currPos
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function location() {
|
||||||
|
return peg$computeLocation(peg$savedPos, peg$currPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expected(description, location) {
|
||||||
|
location = location !== undefined
|
||||||
|
? location
|
||||||
|
: peg$computeLocation(peg$savedPos, peg$currPos);
|
||||||
|
|
||||||
|
throw peg$buildStructuredError(
|
||||||
|
[peg$otherExpectation(description)],
|
||||||
|
input.substring(peg$savedPos, peg$currPos),
|
||||||
|
location
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(message, location) {
|
||||||
|
location = location !== undefined
|
||||||
|
? location
|
||||||
|
: peg$computeLocation(peg$savedPos, peg$currPos);
|
||||||
|
|
||||||
|
throw peg$buildSimpleError(message, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$literalExpectation(text, ignoreCase) {
|
||||||
|
return { type: "literal", text: text, ignoreCase: ignoreCase };
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$classExpectation(parts, inverted, ignoreCase) {
|
||||||
|
return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$anyExpectation() {
|
||||||
|
return { type: "any" };
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$endExpectation() {
|
||||||
|
return { type: "end" };
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$otherExpectation(description) {
|
||||||
|
return { type: "other", description: description };
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$computePosDetails(pos) {
|
||||||
|
var details = peg$posDetailsCache[pos];
|
||||||
|
var p;
|
||||||
|
|
||||||
|
if (details) {
|
||||||
|
return details;
|
||||||
|
} else {
|
||||||
|
p = pos - 1;
|
||||||
|
while (!peg$posDetailsCache[p]) {
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
|
||||||
|
details = peg$posDetailsCache[p];
|
||||||
|
details = {
|
||||||
|
line: details.line,
|
||||||
|
column: details.column
|
||||||
|
};
|
||||||
|
|
||||||
|
while (p < pos) {
|
||||||
|
if (input.charCodeAt(p) === 10) {
|
||||||
|
details.line++;
|
||||||
|
details.column = 1;
|
||||||
|
} else {
|
||||||
|
details.column++;
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$posDetailsCache[pos] = details;
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$computeLocation(startPos, endPos) {
|
||||||
|
var startPosDetails = peg$computePosDetails(startPos);
|
||||||
|
var endPosDetails = peg$computePosDetails(endPos);
|
||||||
|
|
||||||
|
return {
|
||||||
|
source: peg$source,
|
||||||
|
start: {
|
||||||
|
offset: startPos,
|
||||||
|
line: startPosDetails.line,
|
||||||
|
column: startPosDetails.column
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
offset: endPos,
|
||||||
|
line: endPosDetails.line,
|
||||||
|
column: endPosDetails.column
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$fail(expected) {
|
||||||
|
if (peg$currPos < peg$maxFailPos) { return; }
|
||||||
|
|
||||||
|
if (peg$currPos > peg$maxFailPos) {
|
||||||
|
peg$maxFailPos = peg$currPos;
|
||||||
|
peg$maxFailExpected = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$maxFailExpected.push(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$buildSimpleError(message, location) {
|
||||||
|
return new peg$SyntaxError(message, null, null, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$buildStructuredError(expected, found, location) {
|
||||||
|
return new peg$SyntaxError(
|
||||||
|
peg$SyntaxError.buildMessage(expected, found),
|
||||||
|
expected,
|
||||||
|
found,
|
||||||
|
location
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parsestart() {
|
||||||
|
var s0, s1, s2, s3;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 0;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = peg$currPos;
|
||||||
|
s1 = peg$parseincludes();
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
s2 = [];
|
||||||
|
s3 = peg$parsenewLine();
|
||||||
|
while (s3 !== peg$FAILED) {
|
||||||
|
s2.push(s3);
|
||||||
|
s3 = peg$parsenewLine();
|
||||||
|
}
|
||||||
|
s3 = peg$parseignore();
|
||||||
|
s0 = s1;
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parseincludes() {
|
||||||
|
var s0, s1, s2, s3, s4, s5;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 1;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = peg$currPos;
|
||||||
|
s1 = peg$parseincludeStatement();
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
s2 = [];
|
||||||
|
s3 = peg$currPos;
|
||||||
|
s4 = [];
|
||||||
|
s5 = peg$parsenewLine();
|
||||||
|
if (s5 !== peg$FAILED) {
|
||||||
|
while (s5 !== peg$FAILED) {
|
||||||
|
s4.push(s5);
|
||||||
|
s5 = peg$parsenewLine();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
}
|
||||||
|
if (s4 !== peg$FAILED) {
|
||||||
|
s5 = peg$parseincludeStatement();
|
||||||
|
if (s5 !== peg$FAILED) {
|
||||||
|
s3 = s5;
|
||||||
|
} else {
|
||||||
|
peg$currPos = s3;
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peg$currPos = s3;
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
}
|
||||||
|
while (s3 !== peg$FAILED) {
|
||||||
|
s2.push(s3);
|
||||||
|
s3 = peg$currPos;
|
||||||
|
s4 = [];
|
||||||
|
s5 = peg$parsenewLine();
|
||||||
|
if (s5 !== peg$FAILED) {
|
||||||
|
while (s5 !== peg$FAILED) {
|
||||||
|
s4.push(s5);
|
||||||
|
s5 = peg$parsenewLine();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
}
|
||||||
|
if (s4 !== peg$FAILED) {
|
||||||
|
s5 = peg$parseincludeStatement();
|
||||||
|
if (s5 !== peg$FAILED) {
|
||||||
|
s3 = s5;
|
||||||
|
} else {
|
||||||
|
peg$currPos = s3;
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peg$currPos = s3;
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peg$savedPos = s0;
|
||||||
|
s0 = peg$f0(s1, s2);
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s0 = peg$currPos;
|
||||||
|
s1 = peg$parseignore();
|
||||||
|
peg$savedPos = s0;
|
||||||
|
s1 = peg$f1();
|
||||||
|
s0 = s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parseincludeStatement() {
|
||||||
|
var s0, s1, s2, s3, s4, s5;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 2;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = peg$currPos;
|
||||||
|
if (input.substr(peg$currPos, 8) === peg$c0) {
|
||||||
|
s1 = peg$c0;
|
||||||
|
peg$currPos += 8;
|
||||||
|
} else {
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e0); }
|
||||||
|
}
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
s2 = [];
|
||||||
|
s3 = peg$parse_();
|
||||||
|
while (s3 !== peg$FAILED) {
|
||||||
|
s2.push(s3);
|
||||||
|
s3 = peg$parse_();
|
||||||
|
}
|
||||||
|
s3 = peg$parsestring();
|
||||||
|
if (s3 !== peg$FAILED) {
|
||||||
|
s4 = [];
|
||||||
|
s5 = peg$parse_();
|
||||||
|
while (s5 !== peg$FAILED) {
|
||||||
|
s4.push(s5);
|
||||||
|
s5 = peg$parse_();
|
||||||
|
}
|
||||||
|
s0 = s3;
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s0 = peg$parsecomment();
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s0 = peg$parsedelimitedComment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parsestring() {
|
||||||
|
var s0, s1, s2, s3, s4;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 3;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$silentFails++;
|
||||||
|
s0 = peg$currPos;
|
||||||
|
s1 = peg$currPos;
|
||||||
|
if (input.charCodeAt(peg$currPos) === 39) {
|
||||||
|
s2 = peg$c1;
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s2 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e2); }
|
||||||
|
}
|
||||||
|
if (s2 !== peg$FAILED) {
|
||||||
|
s3 = [];
|
||||||
|
if (peg$r0.test(input.charAt(peg$currPos))) {
|
||||||
|
s4 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e3); }
|
||||||
|
}
|
||||||
|
while (s4 !== peg$FAILED) {
|
||||||
|
s3.push(s4);
|
||||||
|
if (peg$r0.test(input.charAt(peg$currPos))) {
|
||||||
|
s4 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e3); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (input.charCodeAt(peg$currPos) === 39) {
|
||||||
|
s4 = peg$c1;
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e2); }
|
||||||
|
}
|
||||||
|
if (s4 !== peg$FAILED) {
|
||||||
|
s1 = s3;
|
||||||
|
} else {
|
||||||
|
peg$currPos = s1;
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peg$currPos = s1;
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
}
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
peg$savedPos = s0;
|
||||||
|
s1 = peg$f2(s1);
|
||||||
|
}
|
||||||
|
s0 = s1;
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s0 = peg$currPos;
|
||||||
|
s1 = peg$currPos;
|
||||||
|
if (input.charCodeAt(peg$currPos) === 34) {
|
||||||
|
s2 = peg$c2;
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s2 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e4); }
|
||||||
|
}
|
||||||
|
if (s2 !== peg$FAILED) {
|
||||||
|
s3 = [];
|
||||||
|
if (peg$r1.test(input.charAt(peg$currPos))) {
|
||||||
|
s4 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e5); }
|
||||||
|
}
|
||||||
|
while (s4 !== peg$FAILED) {
|
||||||
|
s3.push(s4);
|
||||||
|
if (peg$r1.test(input.charAt(peg$currPos))) {
|
||||||
|
s4 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e5); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (input.charCodeAt(peg$currPos) === 34) {
|
||||||
|
s4 = peg$c2;
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s4 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e4); }
|
||||||
|
}
|
||||||
|
if (s4 !== peg$FAILED) {
|
||||||
|
s1 = s3;
|
||||||
|
} else {
|
||||||
|
peg$currPos = s1;
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peg$currPos = s1;
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
}
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
peg$savedPos = s0;
|
||||||
|
s1 = peg$f3(s1);
|
||||||
|
}
|
||||||
|
s0 = s1;
|
||||||
|
}
|
||||||
|
peg$silentFails--;
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parseignore() {
|
||||||
|
var s0, s1;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 4;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = [];
|
||||||
|
s1 = peg$parseany();
|
||||||
|
if (s1 === peg$FAILED) {
|
||||||
|
s1 = peg$parsenewLine();
|
||||||
|
if (s1 === peg$FAILED) {
|
||||||
|
s1 = peg$parse_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (s1 !== peg$FAILED) {
|
||||||
|
s0.push(s1);
|
||||||
|
s1 = peg$parseany();
|
||||||
|
if (s1 === peg$FAILED) {
|
||||||
|
s1 = peg$parsenewLine();
|
||||||
|
if (s1 === peg$FAILED) {
|
||||||
|
s1 = peg$parse_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parsecomment() {
|
||||||
|
var s0, s1, s2, s3;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 5;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = peg$currPos;
|
||||||
|
if (input.substr(peg$currPos, 2) === peg$c3) {
|
||||||
|
s1 = peg$c3;
|
||||||
|
peg$currPos += 2;
|
||||||
|
} else {
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e6); }
|
||||||
|
}
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
s2 = [];
|
||||||
|
s3 = peg$parseany();
|
||||||
|
while (s3 !== peg$FAILED) {
|
||||||
|
s2.push(s3);
|
||||||
|
s3 = peg$parseany();
|
||||||
|
}
|
||||||
|
peg$savedPos = s0;
|
||||||
|
s0 = peg$f4();
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parsedelimitedComment() {
|
||||||
|
var s0, s1, s2, s3;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 6;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = peg$currPos;
|
||||||
|
if (input.substr(peg$currPos, 2) === peg$c4) {
|
||||||
|
s1 = peg$c4;
|
||||||
|
peg$currPos += 2;
|
||||||
|
} else {
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e7); }
|
||||||
|
}
|
||||||
|
if (s1 !== peg$FAILED) {
|
||||||
|
s2 = [];
|
||||||
|
if (peg$r2.test(input.charAt(peg$currPos))) {
|
||||||
|
s3 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e8); }
|
||||||
|
}
|
||||||
|
while (s3 !== peg$FAILED) {
|
||||||
|
s2.push(s3);
|
||||||
|
if (peg$r2.test(input.charAt(peg$currPos))) {
|
||||||
|
s3 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e8); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (input.substr(peg$currPos, 2) === peg$c5) {
|
||||||
|
s3 = peg$c5;
|
||||||
|
peg$currPos += 2;
|
||||||
|
} else {
|
||||||
|
s3 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e9); }
|
||||||
|
}
|
||||||
|
if (s3 !== peg$FAILED) {
|
||||||
|
peg$savedPos = s0;
|
||||||
|
s0 = peg$f5();
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peg$currPos = s0;
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parse_() {
|
||||||
|
var s0, s1;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 7;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$silentFails++;
|
||||||
|
if (peg$r3.test(input.charAt(peg$currPos))) {
|
||||||
|
s0 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e11); }
|
||||||
|
}
|
||||||
|
peg$silentFails--;
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e10); }
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parsenewLine() {
|
||||||
|
var s0, s1;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 8;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$silentFails++;
|
||||||
|
if (peg$r4.test(input.charAt(peg$currPos))) {
|
||||||
|
s0 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e13); }
|
||||||
|
}
|
||||||
|
peg$silentFails--;
|
||||||
|
if (s0 === peg$FAILED) {
|
||||||
|
s1 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e12); }
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function peg$parseany() {
|
||||||
|
var s0;
|
||||||
|
|
||||||
|
var key = peg$currPos * 10 + 9;
|
||||||
|
var cached = peg$resultsCache[key];
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
peg$currPos = cached.nextPos;
|
||||||
|
|
||||||
|
return cached.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peg$r5.test(input.charAt(peg$currPos))) {
|
||||||
|
s0 = input.charAt(peg$currPos);
|
||||||
|
peg$currPos++;
|
||||||
|
} else {
|
||||||
|
s0 = peg$FAILED;
|
||||||
|
if (peg$silentFails === 0) { peg$fail(peg$e14); }
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
peg$result = peg$startRuleFunction();
|
||||||
|
|
||||||
|
if (peg$result !== peg$FAILED && peg$currPos === input.length) {
|
||||||
|
return peg$result;
|
||||||
|
} else {
|
||||||
|
if (peg$result !== peg$FAILED && peg$currPos < input.length) {
|
||||||
|
peg$fail(peg$endExpectation());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw peg$buildStructuredError(
|
||||||
|
peg$maxFailExpected,
|
||||||
|
peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
|
||||||
|
peg$maxFailPos < input.length
|
||||||
|
? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
|
||||||
|
: peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SyntaxError: peg$SyntaxError,
|
||||||
|
parse: peg$parse
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Includes are at the start of the file, before any other code.
|
||||||
|
// There might be some comments before or between the includes.
|
||||||
|
// #include "string"
|
||||||
|
// #include "string2"
|
||||||
|
|
||||||
|
|
||||||
|
start
|
||||||
|
= @includes newLine* ignore
|
||||||
|
|
||||||
|
includes
|
||||||
|
= head:includeStatement tail:(newLine+ @includeStatement)*
|
||||||
|
{return [head, ...tail].filter( e => e != '');}
|
||||||
|
/ ignore
|
||||||
|
{return [];}
|
||||||
|
|
||||||
|
includeStatement
|
||||||
|
= '#include' _* @string _*
|
||||||
|
/ comment
|
||||||
|
/ delimitedComment
|
||||||
|
|
||||||
|
string 'string'
|
||||||
|
= characters:("'" @([^'])* "'") {return characters.join('');}
|
||||||
|
/ characters:('"' @([^"])* '"') {return characters.join('');}
|
||||||
|
|
||||||
|
ignore = (any / newLine / _)*
|
||||||
|
|
||||||
|
comment
|
||||||
|
= '//'any*
|
||||||
|
{ return '';}
|
||||||
|
|
||||||
|
delimitedComment
|
||||||
|
= '/*' ([^*]*) '*/'
|
||||||
|
{ return '';}
|
||||||
|
|
||||||
|
_ "white space"
|
||||||
|
= [ \t]
|
||||||
|
|
||||||
|
newLine "newline"
|
||||||
|
= [\n\r]
|
||||||
|
|
||||||
|
any = [^\r\n]
|
|
@ -0,0 +1,8 @@
|
||||||
|
@module("./ReducerProject_IncludeParser.js") external parse__: string => array<string> = "parse"
|
||||||
|
|
||||||
|
let parseIncludes = (expr: string): array<string> =>
|
||||||
|
try {
|
||||||
|
parse__(expr)
|
||||||
|
} catch {
|
||||||
|
| Js.Exn.Error(_obj) => []
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
module ProjectItemT = ReducerProject_ProjectItem_T
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
|
||||||
|
type projectAccessors = {
|
||||||
|
stdLib: Reducer_Bindings.t,
|
||||||
|
environment: ExpressionT.environment,
|
||||||
|
mutable continuation: ProjectItemT.continuationArgumentType,
|
||||||
|
}
|
||||||
|
|
||||||
|
type t = projectAccessors
|
||||||
|
|
||||||
|
let identityAccessors: t = {
|
||||||
|
continuation: Bindings.emptyBindings,
|
||||||
|
stdLib: ReducerInterface_StdLib.internalStdLib,
|
||||||
|
environment: InternalExpressionValue.defaultEnvironment,
|
||||||
|
}
|
||||||
|
|
||||||
|
let identityAccessorsWithEnvironment = (environment): t => {
|
||||||
|
continuation: Bindings.emptyBindings,
|
||||||
|
stdLib: ReducerInterface_StdLib.internalStdLib,
|
||||||
|
environment: environment,
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
// TODO: Use actual types instead of aliases in public functions
|
||||||
|
// TODO: Use topological sorting to prevent unnecessary runs
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module Continuation = ReducerInterface_Value_Continuation
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
module ReducerFnT = ReducerProject_ReducerFn_T
|
||||||
|
module T = ReducerProject_ProjectItem_T
|
||||||
|
|
||||||
|
type projectItem = T.projectItem
|
||||||
|
type t = T.t
|
||||||
|
|
||||||
|
let emptyItem = T.ProjectItem({
|
||||||
|
source: "",
|
||||||
|
rawParse: None,
|
||||||
|
expression: None,
|
||||||
|
continuation: Bindings.emptyBindings,
|
||||||
|
result: None,
|
||||||
|
continues: [],
|
||||||
|
includes: []->Ok,
|
||||||
|
})
|
||||||
|
// source -> rawParse -> includes -> expression -> continuation -> externalBindings -> result -> externalResult
|
||||||
|
|
||||||
|
let getSource = (T.ProjectItem(r)): T.sourceType => r.source
|
||||||
|
let getRawParse = (T.ProjectItem(r)): T.rawParseType => r.rawParse
|
||||||
|
let getExpression = (T.ProjectItem(r)): T.expressionType => r.expression
|
||||||
|
let getContinuation = (T.ProjectItem(r)): T.continuationArgumentType => r.continuation
|
||||||
|
let toExternalBindings = continuation =>
|
||||||
|
continuation->InternalExpressionValue.nameSpaceToTypeScriptBindings
|
||||||
|
let getResult = (T.ProjectItem(r)): T.resultType => r.result
|
||||||
|
let getExternalResult = (T.ProjectItem(r)): T.externalResultType =>
|
||||||
|
r.result->Belt.Option.map(opt =>
|
||||||
|
opt->Belt.Result.map(value => value->InternalExpressionValue.toExternal)
|
||||||
|
)
|
||||||
|
|
||||||
|
let getContinues = (T.ProjectItem(r)): T.continuesType => r.continues
|
||||||
|
let getIncludes = (T.ProjectItem(r)): T.includesType => r.includes
|
||||||
|
|
||||||
|
let touchSource = (this: t): t => {
|
||||||
|
let T.ProjectItem(r) = emptyItem
|
||||||
|
T.ProjectItem({
|
||||||
|
...r,
|
||||||
|
includes: getIncludes(this),
|
||||||
|
continues: getContinues(this),
|
||||||
|
source: getSource(this),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let touchRawParse = (this: t): t => {
|
||||||
|
let T.ProjectItem(r) = emptyItem
|
||||||
|
T.ProjectItem({
|
||||||
|
...r,
|
||||||
|
continues: getContinues(this),
|
||||||
|
source: getSource(this),
|
||||||
|
rawParse: getRawParse(this),
|
||||||
|
includes: getIncludes(this),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let touchExpression = (this: t): t => {
|
||||||
|
let T.ProjectItem(r) = emptyItem
|
||||||
|
T.ProjectItem({
|
||||||
|
...r,
|
||||||
|
continues: getContinues(this),
|
||||||
|
source: getSource(this),
|
||||||
|
rawParse: getRawParse(this),
|
||||||
|
includes: getIncludes(this),
|
||||||
|
expression: getExpression(this),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let setSource = (T.ProjectItem(r): t, source: T.sourceArgumentType): t =>
|
||||||
|
T.ProjectItem({...r, source: source})->touchSource
|
||||||
|
|
||||||
|
let setRawParse = (T.ProjectItem(r): t, rawParse: T.rawParseArgumentType): t =>
|
||||||
|
T.ProjectItem({...r, rawParse: Some(rawParse)})->touchRawParse
|
||||||
|
|
||||||
|
let setExpression = (T.ProjectItem(r): t, expression: T.expressionArgumentType): t =>
|
||||||
|
T.ProjectItem({...r, expression: Some(expression)})->touchExpression
|
||||||
|
|
||||||
|
let setContinuation = (T.ProjectItem(r): t, continuation: T.continuationArgumentType): t => {
|
||||||
|
T.ProjectItem({...r, continuation: continuation})
|
||||||
|
}
|
||||||
|
|
||||||
|
let setResult = (T.ProjectItem(r): t, result: T.resultArgumentType): t => T.ProjectItem({
|
||||||
|
...r,
|
||||||
|
result: Some(result),
|
||||||
|
})
|
||||||
|
|
||||||
|
let cleanResults = touchExpression
|
||||||
|
|
||||||
|
let clean = (this: t): t => {
|
||||||
|
let T.ProjectItem(r) = emptyItem
|
||||||
|
T.ProjectItem({
|
||||||
|
...r,
|
||||||
|
source: getSource(this),
|
||||||
|
continuation: getContinuation(this),
|
||||||
|
result: getResult(this),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let getImmediateDependencies = (this: t): T.includesType =>
|
||||||
|
getIncludes(this)->Belt.Result.map(Js.Array2.concat(_, getContinues(this)))
|
||||||
|
|
||||||
|
let setContinues = (T.ProjectItem(r): t, continues: array<string>): t =>
|
||||||
|
T.ProjectItem({...r, continues: continues})->touchSource
|
||||||
|
let removeContinues = (T.ProjectItem(r): t): t => T.ProjectItem({...r, continues: []})->touchSource
|
||||||
|
|
||||||
|
let setIncludes = (T.ProjectItem(r): t, includes: T.includesType): t => T.ProjectItem({
|
||||||
|
...r,
|
||||||
|
includes: includes,
|
||||||
|
})
|
||||||
|
|
||||||
|
//TODO: forward parse errors to the user
|
||||||
|
let parseIncludes = (this: t): t =>
|
||||||
|
setIncludes(this, getSource(this)->ReducerProject_ParseIncludes.parseIncludes->Ok)
|
||||||
|
|
||||||
|
let doRawParse = (this: t): T.rawParseArgumentType => this->getSource->Reducer_Peggy_Parse.parse
|
||||||
|
|
||||||
|
let rawParse = (this: t): t =>
|
||||||
|
this->getRawParse->E.O2.defaultFn(() => doRawParse(this))->setRawParse(this, _)
|
||||||
|
|
||||||
|
let doBuildExpression = (this: t): T.expressionType =>
|
||||||
|
this
|
||||||
|
->getRawParse
|
||||||
|
->Belt.Option.map(o => o->Belt.Result.map(r => r->Reducer_Peggy_ToExpression.fromNode))
|
||||||
|
|
||||||
|
let buildExpression = (this: t): t => {
|
||||||
|
let withRawParse: t = this->rawParse
|
||||||
|
switch withRawParse->getExpression {
|
||||||
|
| Some(_) => withRawParse
|
||||||
|
| None =>
|
||||||
|
withRawParse
|
||||||
|
->doBuildExpression
|
||||||
|
->Belt.Option.map(setExpression(withRawParse, _))
|
||||||
|
->E.O2.defaultFn(() => withRawParse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let wrappedReducer = (
|
||||||
|
rExpression: T.expressionArgumentType,
|
||||||
|
aContinuation: T.continuation,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
): T.resultArgumentType => {
|
||||||
|
Belt.Result.flatMap(
|
||||||
|
rExpression,
|
||||||
|
Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let doBuildResult = (
|
||||||
|
this: t,
|
||||||
|
aContinuation: T.continuation,
|
||||||
|
accessors: ProjectAccessorsT.t,
|
||||||
|
): T.resultType =>
|
||||||
|
this
|
||||||
|
->getExpression
|
||||||
|
->Belt.Option.map(
|
||||||
|
Belt.Result.flatMap(
|
||||||
|
_,
|
||||||
|
Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
let buildResult = (this: t, aContinuation: T.continuation, accessors: ProjectAccessorsT.t): t => {
|
||||||
|
let withExpression: t = this->buildExpression
|
||||||
|
switch withExpression->getResult {
|
||||||
|
| Some(_) => withExpression
|
||||||
|
| None =>
|
||||||
|
withExpression
|
||||||
|
->doBuildResult(aContinuation, accessors)
|
||||||
|
->Belt.Option.map(setResult(withExpression, _))
|
||||||
|
->E.O2.defaultFn(() => withExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let run = buildResult
|
|
@ -0,0 +1,39 @@
|
||||||
|
module Parse = Reducer_Peggy_Parse
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||||
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
|
type sourceArgumentType = string
|
||||||
|
type sourceType = string
|
||||||
|
type rawParseArgumentType = result<Parse.node, errorValue>
|
||||||
|
type rawParseType = option<rawParseArgumentType>
|
||||||
|
type expressionArgumentType = result<ExpressionT.t, errorValue>
|
||||||
|
type expressionType = option<expressionArgumentType>
|
||||||
|
type continuation = InternalExpressionValue.nameSpace
|
||||||
|
type continuationArgumentType = InternalExpressionValue.nameSpace
|
||||||
|
type continuationType = option<continuationArgumentType>
|
||||||
|
type continuationResultType = option<result<continuationArgumentType, errorValue>>
|
||||||
|
type externalBindingsArgumentType = ExternalExpressionValue.record
|
||||||
|
type externalBindingsType = option<externalBindingsArgumentType>
|
||||||
|
type resultArgumentType = result<InternalExpressionValue.t, errorValue>
|
||||||
|
type resultType = option<resultArgumentType>
|
||||||
|
type externalResultArgumentType = result<ExternalExpressionValue.t, errorValue>
|
||||||
|
type externalResultType = option<externalResultArgumentType>
|
||||||
|
type continuesArgumentType = array<string>
|
||||||
|
type continuesType = array<string>
|
||||||
|
type includesArgumentType = string
|
||||||
|
type includesType = result<array<string>, errorValue>
|
||||||
|
|
||||||
|
type projectItem =
|
||||||
|
| ProjectItem({
|
||||||
|
source: sourceType,
|
||||||
|
rawParse: rawParseType,
|
||||||
|
expression: expressionType,
|
||||||
|
continuation: continuationArgumentType,
|
||||||
|
result: resultType,
|
||||||
|
continues: continuesType,
|
||||||
|
includes: includesType,
|
||||||
|
})
|
||||||
|
|
||||||
|
type t = projectItem
|
|
@ -0,0 +1,9 @@
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
|
||||||
|
type t = (
|
||||||
|
ExpressionT.t,
|
||||||
|
ExpressionT.bindings,
|
||||||
|
ProjectAccessorsT.t,
|
||||||
|
) => result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>
|
|
@ -0,0 +1,25 @@
|
||||||
|
module ProjectItem = ReducerProject_ProjectItem
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
|
||||||
|
type project = Object
|
||||||
|
type t = project
|
||||||
|
|
||||||
|
module Private = {
|
||||||
|
type internalProject = {
|
||||||
|
"items": Belt.Map.String.t<ProjectItem.t>,
|
||||||
|
"stdLib": Reducer_Bindings.t,
|
||||||
|
"environment": ExpressionT.environment,
|
||||||
|
}
|
||||||
|
type t = internalProject
|
||||||
|
|
||||||
|
@set
|
||||||
|
external setFieldItems: (t, Belt.Map.String.t<ProjectItem.t>) => unit = "items"
|
||||||
|
@set
|
||||||
|
external setFieldStdLib: (t, Reducer_Bindings.t) => unit = "stdLib"
|
||||||
|
@set
|
||||||
|
external setFieldEnvironment: (t, ExpressionT.environment) => unit = "stdLib"
|
||||||
|
|
||||||
|
external castFromInternalProject: t => project = "%identity"
|
||||||
|
external castToInternalProject: project => t = "%identity"
|
||||||
|
}
|
|
@ -34,17 +34,17 @@ type resultString = result<string, distributionError>
|
||||||
@genType
|
@genType
|
||||||
let makeSampleSetDist = SampleSetDist.make
|
let makeSampleSetDist = SampleSetDist.make
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let evaluate = Reducer.evaluate
|
// let evaluate = Reducer.evaluate
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
// let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let parse = Reducer_Peggy_Parse.parse
|
let parse = Reducer_Peggy_Parse.parse
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
// let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type externalBindings = Reducer.externalBindings
|
type externalBindings = Reducer.externalBindings
|
||||||
|
@ -91,8 +91,8 @@ type environment = ReducerInterface_ExternalExpressionValue.environment
|
||||||
@genType
|
@genType
|
||||||
let defaultEnvironment = ReducerInterface_ExternalExpressionValue.defaultEnvironment
|
let defaultEnvironment = ReducerInterface_ExternalExpressionValue.defaultEnvironment
|
||||||
|
|
||||||
@genType
|
// @genType
|
||||||
let foreignFunctionInterface = Reducer.foreignFunctionInterface
|
// let foreignFunctionInterface = Reducer.foreignFunctionInterface
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type declarationArg = Declaration.arg
|
type declarationArg = Declaration.arg
|
||||||
|
|
Loading…
Reference in New Issue
Block a user