Merge pull request #968 from quantified-uncertainty/reducer-project
Reducer Project - API Revamp
This commit is contained in:
commit
05299c78e6
|
@ -1,10 +1,14 @@
|
|||
module ExpressionValue = ReducerInterface.ExternalExpressionValue
|
||||
module ExpressionValue = ReducerInterface.InternalExpressionValue
|
||||
module Expression = Reducer_Expression
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
|
||||
let expectEvalToBe = (expr: string, answer: string) =>
|
||||
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
||||
let expectEvalToBe = (sourceCode: string, answer: string) =>
|
||||
Expression.BackCompatible.evaluateString(sourceCode)
|
||||
->ExpressionValue.toStringResult
|
||||
->expect
|
||||
->toBe(answer)
|
||||
|
||||
let testEval = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Reducer_Helpers
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExternalExpressionValue = ReducerInterface.ExternalExpressionValue
|
||||
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
|
@ -15,8 +14,4 @@ let removeDefaultsInternal = (iev: InternalExpressionValue.t) => {
|
|||
}
|
||||
}
|
||||
|
||||
let removeDefaultsExternal = (ev: ExternalExpressionValue.t): ExternalExpressionValue.t =>
|
||||
ev->InternalExpressionValue.toInternal->removeDefaultsInternal->InternalExpressionValue.toExternal
|
||||
|
||||
let rRemoveDefaultsInternal = r => Belt.Result.map(r, removeDefaultsInternal)
|
||||
let rRemoveDefaultsExternal = r => Belt.Result.map(r, removeDefaultsExternal)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module MathJs = Reducer_MathJs
|
||||
module ErrorValue = Reducer.ErrorValue
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
|
||||
open Jest
|
||||
open ExpectJs
|
||||
|
|
|
@ -3,241 +3,346 @@ open Reducer_Peggy_TestHelpers
|
|||
|
||||
describe("Peggy parse", () => {
|
||||
describe("float", () => {
|
||||
testParse("1.", "{1}")
|
||||
testParse("1.1", "{1.1}")
|
||||
testParse(".1", "{0.1}")
|
||||
testParse("0.1", "{0.1}")
|
||||
testParse("1e1", "{10}")
|
||||
testParse("1e-1", "{0.1}")
|
||||
testParse(".1e1", "{1}")
|
||||
testParse("0.1e1", "{1}")
|
||||
testParse("1.", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("1.1", "{(::$_endOfOuterBlock_$ () 1.1)}")
|
||||
testParse(".1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
||||
testParse("0.1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
||||
testParse("1e1", "{(::$_endOfOuterBlock_$ () 10)}")
|
||||
testParse("1e-1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
||||
testParse(".1e1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("0.1e1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
})
|
||||
|
||||
describe("literals operators parenthesis", () => {
|
||||
// Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement
|
||||
testParse("1", "{1}")
|
||||
testParse("'hello'", "{'hello'}")
|
||||
testParse("true", "{true}")
|
||||
testParse("1+2", "{(::add 1 2)}")
|
||||
testParse("add(1,2)", "{(::add 1 2)}")
|
||||
testParse("(1)", "{1}")
|
||||
testParse("(1+2)", "{(::add 1 2)}")
|
||||
testParse("1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("'hello'", "{(::$_endOfOuterBlock_$ () 'hello')}")
|
||||
testParse("true", "{(::$_endOfOuterBlock_$ () true)}")
|
||||
testParse("1+2", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||
testParse("add(1,2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||
testParse("(1)", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("(1+2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||
})
|
||||
|
||||
describe("unary", () => {
|
||||
testParse("-1", "{(::unaryMinus 1)}")
|
||||
testParse("!true", "{(::not true)}")
|
||||
testParse("1 + -1", "{(::add 1 (::unaryMinus 1))}")
|
||||
testParse("-a[0]", "{(::unaryMinus (::$_atIndex_$ :a 0))}")
|
||||
testParse("!a[0]", "{(::not (::$_atIndex_$ :a 0))}")
|
||||
testParse("-1", "{(::$_endOfOuterBlock_$ () (::unaryMinus 1))}")
|
||||
testParse("!true", "{(::$_endOfOuterBlock_$ () (::not true))}")
|
||||
testParse("1 + -1", "{(::$_endOfOuterBlock_$ () (::add 1 (::unaryMinus 1)))}")
|
||||
testParse("-a[0]", "{(::$_endOfOuterBlock_$ () (::unaryMinus (::$_atIndex_$ :a 0)))}")
|
||||
testParse("!a[0]", "{(::$_endOfOuterBlock_$ () (::not (::$_atIndex_$ :a 0)))}")
|
||||
})
|
||||
|
||||
describe("multiplicative", () => {
|
||||
testParse("1 * 2", "{(::multiply 1 2)}")
|
||||
testParse("1 / 2", "{(::divide 1 2)}")
|
||||
testParse("1 * 2 * 3", "{(::multiply (::multiply 1 2) 3)}")
|
||||
testParse("1 * 2 / 3", "{(::divide (::multiply 1 2) 3)}")
|
||||
testParse("1 / 2 * 3", "{(::multiply (::divide 1 2) 3)}")
|
||||
testParse("1 / 2 / 3", "{(::divide (::divide 1 2) 3)}")
|
||||
testParse("1 * 2 + 3 * 4", "{(::add (::multiply 1 2) (::multiply 3 4))}")
|
||||
testParse("1 * 2 - 3 * 4", "{(::subtract (::multiply 1 2) (::multiply 3 4))}")
|
||||
testParse("1 * 2 .+ 3 * 4", "{(::dotAdd (::multiply 1 2) (::multiply 3 4))}")
|
||||
testParse("1 * 2 .- 3 * 4", "{(::dotSubtract (::multiply 1 2) (::multiply 3 4))}")
|
||||
testParse("1 * 2 + 3 .* 4", "{(::add (::multiply 1 2) (::dotMultiply 3 4))}")
|
||||
testParse("1 * 2 + 3 / 4", "{(::add (::multiply 1 2) (::divide 3 4))}")
|
||||
testParse("1 * 2 + 3 ./ 4", "{(::add (::multiply 1 2) (::dotDivide 3 4))}")
|
||||
testParse("1 * 2 - 3 .* 4", "{(::subtract (::multiply 1 2) (::dotMultiply 3 4))}")
|
||||
testParse("1 * 2 - 3 / 4", "{(::subtract (::multiply 1 2) (::divide 3 4))}")
|
||||
testParse("1 * 2 - 3 ./ 4", "{(::subtract (::multiply 1 2) (::dotDivide 3 4))}")
|
||||
testParse("1 * 2 - 3 * 4^5", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5)))}")
|
||||
testParse("1 * 2", "{(::$_endOfOuterBlock_$ () (::multiply 1 2))}")
|
||||
testParse("1 / 2", "{(::$_endOfOuterBlock_$ () (::divide 1 2))}")
|
||||
testParse("1 * 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::multiply 1 2) 3))}")
|
||||
testParse("1 * 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::multiply 1 2) 3))}")
|
||||
testParse("1 / 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::divide 1 2) 3))}")
|
||||
testParse("1 / 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::divide 1 2) 3))}")
|
||||
testParse(
|
||||
"1 * 2 + 3 * 4",
|
||||
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::multiply 3 4)))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 - 3 * 4",
|
||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 4)))}",
|
||||
)
|
||||
testParse(
|
||||
"1 * 2 .+ 3 * 4",
|
||||
"{(::$_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(
|
||||
"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", () => {
|
||||
testParse("x=1; 2", "{:x = {1}; 2}")
|
||||
testParse("x=1; y=2", "{:x = {1}; :y = {2}}")
|
||||
testParse("x=1; 2", "{:x = {1}; (::$_endOfOuterBlock_$ () 2)}")
|
||||
testParse("x=1; y=2", "{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}")
|
||||
})
|
||||
|
||||
describe("variables", () => {
|
||||
testParse("x = 1", "{:x = {1}}")
|
||||
testParse("x", "{:x}")
|
||||
testParse("x = 1; x", "{:x = {1}; :x}")
|
||||
testParse("x = 1", "{:x = {1}; (::$_endOfOuterBlock_$ () ())}")
|
||||
testParse("x", "{(::$_endOfOuterBlock_$ () :x)}")
|
||||
testParse("x = 1; x", "{:x = {1}; (::$_endOfOuterBlock_$ () :x)}")
|
||||
})
|
||||
|
||||
describe("functions", () => {
|
||||
testParse("identity(x) = x", "{:identity = {|:x| {:x}}}") // Function definitions become lambda assignments
|
||||
testParse("identity(x)", "{(::identity :x)}")
|
||||
testParse("identity(x) = x", "{:identity = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions become lambda assignments
|
||||
testParse("identity(x)", "{(::$_endOfOuterBlock_$ () (::identity :x))}")
|
||||
})
|
||||
|
||||
describe("arrays", () => {
|
||||
testParse("[]", "{(::$_constructArray_$ ())}")
|
||||
testParse("[0, 1, 2]", "{(::$_constructArray_$ (0 1 2))}")
|
||||
testParse("['hello', 'world']", "{(::$_constructArray_$ ('hello' 'world'))}")
|
||||
testParse("([0,1,2])[1]", "{(::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1)}")
|
||||
testParse("[]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ ()))}")
|
||||
testParse("[0, 1, 2]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ (0 1 2)))}")
|
||||
testParse(
|
||||
"['hello', 'world']",
|
||||
"{(::$_endOfOuterBlock_$ () (::$_constructArray_$ ('hello' 'world')))}",
|
||||
)
|
||||
testParse(
|
||||
"([0,1,2])[1]",
|
||||
"{(::$_endOfOuterBlock_$ () (::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1))}",
|
||||
)
|
||||
})
|
||||
|
||||
describe("records", () => {
|
||||
testParse("{a: 1, b: 2}", "{(::$_constructRecord_$ ('a': 1 'b': 2))}")
|
||||
testParse("{1+0: 1, 2+0: 2}", "{(::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2))}") // key can be any expression
|
||||
testParse("record.property", "{(::$_atIndex_$ :record 'property')}")
|
||||
testParse(
|
||||
"{a: 1, b: 2}",
|
||||
"{(::$_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", () => {
|
||||
//function call, array and record access are post operators with higher priority than unary operators
|
||||
testParse("a==!b(1)", "{(::equal :a (::not (::b 1)))}")
|
||||
testParse("a==!b[1]", "{(::equal :a (::not (::$_atIndex_$ :b 1)))}")
|
||||
testParse("a==!b.one", "{(::equal :a (::not (::$_atIndex_$ :b 'one')))}")
|
||||
testParse("a==!b(1)", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::b 1))))}")
|
||||
testParse("a==!b[1]", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 1))))}")
|
||||
testParse(
|
||||
"a==!b.one",
|
||||
"{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 'one'))))}",
|
||||
)
|
||||
})
|
||||
|
||||
describe("comments", () => {
|
||||
testParse("1 # This is a line comment", "{1}")
|
||||
testParse("1 // This is a line comment", "{1}")
|
||||
testParse("1 /* This is a multi line comment */", "{1}")
|
||||
testParse("/* This is a multi line comment */ 1", "{1}")
|
||||
testParse("1 # This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("1 // This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("1 /* This is a multi line comment */", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse("/* This is a multi line comment */ 1", "{(::$_endOfOuterBlock_$ () 1)}")
|
||||
testParse(
|
||||
`
|
||||
/* This is
|
||||
a multi line
|
||||
comment */
|
||||
1`,
|
||||
"{1}",
|
||||
"{(::$_endOfOuterBlock_$ () 1)}",
|
||||
)
|
||||
})
|
||||
|
||||
describe("ternary operator", () => {
|
||||
testParse("true ? 2 : 3", "{(::$$_ternary_$$ true 2 3)}")
|
||||
testParse("true ? 2 : 3", "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true 2 3))}")
|
||||
testParse(
|
||||
"false ? 2 : false ? 4 : 5",
|
||||
"{(::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5))}",
|
||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5)))}",
|
||||
) // nested ternary
|
||||
})
|
||||
|
||||
describe("if then else", () => {
|
||||
testParse("if true then 2 else 3", "{(::$$_ternary_$$ true {2} {3})}")
|
||||
testParse("if false then {2} else {3}", "{(::$$_ternary_$$ false {2} {3})}")
|
||||
testParse(
|
||||
"if true then 2 else 3",
|
||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true {2} {3}))}",
|
||||
)
|
||||
testParse(
|
||||
"if false then {2} else {3}",
|
||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} {3}))}",
|
||||
)
|
||||
testParse(
|
||||
"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
|
||||
})
|
||||
|
||||
describe("logical", () => {
|
||||
testParse("true || false", "{(::or true false)}")
|
||||
testParse("true && false", "{(::and true false)}")
|
||||
testParse("a * b + c", "{(::add (::multiply :a :b) :c)}") // for comparison
|
||||
testParse("a && b || c", "{(::or (::and :a :b) :c)}")
|
||||
testParse("a && b || c && d", "{(::or (::and :a :b) (::and :c :d))}")
|
||||
testParse("a && !b || c", "{(::or (::and :a (::not :b)) :c)}")
|
||||
testParse("a && b==c || d", "{(::or (::and :a (::equal :b :c)) :d)}")
|
||||
testParse("a && b!=c || d", "{(::or (::and :a (::unequal :b :c)) :d)}")
|
||||
testParse("a && !(b==c) || d", "{(::or (::and :a (::not (::equal :b :c))) :d)}")
|
||||
testParse("a && b>=c || d", "{(::or (::and :a (::largerEq :b :c)) :d)}")
|
||||
testParse("a && !(b>=c) || d", "{(::or (::and :a (::not (::largerEq :b :c))) :d)}")
|
||||
testParse("a && b<=c || d", "{(::or (::and :a (::smallerEq :b :c)) :d)}")
|
||||
testParse("a && b>c || d", "{(::or (::and :a (::larger :b :c)) :d)}")
|
||||
testParse("a && b<c || d", "{(::or (::and :a (::smaller :b :c)) :d)}")
|
||||
testParse("a && b<c[i] || d", "{(::or (::and :a (::smaller :b (::$_atIndex_$ :c :i))) :d)}")
|
||||
testParse("a && b<c.i || d", "{(::or (::and :a (::smaller :b (::$_atIndex_$ :c 'i'))) :d)}")
|
||||
testParse("a && b<c(i) || d", "{(::or (::and :a (::smaller :b (::c :i))) :d)}")
|
||||
testParse("a && b<1+2 || d", "{(::or (::and :a (::smaller :b (::add 1 2))) :d)}")
|
||||
testParse("true || false", "{(::$_endOfOuterBlock_$ () (::or true false))}")
|
||||
testParse("true && false", "{(::$_endOfOuterBlock_$ () (::and true false))}")
|
||||
testParse("a * b + c", "{(::$_endOfOuterBlock_$ () (::add (::multiply :a :b) :c))}") // for comparison
|
||||
testParse("a && b || c", "{(::$_endOfOuterBlock_$ () (::or (::and :a :b) :c))}")
|
||||
testParse("a && b || c && d", "{(::$_endOfOuterBlock_$ () (::or (::and :a :b) (::and :c :d)))}")
|
||||
testParse("a && !b || c", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::not :b)) :c))}")
|
||||
testParse("a && b==c || d", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::equal :b :c)) :d))}")
|
||||
testParse(
|
||||
"a && b!=c || d",
|
||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::unequal :b :c)) :d))}",
|
||||
)
|
||||
testParse(
|
||||
"a && !(b==c) || d",
|
||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::not (::equal :b :c))) :d))}",
|
||||
)
|
||||
testParse(
|
||||
"a && b>=c || 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(
|
||||
"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(
|
||||
"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(
|
||||
"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", () => {
|
||||
testParse("1 -> add(2)", "{(::add 1 2)}")
|
||||
testParse("-1 -> add(2)", "{(::add (::unaryMinus 1) 2)}")
|
||||
testParse("-a[1] -> add(2)", "{(::add (::unaryMinus (::$_atIndex_$ :a 1)) 2)}")
|
||||
testParse("-f(1) -> add(2)", "{(::add (::unaryMinus (::f 1)) 2)}")
|
||||
testParse("1 + 2 -> add(3)", "{(::add 1 (::add 2 3))}")
|
||||
testParse("1 -> add(2) * 3", "{(::multiply (::add 1 2) 3)}")
|
||||
testParse("1 -> subtract(2)", "{(::subtract 1 2)}")
|
||||
testParse("-1 -> subtract(2)", "{(::subtract (::unaryMinus 1) 2)}")
|
||||
testParse("1 -> subtract(2) * 3", "{(::multiply (::subtract 1 2) 3)}")
|
||||
testParse("1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
||||
testParse("-1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus 1) 2))}")
|
||||
testParse(
|
||||
"-a[1] -> add(2)",
|
||||
"{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::$_atIndex_$ :a 1)) 2))}",
|
||||
)
|
||||
testParse("-f(1) -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::f 1)) 2))}")
|
||||
testParse("1 + 2 -> add(3)", "{(::$_endOfOuterBlock_$ () (::add 1 (::add 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", () => {
|
||||
//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", () => {
|
||||
testParse("1 to 2", "{(::credibleIntervalToDistribution 1 2)}")
|
||||
testParse("-1 to -2", "{(::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2))}") // lower than unary
|
||||
testParse("1 to 2", "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution 1 2))}")
|
||||
testParse(
|
||||
"-1 to -2",
|
||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2)))}",
|
||||
) // lower than unary
|
||||
testParse(
|
||||
"a[1] to a[2]",
|
||||
"{(::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2))}",
|
||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2)))}",
|
||||
) // lower than post
|
||||
testParse(
|
||||
"a.p1 to a.p2",
|
||||
"{(::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2'))}",
|
||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2')))}",
|
||||
) // lower than post
|
||||
testParse("1 to 2 + 3", "{(::add (::credibleIntervalToDistribution 1 2) 3)}") // higher than binary operators
|
||||
testParse(
|
||||
"1 to 2 + 3",
|
||||
"{(::$_endOfOuterBlock_$ () (::add (::credibleIntervalToDistribution 1 2) 3))}",
|
||||
) // higher than binary operators
|
||||
testParse(
|
||||
"1->add(2) to 3->add(4) -> add(4)",
|
||||
"{(::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4))}",
|
||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4)))}",
|
||||
) // lower than chain
|
||||
})
|
||||
|
||||
describe("inner block", () => {
|
||||
// inner blocks are 0 argument lambdas. They can be used whenever a value is required.
|
||||
// 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", () => {
|
||||
testParse("{|x| x}", "{{|:x| {:x}}}")
|
||||
testParse("f={|x| x}", "{:f = {{|:x| {:x}}}}")
|
||||
testParse("f(x)=x", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments
|
||||
testParse("f(x)=x ? 1 : 0", "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}") // Function definitions are lambda assignments
|
||||
testParse("{|x| x}", "{(::$_endOfOuterBlock_$ () {|:x| {:x}})}")
|
||||
testParse("f={|x| x}", "{:f = {{|:x| {:x}}}; (::$_endOfOuterBlock_$ () ())}")
|
||||
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)}}; (::$_endOfOuterBlock_$ () ())}",
|
||||
) // Function definitions are lambda assignments
|
||||
})
|
||||
|
||||
describe("Using lambda as value", () => {
|
||||
testParse(
|
||||
"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(
|
||||
"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(
|
||||
"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(
|
||||
"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(
|
||||
"[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", () => {
|
||||
testParse("1m", "{(::fromUnit_m 1)}")
|
||||
testParse("1M", "{(::fromUnit_M 1)}")
|
||||
testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}")
|
||||
testParse("1m", "{(::$_endOfOuterBlock_$ () (::fromUnit_m 1))}")
|
||||
testParse("1M", "{(::$_endOfOuterBlock_$ () (::fromUnit_M 1))}")
|
||||
testParse("1m+2cm", "{(::$_endOfOuterBlock_$ () (::add (::fromUnit_m 1) (::fromUnit_cm 2)))}")
|
||||
})
|
||||
describe("Module", () => {
|
||||
testParse("x", "{:x}")
|
||||
testParse("Math.pi", "{:Math.pi}")
|
||||
testParse("x", "{(::$_endOfOuterBlock_$ () :x)}")
|
||||
testParse("Math.pi", "{(::$_endOfOuterBlock_$ () :Math.pi)}")
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -246,19 +351,19 @@ describe("parsing new line", () => {
|
|||
`
|
||||
a +
|
||||
b`,
|
||||
"{(::add :a :b)}",
|
||||
"{(::$_endOfOuterBlock_$ () (::add :a :b))}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
x=
|
||||
1`,
|
||||
"{:x = {1}}",
|
||||
"{:x = {1}; (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
x=1
|
||||
y=2`,
|
||||
"{:x = {1}; :y = {2}}",
|
||||
"{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -266,7 +371,7 @@ describe("parsing new line", () => {
|
|||
y=2;
|
||||
y }
|
||||
x`,
|
||||
"{:x = {:y = {2}; :y}; :x}",
|
||||
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -274,7 +379,7 @@ describe("parsing new line", () => {
|
|||
y=2
|
||||
y }
|
||||
x`,
|
||||
"{:x = {:y = {2}; :y}; :x}",
|
||||
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -283,7 +388,7 @@ describe("parsing new line", () => {
|
|||
y
|
||||
}
|
||||
x`,
|
||||
"{:x = {:y = {2}; :y}; :x}",
|
||||
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -291,7 +396,7 @@ describe("parsing new line", () => {
|
|||
y=2
|
||||
z=3
|
||||
`,
|
||||
"{:x = {1}; :y = {2}; :z = {3}}",
|
||||
"{:x = {1}; :y = {2}; :z = {3}; (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -302,7 +407,7 @@ describe("parsing new line", () => {
|
|||
x+y+z
|
||||
}
|
||||
`,
|
||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}}",
|
||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -315,7 +420,7 @@ describe("parsing new line", () => {
|
|||
g=f+4
|
||||
g
|
||||
`,
|
||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; :g}",
|
||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () :g)}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -337,7 +442,7 @@ describe("parsing new line", () => {
|
|||
p ->
|
||||
q
|
||||
`,
|
||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::q (::p (::h :g)))}",
|
||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () (::q (::p (::h :g))))}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -346,7 +451,7 @@ describe("parsing new line", () => {
|
|||
c |>
|
||||
d
|
||||
`,
|
||||
"{(::d (::c (::b :a)))}",
|
||||
"{(::$_endOfOuterBlock_$ () (::d (::c (::b :a))))}",
|
||||
)
|
||||
testParse(
|
||||
`
|
||||
|
@ -356,6 +461,6 @@ describe("parsing new line", () => {
|
|||
d +
|
||||
e
|
||||
`,
|
||||
"{(::add (::d (::c (::b :a))) :e)}",
|
||||
"{(::$_endOfOuterBlock_$ () (::add (::d (::c (::b :a))) :e))}",
|
||||
)
|
||||
})
|
||||
|
|
|
@ -3,77 +3,83 @@ open Reducer_Peggy_TestHelpers
|
|||
|
||||
describe("Peggy parse type", () => {
|
||||
describe("type of", () => {
|
||||
testParse("p: number", "{(::$_typeOf_$ :p #number)}")
|
||||
testParse("p: number", "{(::$_typeOf_$ :p #number); (::$_endOfOuterBlock_$ () ())}")
|
||||
})
|
||||
describe("type alias", () => {
|
||||
testParse("type index=number", "{(::$_typeAlias_$ #index #number)}")
|
||||
testParse(
|
||||
"type index=number",
|
||||
"{(::$_typeAlias_$ #index #number); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
})
|
||||
describe("type or", () => {
|
||||
testParse(
|
||||
"answer: number|string",
|
||||
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string))))}",
|
||||
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string)))); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
})
|
||||
describe("type function", () => {
|
||||
testParse(
|
||||
"f: number=>number=>number",
|
||||
"{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}",
|
||||
"{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number)))); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
})
|
||||
describe("high priority contract", () => {
|
||||
testParse(
|
||||
"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(
|
||||
"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", () => {
|
||||
testParse(
|
||||
"answer: number | string $ opaque",
|
||||
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
||||
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string))))); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
})
|
||||
describe("type array", () => {
|
||||
testParse("answer: [number]", "{(::$_typeOf_$ :answer (::$_typeArray_$ #number))}")
|
||||
testParse(
|
||||
"answer: [number]",
|
||||
"{(::$_typeOf_$ :answer (::$_typeArray_$ #number)); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
})
|
||||
describe("type record", () => {
|
||||
testParse(
|
||||
"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", () => {
|
||||
testParse(
|
||||
"answer: Age(number)",
|
||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number))))}",
|
||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number)))); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
testParse(
|
||||
"answer: Complex(number, number)",
|
||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number))))}",
|
||||
"{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number)))); (::$_endOfOuterBlock_$ () ())}",
|
||||
)
|
||||
testParse(
|
||||
"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(
|
||||
"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", () => {
|
||||
//$ is introduced to avoid parenthesis
|
||||
testParse(
|
||||
"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", () => {
|
||||
testParse(
|
||||
"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 {
|
||||
let a2 =
|
||||
rExpr
|
||||
->Result.flatMap(expr =>
|
||||
Expression.reduceExpression(
|
||||
expr,
|
||||
ReducerInterface_StdLib.internalStdLib,
|
||||
ExpressionValue.defaultEnvironment,
|
||||
)
|
||||
)
|
||||
->Result.flatMap(expr => Expression.BackCompatible.evaluate(expr))
|
||||
->Reducer_Helpers.rRemoveDefaultsInternal
|
||||
->ExpressionValue.toStringResultOkless
|
||||
(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("literals operators parenthesis", () => {
|
||||
// Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement
|
||||
testToExpression("1", "{1}", ~v="1", ())
|
||||
testToExpression("'hello'", "{'hello'}", ~v="'hello'", ())
|
||||
testToExpression("true", "{true}", ~v="true", ())
|
||||
testToExpression("1+2", "{(:add 1 2)}", ~v="3", ())
|
||||
testToExpression("add(1,2)", "{(:add 1 2)}", ~v="3", ())
|
||||
testToExpression("(1)", "{1}", ())
|
||||
testToExpression("(1+2)", "{(:add 1 2)}", ())
|
||||
testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||
testToExpression("'hello'", "{(:$_endOfOuterBlock_$ () 'hello')}", ~v="'hello'", ())
|
||||
testToExpression("true", "{(:$_endOfOuterBlock_$ () true)}", ~v="true", ())
|
||||
testToExpression("1+2", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||
testToExpression("add(1,2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||
testToExpression("(1)", "{(:$_endOfOuterBlock_$ () 1)}", ())
|
||||
testToExpression("(1+2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ())
|
||||
})
|
||||
|
||||
describe("unary", () => {
|
||||
testToExpression("-1", "{(:unaryMinus 1)}", ~v="-1", ())
|
||||
testToExpression("!true", "{(:not true)}", ~v="false", ())
|
||||
testToExpression("1 + -1", "{(:add 1 (:unaryMinus 1))}", ~v="0", ())
|
||||
testToExpression("-a[0]", "{(:unaryMinus (:$_atIndex_$ :a 0))}", ())
|
||||
testToExpression("-1", "{(:$_endOfOuterBlock_$ () (:unaryMinus 1))}", ~v="-1", ())
|
||||
testToExpression("!true", "{(:$_endOfOuterBlock_$ () (:not true))}", ~v="false", ())
|
||||
testToExpression("1 + -1", "{(:$_endOfOuterBlock_$ () (:add 1 (:unaryMinus 1)))}", ~v="0", ())
|
||||
testToExpression("-a[0]", "{(:$_endOfOuterBlock_$ () (:unaryMinus (:$_atIndex_$ :a 0)))}", ())
|
||||
})
|
||||
|
||||
describe("multi-line", () => {
|
||||
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); 2}", ~v="2", ())
|
||||
testToExpression("x=1; y=2", "{(:$_let_$ :x {1}); (:$_let_$ :y {2})}", ~v="@{x: 1,y: 2}", ())
|
||||
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ())
|
||||
testToExpression(
|
||||
"x=1; y=2",
|
||||
"{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
||||
describe("variables", () => {
|
||||
testToExpression("x = 1", "{(:$_let_$ :x {1})}", ~v="@{x: 1}", ())
|
||||
testToExpression("x", "{:x}", ~v=":x", ()) //TODO: value should return error
|
||||
testToExpression("x = 1; x", "{(:$_let_$ :x {1}); :x}", ~v="1", ())
|
||||
testToExpression("x = 1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ())
|
||||
testToExpression("x", "{(:$_endOfOuterBlock_$ () :x)}", ~v="Error(x is not defined)", ()) //TODO: value should return error
|
||||
testToExpression("x = 1; x", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () :x)}", ~v="1", ())
|
||||
})
|
||||
|
||||
describe("functions", () => {
|
||||
testToExpression(
|
||||
"identity(x) = x",
|
||||
"{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x}))}",
|
||||
~v="@{identity: lambda(x=>internal code)}",
|
||||
"{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}",
|
||||
(),
|
||||
) // 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(
|
||||
"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",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
||||
describe("arrays", () => {
|
||||
testToExpression("[]", "{(:$_constructArray_$ ())}", ~v="[]", ())
|
||||
testToExpression("[0, 1, 2]", "{(:$_constructArray_$ (0 1 2))}", ~v="[0,1,2]", ())
|
||||
testToExpression("[]", "{(:$_endOfOuterBlock_$ () (:$_constructArray_$ ()))}", ~v="[]", ())
|
||||
testToExpression(
|
||||
"[0, 1, 2]",
|
||||
"{(:$_endOfOuterBlock_$ () (:$_constructArray_$ (0 1 2)))}",
|
||||
~v="[0,1,2]",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"['hello', 'world']",
|
||||
"{(:$_constructArray_$ ('hello' 'world'))}",
|
||||
"{(:$_endOfOuterBlock_$ () (:$_constructArray_$ ('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", () => {
|
||||
testToExpression(
|
||||
"{a: 1, b: 2}",
|
||||
"{(:$_constructRecord_$ (('a' 1) ('b' 2)))}",
|
||||
"{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (('a' 1) ('b' 2))))}",
|
||||
~v="{a: 1,b: 2}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"{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
|
||||
testToExpression("record.property", "{(:$_atIndex_$ :record 'property')}", ())
|
||||
testToExpression(
|
||||
"record.property",
|
||||
"{(:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"record={property: 1}; record.property",
|
||||
"{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_atIndex_$ :record 'property')}",
|
||||
"{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
||||
describe("comments", () => {
|
||||
testToExpression("1 # This is a line comment", "{1}", ~v="1", ())
|
||||
testToExpression("1 // This is a line comment", "{1}", ~v="1", ())
|
||||
testToExpression("1 /* This is a multi line comment */", "{1}", ~v="1", ())
|
||||
testToExpression("/* This is a multi line comment */ 1", "{1}", ~v="1", ())
|
||||
testToExpression("1 # This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||
testToExpression("1 // This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
||||
testToExpression(
|
||||
"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", () => {
|
||||
testToExpression("true ? 1 : 0", "{(:$$_ternary_$$ true 1 0)}", ~v="1", ())
|
||||
testToExpression("false ? 1 : 0", "{(:$$_ternary_$$ false 1 0)}", ~v="0", ())
|
||||
testToExpression(
|
||||
"true ? 1 : 0",
|
||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 0))}",
|
||||
~v="1",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"false ? 1 : 0",
|
||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 0))}",
|
||||
~v="0",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"true ? 1 : false ? 2 : 0",
|
||||
"{(:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0))}",
|
||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0)))}",
|
||||
~v="1",
|
||||
(),
|
||||
) // nested ternary
|
||||
testToExpression(
|
||||
"false ? 1 : false ? 2 : 0",
|
||||
"{(:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0))}",
|
||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0)))}",
|
||||
~v="0",
|
||||
(),
|
||||
) // nested ternary
|
||||
|
@ -109,21 +146,21 @@ describe("Peggy to Expression", () => {
|
|||
testToExpression(
|
||||
// expression binding
|
||||
"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",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
// when true binding
|
||||
"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",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
// when false binding
|
||||
"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",
|
||||
(),
|
||||
)
|
||||
|
@ -131,23 +168,41 @@ describe("Peggy to Expression", () => {
|
|||
})
|
||||
|
||||
describe("if then else", () => {
|
||||
testToExpression("if true then 2 else 3", "{(:$$_ternary_$$ true {2} {3})}", ())
|
||||
testToExpression("if true then {2} else {3}", "{(:$$_ternary_$$ true {2} {3})}", ())
|
||||
testToExpression(
|
||||
"if true then 2 else 3",
|
||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"if true then {2} else {3}",
|
||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"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
|
||||
})
|
||||
|
||||
describe("pipe", () => {
|
||||
testToExpression("1 -> add(2)", "{(:add 1 2)}", ~v="3", ())
|
||||
testToExpression("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}", ~v="1", ()) // note that unary has higher priority naturally
|
||||
testToExpression("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}", ~v="9", ())
|
||||
testToExpression("1 -> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
||||
testToExpression(
|
||||
"-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", () => {
|
||||
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
|
||||
|
@ -157,30 +212,31 @@ describe("Peggy to Expression", () => {
|
|||
// Like lambdas they have a local scope.
|
||||
testToExpression(
|
||||
"y=99; x={y=1; y}",
|
||||
"{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y})}",
|
||||
~v="@{x: 1,y: 99}",
|
||||
"{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y}); (:$_endOfOuterBlock_$ () ())}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
||||
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(
|
||||
"f={|x| x}",
|
||||
"{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})})}",
|
||||
~v="@{f: lambda(x=>internal code)}",
|
||||
"{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})}); (:$_endOfOuterBlock_$ () ())}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"f(x)=x",
|
||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {:x}))}",
|
||||
~v="@{f: lambda(x=>internal code)}",
|
||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}",
|
||||
(),
|
||||
) // Function definitions are lambda assignments
|
||||
testToExpression(
|
||||
"f(x)=x ? 1 : 0",
|
||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)}))}",
|
||||
~v="@{f: lambda(x=>internal code)}",
|
||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)})); (:$_endOfOuterBlock_$ () ())}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
@ -194,6 +250,6 @@ describe("Peggy to Expression", () => {
|
|||
// ->expect
|
||||
// ->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", () => {
|
||||
testToExpression(
|
||||
"p: number",
|
||||
"{(:$_typeOf_$ :p #number)}",
|
||||
~v="@{_typeReferences_: {p: #number}}",
|
||||
"{(:$_typeOf_$ :p #number); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {p: #number}}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
describe("type alias", () => {
|
||||
testToExpression(
|
||||
"type index=number",
|
||||
"{(:$_typeAlias_$ #index #number)}",
|
||||
~v="@{_typeAliases_: {index: #number}}",
|
||||
"{(:$_typeAlias_$ #index #number); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeAliases_: {index: #number}}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
describe("type or", () => {
|
||||
testToExpression(
|
||||
"answer: number|string|distribution",
|
||||
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution))))}",
|
||||
~v="@{_typeReferences_: {answer: {typeOr: [#number,#string,#distribution],typeTag: 'typeOr'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution)))); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {typeOr: [#number,#string,#distribution],typeTag: 'typeOr'}}}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
describe("type function", () => {
|
||||
testToExpression(
|
||||
"f: number=>number=>number",
|
||||
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number))))}",
|
||||
~v="@{_typeReferences_: {f: {inputs: [#number,#number],output: #number,typeTag: 'typeFunction'}}}",
|
||||
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number)))); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {f: {inputs: [#number,#number],output: #number,typeTag: 'typeFunction'}}}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"f: number=>number",
|
||||
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number))))}",
|
||||
~v="@{_typeReferences_: {f: {inputs: [#number],output: #number,typeTag: 'typeFunction'}}}",
|
||||
"{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number)))); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {f: {inputs: [#number],output: #number,typeTag: 'typeFunction'}}}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
describe("high priority contract", () => {
|
||||
testToExpression(
|
||||
"answer: number<-min(1)<-max(100)|string",
|
||||
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}",
|
||||
~v="@{_typeReferences_: {answer: {typeOr: [{max: 100,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'},#string],typeTag: 'typeOr'}}}",
|
||||
"{(:$_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'}}}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"answer: number<-memberOf([1,3,5])",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5))))}",
|
||||
~v="@{_typeReferences_: {answer: {memberOf: [1,3,5],typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5)))); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {memberOf: [1,3,5],typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"answer: number<-min(1)",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1))}",
|
||||
~v="@{_typeReferences_: {answer: {min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1)); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"answer: number<-max(10)",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10))}",
|
||||
~v="@{_typeReferences_: {answer: {max: 10,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10)); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {max: 10,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"answer: number<-min(1)<-max(10)",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10))}",
|
||||
~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10)); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
(),
|
||||
)
|
||||
testToExpression(
|
||||
"answer: number<-max(10)<-min(1)",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1))}",
|
||||
~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1)); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {max: 10,min: 1,typeIdentifier: #number,typeTag: 'typeIdentifier'}}}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
describe("low priority contract", () => {
|
||||
testToExpression(
|
||||
"answer: number | string $ opaque",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}",
|
||||
~v="@{_typeReferences_: {answer: {opaque: true,typeOr: [#number,#string],typeTag: 'typeOr'}}}",
|
||||
"{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string))))); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_typeReferences_: {answer: {opaque: true,typeOr: [#number,#string],typeTag: 'typeOr'}}}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
describe("squiggle expressions in type contracts", () => {
|
||||
testToExpression(
|
||||
"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)))}",
|
||||
~v="@{_typeAliases_: {odds: {memberOf: [1,3,5,7,9],typeIdentifier: #number,typeTag: 'typeIdentifier'}},odds1: [1,3,5],odds2: [7,9]}",
|
||||
"{(:$_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]}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -3,18 +3,23 @@ open Reducer_Peggy_TestHelpers
|
|||
|
||||
describe("Peggy void", () => {
|
||||
//literal
|
||||
testToExpression("()", "{()}", ~v="()", ())
|
||||
testToExpression("()", "{(:$_endOfOuterBlock_$ () ())}", ~v="()", ())
|
||||
testToExpression(
|
||||
"fn()=1",
|
||||
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1}))}",
|
||||
~v="@{fn: lambda(_=>internal code)}",
|
||||
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~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(
|
||||
"fn(a)=(); call fn(1)",
|
||||
"{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)})}",
|
||||
~v="@{_: (),fn: lambda(a=>internal code)}",
|
||||
"{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)}); (:$_endOfOuterBlock_$ () ())}",
|
||||
// ~v="@{_: (),fn: lambda(a=>internal code)}",
|
||||
(),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module ExpressionT = Reducer_Expression_T
|
||||
module ExternalExpressionValue = ReducerInterface.ExternalExpressionValue
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module Expression = Reducer_Expression
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
|
@ -8,30 +9,26 @@ open Expect
|
|||
let unwrapRecord = rValue =>
|
||||
rValue->Belt.Result.flatMap(value =>
|
||||
switch value {
|
||||
| ExternalExpressionValue.EvRecord(aRecord) => Ok(aRecord)
|
||||
| _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error
|
||||
| InternalExpressionValue.IEvRecord(aRecord) => Ok(aRecord)
|
||||
| _ => ErrorValue.RETodo("TODO: Internal bindings must be returned")->Error
|
||||
}
|
||||
)
|
||||
|
||||
let expectParseToBe = (expr: string, answer: string) =>
|
||||
Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer)
|
||||
let expectParseToBe = (code: string, answer: string) =>
|
||||
Expression.BackCompatible.parse(code)->ExpressionT.toStringResult->expect->toBe(answer)
|
||||
|
||||
let expectEvalToBe = (expr: string, answer: string) =>
|
||||
Reducer.evaluate(expr)
|
||||
->Reducer_Helpers.rRemoveDefaultsExternal
|
||||
->ExternalExpressionValue.toStringResult
|
||||
let expectEvalToBe = (code: string, answer: string) =>
|
||||
Expression.BackCompatible.evaluateString(code)
|
||||
->Reducer_Helpers.rRemoveDefaultsInternal
|
||||
->InternalExpressionValue.toStringResult
|
||||
->expect
|
||||
->toBe(answer)
|
||||
|
||||
let expectEvalError = (expr: string) =>
|
||||
Reducer.evaluate(expr)->ExternalExpressionValue.toStringResult->expect->toMatch("Error\(")
|
||||
|
||||
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
||||
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None)
|
||||
->Reducer_Helpers.rRemoveDefaultsExternal
|
||||
->ExternalExpressionValue.toStringResult
|
||||
let expectEvalError = (code: string) =>
|
||||
Expression.BackCompatible.evaluateString(code)
|
||||
->InternalExpressionValue.toStringResult
|
||||
->expect
|
||||
->toBe(answer)
|
||||
->toMatch("Error\(")
|
||||
|
||||
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
||||
let testDescriptionParseToBe = (desc, expr, answer) =>
|
||||
|
@ -40,18 +37,12 @@ let testDescriptionParseToBe = (desc, expr, answer) =>
|
|||
let testEvalError = expr => test(expr, () => expectEvalError(expr))
|
||||
let testEvalToBe = (expr, answer) => test(expr, () => 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 = {
|
||||
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(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 = {
|
||||
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(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 Expect
|
||||
|
||||
module Bindings = Reducer_Bindings
|
||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||
module Expression = Reducer_Expression
|
||||
// module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
||||
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
||||
module Macro = Reducer_Expression_Macro
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module T = Reducer_Expression_T
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
let testMacro_ = (
|
||||
tester,
|
||||
|
@ -21,8 +21,8 @@ let testMacro_ = (
|
|||
expr
|
||||
->Macro.expandMacroCall(
|
||||
bindings,
|
||||
InternalExpressionValue.defaultEnvironment,
|
||||
Expression.reduceExpression,
|
||||
ProjectAccessorsT.identityAccessors,
|
||||
Expression.reduceExpressionInProject,
|
||||
)
|
||||
->ExpressionWithContext.toStringResult
|
||||
->expect
|
||||
|
@ -41,8 +41,8 @@ let testMacroEval_ = (
|
|||
expr
|
||||
->Macro.doMacroCall(
|
||||
bindings,
|
||||
InternalExpressionValue.defaultEnvironment,
|
||||
Expression.reduceExpression,
|
||||
ProjectAccessorsT.identityAccessors,
|
||||
Expression.reduceExpressionInProject,
|
||||
)
|
||||
->InternalExpressionValue.toStringResult
|
||||
->expect
|
||||
|
|
|
@ -8,7 +8,7 @@ open Jest
|
|||
open Expect
|
||||
|
||||
let myIevEval = (aTypeSourceCode: string) =>
|
||||
TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpression)
|
||||
TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpressionInProject)
|
||||
let myIevEvalToString = (aTypeSourceCode: string) =>
|
||||
myIevEval(aTypeSourceCode)->InternalExpressionValue.toStringResult
|
||||
|
||||
|
@ -19,7 +19,7 @@ let myIevTest = (test, aTypeSourceCode, answer) =>
|
|||
test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer))
|
||||
|
||||
let myTypeEval = (aTypeSourceCode: string) =>
|
||||
TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpression)
|
||||
TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpressionInProject)
|
||||
let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode)->T.toStringResult
|
||||
|
||||
let myTypeExpectEqual = (aTypeSourceCode, answer) =>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module Expression = Reducer_Expression
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Bindings = Reducer_Bindings
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module T = Reducer_Type_T
|
||||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
|
||||
|
@ -13,10 +14,10 @@ let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): re
|
|||
'v,
|
||||
ErrorValue.t,
|
||||
> => {
|
||||
let reducerFn = Expression.reduceExpression
|
||||
let reducerFn = Expression.reduceExpressionInProject
|
||||
let rResult =
|
||||
Reducer.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||
reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment)
|
||||
Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
||||
)
|
||||
rResult->Belt.Result.flatMap(result =>
|
||||
switch result {
|
||||
|
|
|
@ -5,6 +5,7 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|||
module Bindings = Reducer_Bindings
|
||||
module T = Reducer_Type_T
|
||||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
|
@ -16,10 +17,10 @@ let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result<
|
|||
'v,
|
||||
ErrorValue.t,
|
||||
> => {
|
||||
let reducerFn = Expression.reduceExpression
|
||||
let reducerFn = Expression.reduceExpressionInProject
|
||||
let rResult =
|
||||
Reducer.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||
reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment)
|
||||
Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
||||
)
|
||||
rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn))
|
||||
}
|
||||
|
|
|
@ -4,8 +4,11 @@ open Expect
|
|||
module DispatchT = Reducer_Dispatch_T
|
||||
module Expression = Reducer_Expression
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module TypeCompile = Reducer_Type_Compile
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
module TypeCompile = Reducer_Type_Compile
|
||||
|
||||
open ReducerInterface_InternalExpressionValue
|
||||
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
|
@ -14,13 +17,14 @@ type errorValue = Reducer_ErrorValue.errorValue
|
|||
// In dispatchChainPiece, we execute an return the result of execution if there is a type match.
|
||||
// Otherwise we return None so that the call chain can continue.
|
||||
// So we want to build a function like
|
||||
// dispatchChainPiece = (call: functionCall, environment): option<result<internalExpressionValue, errorValue>>
|
||||
// dispatchChainPiece = (call: functionCall, accessors): option<result<internalExpressionValue, errorValue>>
|
||||
// Use accessors.environment to get the environment finally.
|
||||
|
||||
// Now lets make the dispatchChainPiece itself.
|
||||
// Note that I am not passing the reducer to the dispatchChainPiece as an argument because it is in the context anyway.
|
||||
// Keep in mind that reducerFn is necessary for map/reduce so dispatchChainPiece should have a reducerFn in context.
|
||||
|
||||
let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispatchChainPiece => {
|
||||
let makeMyDispatchChainPiece = (reducer: ProjectReducerFnT.t): DispatchT.dispatchChainPiece => {
|
||||
// Let's have a pure implementations
|
||||
module Implementation = {
|
||||
let stringConcat = (a: string, b: string): string => Js.String2.concat(a, b)
|
||||
|
@ -45,15 +49,15 @@ let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispa
|
|||
|
||||
// Let's bridge the pure implementation to expression values
|
||||
module Bridge = {
|
||||
let stringConcat: DispatchT.genericIEvFunction = (args, _environment) => {
|
||||
let stringConcat: DispatchT.genericIEvFunction = (args, _accessors: ProjectAccessorsT.t) => {
|
||||
let (a, b) = extractStringString(args)
|
||||
Implementation.stringConcat(a, b)->IEvString->Ok
|
||||
}
|
||||
let arrayConcat: DispatchT.genericIEvFunction = (args, _environment) => {
|
||||
let arrayConcat: DispatchT.genericIEvFunction = (args, _accessors: ProjectAccessorsT.t) => {
|
||||
let (a, b) = extractArrayArray(args)
|
||||
Implementation.arrayConcat(a, b)->IEvArray->Ok
|
||||
}
|
||||
let plot: DispatchT.genericIEvFunction = (args, _environment) => {
|
||||
let plot: DispatchT.genericIEvFunction = (args, _accessors: ProjectAccessorsT.t) => {
|
||||
switch args {
|
||||
// Just assume that we are doing the business of extracting and converting the deep record
|
||||
| [IEvRecord(_)] => Implementation.plot({"title": "This is a plot"})->IEvString->Ok
|
||||
|
@ -98,12 +102,12 @@ let makeMyDispatchChainPiece = (reducer: ExpressionT.reducerFn): DispatchT.dispa
|
|||
// Exactly the same as the one used in real life
|
||||
let _dispatch = (
|
||||
call: functionCall,
|
||||
environment,
|
||||
reducer: Reducer_Expression_T.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
chain,
|
||||
): result<internalExpressionValue, 'e> => {
|
||||
let dispatchChainPiece = makeMyDispatchChainPiece(reducer)
|
||||
dispatchChainPiece(call, environment)->E.O2.defaultFn(() => chain(call, environment, reducer))
|
||||
dispatchChainPiece(call, accessors)->E.O2.defaultFn(() => chain(call, accessors, reducer))
|
||||
}
|
||||
|
||||
// What is important about this implementation?
|
||||
|
@ -112,12 +116,12 @@ let _dispatch = (
|
|||
// B) Complicated recursive record types are not a problem.
|
||||
|
||||
describe("Type Dispatch", () => {
|
||||
let reducerFn = Expression.reduceExpression
|
||||
let reducerFn = Expression.reduceExpressionInProject
|
||||
let dispatchChainPiece = makeMyDispatchChainPiece(reducerFn)
|
||||
test("stringConcat", () => {
|
||||
let call: functionCall = ("concat", [IEvString("hello"), IEvString("world")])
|
||||
|
||||
let result = dispatchChainPiece(call, defaultEnvironment)
|
||||
let result = dispatchChainPiece(call, ProjectAccessorsT.identityAccessors)
|
||||
expect(result)->toEqual(Some(Ok(IEvString("helloworld"))))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
||||
describe("Parse function assignment", () => {
|
||||
testParseToBe("f(x)=x", "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {:x}))})")
|
||||
testParseToBe("f(x)=2*x", "Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {(:multiply 2 :x)}))})")
|
||||
testParseToBe(
|
||||
"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
|
||||
})
|
||||
|
||||
|
|
|
@ -39,33 +39,27 @@ describe("symbol not defined", () => {
|
|||
})
|
||||
|
||||
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=1;y=2", "Ok(@{f: 1,y: 2})")
|
||||
testEvalToBe("f(x)=x+1; y=f(1)", "Ok(@{f: lambda(x=>internal code),y: 2})")
|
||||
testEvalToBe("f=1;y=2", "Ok(())")
|
||||
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); z=f(1)", "Ok(@{f: lambda(x=>internal code),y: 2,z: 2})")
|
||||
testEvalToBe(
|
||||
"f(x)=x+1; g(x)=f(x)+1",
|
||||
"Ok(@{f: lambda(x=>internal code),g: lambda(x=>internal code)})",
|
||||
)
|
||||
testEvalToBe("f(x)=x+1; y=f(1); z=f(1); z", "Ok(2)")
|
||||
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(0)", "Ok(2)")
|
||||
testParseToBe(
|
||||
"f=99; g(x)=f; g(2)",
|
||||
"Ok({(:$_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(x)=x; g(x)=f(x); g(2)", "Ok(2)")
|
||||
testEvalToBe(
|
||||
"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; y=g(2); y", "Ok(4)")
|
||||
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)")
|
||||
})
|
||||
|
||||
describe("function tricks", () => {
|
||||
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)=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+x; f(1,2)", "????") // TODO: Duplicate parameters
|
||||
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", () => {
|
||||
testEvalToBe(
|
||||
"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]", "Ok(())")
|
||||
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("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
|
||||
|
||||
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", () => {
|
||||
|
|
|
@ -48,7 +48,7 @@ describe("eval", () => {
|
|||
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
||||
testEvalError("1; x=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("power", () => {
|
||||
testParse("normal(5,2) ^ normal(5,1)", "Ok({(:pow (:normal 5 2) (:normal 5 1))})")
|
||||
testParse("3 ^ normal(5,1)", "Ok({(:pow 3 (:normal 5 1))})")
|
||||
testParse("normal(5,2) ^ 3", "Ok({(:pow (:normal 5 2) 3)})")
|
||||
testParse(
|
||||
"normal(5,2) ^ normal(5,1)",
|
||||
"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", () => {
|
||||
testParse("10 - normal(5,1)", "Ok({(:subtract 10 (:normal 5 1))})")
|
||||
testParse("normal(5,1) - 10", "Ok({(:subtract (:normal 5 1) 10)})")
|
||||
testParse("10 - normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:subtract 10 (:normal 5 1)))})")
|
||||
testParse("normal(5,1) - 10", "Ok({(:$_endOfOuterBlock_$ () (:subtract (:normal 5 1) 10))})")
|
||||
})
|
||||
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((:$$_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))})"
|
||||
)
|
||||
testParse("normal(5,2) .* normal(5,1)", "Ok({(:dotMultiply (:normal 5 2) (:normal 5 1))})")
|
||||
testParse("normal(5,2) ./ normal(5,1)", "Ok({(:dotDivide (:normal 5 2) (:normal 5 1))})")
|
||||
testParse("normal(5,2) .^ normal(5,1)", "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})")
|
||||
testParse(
|
||||
"normal(5,2) .* normal(5,1)",
|
||||
"Ok({(:$_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", () => {
|
||||
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", () => {
|
||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
open ReducerInterface.ExternalExpressionValue
|
||||
open ReducerInterface.InternalExpressionValue
|
||||
open Jest
|
||||
open Expect
|
||||
|
||||
describe("ExpressionValue", () => {
|
||||
test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1,'a'"))
|
||||
test("argsToString", () => expect([IEvNumber(1.), IEvString("a")]->argsToString)->toBe("1,'a'"))
|
||||
|
||||
test("toStringFunctionCall", () =>
|
||||
expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')")
|
||||
expect(("fn", [IEvNumber(1.), IEvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')")
|
||||
)
|
||||
})
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
Only.describe("Parse includes", () => {
|
||||
let project = Project.createProject()
|
||||
Project.setSource(
|
||||
project,
|
||||
"main",
|
||||
`
|
||||
#include 'common'
|
||||
x=1`,
|
||||
)
|
||||
Project.parseIncludes(project, "main")
|
||||
test("dependencies", () => {
|
||||
expect(Project.getDependencies(project, "main")) == ["common"]
|
||||
})
|
||||
test("dependents", () => {
|
||||
expect(Project.getDependents(project, "main")) == []
|
||||
})
|
||||
test("getIncludes", () => {
|
||||
let mainIncludes = Project.getIncludes(project, "main")
|
||||
switch mainIncludes {
|
||||
| Ok(includes) => expect(includes) == ["common"]
|
||||
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,174 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
// test("", () => expect(1)->toBe(1))
|
||||
|
||||
let runFetchResult = (project, sourceId) => {
|
||||
Project.run(project, sourceId)
|
||||
Project.getResult(project, sourceId)->InternalExpressionValue.toStringResult
|
||||
}
|
||||
|
||||
let runFetchBindings = (project, sourceId) => {
|
||||
Project.run(project, sourceId)
|
||||
Project.getBindings(project, sourceId)
|
||||
->InternalExpressionValue.IEvBindings
|
||||
->InternalExpressionValue.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}")
|
||||
})
|
||||
})
|
|
@ -0,0 +1,109 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
describe("ReducerProject Tutorial", () => {
|
||||
describe("Single source", () => {
|
||||
/*
|
||||
Case "Running a single source".
|
||||
*/
|
||||
test("run", () => {
|
||||
/* Let's start with running a single source and getting Result as well as the Bindings
|
||||
First you need to create a project. A project is a collection of sources.
|
||||
Project takes care of the dependencies between the sources, correct compilation and run order.
|
||||
You can run any source in the project. It will be compiled and run if it is not already done else already existing results will be presented.
|
||||
The dependencies will be automatically compiled and run. So you don't need to worry about that in a multi source project.
|
||||
In summary you issue a run command on the whole project or on a specific source to ensure that there is a result for that source.
|
||||
*/
|
||||
let project = Project.createProject()
|
||||
/* Every source has a name. This is used for debugging, dependencies and error messages. */
|
||||
Project.setSource(project, "main", "1 + 2")
|
||||
/* Let's run "main" source. */
|
||||
project->Project.run("main")
|
||||
/* Now you have a result for "main" source.
|
||||
Running one by one is necessary for UI to navigate among the sources and to see the results by source.
|
||||
And you're free to run any source you want.
|
||||
You will look at the results of this source and you don't want to run the others if not required.
|
||||
*/
|
||||
|
||||
/* However, you could also run the whole project.
|
||||
If you have all the sources, you can always run the whole project.
|
||||
Dependencies and recompiling on demand will be taken care of by the project.
|
||||
*/
|
||||
project->Project.runAll
|
||||
|
||||
/* Either with run or runAll you executed the project.
|
||||
You can get the result of a specific source by calling getResult for that source.
|
||||
You can get the bindings of a specific source by calling getBindings for that source.
|
||||
If there is any runtime error, getResult will return the error.
|
||||
|
||||
Note that getResult returns None if the source has not been run.
|
||||
Getting None means you have forgotten to run the source.
|
||||
*/
|
||||
let result = project->Project.getResult("main")
|
||||
let bindings = project->Project.getBindings("main")
|
||||
|
||||
/* Let's display the result and bindings */
|
||||
(
|
||||
result->InternalExpressionValue.toStringResult,
|
||||
bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(3)", "@{}")
|
||||
/* You've got 3 with empty bindings. */
|
||||
})
|
||||
|
||||
test("run summary", () => {
|
||||
let project = Project.createProject()
|
||||
Project.setSource(project, "main", "1 + 2")
|
||||
Project.runAll(project)
|
||||
let result = Project.getResult(project, "main")
|
||||
let bindings = Project.getBindings(project, "main")
|
||||
/* Now you have external bindings and external result. */
|
||||
(
|
||||
result->InternalExpressionValue.toStringResult,
|
||||
bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(3)", "@{}")
|
||||
})
|
||||
|
||||
test("run with an environment", () => {
|
||||
/* Running the source code like above allows you to set a custom environment */
|
||||
let project = Project.createProject()
|
||||
|
||||
/* Optional. Set your custom environment anytime before running */
|
||||
Project.setEnvironment(project, InternalExpressionValue.defaultEnvironment)
|
||||
|
||||
Project.setSource(project, "main", "1 + 2")
|
||||
Project.runAll(project)
|
||||
let result = Project.getResult(project, "main")
|
||||
let _bindings = Project.getBindings(project, "main")
|
||||
result->InternalExpressionValue.toStringResult->expect == "Ok(3)"
|
||||
})
|
||||
|
||||
test("shortcut", () => {
|
||||
/* If you are running single source without includes and you don't need a custom environment, you can use the shortcut. */
|
||||
/* Examples above was to prepare you for the multi source tutorial. */
|
||||
let (result, bindings) = Project.evaluate("1+2")
|
||||
(
|
||||
result->InternalExpressionValue.toStringResult,
|
||||
bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(3)", "@{}")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
//TODO multiple sources
|
||||
//TODO multiple sources with includes. Introduction to includes
|
||||
//TODO multiple sources with multi level includes. Cycle detection
|
||||
//TODO
|
||||
//TODO: Implement a runOrder consideration - clean results based on run order.
|
||||
//TODO: runOrder vs setSource/touchSource
|
||||
//TODO: Advanced details: (below)
|
||||
//TODO runOrder. includes vs continues. Run order based reexecution
|
||||
//TODO: dependents and reexecution
|
||||
//TODO: dependencies and reexecution
|
||||
//TODO: cleanAllResults clean
|
||||
//TODO: cleanAll clean
|
|
@ -0,0 +1,112 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
describe("ReducerProject Tutorial", () => {
|
||||
describe("Multi source", () => {
|
||||
/*
|
||||
Case "Running multiple sources" */
|
||||
test("Chaining", () => {
|
||||
let project = Project.createProject()
|
||||
/* This time let's add 3 sources and chain them together */
|
||||
Project.setSource(project, "source1", "x=1")
|
||||
|
||||
Project.setSource(project, "source2", "y=2")
|
||||
/* To run, source2 depends on source1 */
|
||||
Project.setContinues(project, "source2", ["source1"])
|
||||
|
||||
Project.setSource(project, "source3", "z=3")
|
||||
/* To run, source3 depends on source2 */
|
||||
Project.setContinues(project, "source3", ["source2"])
|
||||
|
||||
/* Now we can run the project */
|
||||
Project.runAll(project)
|
||||
|
||||
/* And let's check the result and bindings of source3 */
|
||||
let result3 = Project.getResult(project, "source3")
|
||||
let bindings3 = Project.getBindings(project, "source3")
|
||||
|
||||
(
|
||||
result3->InternalExpressionValue.toStringResult,
|
||||
bindings3->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}")
|
||||
})
|
||||
|
||||
test("Depending", () => {
|
||||
/* Instead of chaining the sources, we could have a dependency tree */
|
||||
/* The point here is that any source can depend on multiple sources */
|
||||
let project = Project.createProject()
|
||||
|
||||
/* This time source1 and source2 are not depending on anything */
|
||||
Project.setSource(project, "source1", "x=1")
|
||||
Project.setSource(project, "source2", "y=2")
|
||||
|
||||
Project.setSource(project, "source3", "z=3")
|
||||
/* To run, source3 depends on source1 and source3 together */
|
||||
Project.setContinues(project, "source3", ["source1", "source2"])
|
||||
|
||||
/* Now we can run the project */
|
||||
Project.runAll(project)
|
||||
|
||||
/* And let's check the result and bindings of source3 */
|
||||
let result3 = Project.getResult(project, "source3")
|
||||
let bindings3 = Project.getBindings(project, "source3")
|
||||
|
||||
(
|
||||
result3->InternalExpressionValue.toStringResult,
|
||||
bindings3->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}")
|
||||
})
|
||||
|
||||
test("Intro to including", () => {
|
||||
/* Though it would not be practical for a storybook,
|
||||
let's write the same project above with includes.
|
||||
You will see that parsing includes is setting the dependencies the same way as before. */
|
||||
let project = Project.createProject()
|
||||
|
||||
/* This time source1 and source2 are not depending on anything */
|
||||
Project.setSource(project, "source1", "x=1")
|
||||
Project.setSource(project, "source2", "y=2")
|
||||
|
||||
Project.setSource(
|
||||
project,
|
||||
"source3",
|
||||
`
|
||||
#include "source1"
|
||||
#include "source2"
|
||||
z=3`,
|
||||
)
|
||||
/* We need to parse the includes to set the dependencies */
|
||||
Project.parseIncludes(project, "source3")
|
||||
|
||||
/* Now we can run the project */
|
||||
Project.runAll(project)
|
||||
|
||||
/* And let's check the result and bindings of source3
|
||||
This time you are getting all the variables because we are including the other sources
|
||||
Behind the scenes parseIncludes is setting the dependencies */
|
||||
let result3 = Project.getResult(project, "source3")
|
||||
let bindings3 = Project.getBindings(project, "source3")
|
||||
|
||||
(
|
||||
result3->InternalExpressionValue.toStringResult,
|
||||
bindings3->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}")
|
||||
/*
|
||||
Doing it like this is too verbose for a storybook
|
||||
But I hope you have seen the relation of setContinues and parseIncludes */
|
||||
/*
|
||||
Dealing with includes needs more.
|
||||
- There are parse errors
|
||||
- There are cyclic includes
|
||||
- And the depended source1 and source2 is not already there in the project
|
||||
- If you knew the includes before hand there would not be point of the include directive.
|
||||
More on those on the next section. */
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,156 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
describe("ReducerProject Tutorial", () => {
|
||||
/* Case: Includes
|
||||
In the previous tutorial we have set the similarity between setContinues and parseIncludes.
|
||||
Here we will finally proceed to a real life scenario. */
|
||||
|
||||
describe("parseIncludes", () => {
|
||||
/* Here we investigate the details about parseIncludes, before setting up a real life senario in the next section. */
|
||||
/* Everything happens inside a project, so let's have a project */
|
||||
let project = Project.createProject()
|
||||
Project.setSource(
|
||||
project,
|
||||
"main",
|
||||
`
|
||||
#include "common"
|
||||
x=1
|
||||
`,
|
||||
)
|
||||
/* We need to parse includes after changing the source */
|
||||
Project.parseIncludes(project, "main")
|
||||
test("getDependencies", () => {
|
||||
/* Parse includes has set the dependencies */
|
||||
Project.getDependencies(project, "main")->expect == ["common"]
|
||||
/* If there were no includes than there would be no dependencies */
|
||||
/* However if there was a syntax error at includes then would be no dependencies also */
|
||||
/* Therefore looking at dependencies is not the right way to load includes */
|
||||
/* getDependencies does not distinguish between setContinues or parseIncludes */
|
||||
})
|
||||
test("getIncludes", () => {
|
||||
/* Parse includes has set the includes */
|
||||
switch Project.getIncludes(project, "main") {
|
||||
| Ok(includes) => includes->expect == ["common"]
|
||||
| Error(err) => err->Reducer_ErrorValue.errorToString->fail
|
||||
}
|
||||
/* If the includes cannot be parsed then you get a syntax error.
|
||||
Otherwise you get the includes.
|
||||
If there is no syntax error then you can load that file and use setSource to add it to the project.
|
||||
And so on recursively... */
|
||||
})
|
||||
test("getDependents", () => {
|
||||
/* For any reason, you are able to query what other sources
|
||||
include or depend on the current source.
|
||||
But you don't need to use this to execute the projects.
|
||||
It is provided for completeness of information. */
|
||||
Project.getDependents(project, "main")->expect == []
|
||||
/* Nothing is depending on or including main */
|
||||
})
|
||||
|
||||
describe("Real Like", () => {
|
||||
/* Now let's look at recursive and possibly cyclic includes */
|
||||
/* There is no function provided to load the include files.
|
||||
Because we have no idea if will it be an ordinary function or will it use promises.
|
||||
Therefore one has to write a function to load sources recursively and and setSources
|
||||
while checking for dependencies */
|
||||
|
||||
/* Let's make a dummy loader */
|
||||
let loadSource = (sourceName: string) =>
|
||||
switch sourceName {
|
||||
| "source1" => "x=1"
|
||||
| "source2" => `
|
||||
#include "source1"
|
||||
y=2`
|
||||
| "source3" => `
|
||||
#include "source2"
|
||||
z=3`
|
||||
| _ => `source ${sourceName} not found`->Js.Exn.raiseError
|
||||
}
|
||||
|
||||
/* let's recursively load the sources */
|
||||
let rec loadIncludesRecursively = (project, sourceName, visited) => {
|
||||
if Js.Array2.includes(visited, sourceName) {
|
||||
/* Oh we have already visited this source. There is an include cycle */
|
||||
"Cyclic include ${sourceName}"->Js.Exn.raiseError
|
||||
} else {
|
||||
let newVisited = Js.Array2.copy(visited)
|
||||
let _ = Js.Array2.push(newVisited, sourceName)
|
||||
/* Let's parse the includes and dive into them */
|
||||
Project.parseIncludes(project, sourceName)
|
||||
let rIncludes = Project.getIncludes(project, sourceName)
|
||||
switch rIncludes {
|
||||
/* Maybe there is an include syntax error */
|
||||
| Error(err) => err->Reducer_ErrorValue.errorToString->Js.Exn.raiseError
|
||||
|
||||
| Ok(includes) =>
|
||||
Belt.Array.forEach(includes, newIncludeName => {
|
||||
/* We have got one of the new includes.
|
||||
Let's load it and add it to the project */
|
||||
let newSource = loadSource(newIncludeName)
|
||||
Project.setSource(project, newIncludeName, newSource)
|
||||
/* The new source is loaded and added to the project. */
|
||||
/* Of course the new source might have includes too. */
|
||||
/* Let's recursively load them */
|
||||
loadIncludesRecursively(project, newIncludeName, newVisited)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
/* As we have a fake source loader and a recursive include handler,
|
||||
We can not set up a real project */
|
||||
|
||||
/* * Here starts our real life project! * */
|
||||
|
||||
let project = Project.createProject()
|
||||
|
||||
/* main includes source3 which includes source2 which includes source1 */
|
||||
Project.setSource(
|
||||
project,
|
||||
"main",
|
||||
`
|
||||
#include "source3"
|
||||
x+y+z
|
||||
`,
|
||||
)
|
||||
/* Setting source requires parsing and loading the includes recursively */
|
||||
loadIncludesRecursively(project, "main", []) //No visited yet
|
||||
|
||||
/* Let's salt it more. Let's have another source in the project which also has includes */
|
||||
/* doubleX includes source1 which is eventually included by main as well */
|
||||
Project.setSource(
|
||||
project,
|
||||
"doubleX",
|
||||
`
|
||||
#include "source1"
|
||||
doubleX = x * 2
|
||||
`,
|
||||
)
|
||||
loadIncludesRecursively(project, "doubleX", [])
|
||||
/* Remember, any time you set a source, you need to load includes recursively */
|
||||
|
||||
/* As doubleX is not included by main, it is not loaded recursively.
|
||||
So we link it to the project as a dependency */
|
||||
Project.setContinues(project, "main", ["doubleX"])
|
||||
|
||||
/* Let's run the project */
|
||||
Project.runAll(project)
|
||||
let result = Project.getResult(project, "main")
|
||||
let bindings = Project.getBindings(project, "main")
|
||||
/* And see the result and bindings.. */
|
||||
test("recursive includes", () => {
|
||||
(
|
||||
result->InternalExpressionValue.toStringResult,
|
||||
bindings->InternalExpressionValue.IEvBindings->InternalExpressionValue.toString,
|
||||
)->expect == ("Ok(6)", "@{doubleX: 2,x: 1,y: 2,z: 3}")
|
||||
/* Everything as expected */
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,39 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
describe("ReducerProject Tutorial", () => {
|
||||
/* Let's build a project that depends on values from the UI */
|
||||
let project = Project.createProject()
|
||||
Project.setSource(project, "main", "x+y+z")
|
||||
/* x, y and z is not defined in the project but they has to come from the user */
|
||||
test("Injecting user values", () => {
|
||||
/* User has input the values */
|
||||
let x = 1
|
||||
let y = 2
|
||||
let z = 3
|
||||
/* Then we construct a source code to define those values */
|
||||
let userCode = `
|
||||
x = ${x->Js.Int.toString}
|
||||
y = ${y->Js.Int.toString}
|
||||
z = ${z->Js.Int.toString}
|
||||
`
|
||||
/* We inject the user code into the project */
|
||||
Project.setSource(project, "userCode", userCode)
|
||||
/* "main" is depending on the user code */
|
||||
Project.setContinues(project, "main", ["userCode"])
|
||||
/* We can now run the project */
|
||||
Project.runAll(project)
|
||||
let result = Project.getResult(project, "main")
|
||||
result->InternalExpressionValue.toStringResult->expect == "Ok(6)"
|
||||
})
|
||||
})
|
||||
|
||||
/* Note that this is not final version of the project */
|
||||
/* In the future, for safety, we will provide a way to inject values instead of a source code */
|
||||
/* But time is limited for now... */
|
|
@ -0,0 +1,39 @@
|
|||
@@warning("-44")
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Project = ForTS_ReducerProject
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
open Expect.Operators
|
||||
|
||||
describe("ReducerProject Tutorial", () => {
|
||||
/* Let's build a project to provide a function. */
|
||||
/* But we will call that function on an array of user input. */
|
||||
let project = Project.createProject()
|
||||
Project.setSource(project, "library", "double(x) = x * 2")
|
||||
/* userCode is not here yet but its dependency is fixed. So we can set it once and for all */
|
||||
Project.setContinues(project, "userCode", ["library"])
|
||||
|
||||
let userValues = [1, 2, 3, 4, 5]
|
||||
|
||||
let userResults = Belt.Array.map(userValues, aUserValue => {
|
||||
let userCode = `double(${aUserValue->Js.Int.toString})`
|
||||
/* Put the constructed source in the project */
|
||||
/* We have already set that it depends on "library" */
|
||||
Project.setSource(project, "userCode", userCode)
|
||||
/* Run the project */
|
||||
Project.runAll(project)
|
||||
/* Get the result */
|
||||
Project.getResult(project, "userCode")
|
||||
/* I have to remind you that the "library" is run only once and for all.
|
||||
The library is not run for each user value. */
|
||||
})
|
||||
|
||||
test("userResults", () => {
|
||||
let userResultsAsString = Belt.Array.map(userResults, aResult =>
|
||||
aResult->InternalExpressionValue.toStringResult
|
||||
)
|
||||
userResultsAsString->expect == ["Ok(2)", "Ok(4)", "Ok(6)", "Ok(8)", "Ok(10)"]
|
||||
})
|
||||
})
|
|
@ -2,8 +2,12 @@ open Jest
|
|||
open Expect
|
||||
open Reducer_TestHelpers
|
||||
|
||||
let expectEvalToBeOk = (expr: string) =>
|
||||
Reducer.evaluate(expr)->Reducer_Helpers.rRemoveDefaultsExternal->E.R.isOk->expect->toBe(true)
|
||||
let expectEvalToBeOk = (code: string) =>
|
||||
Reducer_Expression.BackCompatible.evaluateString(code)
|
||||
->Reducer_Helpers.rRemoveDefaultsInternal
|
||||
->E.R.isOk
|
||||
->expect
|
||||
->toBe(true)
|
||||
|
||||
let registry = FunctionRegistry_Library.registry
|
||||
let examples = E.A.to_list(FunctionRegistry_Core.Registry.allExamples(registry))
|
||||
|
@ -88,8 +92,8 @@ describe("FunctionRegistry Library", () => {
|
|||
((fn, example)) => {
|
||||
let responseType =
|
||||
example
|
||||
->Reducer.evaluate
|
||||
->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType)
|
||||
->Reducer_Expression.BackCompatible.evaluateString
|
||||
->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType)
|
||||
let expectedOutputType = fn.output |> E.O.toExn("")
|
||||
expect(responseType)->toEqual(Ok(expectedOutputType))
|
||||
},
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
/* Some of the types have moved to ForTS__Types.
|
||||
Needs to be reimported here if necessary and distribution related
|
||||
|
||||
We only need distribution related extras for back compatibility. Umur
|
||||
|
||||
Instead of a global function namespace we should use modules under ForTS directly maybe renaming them for ease.
|
||||
|
||||
.e.g. Project.run(project)
|
||||
.e.g. Distribution.makeSampleSetDist
|
||||
|
||||
*/
|
||||
|
||||
import * as _ from "lodash";
|
||||
import type {
|
||||
environment,
|
||||
|
@ -44,162 +56,164 @@ export let defaultSamplingInputs: environment = {
|
|||
xyPointLength: 10000,
|
||||
};
|
||||
|
||||
export function run(
|
||||
squiggleString: string,
|
||||
bindings?: externalBindings,
|
||||
environment?: environment,
|
||||
imports?: jsImports
|
||||
): result<squiggleExpression, errorValue> {
|
||||
let b = bindings ? bindings : defaultBindings;
|
||||
let i = imports ? imports : defaultImports;
|
||||
let e = environment ? environment : defaultEnvironment;
|
||||
let res: result<expressionValue, errorValue> = evaluateUsingOptions(
|
||||
{ externalBindings: mergeImportsWithBindings(b, i), environment: e },
|
||||
squiggleString
|
||||
);
|
||||
return resultMap(res, (x) => createTsExport(x, e));
|
||||
}
|
||||
/* Umur: All the functions below are invalid. ForTS_Reducer project is the new way to do this. */
|
||||
|
||||
// Run Partial. A partial is a block of code that doesn't return a value
|
||||
export function runPartial(
|
||||
squiggleString: string,
|
||||
bindings?: externalBindings,
|
||||
environment?: environment,
|
||||
imports?: jsImports
|
||||
): result<externalBindings, errorValue> {
|
||||
let b = bindings ? bindings : defaultBindings;
|
||||
let i = imports ? imports : defaultImports;
|
||||
let e = environment ? environment : defaultEnvironment;
|
||||
// export function run(
|
||||
// squiggleString: string,
|
||||
// bindings?: externalBindings,
|
||||
// environment?: environment,
|
||||
// imports?: jsImports
|
||||
// ): result<squiggleExpression, errorValue> {
|
||||
// let b = bindings ? bindings : defaultBindings;
|
||||
// let i = imports ? imports : defaultImports;
|
||||
// let e = environment ? environment : defaultEnvironment;
|
||||
// let res: result<expressionValue, errorValue> = evaluateUsingOptions(
|
||||
// { externalBindings: mergeImportsWithBindings(b, i), environment: e },
|
||||
// squiggleString
|
||||
// );
|
||||
// return resultMap(res, (x) => createTsExport(x, e));
|
||||
// }
|
||||
|
||||
return evaluatePartialUsingExternalBindings(
|
||||
squiggleString,
|
||||
mergeImportsWithBindings(b, i),
|
||||
e
|
||||
);
|
||||
}
|
||||
// // Run Partial. A partial is a block of code that doesn't return a value
|
||||
// export function runPartial(
|
||||
// squiggleString: string,
|
||||
// bindings?: externalBindings,
|
||||
// environment?: environment,
|
||||
// imports?: jsImports
|
||||
// ): result<externalBindings, errorValue> {
|
||||
// let b = bindings ? bindings : defaultBindings;
|
||||
// let i = imports ? imports : defaultImports;
|
||||
// let e = environment ? environment : defaultEnvironment;
|
||||
|
||||
export function runForeign(
|
||||
fn: lambdaValue,
|
||||
args: jsValue[],
|
||||
environment?: environment
|
||||
): result<squiggleExpression, errorValue> {
|
||||
let e = environment ? environment : defaultEnvironment;
|
||||
let res: result<expressionValue, errorValue> = foreignFunctionInterface(
|
||||
fn,
|
||||
args.map(jsValueToExpressionValue),
|
||||
e
|
||||
);
|
||||
return resultMap(res, (x) => createTsExport(x, e));
|
||||
}
|
||||
// return evaluatePartialUsingExternalBindings(
|
||||
// squiggleString,
|
||||
// mergeImportsWithBindings(b, i),
|
||||
// e
|
||||
// );
|
||||
// }
|
||||
|
||||
function mergeImportsWithBindings(
|
||||
bindings: externalBindings,
|
||||
imports: jsImports
|
||||
): externalBindings {
|
||||
let transformedImports = Object.fromEntries(
|
||||
Object.entries(imports).map(([key, value]) => [
|
||||
"$" + key,
|
||||
jsValueToBinding(value),
|
||||
])
|
||||
);
|
||||
return _.merge(bindings, transformedImports);
|
||||
}
|
||||
// export function runForeign(
|
||||
// fn: lambdaValue,
|
||||
// args: jsValue[],
|
||||
// environment?: environment
|
||||
// ): result<squiggleExpression, errorValue> {
|
||||
// let e = environment ? environment : defaultEnvironment;
|
||||
// let res: result<expressionValue, errorValue> = foreignFunctionInterface(
|
||||
// fn,
|
||||
// args.map(jsValueToExpressionValue),
|
||||
// e
|
||||
// );
|
||||
// return resultMap(res, (x) => createTsExport(x, e));
|
||||
// }
|
||||
|
||||
type jsImports = { [key: string]: jsValue };
|
||||
// function mergeImportsWithBindings(
|
||||
// bindings: externalBindings,
|
||||
// imports: jsImports
|
||||
// ): externalBindings {
|
||||
// let transformedImports = Object.fromEntries(
|
||||
// Object.entries(imports).map(([key, value]) => [
|
||||
// "$" + key,
|
||||
// jsValueToBinding(value),
|
||||
// ])
|
||||
// );
|
||||
// return _.merge(bindings, transformedImports);
|
||||
// }
|
||||
|
||||
export let defaultImports: jsImports = {};
|
||||
export let defaultBindings: externalBindings = {};
|
||||
// type jsImports = { [key: string]: jsValue };
|
||||
|
||||
export function mergeBindings(
|
||||
allBindings: externalBindings[]
|
||||
): externalBindings {
|
||||
return allBindings.reduce((acc, x) => ({ ...acc, ...x }));
|
||||
}
|
||||
// export let defaultImports: jsImports = {};
|
||||
// export let defaultBindings: externalBindings = {};
|
||||
|
||||
function createTsExport(
|
||||
x: expressionValue,
|
||||
environment: environment
|
||||
): squiggleExpression {
|
||||
switch (x) {
|
||||
case "EvVoid":
|
||||
return tag("void", "");
|
||||
default: {
|
||||
switch (x.tag) {
|
||||
case "EvArray":
|
||||
// genType doesn't convert anything more than 2 layers down into {tag: x, value: x}
|
||||
// format, leaving it as the raw values. This converts the raw values
|
||||
// directly into typescript values.
|
||||
//
|
||||
// The casting here is because genType is about the types of the returned
|
||||
// values, claiming they are fully recursive when that's not actually the
|
||||
// case
|
||||
return tag(
|
||||
"array",
|
||||
x.value.map(
|
||||
(arrayItem): squiggleExpression =>
|
||||
convertRawToTypescript(
|
||||
arrayItem as unknown as rescriptExport,
|
||||
environment
|
||||
)
|
||||
)
|
||||
);
|
||||
case "EvArrayString":
|
||||
return tag("arraystring", x.value);
|
||||
case "EvBool":
|
||||
return tag("boolean", x.value);
|
||||
case "EvCall":
|
||||
return tag("call", x.value);
|
||||
case "EvLambda":
|
||||
return tag("lambda", x.value);
|
||||
case "EvDistribution":
|
||||
return tag("distribution", new Distribution(x.value, environment));
|
||||
case "EvNumber":
|
||||
return tag("number", x.value);
|
||||
case "EvRecord":
|
||||
// genType doesn't support records, so we have to do the raw conversion ourself
|
||||
let result: tagged<"record", { [key: string]: squiggleExpression }> =
|
||||
tag(
|
||||
"record",
|
||||
_.mapValues(x.value, (x: unknown) =>
|
||||
convertRawToTypescript(x as rescriptExport, environment)
|
||||
)
|
||||
);
|
||||
return result;
|
||||
case "EvString":
|
||||
return tag("string", x.value);
|
||||
case "EvSymbol":
|
||||
return tag("symbol", x.value);
|
||||
case "EvDate":
|
||||
return tag("date", x.value);
|
||||
case "EvTimeDuration":
|
||||
return tag("timeDuration", x.value);
|
||||
case "EvDeclaration":
|
||||
return tag("lambdaDeclaration", x.value);
|
||||
case "EvTypeIdentifier":
|
||||
return tag("typeIdentifier", x.value);
|
||||
case "EvType":
|
||||
let typeResult: tagged<
|
||||
"type",
|
||||
{ [key: string]: squiggleExpression }
|
||||
> = tag(
|
||||
"type",
|
||||
_.mapValues(x.value, (x: unknown) =>
|
||||
convertRawToTypescript(x as rescriptExport, environment)
|
||||
)
|
||||
);
|
||||
return typeResult;
|
||||
case "EvModule":
|
||||
let moduleResult: tagged<
|
||||
"module",
|
||||
{ [key: string]: squiggleExpression }
|
||||
> = tag(
|
||||
"module",
|
||||
_.mapValues(x.value, (x: unknown) =>
|
||||
convertRawToTypescript(x as rescriptExport, environment)
|
||||
)
|
||||
);
|
||||
return moduleResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// export function mergeBindings(
|
||||
// allBindings: externalBindings[]
|
||||
// ): externalBindings {
|
||||
// return allBindings.reduce((acc, x) => ({ ...acc, ...x }));
|
||||
// }
|
||||
|
||||
// function createTsExport(
|
||||
// x: expressionValue,
|
||||
// environment: environment
|
||||
// ): squiggleExpression {
|
||||
// switch (x) {
|
||||
// case "EvVoid":
|
||||
// return tag("void", "");
|
||||
// default: {
|
||||
// switch (x.tag) {
|
||||
// case "EvArray":
|
||||
// // genType doesn't convert anything more than 2 layers down into {tag: x, value: x}
|
||||
// // format, leaving it as the raw values. This converts the raw values
|
||||
// // directly into typescript values.
|
||||
// //
|
||||
// // The casting here is because genType is about the types of the returned
|
||||
// // values, claiming they are fully recursive when that's not actually the
|
||||
// // case
|
||||
// return tag(
|
||||
// "array",
|
||||
// x.value.map(
|
||||
// (arrayItem): squiggleExpression =>
|
||||
// convertRawToTypescript(
|
||||
// arrayItem as unknown as rescriptExport,
|
||||
// environment
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
// case "EvArrayString":
|
||||
// return tag("arraystring", x.value);
|
||||
// case "EvBool":
|
||||
// return tag("boolean", x.value);
|
||||
// case "EvCall":
|
||||
// return tag("call", x.value);
|
||||
// case "EvLambda":
|
||||
// return tag("lambda", x.value);
|
||||
// case "EvDistribution":
|
||||
// return tag("distribution", new Distribution(x.value, environment));
|
||||
// case "EvNumber":
|
||||
// return tag("number", x.value);
|
||||
// case "EvRecord":
|
||||
// // genType doesn't support records, so we have to do the raw conversion ourself
|
||||
// let result: tagged<"record", { [key: string]: squiggleExpression }> =
|
||||
// tag(
|
||||
// "record",
|
||||
// _.mapValues(x.value, (x: unknown) =>
|
||||
// convertRawToTypescript(x as rescriptExport, environment)
|
||||
// )
|
||||
// );
|
||||
// return result;
|
||||
// case "EvString":
|
||||
// return tag("string", x.value);
|
||||
// case "EvSymbol":
|
||||
// return tag("symbol", x.value);
|
||||
// case "EvDate":
|
||||
// return tag("date", x.value);
|
||||
// case "EvTimeDuration":
|
||||
// return tag("timeDuration", x.value);
|
||||
// case "EvDeclaration":
|
||||
// return tag("lambdaDeclaration", x.value);
|
||||
// case "EvTypeIdentifier":
|
||||
// return tag("typeIdentifier", x.value);
|
||||
// case "EvType":
|
||||
// let typeResult: tagged<
|
||||
// "type",
|
||||
// { [key: string]: squiggleExpression }
|
||||
// > = tag(
|
||||
// "type",
|
||||
// _.mapValues(x.value, (x: unknown) =>
|
||||
// convertRawToTypescript(x as rescriptExport, environment)
|
||||
// )
|
||||
// );
|
||||
// return typeResult;
|
||||
// case "EvModule":
|
||||
// let moduleResult: tagged<
|
||||
// "module",
|
||||
// { [key: string]: squiggleExpression }
|
||||
// > = tag(
|
||||
// "module",
|
||||
// _.mapValues(x.value, (x: unknown) =>
|
||||
// convertRawToTypescript(x as rescriptExport, environment)
|
||||
// )
|
||||
// );
|
||||
// return moduleResult;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,269 +1,279 @@
|
|||
import * as _ from "lodash";
|
||||
import type {
|
||||
expressionValue,
|
||||
mixedShape,
|
||||
sampleSetDist,
|
||||
genericDist,
|
||||
environment,
|
||||
symbolicDist,
|
||||
discreteShape,
|
||||
continuousShape,
|
||||
lambdaValue,
|
||||
lambdaDeclaration,
|
||||
declarationArg,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
import { Distribution } from "./distribution";
|
||||
import { tagged, tag } from "./types";
|
||||
/**
|
||||
Umur: Delete this file! There is nothing left to see here.
|
||||
**/
|
||||
|
||||
// import * as _ from "lodash";
|
||||
// import type {
|
||||
// // expressionValue,
|
||||
// mixedShape,
|
||||
// sampleSetDist,
|
||||
// genericDist,
|
||||
// // environment,
|
||||
// symbolicDist,
|
||||
// discreteShape,
|
||||
// continuousShape,
|
||||
// // lambdaValue,
|
||||
// // lambdaDeclaration,
|
||||
// // declarationArg,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// import { Distribution } from "./distribution";
|
||||
// import { tagged, tag } from "./types";
|
||||
// This file is here to compensate for genType not fully recursively converting types
|
||||
|
||||
// Raw rescript types.
|
||||
export type rescriptExport =
|
||||
| 0 // EvVoid
|
||||
| {
|
||||
TAG: 0; // EvArray
|
||||
_0: rescriptExport[];
|
||||
}
|
||||
| {
|
||||
TAG: 1; // EvString
|
||||
_0: string[];
|
||||
}
|
||||
| {
|
||||
TAG: 2; // EvBool
|
||||
_0: boolean;
|
||||
}
|
||||
| {
|
||||
TAG: 3; // EvCall
|
||||
_0: string;
|
||||
}
|
||||
| {
|
||||
TAG: 4; // EvDistribution
|
||||
_0: rescriptDist;
|
||||
}
|
||||
| {
|
||||
TAG: 5; // EvLambda
|
||||
_0: lambdaValue;
|
||||
}
|
||||
| {
|
||||
TAG: 6; // EvNumber
|
||||
_0: number;
|
||||
}
|
||||
| {
|
||||
TAG: 7; // EvRecord
|
||||
_0: { [key: string]: rescriptExport };
|
||||
}
|
||||
| {
|
||||
TAG: 8; // EvString
|
||||
_0: string;
|
||||
}
|
||||
| {
|
||||
TAG: 9; // EvSymbol
|
||||
_0: string;
|
||||
}
|
||||
| {
|
||||
TAG: 10; // EvDate
|
||||
_0: Date;
|
||||
}
|
||||
| {
|
||||
TAG: 11; // EvTimeDuration
|
||||
_0: number;
|
||||
}
|
||||
| {
|
||||
TAG: 12; // EvDeclaration
|
||||
_0: rescriptLambdaDeclaration;
|
||||
}
|
||||
| {
|
||||
TAG: 13; // EvTypeIdentifier
|
||||
_0: string;
|
||||
}
|
||||
| {
|
||||
TAG: 14; // EvModule
|
||||
_0: { [key: string]: rescriptExport };
|
||||
};
|
||||
// Umur: Rescript expression values are opaque!
|
||||
// export type rescriptExport =
|
||||
// | 0 // EvVoid
|
||||
// | {
|
||||
// TAG: 0; // EvArray
|
||||
// _0: rescriptExport[];
|
||||
// }
|
||||
// | {
|
||||
// TAG: 1; // EvString
|
||||
// _0: string[];
|
||||
// }
|
||||
// | {
|
||||
// TAG: 2; // EvBool
|
||||
// _0: boolean;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 3; // EvCall
|
||||
// _0: string;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 4; // EvDistribution
|
||||
// _0: rescriptDist;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 5; // EvLambda
|
||||
// _0: lambdaValue;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 6; // EvNumber
|
||||
// _0: number;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 7; // EvRecord
|
||||
// _0: { [key: string]: rescriptExport };
|
||||
// }
|
||||
// | {
|
||||
// TAG: 8; // EvString
|
||||
// _0: string;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 9; // EvSymbol
|
||||
// _0: string;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 10; // EvDate
|
||||
// _0: Date;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 11; // EvTimeDuration
|
||||
// _0: number;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 12; // EvDeclaration
|
||||
// _0: rescriptLambdaDeclaration;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 13; // EvTypeIdentifier
|
||||
// _0: string;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 14; // EvModule
|
||||
// _0: { [key: string]: rescriptExport };
|
||||
// };
|
||||
|
||||
type rescriptDist =
|
||||
| { TAG: 0; _0: rescriptPointSetDist }
|
||||
| { TAG: 1; _0: sampleSetDist }
|
||||
| { TAG: 2; _0: symbolicDist };
|
||||
// Umur: opaque type
|
||||
// type rescriptDist =
|
||||
// | { TAG: 0; _0: rescriptPointSetDist }
|
||||
// | { TAG: 1; _0: sampleSetDist }
|
||||
// | { TAG: 2; _0: symbolicDist };
|
||||
|
||||
type rescriptPointSetDist =
|
||||
| {
|
||||
TAG: 0; // Mixed
|
||||
_0: mixedShape;
|
||||
}
|
||||
| {
|
||||
TAG: 1; // Discrete
|
||||
_0: discreteShape;
|
||||
}
|
||||
| {
|
||||
TAG: 2; // ContinuousShape
|
||||
_0: continuousShape;
|
||||
};
|
||||
// Umur: opaque type, no conversion
|
||||
// type rescriptPointSetDist =
|
||||
// | {
|
||||
// TAG: 0; // Mixed
|
||||
// _0: mixedShape;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 1; // Discrete
|
||||
// _0: discreteShape;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 2; // ContinuousShape
|
||||
// _0: continuousShape;
|
||||
// };
|
||||
|
||||
type rescriptLambdaDeclaration = {
|
||||
readonly fn: lambdaValue;
|
||||
readonly args: rescriptDeclarationArg[];
|
||||
};
|
||||
// type rescriptLambdaDeclaration = {
|
||||
// readonly fn: lambdaValue;
|
||||
// readonly args: rescriptDeclarationArg[];
|
||||
// };
|
||||
|
||||
type rescriptDeclarationArg =
|
||||
| {
|
||||
TAG: 0; // Float
|
||||
min: number;
|
||||
max: number;
|
||||
}
|
||||
| {
|
||||
TAG: 1; // Date
|
||||
min: Date;
|
||||
max: Date;
|
||||
};
|
||||
// type rescriptDeclarationArg =
|
||||
// | {
|
||||
// TAG: 0; // Float
|
||||
// min: number;
|
||||
// max: number;
|
||||
// }
|
||||
// | {
|
||||
// TAG: 1; // Date
|
||||
// min: Date;
|
||||
// max: Date;
|
||||
// };
|
||||
|
||||
export type squiggleExpression =
|
||||
| tagged<"symbol", string>
|
||||
| tagged<"string", string>
|
||||
| tagged<"call", string>
|
||||
| tagged<"lambda", lambdaValue>
|
||||
| tagged<"array", squiggleExpression[]>
|
||||
| tagged<"arraystring", string[]>
|
||||
| tagged<"boolean", boolean>
|
||||
| tagged<"distribution", Distribution>
|
||||
| tagged<"number", number>
|
||||
| tagged<"date", Date>
|
||||
| tagged<"timeDuration", number>
|
||||
| tagged<"lambdaDeclaration", lambdaDeclaration>
|
||||
| tagged<"record", { [key: string]: squiggleExpression }>
|
||||
| tagged<"type", { [key: string]: squiggleExpression }>
|
||||
| tagged<"typeIdentifier", string>
|
||||
| tagged<"module", { [key: string]: squiggleExpression }>
|
||||
| tagged<"void", string>;
|
||||
// Umur: Squiggle expressions are opaque!
|
||||
// export type squiggleExpression =
|
||||
// | tagged<"symbol", string>
|
||||
// | tagged<"string", string>
|
||||
// | tagged<"call", string>
|
||||
// | tagged<"lambda", lambdaValue>
|
||||
// | tagged<"array", squiggleExpression[]>
|
||||
// | tagged<"arraystring", string[]>
|
||||
// | tagged<"boolean", boolean>
|
||||
// | tagged<"distribution", Distribution>
|
||||
// | tagged<"number", number>
|
||||
// | tagged<"date", Date>
|
||||
// | tagged<"timeDuration", number>
|
||||
// | tagged<"lambdaDeclaration", lambdaDeclaration>
|
||||
// | tagged<"record", { [key: string]: squiggleExpression }>
|
||||
// | tagged<"type", { [key: string]: squiggleExpression }>
|
||||
// | tagged<"typeIdentifier", string>
|
||||
// | tagged<"module", { [key: string]: squiggleExpression }>
|
||||
// | tagged<"void", string>;
|
||||
|
||||
export { lambdaValue };
|
||||
// export { lambdaValue };
|
||||
|
||||
export function convertRawToTypescript(
|
||||
result: rescriptExport,
|
||||
environment: environment
|
||||
): squiggleExpression {
|
||||
if (typeof result === "number") {
|
||||
// EvVoid
|
||||
return tag("void", "");
|
||||
}
|
||||
switch (result.TAG) {
|
||||
case 0: // EvArray
|
||||
return tag(
|
||||
"array",
|
||||
result._0.map((x) => convertRawToTypescript(x, environment))
|
||||
);
|
||||
case 1: // EvArrayString
|
||||
return tag("arraystring", result._0);
|
||||
case 2: // EvBool
|
||||
return tag("boolean", result._0);
|
||||
case 3: // EvCall
|
||||
return tag("call", result._0);
|
||||
case 4: // EvDistribution
|
||||
return tag(
|
||||
"distribution",
|
||||
new Distribution(
|
||||
convertRawDistributionToGenericDist(result._0),
|
||||
environment
|
||||
)
|
||||
);
|
||||
case 5: // EvDistribution
|
||||
return tag("lambda", result._0);
|
||||
case 6: // EvNumber
|
||||
return tag("number", result._0);
|
||||
case 7: // EvRecord
|
||||
return tag(
|
||||
"record",
|
||||
_.mapValues(result._0, (x) => convertRawToTypescript(x, environment))
|
||||
);
|
||||
case 8: // EvString
|
||||
return tag("string", result._0);
|
||||
case 9: // EvSymbol
|
||||
return tag("symbol", result._0);
|
||||
case 10: // EvDate
|
||||
return tag("date", result._0);
|
||||
case 11: // EvTimeDuration
|
||||
return tag("number", result._0);
|
||||
case 12: // EvDeclaration
|
||||
return tag("lambdaDeclaration", {
|
||||
fn: result._0.fn,
|
||||
args: result._0.args.map(convertDeclaration),
|
||||
});
|
||||
case 13: // EvSymbol
|
||||
return tag("typeIdentifier", result._0);
|
||||
case 14: // EvModule
|
||||
return tag(
|
||||
"module",
|
||||
_.mapValues(result._0, (x) => convertRawToTypescript(x, environment))
|
||||
);
|
||||
}
|
||||
}
|
||||
// Umur: Opaque type no conversion!
|
||||
// export function convertRawToTypescript(
|
||||
// result: rescriptExport,
|
||||
// environment: environment
|
||||
// ): squiggleExpression {
|
||||
// if (typeof result === "number") {
|
||||
// // EvVoid
|
||||
// return tag("void", "");
|
||||
// }
|
||||
// switch (result.TAG) {
|
||||
// case 0: // EvArray
|
||||
// return tag(
|
||||
// "array",
|
||||
// result._0.map((x) => convertRawToTypescript(x, environment))
|
||||
// );
|
||||
// case 1: // EvArrayString
|
||||
// return tag("arraystring", result._0);
|
||||
// case 2: // EvBool
|
||||
// return tag("boolean", result._0);
|
||||
// case 3: // EvCall
|
||||
// return tag("call", result._0);
|
||||
// case 4: // EvDistribution
|
||||
// return tag(
|
||||
// "distribution",
|
||||
// new Distribution(
|
||||
// convertRawDistributionToGenericDist(result._0),
|
||||
// environment
|
||||
// )
|
||||
// );
|
||||
// case 5: // EvDistribution
|
||||
// return tag("lambda", result._0);
|
||||
// case 6: // EvNumber
|
||||
// return tag("number", result._0);
|
||||
// case 7: // EvRecord
|
||||
// return tag(
|
||||
// "record",
|
||||
// _.mapValues(result._0, (x) => convertRawToTypescript(x, environment))
|
||||
// );
|
||||
// case 8: // EvString
|
||||
// return tag("string", result._0);
|
||||
// case 9: // EvSymbol
|
||||
// return tag("symbol", result._0);
|
||||
// case 10: // EvDate
|
||||
// return tag("date", result._0);
|
||||
// case 11: // EvTimeDuration
|
||||
// return tag("number", result._0);
|
||||
// case 12: // EvDeclaration
|
||||
// return tag("lambdaDeclaration", {
|
||||
// fn: result._0.fn,
|
||||
// args: result._0.args.map(convertDeclaration),
|
||||
// });
|
||||
// case 13: // EvSymbol
|
||||
// return tag("typeIdentifier", result._0);
|
||||
// case 14: // EvModule
|
||||
// return tag(
|
||||
// "module",
|
||||
// _.mapValues(result._0, (x) => convertRawToTypescript(x, environment))
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
function convertDeclaration(
|
||||
declarationArg: rescriptDeclarationArg
|
||||
): declarationArg {
|
||||
switch (declarationArg.TAG) {
|
||||
case 0: // Float
|
||||
return tag("Float", { min: declarationArg.min, max: declarationArg.max });
|
||||
case 1: // Date
|
||||
return tag("Date", { min: declarationArg.min, max: declarationArg.max });
|
||||
}
|
||||
}
|
||||
// function convertDeclaration(
|
||||
// declarationArg: rescriptDeclarationArg
|
||||
// ): declarationArg {
|
||||
// switch (declarationArg.TAG) {
|
||||
// case 0: // Float
|
||||
// return tag("Float", { min: declarationArg.min, max: declarationArg.max });
|
||||
// case 1: // Date
|
||||
// return tag("Date", { min: declarationArg.min, max: declarationArg.max });
|
||||
// }
|
||||
// }
|
||||
|
||||
function convertRawDistributionToGenericDist(
|
||||
result: rescriptDist
|
||||
): genericDist {
|
||||
switch (result.TAG) {
|
||||
case 0: // Point Set Dist
|
||||
switch (result._0.TAG) {
|
||||
case 0: // Mixed
|
||||
return tag("PointSet", tag("Mixed", result._0._0));
|
||||
case 1: // Discrete
|
||||
return tag("PointSet", tag("Discrete", result._0._0));
|
||||
case 2: // Continuous
|
||||
return tag("PointSet", tag("Continuous", result._0._0));
|
||||
}
|
||||
case 1: // Sample Set Dist
|
||||
return tag("SampleSet", result._0);
|
||||
case 2: // Symbolic Dist
|
||||
return tag("Symbolic", result._0);
|
||||
}
|
||||
}
|
||||
// Umur: opaque type no conversion!
|
||||
// function convertRawDistributionToGenericDist(
|
||||
// result: rescriptDist
|
||||
// ): genericDist {
|
||||
// switch (result.TAG) {
|
||||
// case 0: // Point Set Dist
|
||||
// switch (result._0.TAG) {
|
||||
// case 0: // Mixed
|
||||
// return tag("PointSet", tag("Mixed", result._0._0));
|
||||
// case 1: // Discrete
|
||||
// return tag("PointSet", tag("Discrete", result._0._0));
|
||||
// case 2: // Continuous
|
||||
// return tag("PointSet", tag("Continuous", result._0._0));
|
||||
// }
|
||||
// case 1: // Sample Set Dist
|
||||
// return tag("SampleSet", result._0);
|
||||
// case 2: // Symbolic Dist
|
||||
// return tag("Symbolic", result._0);
|
||||
// }
|
||||
// }
|
||||
|
||||
export type jsValue =
|
||||
| string
|
||||
| number
|
||||
| jsValue[]
|
||||
| { [key: string]: jsValue }
|
||||
| boolean;
|
||||
// export type jsValue =
|
||||
// | string
|
||||
// | number
|
||||
// | jsValue[]
|
||||
// | { [key: string]: jsValue }
|
||||
// | boolean;
|
||||
|
||||
export function jsValueToBinding(value: jsValue): rescriptExport {
|
||||
if (typeof value === "boolean") {
|
||||
return { TAG: 2, _0: value as boolean };
|
||||
} else if (typeof value === "string") {
|
||||
return { TAG: 8, _0: value as string };
|
||||
} else if (typeof value === "number") {
|
||||
return { TAG: 6, _0: value as number };
|
||||
} else if (Array.isArray(value)) {
|
||||
return { TAG: 0, _0: value.map(jsValueToBinding) };
|
||||
} else {
|
||||
// Record
|
||||
return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) };
|
||||
}
|
||||
}
|
||||
// export function jsValueToBinding(value: jsValue): rescriptExport {
|
||||
// if (typeof value === "boolean") {
|
||||
// return { TAG: 2, _0: value as boolean };
|
||||
// } else if (typeof value === "string") {
|
||||
// return { TAG: 8, _0: value as string };
|
||||
// } else if (typeof value === "number") {
|
||||
// return { TAG: 6, _0: value as number };
|
||||
// } else if (Array.isArray(value)) {
|
||||
// return { TAG: 0, _0: value.map(jsValueToBinding) };
|
||||
// } else {
|
||||
// // Record
|
||||
// return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) };
|
||||
// }
|
||||
// }
|
||||
|
||||
export function jsValueToExpressionValue(value: jsValue): expressionValue {
|
||||
if (typeof value === "boolean") {
|
||||
return { tag: "EvBool", value: value as boolean };
|
||||
} else if (typeof value === "string") {
|
||||
return { tag: "EvString", value: value as string };
|
||||
} else if (typeof value === "number") {
|
||||
return { tag: "EvNumber", value: value as number };
|
||||
} else if (Array.isArray(value)) {
|
||||
return { tag: "EvArray", value: value.map(jsValueToExpressionValue) };
|
||||
} else {
|
||||
// Record
|
||||
return {
|
||||
tag: "EvRecord",
|
||||
value: _.mapValues(value, jsValueToExpressionValue),
|
||||
};
|
||||
}
|
||||
}
|
||||
// export function jsValueToExpressionValue(value: jsValue): expressionValue {
|
||||
// if (typeof value === "boolean") {
|
||||
// return { tag: "EvBool", value: value as boolean };
|
||||
// } else if (typeof value === "string") {
|
||||
// return { tag: "EvString", value: value as string };
|
||||
// } else if (typeof value === "number") {
|
||||
// return { tag: "EvNumber", value: value as number };
|
||||
// } else if (Array.isArray(value)) {
|
||||
// return { tag: "EvArray", value: value.map(jsValueToExpressionValue) };
|
||||
// } else {
|
||||
// // Record
|
||||
// return {
|
||||
// tag: "EvRecord",
|
||||
// value: _.mapValues(value, jsValueToExpressionValue),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@genType
|
||||
//FIXME accessor methods or not opaque?
|
||||
@genType.opaque
|
||||
type genericDist =
|
||||
| PointSet(PointSetTypes.pointSetDist)
|
||||
| SampleSet(SampleSetDist.t)
|
||||
|
@ -6,7 +7,7 @@ type genericDist =
|
|||
|
||||
type asAlgebraicCombinationStrategy = AsDefault | AsSymbolic | AsMonteCarlo | AsConvolution
|
||||
|
||||
@genType
|
||||
@genType.opaque
|
||||
type error =
|
||||
| NotYetImplemented
|
||||
| Unreachable
|
||||
|
@ -27,7 +28,6 @@ module Error = {
|
|||
|
||||
let fromString = (s: string): t => OtherError(s)
|
||||
|
||||
@genType
|
||||
let toString = (err: error): string =>
|
||||
switch err {
|
||||
| NotYetImplemented => "Function not yet implemented"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//TODO: multimodal, add interface, test somehow, track performance, refactor sampleSet, refactor ASTEvaluator.res.
|
||||
|
||||
type t = DistributionTypes.genericDist
|
||||
type error = DistributionTypes.error
|
||||
type toPointSetFn = t => result<PointSetTypes.pointSetDist, error>
|
||||
|
|
|
@ -47,7 +47,7 @@ type pointSetDistMonad<'a, 'b, 'c> =
|
|||
| Discrete('b)
|
||||
| Continuous('c)
|
||||
|
||||
@genType
|
||||
@genType.opaque
|
||||
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
|
||||
|
||||
module ShapeMonad = {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Genetic Distribution happens to be abstract distribution
|
||||
@genType type distribution = DistributionTypes.genericDist
|
||||
@genType type pointSetDistribution = ForTS_Distribution_PointSetDistribution.pointSetDistribution
|
||||
@genType type sampleSetDistribution = ForTS_Distribution_SampleSetDistribution.sampleSetDistribution
|
||||
@genType type symbolicDistribution = ForTS_Distribution_SymbolicDistribution.symbolicDistribution
|
||||
|
||||
type environment = ForTS_Distribution_Environment.environment //use
|
||||
|
||||
@genType
|
||||
let defaultEnvironment: environment = DistributionOperation.defaultEnv
|
||||
|
||||
@module("ForTS_Distribution_tag") @scope("distributionTag")
|
||||
external dtPointSet_: int = "DtPointSet"
|
||||
|
||||
@module("ForTS_Distribution_tag") @scope("distributionTag")
|
||||
external dtSampleSet_: int = "DtSampleSet"
|
||||
|
||||
@module("ForTS_Distribution_tag") @scope("distributionTag")
|
||||
external dtSymbolic_: int = "DtSymbolic"
|
||||
|
||||
@genType.import("./ForTS_Distribution_tag")
|
||||
type distributionTag
|
||||
|
||||
external castEnum: int => distributionTag = "%identity"
|
||||
|
||||
// type genericDist =
|
||||
// | PointSet(PointSetTypes.pointSetDist)
|
||||
// | SampleSet(SampleSetDist.t)
|
||||
// | Symbolic(SymbolicDistTypes.symbolicDist)
|
||||
@genType
|
||||
let getTag = (variant: distribution): distributionTag =>
|
||||
switch variant {
|
||||
| PointSet(_) => dtPointSet_->castEnum
|
||||
| SampleSet(_) => dtSampleSet_->castEnum
|
||||
| Symbolic(_) => dtSymbolic_->castEnum
|
||||
}
|
||||
|
||||
@genType
|
||||
let getPointSet = (variant: distribution): option<pointSetDistribution> =>
|
||||
switch variant {
|
||||
| PointSet(dist) => dist->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getSampleSet = (variant: distribution): option<sampleSetDistribution> =>
|
||||
switch variant {
|
||||
| SampleSet(dist) => dist->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getSymbolic = (variant: distribution): option<symbolicDistribution> =>
|
||||
switch variant {
|
||||
| Symbolic(dist) => dist->Some
|
||||
| _ => None
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@genType type environment = GenericDist.env //re-export
|
|
@ -0,0 +1,4 @@
|
|||
@genType type distributionError = DistributionTypes.error
|
||||
|
||||
@genType
|
||||
let toString = (e: distributionError) => DistributionTypes.Error.toString(e)
|
|
@ -0,0 +1,44 @@
|
|||
@genType type pointSetDistribution = PointSetTypes.pointSetDist
|
||||
|
||||
@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag")
|
||||
external pstMixed_: int = "PstMixed"
|
||||
|
||||
@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag")
|
||||
external pstDiscrete_: int = "PstDiscrete"
|
||||
|
||||
@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag")
|
||||
external pstContinuous_: int = "PstContinuous"
|
||||
|
||||
@genType.import("./ForTS_Distribution_PointSetDistribution_tag")
|
||||
type pointSetDistributionTag
|
||||
|
||||
external castEnum: int => pointSetDistributionTag = "%identity"
|
||||
|
||||
@genType
|
||||
let getTag = (variant: pointSetDistribution): pointSetDistributionTag =>
|
||||
switch variant {
|
||||
| Mixed(_) => pstMixed_->castEnum
|
||||
| Discrete(_) => pstDiscrete_->castEnum
|
||||
| Continuous(_) => pstContinuous_->castEnum
|
||||
}
|
||||
|
||||
@genType
|
||||
let getMixed = (variant: pointSetDistribution): 'd =>
|
||||
switch variant {
|
||||
| Mixed(mixed) => mixed->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getDiscrete = (variant: pointSetDistribution): 'd =>
|
||||
switch variant {
|
||||
| Discrete(discrete) => discrete->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getContinues = (variant: pointSetDistribution): 'd =>
|
||||
switch variant {
|
||||
| Continuous(continuous) => continuous->Some
|
||||
| _ => None
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.pointSetDistributionTag = void 0;
|
||||
var pointSetDistributionTag;
|
||||
(function (pointSetDistributionTag) {
|
||||
pointSetDistributionTag[(pointSetDistributionTag["PstMixed"] = 0)] =
|
||||
"PstMixed";
|
||||
pointSetDistributionTag[(pointSetDistributionTag["PstDiscrete"] = 1)] =
|
||||
"PstDiscrete";
|
||||
pointSetDistributionTag[(pointSetDistributionTag["PstContinuous"] = 2)] =
|
||||
"PstContinuous";
|
||||
})(
|
||||
(pointSetDistributionTag =
|
||||
exports.pointSetDistributionTag || (exports.pointSetDistributionTag = {}))
|
||||
);
|
|
@ -0,0 +1,5 @@
|
|||
export enum pointSetDistributionTag {
|
||||
PstMixed,
|
||||
PstDiscrete,
|
||||
PstContinuous,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@genType type sampleSetDistribution = SampleSetDist.t
|
|
@ -0,0 +1 @@
|
|||
@genType type symbolicDistribution = SymbolicDistTypes.symbolicDist
|
|
@ -0,0 +1,5 @@
|
|||
export enum distributionTag {
|
||||
DtPointSet,
|
||||
DtSampleSet,
|
||||
DtSymbolic,
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
@genType type reducerProject = ReducerProject_T.t //re-export
|
||||
|
||||
type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use
|
||||
|
||||
type squiggleValue = ForTS_SquiggleValue.squiggleValue //use
|
||||
type squiggleValue_Module = ForTS_SquiggleValue_Module.squiggleValue_Module //use
|
||||
|
||||
type environment = ForTS_Distribution_Environment.environment //use
|
||||
|
||||
module T = ReducerProject_T
|
||||
module Private = ReducerProject.Private
|
||||
|
||||
/*
|
||||
PUBLIC FUNCTIONS
|
||||
*/
|
||||
|
||||
/*
|
||||
A project links and runs sources that continue or include each other.
|
||||
|
||||
Creates a new project to hold the sources, executables, bindings, and other data.
|
||||
The new project runs the sources according to their topological sorting because of the includes and continues.
|
||||
|
||||
Any source can include or continue other sources. "Therefore, the project is a graph data structure."
|
||||
The difference between including and continuing is that includes are stated inside the source code while continues are stated in the project.
|
||||
|
||||
To run a group of source codes and get results/bindings, the necessary methods are
|
||||
- setSource
|
||||
- setContinues
|
||||
- parseIncludes
|
||||
- run or runAll
|
||||
- getExternalBindings
|
||||
- getExternalResult
|
||||
|
||||
A project has a public field tag with a constant value "reducerProject"
|
||||
project = {tag: "reducerProject"}
|
||||
*/
|
||||
@genType
|
||||
let createProject = (): reducerProject => Private.createProject()->T.Private.castFromInternalProject
|
||||
|
||||
/*
|
||||
Answer all the source ids of all the sources in the project.
|
||||
*/
|
||||
@genType
|
||||
let getSourceIds = (project: reducerProject): array<string> =>
|
||||
project->T.Private.castToInternalProject->Private.getSourceIds
|
||||
|
||||
/*
|
||||
Sets the source for a given source Id.
|
||||
*/
|
||||
@genType
|
||||
let setSource = (project: reducerProject, sourceId: string, value: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.setSource(sourceId, value)
|
||||
|
||||
/*
|
||||
Gets the source for a given source id.
|
||||
*/
|
||||
@genType
|
||||
let getSource = (project: reducerProject, sourceId: string): option<string> =>
|
||||
project->T.Private.castToInternalProject->Private.getSource(sourceId)
|
||||
|
||||
/*
|
||||
Touches the source for a given source id. This and dependent, sources are set to be re-evaluated.
|
||||
*/
|
||||
@genType
|
||||
let touchSource = (project: reducerProject, sourceId: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.touchSource(sourceId)
|
||||
|
||||
/*
|
||||
Cleans the compilation artifacts for a given source ID. The results stay untouched, so compilation won't be run again.
|
||||
|
||||
Normally, you would never need the compilation artifacts again as the results with the same sources would never change. However, they are needed in case of any debugging reruns
|
||||
*/
|
||||
@genType
|
||||
let clean = (project: reducerProject, sourceId: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.clean(sourceId)
|
||||
|
||||
/*
|
||||
Cleans all the compilation artifacts in all of the project
|
||||
*/
|
||||
@genType
|
||||
let cleanAll = (project: reducerProject): unit =>
|
||||
project->T.Private.castToInternalProject->Private.cleanAll
|
||||
|
||||
/*
|
||||
Cleans results. Compilation stays untouched to be able to re-run the source.
|
||||
You would not do this if you were not trying to debug the source code.
|
||||
*/
|
||||
@genType
|
||||
let cleanResults = (project: reducerProject, sourceId: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.cleanResults(sourceId)
|
||||
|
||||
/*
|
||||
Cleans all results. Compilations remains untouched to rerun the source.
|
||||
*/
|
||||
@genType
|
||||
let cleanAllResults = (project: reducerProject): unit =>
|
||||
project->T.Private.castToInternalProject->Private.cleanAllResults
|
||||
|
||||
/*
|
||||
To set the includes one first has to call "parseIncludes". The parsed includes or the parser error is returned.
|
||||
*/
|
||||
@genType
|
||||
let getIncludes = (project: reducerProject, sourceId: string): result<
|
||||
array<string>,
|
||||
reducerErrorValue,
|
||||
> => project->T.Private.castToInternalProject->Private.getIncludes(sourceId)
|
||||
|
||||
/*
|
||||
Answers the source codes after which this source code is continuing
|
||||
*/
|
||||
@genType
|
||||
let getContinues = (project: reducerProject, sourceId: string): array<string> =>
|
||||
project->T.Private.castToInternalProject->Private.getContinues(sourceId)
|
||||
|
||||
/*
|
||||
"continues" acts like hidden includes in the source.
|
||||
It is used to define a continuation that is not visible in the source code.
|
||||
You can chain source codes on the web interface for example
|
||||
*/
|
||||
@genType
|
||||
let setContinues = (project: reducerProject, sourceId: string, continues: array<string>): unit =>
|
||||
project->T.Private.castToInternalProject->Private.setContinues(sourceId, continues)
|
||||
|
||||
/*
|
||||
This source depends on the array of sources returned.
|
||||
*/
|
||||
@genType
|
||||
let getDependencies = (project: reducerProject, sourceId: string): array<string> =>
|
||||
project->T.Private.castToInternalProject->Private.getDependencies(sourceId)
|
||||
|
||||
/*
|
||||
The sources returned are dependent on this
|
||||
*/
|
||||
@genType
|
||||
let getDependents = (project: reducerProject, sourceId: string): array<string> =>
|
||||
project->T.Private.castToInternalProject->Private.getDependents(sourceId)
|
||||
|
||||
/*
|
||||
Get the run order for the sources in the project.
|
||||
*/
|
||||
@genType
|
||||
let getRunOrder = (project: reducerProject): array<string> =>
|
||||
project->T.Private.castToInternalProject->Private.getRunOrder
|
||||
|
||||
/*
|
||||
Get the run order to get the results of this specific source
|
||||
*/
|
||||
@genType
|
||||
let getRunOrderFor = (project: reducerProject, sourceId: string) =>
|
||||
project->T.Private.castToInternalProject->Private.getRunOrderFor(sourceId)
|
||||
|
||||
/*
|
||||
Parse includes so that you can load them before running.
|
||||
Load includes by calling getIncludes which returns the includes that have been parsed.
|
||||
It is your responsibility to load the includes before running.
|
||||
*/
|
||||
|
||||
@genType
|
||||
let parseIncludes = (project: reducerProject, sourceId: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.parseIncludes(sourceId)
|
||||
|
||||
/*
|
||||
Parse the source code if it is not done already.
|
||||
Use getRawParse to get the parse tree.
|
||||
You would need this function if you want to see the parse tree without running the source code.
|
||||
*/
|
||||
@genType
|
||||
let rawParse = (project: reducerProject, sourceId: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.rawParse(sourceId)
|
||||
|
||||
/*
|
||||
Runs a specific source code if it is not done already. The code is parsed if it is not already done. It runs the dependencies if it is not already done.
|
||||
*/
|
||||
@genType
|
||||
let run = (project: reducerProject, sourceId: string): unit =>
|
||||
project->T.Private.castToInternalProject->Private.run(sourceId)
|
||||
|
||||
/*
|
||||
Runs all of the sources in a project. Their results and bindings will be available
|
||||
*/
|
||||
@genType
|
||||
let runAll = (project: reducerProject): unit =>
|
||||
project->T.Private.castToInternalProject->Private.runAll
|
||||
|
||||
/*
|
||||
Get the bindings after running this source file or the project
|
||||
*/
|
||||
@genType
|
||||
let getBindings = (project: reducerProject, sourceId: string): squiggleValue_Module =>
|
||||
project->T.Private.castToInternalProject->Private.getBindings(sourceId)
|
||||
|
||||
/*
|
||||
Get the result after running this source file or the project
|
||||
*/
|
||||
@genType
|
||||
let getResult = (project: reducerProject, sourceId: string): result<
|
||||
squiggleValue,
|
||||
reducerErrorValue,
|
||||
> => project->T.Private.castToInternalProject->Private.getResult(sourceId)
|
||||
|
||||
/*
|
||||
This is a convenience function to get the result of a single source without creating a project.
|
||||
However, without a project, you cannot handle include directives.
|
||||
The source has to be include free
|
||||
*/
|
||||
@genType
|
||||
let evaluate = (sourceCode: string): (
|
||||
result<squiggleValue, reducerErrorValue>,
|
||||
squiggleValue_Module,
|
||||
) => Private.evaluate(sourceCode)
|
||||
|
||||
@genType
|
||||
let setEnvironment = (project: reducerProject, environment: environment): unit =>
|
||||
project->T.Private.castToInternalProject->Private.setEnvironment(environment)
|
||||
|
||||
/*
|
||||
Foreign function interface is intentionally demolished.
|
||||
There is another way to do that: Umur.
|
||||
Also there is no more conversion from javascript to squiggle values currently.
|
||||
If the conversion to the new project is too difficult, I can add it later.
|
||||
*/
|
||||
|
||||
// let foreignFunctionInterface = (
|
||||
// lambdaValue: squiggleValue_Lambda,
|
||||
// argArray: array<squiggleValue>,
|
||||
// environment: environment,
|
||||
// ): result<squiggleValue, reducerErrorValue> => {
|
||||
// let accessors = ReducerProject_ProjectAccessors_T.identityAccessorsWithEnvironment(environment)
|
||||
// Reducer_Expression_Lambda.foreignFunctionInterface(
|
||||
// lambdaValue,
|
||||
// argArray,
|
||||
// accessors,
|
||||
// Reducer_Expression.reduceExpressionInProject,
|
||||
// )
|
||||
// }
|
|
@ -0,0 +1,12 @@
|
|||
@genType type reducerErrorValue = Reducer_ErrorValue.errorValue //alias
|
||||
@genType type syntaxErrorLocation = Reducer_ErrorValue.syntaxErrorLocation //alias
|
||||
|
||||
@genType
|
||||
let toString = (e: reducerErrorValue): string => Reducer_ErrorValue.errorToString(e)
|
||||
|
||||
@genType
|
||||
let getLocation = (e: reducerErrorValue): option<syntaxErrorLocation> =>
|
||||
switch e {
|
||||
| RESyntaxError(_, optionalLocation) => optionalLocation
|
||||
| _ => None
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export type result<a, b> =
|
||||
| {
|
||||
tag: "Ok";
|
||||
value: a;
|
||||
}
|
||||
| {
|
||||
tag: "Error";
|
||||
value: b;
|
||||
};
|
|
@ -0,0 +1,213 @@
|
|||
@genType type squiggleValue = ReducerInterface_InternalExpressionValue.t //re-export
|
||||
type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use
|
||||
|
||||
@genType type squiggleValue_Array = ReducerInterface_InternalExpressionValue.squiggleArray //re-export recursive type
|
||||
@genType type squiggleValue_Module = ReducerInterface_InternalExpressionValue.nameSpace //re-export recursive type
|
||||
@genType type squiggleValue_Record = ReducerInterface_InternalExpressionValue.map //re-export recursive type
|
||||
@genType type squiggleValue_Type = ReducerInterface_InternalExpressionValue.map //re-export recursive type
|
||||
type squiggleValue_Declaration = ForTS_SquiggleValue_Declaration.squiggleValue_Declaration //use
|
||||
type squiggleValue_Distribution = ForTS_SquiggleValue_Distribution.squiggleValue_Distribution //use
|
||||
type squiggleValue_Lambda = ForTS_SquiggleValue_Lambda.squiggleValue_Lambda //use
|
||||
|
||||
// Return values are kept as they are if they are JavaScript types.
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtArray_: string = "SvtArray"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtArrayString_: string = "SvtArrayString"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtBool_: string = "SvtBool"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtCall_: string = "SvtCall"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtDate_: string = "SvtDate"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtDeclaration_: string = "SvtDeclaration"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtDistribution_: string = "SvtDistribution"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtLambda_: string = "SvtLambda"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtModule_: string = "SvtModule"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtNumber_: string = "SvtNumber"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtRecord_: string = "SvtRecord"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtString_: string = "SvtString"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtSymbol_: string = "SvtSymbol"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtTimeDuration_: string = "SvtTimeDuration"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtType_: string = "SvtType"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtTypeIdentifier_: string = "SvtUndefined"
|
||||
|
||||
@module("./ForTS_SquiggleValue_tag") @scope("squiggleValueTag")
|
||||
external svtVoid_: string = "SvtVoid"
|
||||
|
||||
@genType.import("./ForTS_SquiggleValue_tag")
|
||||
type squiggleValueTag
|
||||
|
||||
external castEnum: string => squiggleValueTag = "%identity"
|
||||
|
||||
@genType
|
||||
let getTag = (variant: squiggleValue): squiggleValueTag =>
|
||||
switch variant {
|
||||
| IEvArray(_) => svtArray_->castEnum
|
||||
| IEvArrayString(_) => svtArrayString_->castEnum
|
||||
| IEvBool(_) => svtBool_->castEnum
|
||||
| IEvCall(_) => svtCall_->castEnum //Impossible
|
||||
| IEvDate(_) => svtDate_->castEnum
|
||||
| IEvDeclaration(_) => svtDeclaration_->castEnum
|
||||
| IEvDistribution(_) => svtDistribution_->castEnum
|
||||
| IEvLambda(_) => svtLambda_->castEnum
|
||||
| IEvBindings(_) => svtModule_->castEnum //Impossible
|
||||
| IEvNumber(_) => svtNumber_->castEnum
|
||||
| IEvRecord(_) => svtRecord_->castEnum
|
||||
| IEvString(_) => svtString_->castEnum
|
||||
| IEvSymbol(_) => svtSymbol_->castEnum
|
||||
| IEvTimeDuration(_) => svtTimeDuration_->castEnum
|
||||
| IEvType(_) => svtType_->castEnum
|
||||
| IEvTypeIdentifier(_) => svtTypeIdentifier_->castEnum
|
||||
| IEvVoid => svtVoid_->castEnum
|
||||
}
|
||||
|
||||
@genType
|
||||
let toString = (variant: squiggleValue) =>
|
||||
ReducerInterface_InternalExpressionValue.toString(variant)
|
||||
|
||||
// This is a useful method for unit tests.
|
||||
// Convert the result along with the error message to a string.
|
||||
@genType
|
||||
let toStringResult = (variantResult: result<squiggleValue, reducerErrorValue>) =>
|
||||
ReducerInterface_InternalExpressionValue.toStringResult(variantResult)
|
||||
|
||||
@genType
|
||||
let getArray = (variant: squiggleValue): option<squiggleValue_Array> =>
|
||||
//FIXME: Convert
|
||||
switch variant {
|
||||
| IEvArray(arrayLike) => arrayLike->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getArrayString = (variant: squiggleValue): option<array<string>> =>
|
||||
switch variant {
|
||||
| IEvArrayString(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getBool = (variant: squiggleValue): option<bool> =>
|
||||
switch variant {
|
||||
| IEvBool(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getCall = (variant: squiggleValue): option<string> =>
|
||||
switch variant {
|
||||
| IEvCall(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getDate = (variant: squiggleValue): option<Js.Date.t> =>
|
||||
switch variant {
|
||||
| IEvDate(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getDeclaration = (variant: squiggleValue): option<squiggleValue_Declaration> =>
|
||||
switch variant {
|
||||
| IEvDeclaration(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getDistribution = (variant: squiggleValue): option<squiggleValue_Distribution> =>
|
||||
switch variant {
|
||||
| IEvDistribution(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getLambda = (variant: squiggleValue): option<squiggleValue_Lambda> =>
|
||||
switch variant {
|
||||
| IEvLambda(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getModule = (variant: squiggleValue): option<squiggleValue_Module> =>
|
||||
switch variant {
|
||||
| IEvBindings(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getNumber = (variant: squiggleValue): option<float> =>
|
||||
switch variant {
|
||||
| IEvNumber(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getRecord = (variant: squiggleValue): option<squiggleValue_Record> =>
|
||||
switch variant {
|
||||
| IEvRecord(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getString = (variant: squiggleValue): option<string> =>
|
||||
switch variant {
|
||||
| IEvString(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getSymbol = (variant: squiggleValue): option<string> =>
|
||||
switch variant {
|
||||
| IEvSymbol(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getTimeDuration = (variant: squiggleValue): option<float> =>
|
||||
switch variant {
|
||||
| IEvTimeDuration(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getType = (variant: squiggleValue): option<squiggleValue_Type> =>
|
||||
switch variant {
|
||||
| IEvType(value) => value->Some
|
||||
| _ => None
|
||||
}
|
||||
|
||||
@genType
|
||||
let getTypeIdentifier = (variant: squiggleValue): option<string> =>
|
||||
switch variant {
|
||||
| IEvTypeIdentifier(value) => value->Some
|
||||
| _ => None
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
type squiggleValue = ForTS_SquiggleValue.squiggleValue
|
||||
@genType type squiggleValue_Array = ForTS_SquiggleValue.squiggleValue_Array //re-export recursive type
|
||||
|
||||
@genType
|
||||
let getValues = (v: squiggleValue_Array): array<squiggleValue> =>
|
||||
ReducerInterface_InternalExpressionValue.arrayToValueArray(v)
|
|
@ -0,0 +1 @@
|
|||
@genType type squiggleValue_Declaration = ReducerInterface_InternalExpressionValue.lambdaDeclaration //re-export
|
|
@ -0,0 +1 @@
|
|||
@genType type squiggleValue_Distribution = ForTS_Distribution.distribution
|
|
@ -0,0 +1 @@
|
|||
@genType type squiggleValue_Lambda = ReducerInterface_InternalExpressionValue.lambdaValue //re-export
|
|
@ -0,0 +1,6 @@
|
|||
type squiggleValue = ForTS_SquiggleValue.squiggleValue //use
|
||||
@genType type squiggleValue_Module = ForTS_SquiggleValue.squiggleValue_Module //re-export recursive type
|
||||
|
||||
@genType
|
||||
let getKeyValuePairs = (v: squiggleValue_Module): array<(string, squiggleValue)> =>
|
||||
ReducerInterface_InternalExpressionValue.nameSpaceToKeyValuePairs(v)
|
|
@ -0,0 +1,6 @@
|
|||
type squiggleValue = ForTS_SquiggleValue.squiggleValue //use
|
||||
@genType type squiggleValue_Record = ForTS_SquiggleValue.squiggleValue_Record //re-export recursive type
|
||||
|
||||
@genType
|
||||
let getKeyValuePairs = (value: squiggleValue_Record): array<(string, squiggleValue)> =>
|
||||
ReducerInterface_InternalExpressionValue.recordToKeyValuePairs(value)
|
|
@ -0,0 +1,6 @@
|
|||
type squiggleValue = ForTS_SquiggleValue.squiggleValue //use
|
||||
@genType type squiggleValue_Type = ForTS_SquiggleValue.squiggleValue_Type //re-export recursive type
|
||||
|
||||
@genType
|
||||
let getKeyValuePairs = (value: squiggleValue_Type): array<(string, squiggleValue)> =>
|
||||
ReducerInterface_InternalExpressionValue.recordToKeyValuePairs(value)
|
|
@ -0,0 +1,19 @@
|
|||
export enum squiggleValueTag {
|
||||
SvtArray = "Array",
|
||||
SvtArrayString = "ArrayString",
|
||||
SvtBool = "Bool",
|
||||
SvtCall = "Call",
|
||||
SvtDate = "Date",
|
||||
SvtDeclaration = "Declaration",
|
||||
SvtDistribution = "Distribution",
|
||||
SvtLambda = "Lambda",
|
||||
SvtModule = "Module",
|
||||
SvtNumber = "Number",
|
||||
SvtRecord = "Record",
|
||||
SvtString = "String",
|
||||
SvtSymbol = "Symbol",
|
||||
SvtTimeDuration = "TimeDuration",
|
||||
SvtType = "Type",
|
||||
SvtTypeIdentifier = "TypeIdentifier",
|
||||
SvtVoid = "Void",
|
||||
}
|
21
packages/squiggle-lang/src/rescript/ForTS/ForTS__Types.res
Normal file
21
packages/squiggle-lang/src/rescript/ForTS/ForTS__Types.res
Normal file
|
@ -0,0 +1,21 @@
|
|||
@genType type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //re-export
|
||||
@genType type syntaxErrorLocation = ForTS_Reducer_ErrorValue.syntaxErrorLocation //re-export
|
||||
|
||||
@genType type reducerProject = ForTS_ReducerProject.reducerProject //re-export
|
||||
@genType type squiggleValue = ForTS_SquiggleValue.squiggleValue //re-export
|
||||
@genType type squiggleValue_Array = ForTS_SquiggleValue_Array.squiggleValue_Array //re-export
|
||||
@genType type squiggleValue_Declaration = ForTS_SquiggleValue_Declaration.squiggleValue_Declaration //re-export
|
||||
@genType type squiggleValue_Lambda = ForTS_SquiggleValue_Lambda.squiggleValue_Lambda //re-export
|
||||
@genType type squiggleValue_Module = ForTS_SquiggleValue_Module.squiggleValue_Module //re-export
|
||||
@genType type squiggleValue_Record = ForTS_SquiggleValue_Record.squiggleValue_Record //re-export
|
||||
@genType type squiggleValue_Type = ForTS_SquiggleValue_Type.squiggleValue_Type //re-export
|
||||
|
||||
/* Distribution related */
|
||||
@genType type squiggleValue_Distribution = ForTS_Distribution.distribution //re-export
|
||||
@genType type distribution = squiggleValue_Distribution //candid
|
||||
@genType type distributionError = ForTS_Distribution_Error.distributionError //re-export
|
||||
@genType type environment = ForTS_Distribution_Environment.environment //re-export
|
||||
|
||||
@genType type pointSetDistribution = ForTS_Distribution_PointSetDistribution.pointSetDistribution //re-export
|
||||
@genType type sampleSetDistribution = ForTS_Distribution_SampleSetDistribution.sampleSetDistribution //re-export
|
||||
@genType type symbolicDistribution = ForTS_Distribution_SymbolicDistribution.symbolicDistribution //re-export
|
|
@ -1,3 +1,5 @@
|
|||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
type internalExpressionValue = ReducerInterface_InternalExpressionValue.t
|
||||
type internalExpressionValueType = ReducerInterface_InternalExpressionValue.internalExpressionValueType
|
||||
|
||||
|
@ -46,8 +48,8 @@ type fnDefinition = {
|
|||
run: (
|
||||
array<internalExpressionValue>,
|
||||
array<frValue>,
|
||||
GenericDist.env,
|
||||
Reducer_Expression_T.reducerFn,
|
||||
ProjectAccessorsT.t,
|
||||
ProjectReducerFnT.t,
|
||||
) => result<internalExpressionValue, string>,
|
||||
}
|
||||
|
||||
|
@ -382,12 +384,12 @@ module FnDefinition = {
|
|||
let run = (
|
||||
t: t,
|
||||
args: array<internalExpressionValue>,
|
||||
env: GenericDist.env,
|
||||
reducer: Reducer_Expression_T.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
) => {
|
||||
let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
|
||||
switch argValues {
|
||||
| Some(values) => t.run(args, values, env, reducer)
|
||||
| Some(values) => t.run(args, values, accessors, reducer)
|
||||
| None => Error("Incorrect Types")
|
||||
}
|
||||
}
|
||||
|
@ -493,8 +495,8 @@ module Registry = {
|
|||
~registry: registry,
|
||||
~fnName: string,
|
||||
~args: array<internalExpressionValue>,
|
||||
~env: GenericDist.env,
|
||||
~reducer: Reducer_Expression_T.reducerFn,
|
||||
~accessors: ProjectAccessorsT.t,
|
||||
~reducer: ProjectReducerFnT.t,
|
||||
) => {
|
||||
let relevantFunctions = Js.Dict.get(registry.fnNameDict, fnName) |> E.O.default([])
|
||||
let modified = {functions: relevantFunctions, fnNameDict: registry.fnNameDict}
|
||||
|
@ -512,7 +514,7 @@ module Registry = {
|
|||
|
||||
switch Matcher.Registry.findMatches(modified, fnName, args) {
|
||||
| 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)))
|
||||
| _ => None
|
||||
}
|
||||
|
@ -521,10 +523,10 @@ module Registry = {
|
|||
let dispatch = (
|
||||
registry,
|
||||
(fnName, args): ReducerInterface_InternalExpressionValue.functionCall,
|
||||
env,
|
||||
reducer: Reducer_Expression_T.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
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)),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ module DistributionCreation = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber],
|
||||
~run=(_, inputs, env, _) =>
|
||||
inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env),
|
||||
~run=(_, inputs, accessors, _) =>
|
||||
inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env=accessors.environment),
|
||||
(),
|
||||
)
|
||||
}
|
||||
|
@ -31,8 +31,10 @@ module DistributionCreation = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
|
||||
~run=(_, inputs, env, _) =>
|
||||
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env),
|
||||
~run=(_, inputs, accessors, _) =>
|
||||
inputs
|
||||
->Prepare.ToValueTuple.Record.twoDistOrNumber
|
||||
->process(~fn, ~env=accessors.environment),
|
||||
(),
|
||||
)
|
||||
}
|
||||
|
@ -41,8 +43,10 @@ module DistributionCreation = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
|
||||
~run=(_, inputs, env, _) =>
|
||||
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env),
|
||||
~run=(_, inputs, accessors, _) =>
|
||||
inputs
|
||||
->Prepare.ToValueTuple.Record.twoDistOrNumber
|
||||
->process(~fn, ~env=accessors.environment),
|
||||
(),
|
||||
)
|
||||
}
|
||||
|
@ -58,8 +62,8 @@ module DistributionCreation = {
|
|||
FnDefinition.make(
|
||||
~name,
|
||||
~inputs=[FRTypeDistOrNumber],
|
||||
~run=(_, inputs, env, _) =>
|
||||
inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env),
|
||||
~run=(_, inputs, accessors, _) =>
|
||||
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_Helpers
|
||||
|
||||
|
@ -24,17 +27,19 @@ module Internals = {
|
|||
Belt.Array.reverse(array),
|
||||
)
|
||||
|
||||
let map = (array: array<internalExpressionValue>, environment, eLambdaValue, reducer): result<
|
||||
ReducerInterface_InternalExpressionValue.t,
|
||||
Reducer_ErrorValue.errorValue,
|
||||
> => {
|
||||
let map = (
|
||||
array: array<internalExpressionValue>,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
eLambdaValue,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
): result<ReducerInterface_InternalExpressionValue.t, Reducer_ErrorValue.errorValue> => {
|
||||
let rMappedList = array->E.A.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
||||
rAcc->E.R.bind(_, acc => {
|
||||
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
||||
eLambdaValue,
|
||||
list{elem},
|
||||
environment,
|
||||
reducer,
|
||||
(accessors: ProjectAccessorsT.t),
|
||||
(reducer: ProjectReducerFnT.t),
|
||||
)
|
||||
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)
|
||||
}
|
||||
|
||||
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) =>
|
||||
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) =>
|
||||
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) =>
|
||||
rAcc->E.R.bind(_, acc => {
|
||||
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
||||
aLambdaValue,
|
||||
list{elem},
|
||||
environment,
|
||||
accessors,
|
||||
reducer,
|
||||
)
|
||||
rNewElem->E.R2.fmap(newElem => {
|
||||
|
@ -189,10 +211,10 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="map",
|
||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||
switch inputs {
|
||||
| [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)
|
||||
},
|
||||
(),
|
||||
|
@ -209,10 +231,12 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="reduce",
|
||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||
switch inputs {
|
||||
| [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)
|
||||
},
|
||||
(),
|
||||
|
@ -229,12 +253,16 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="reduceReverse",
|
||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||
switch inputs {
|
||||
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
||||
Internals.reduceReverse(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ =>
|
||||
"Error!"
|
||||
)
|
||||
Internals.reduceReverse(
|
||||
array,
|
||||
initialValue,
|
||||
lambda,
|
||||
accessors,
|
||||
reducer,
|
||||
)->E.R2.errMap(_ => "Error!")
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -251,10 +279,10 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="filter",
|
||||
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||
switch inputs {
|
||||
| [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)
|
||||
},
|
||||
(),
|
||||
|
|
|
@ -58,13 +58,13 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="fromDist",
|
||||
~inputs=[FRTypeDist],
|
||||
~run=(_, inputs, env, _) =>
|
||||
~run=(_, inputs, accessors, _) =>
|
||||
switch inputs {
|
||||
| [FRValueDist(dist)] =>
|
||||
GenericDist.toPointSet(
|
||||
dist,
|
||||
~xyPointLength=env.xyPointLength,
|
||||
~sampleCount=env.sampleCount,
|
||||
~xyPointLength=accessors.environment.xyPointLength,
|
||||
~sampleCount=accessors.environment.sampleCount,
|
||||
(),
|
||||
)
|
||||
->E.R2.fmap(Wrappers.pointSet)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
// module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
open FunctionRegistry_Core
|
||||
open FunctionRegistry_Helpers
|
||||
|
||||
|
@ -6,8 +8,14 @@ let requiresNamespace = true
|
|||
|
||||
module Internal = {
|
||||
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)
|
||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||
}
|
||||
|
@ -22,29 +30,26 @@ module Internal = {
|
|||
}
|
||||
|
||||
//TODO: I don't know why this seems to need at least one input
|
||||
let fromFn = (
|
||||
aLambdaValue,
|
||||
env: ReducerInterface_InternalExpressionValue.environment,
|
||||
reducer,
|
||||
) => {
|
||||
let sampleCount = env.sampleCount
|
||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
|
||||
let fromFn = (aLambdaValue, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) => {
|
||||
let sampleCount = accessors.environment.sampleCount
|
||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, accessors, reducer)
|
||||
Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen
|
||||
}
|
||||
|
||||
let map1 = (sampleSetDist: t, aLambdaValue, env, reducer) => {
|
||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
|
||||
let map1 = (sampleSetDist: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => {
|
||||
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, accessors, reducer)
|
||||
SampleSetDist.samplesMap(~fn, sampleSetDist)->toType
|
||||
}
|
||||
|
||||
let map2 = (t1: t, t2: t, aLambdaValue, env, reducer) => {
|
||||
let fn = (a, b) => doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, env, reducer)
|
||||
let map2 = (t1: t, t2: t, aLambdaValue, accessors: ProjectAccessorsT.t, reducer) => {
|
||||
let fn = (a, b) =>
|
||||
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, accessors, reducer)
|
||||
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) =>
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -59,14 +64,19 @@ module Internal = {
|
|||
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) {
|
||||
| Some(t1) =>
|
||||
let fn = a =>
|
||||
doLambdaCall(
|
||||
aLambdaValue,
|
||||
list{IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))},
|
||||
env,
|
||||
accessors,
|
||||
reducer,
|
||||
)
|
||||
SampleSetDist.mapN(~fn, ~t1)->toType
|
||||
|
@ -86,10 +96,10 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="fromDist",
|
||||
~inputs=[FRTypeDist],
|
||||
~run=(_, inputs, env, _) =>
|
||||
~run=(_, inputs, accessors: ProjectAccessorsT.t, _) =>
|
||||
switch inputs {
|
||||
| [FRValueDist(dist)] =>
|
||||
GenericDist.toSampleSetDist(dist, env.sampleCount)
|
||||
GenericDist.toSampleSetDist(dist, accessors.environment.sampleCount)
|
||||
->E.R2.fmap(Wrappers.sampleSet)
|
||||
->E.R2.fmap(Wrappers.evDistribution)
|
||||
->E.R2.errMap(DistributionTypes.Error.toString)
|
||||
|
@ -153,10 +163,10 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="fromFn",
|
||||
~inputs=[FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||
switch inputs {
|
||||
| [IEvLambda(lambda)] =>
|
||||
switch Internal.fromFn(lambda, env, reducer) {
|
||||
switch Internal.fromFn(lambda, accessors, reducer) {
|
||||
| Ok(r) => Ok(r->Wrappers.sampleSet->Wrappers.evDistribution)
|
||||
| Error(e) => Error(Operation.Error.toString(e))
|
||||
}
|
||||
|
@ -177,10 +187,10 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="map",
|
||||
~inputs=[FRTypeDist, FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||
switch inputs {
|
||||
| [IEvDistribution(SampleSet(dist)), IEvLambda(lambda)] =>
|
||||
Internal.map1(dist, lambda, env, reducer)->E.R2.errMap(Reducer_ErrorValue.errorToString)
|
||||
Internal.map1(dist, lambda, accessors, reducer)->E.R2.errMap(_ => "")
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -200,16 +210,14 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="map2",
|
||||
~inputs=[FRTypeDist, FRTypeDist, FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) => {
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) => {
|
||||
switch inputs {
|
||||
| [
|
||||
IEvDistribution(SampleSet(dist1)),
|
||||
IEvDistribution(SampleSet(dist2)),
|
||||
IEvLambda(lambda),
|
||||
] =>
|
||||
Internal.map2(dist1, dist2, lambda, env, reducer)->E.R2.errMap(
|
||||
Reducer_ErrorValue.errorToString,
|
||||
)
|
||||
Internal.map2(dist1, dist2, lambda, accessors, reducer)->E.R2.errMap(_ => "")
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
},
|
||||
|
@ -230,7 +238,7 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="map3",
|
||||
~inputs=[FRTypeDist, FRTypeDist, FRTypeDist, FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||
switch inputs {
|
||||
| [
|
||||
IEvDistribution(SampleSet(dist1)),
|
||||
|
@ -238,9 +246,7 @@ let library = [
|
|||
IEvDistribution(SampleSet(dist3)),
|
||||
IEvLambda(lambda),
|
||||
] =>
|
||||
Internal.map3(dist1, dist2, dist3, lambda, env, reducer)->E.R2.errMap(
|
||||
Reducer_ErrorValue.errorToString,
|
||||
)
|
||||
Internal.map3(dist1, dist2, dist3, lambda, accessors, reducer)->E.R2.errMap(_ => "")
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
@ -260,12 +266,12 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="mapN",
|
||||
~inputs=[FRTypeArray(FRTypeDist), FRTypeLambda],
|
||||
~run=(inputs, _, env, reducer) =>
|
||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||
switch inputs {
|
||||
| [IEvArray(dists), IEvLambda(lambda)] =>
|
||||
Internal.mapN(dists, lambda, env, reducer)->E.R2.errMap(
|
||||
Reducer_ErrorValue.errorToString,
|
||||
)
|
||||
Internal.mapN(dists, lambda, accessors, reducer)->E.R2.errMap(_e => {
|
||||
"AHHH doesn't work"
|
||||
})
|
||||
| _ => Error(impossibleError)
|
||||
},
|
||||
(),
|
||||
|
|
|
@ -30,16 +30,16 @@ let library = [
|
|||
("prior", FRTypeDist),
|
||||
]),
|
||||
],
|
||||
~run=(_, inputs, env, _) => {
|
||||
~run=(_, inputs, accessors, _) => {
|
||||
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) {
|
||||
| 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([
|
||||
FRValueDist(estimate),
|
||||
FRValueDistOrNumber(FRValueNumber(d)),
|
||||
FRValueDist(prior),
|
||||
]) =>
|
||||
runScoring(estimate, Score_Scalar(d), Some(prior), env)
|
||||
runScoring(estimate, Score_Scalar(d), Some(prior), accessors.environment)
|
||||
| Error(e) => Error(e)
|
||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||
}
|
||||
|
@ -49,12 +49,12 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="logScore",
|
||||
~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])],
|
||||
~run=(_, inputs, env, _) => {
|
||||
~run=(_, inputs, accessors, _) => {
|
||||
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) {
|
||||
| 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))]) =>
|
||||
runScoring(estimate, Score_Scalar(d), None, env)
|
||||
runScoring(estimate, Score_Scalar(d), None, accessors.environment)
|
||||
| Error(e) => Error(e)
|
||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||
}
|
||||
|
@ -74,10 +74,10 @@ let library = [
|
|||
FnDefinition.make(
|
||||
~name="klDivergence",
|
||||
~inputs=[FRTypeDist, FRTypeDist],
|
||||
~run=(_, inputs, env, _) => {
|
||||
~run=(_, inputs, accessors, _) => {
|
||||
switch inputs {
|
||||
| [FRValueDist(estimate), FRValueDist(d)] =>
|
||||
runScoring(estimate, Score_Dist(d), None, env)
|
||||
runScoring(estimate, Score_Dist(d), None, accessors.environment)
|
||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
module ErrorValue = Reducer_ErrorValue
|
||||
module Expression = Reducer_Expression
|
||||
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Lambda = Reducer_Expression_Lambda
|
||||
|
||||
type environment = ReducerInterface_InternalExpressionValue.environment
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
type expressionValue = ExternalExpressionValue.t
|
||||
type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings
|
||||
type lambdaValue = ExternalExpressionValue.lambdaValue
|
||||
|
||||
let evaluate = Expression.evaluate
|
||||
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
||||
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 defaultExternalBindings = ReducerInterface_StdLib.externalStdLib
|
|
@ -1,45 +0,0 @@
|
|||
module ErrorValue = Reducer_ErrorValue
|
||||
module Expression = Reducer_Expression
|
||||
|
||||
@genType
|
||||
type environment = ReducerInterface_ExternalExpressionValue.environment
|
||||
@genType
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
@genType
|
||||
type expressionValue = ReducerInterface_ExternalExpressionValue.t
|
||||
@genType
|
||||
type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings
|
||||
@genType
|
||||
type lambdaValue = ReducerInterface_ExternalExpressionValue.lambdaValue
|
||||
|
||||
@genType
|
||||
let evaluateUsingOptions: (
|
||||
~environment: option<QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment>,
|
||||
~externalBindings: option<
|
||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings,
|
||||
>,
|
||||
string,
|
||||
) => result<expressionValue, errorValue>
|
||||
@genType
|
||||
let evaluatePartialUsingExternalBindings: (
|
||||
string,
|
||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.externalBindings,
|
||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment,
|
||||
) => result<externalBindings, errorValue>
|
||||
@genType
|
||||
let evaluate: string => result<expressionValue, errorValue>
|
||||
|
||||
let parse: string => result<Expression.expression, errorValue>
|
||||
|
||||
@genType
|
||||
let foreignFunctionInterface: (
|
||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.lambdaValue,
|
||||
array<QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.t>,
|
||||
QuriSquiggleLang.ReducerInterface_ExternalExpressionValue.environment,
|
||||
) => result<expressionValue, errorValue>
|
||||
|
||||
@genType
|
||||
let defaultEnvironment: environment
|
||||
|
||||
@genType
|
||||
let defaultExternalBindings: externalBindings
|
|
@ -74,9 +74,10 @@ let set = (nameSpace: t, id: string, value): t => {
|
|||
|
||||
let emptyModule: t = NameSpace(emptyMap)
|
||||
let emptyBindings = emptyModule
|
||||
let emptyNameSpace = emptyModule
|
||||
|
||||
let fromTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceFromTypeScriptBindings
|
||||
let toTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceToTypeScriptBindings
|
||||
// let fromTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceFromTypeScriptBindings
|
||||
// let toTypeScriptBindings = ReducerInterface_InternalExpressionValue.nameSpaceToTypeScriptBindings
|
||||
|
||||
let toExpressionValue = (nameSpace: t): internalExpressionValue => IEvBindings(nameSpace)
|
||||
let fromExpressionValue = (aValue: internalExpressionValue): t =>
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||
module Continuation = ReducerInterface_Value_Continuation
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
||||
module Lambda = Reducer_Expression_Lambda
|
||||
module MathJs = Reducer_MathJs
|
||||
module Bindings = Reducer_Bindings
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
module Result = Belt.Result
|
||||
module TypeBuilder = Reducer_Type_TypeBuilder
|
||||
|
||||
open ReducerInterface_InternalExpressionValue
|
||||
open Reducer_ErrorValue
|
||||
|
||||
|
@ -19,10 +23,11 @@ open Reducer_ErrorValue
|
|||
|
||||
exception TestRescriptException
|
||||
|
||||
let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result<
|
||||
'b,
|
||||
errorValue,
|
||||
> => {
|
||||
let callInternal = (
|
||||
call: functionCall,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
): result<'b, errorValue> => {
|
||||
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
||||
switch call {
|
||||
| ("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 doIdentity = (value: internalExpressionValue) => value->Ok
|
||||
|
||||
let doDumpBindings = (continuation: nameSpace, value: internalExpressionValue) => {
|
||||
// let _ = Continuation.inspect(continuation, "doDumpBindings")
|
||||
accessors.states.continuation = continuation
|
||||
value->Ok
|
||||
}
|
||||
|
||||
module SampleMap = {
|
||||
let doLambdaCall = (aLambdaValue, list) =>
|
||||
switch Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
|
||||
switch Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
||||
| Ok(IEvNumber(f)) => Ok(f)
|
||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||
}
|
||||
|
@ -137,12 +150,14 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
|||
| ("$_constructArray_$", [IEvArray(aValueArray)]) => IEvArray(aValueArray)->Ok
|
||||
| ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
||||
| ("$_exportBindings_$", [IEvBindings(nameSpace)]) => doExportBindings(nameSpace)
|
||||
| ("$_exportBindings_$", [evValue]) => doIdentity(evValue)
|
||||
| ("$_setBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) =>
|
||||
doSetBindings(nameSpace, symbol, value)
|
||||
| ("$_setTypeAliasBindings_$", [IEvBindings(nameSpace), IEvTypeIdentifier(symbol), value]) =>
|
||||
doSetTypeAliasBindings(nameSpace, symbol, value)
|
||||
| ("$_setTypeOfBindings_$", [IEvBindings(nameSpace), IEvSymbol(symbol), value]) =>
|
||||
doSetTypeOfBindings(nameSpace, symbol, value)
|
||||
| ("$_dumpBindings_$", [IEvBindings(nameSpace), _, evValue]) => doDumpBindings(nameSpace, evValue)
|
||||
| ("$_typeModifier_memberOf_$", [IEvTypeIdentifier(typeIdentifier), IEvArray(arr)]) =>
|
||||
TypeBuilder.typeModifier_memberOf(IEvTypeIdentifier(typeIdentifier), IEvArray(arr))
|
||||
| ("$_typeModifier_memberOf_$", [IEvType(typeRecord), IEvArray(arr)]) =>
|
||||
|
@ -182,15 +197,16 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
|||
/*
|
||||
Reducer uses Result monad while reducing expressions
|
||||
*/
|
||||
let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result<
|
||||
internalExpressionValue,
|
||||
errorValue,
|
||||
> =>
|
||||
let dispatch = (
|
||||
call: functionCall,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
): result<internalExpressionValue, errorValue> =>
|
||||
try {
|
||||
let (fn, args) = call
|
||||
// There is a bug that prevents string match in patterns
|
||||
// So we have to recreate a copy of the string
|
||||
ExternalLibrary.dispatch((Js.String.make(fn), args), environment, reducer, callInternal)
|
||||
ExternalLibrary.dispatch((Js.String.make(fn), args), accessors, reducer, callInternal)
|
||||
} catch {
|
||||
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
||||
| _ => RETodo("unhandled rescript exception")->Error
|
||||
|
|
|
@ -3,17 +3,19 @@
|
|||
they take expressions as parameters and return a new expression.
|
||||
Macros are used to define language building blocks. They are like Lisp macros.
|
||||
*/
|
||||
module Bindings = Reducer_Bindings
|
||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
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
|
||||
|
||||
open Reducer_Expression_ExpressionBuilder
|
||||
|
||||
type environment = InternalExpressionValue.environment
|
||||
type errorValue = ErrorValue.errorValue
|
||||
type expression = ExpressionT.expression
|
||||
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||
|
@ -21,11 +23,11 @@ type expressionWithContext = ExpressionWithContext.expressionWithContext
|
|||
let dispatchMacroCall = (
|
||||
macroExpression: expression,
|
||||
bindings: ExpressionT.bindings,
|
||||
environment,
|
||||
reduceExpression: ExpressionT.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reduceExpression: ProjectReducerFnT.t,
|
||||
): result<expressionWithContext, errorValue> => {
|
||||
let useExpressionToSetBindings = (bindingExpr: expression, environment, statement, newCode) => {
|
||||
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||
let useExpressionToSetBindings = (bindingExpr: expression, accessors, statement, newCode) => {
|
||||
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, accessors)
|
||||
|
||||
rExternalBindingsValue->Result.flatMap(nameSpaceValue => {
|
||||
let newBindings = Bindings.fromExpressionValue(nameSpaceValue)
|
||||
|
@ -45,16 +47,17 @@ let dispatchMacroCall = (
|
|||
| "$_let_$" => "$_setBindings_$"
|
||||
| "$_typeOf_$" => "$_setTypeOfBindings_$"
|
||||
| "$_typeAlias_$" => "$_setTypeAliasBindings_$"
|
||||
| "$_endOfOuterBlock_$" => "$_dumpBindings_$"
|
||||
| _ => ""
|
||||
}
|
||||
|
||||
let doBindStatement = (bindingExpr: expression, statement: expression, environment) => {
|
||||
let doBindStatement = (bindingExpr: expression, statement: expression, accessors) => {
|
||||
let defaultStatement = ErrorValue.REAssignmentExpected->Error
|
||||
switch statement {
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
||||
let setBindingsFn = correspondingSetBindingsFn(callName)
|
||||
if setBindingsFn !== "" {
|
||||
useExpressionToSetBindings(bindingExpr, environment, statement, (
|
||||
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||
newBindingsExpr,
|
||||
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,
|
||||
errorValue,
|
||||
> => {
|
||||
let defaultStatement = () =>
|
||||
useExpressionToSetBindings(bindingExpr, environment, statement, (
|
||||
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||
_newBindingsExpr,
|
||||
boundStatement,
|
||||
) => boundStatement)
|
||||
|
@ -80,13 +83,13 @@ let dispatchMacroCall = (
|
|||
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
||||
let setBindingsFn = correspondingSetBindingsFn(callName)
|
||||
if setBindingsFn !== "" {
|
||||
useExpressionToSetBindings(bindingExpr, environment, statement, (
|
||||
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||
newBindingsExpr,
|
||||
boundStatement,
|
||||
) =>
|
||||
eFunction(
|
||||
"$_exportBindings_$",
|
||||
list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})},
|
||||
list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})}, // expression returning bindings
|
||||
)
|
||||
)
|
||||
} 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,
|
||||
errorValue,
|
||||
> => {
|
||||
|
@ -130,10 +133,10 @@ let dispatchMacroCall = (
|
|||
ifTrue: expression,
|
||||
ifFalse: expression,
|
||||
bindings: ExpressionT.bindings,
|
||||
environment,
|
||||
accessors,
|
||||
): result<expressionWithContext, errorValue> => {
|
||||
let blockCondition = ExpressionBuilder.eBlock(list{condition})
|
||||
let rCondition = reduceExpression(blockCondition, bindings, environment)
|
||||
let rCondition = reduceExpression(blockCondition, bindings, accessors)
|
||||
rCondition->Result.flatMap(conditionValue =>
|
||||
switch conditionValue {
|
||||
| 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,
|
||||
errorValue,
|
||||
> =>
|
||||
|
@ -159,21 +162,21 @@ let dispatchMacroCall = (
|
|||
bindingExpr: ExpressionT.expression,
|
||||
statement,
|
||||
} =>
|
||||
doBindStatement(bindingExpr, statement, environment)
|
||||
doBindStatement(bindingExpr, statement, accessors)
|
||||
| list{ExpressionT.EValue(IEvCall("$$_bindStatement_$$")), statement} =>
|
||||
// bindings of the context are used when there is no binding expression
|
||||
doBindStatement(eModule(bindings), statement, environment)
|
||||
doBindStatement(eModule(bindings), statement, accessors)
|
||||
| list{
|
||||
ExpressionT.EValue(IEvCall("$$_bindExpression_$$")),
|
||||
bindingExpr: ExpressionT.expression,
|
||||
expression,
|
||||
} =>
|
||||
doBindExpression(bindingExpr, expression, environment)
|
||||
doBindExpression(bindingExpr, expression, accessors)
|
||||
| list{ExpressionT.EValue(IEvCall("$$_bindExpression_$$")), 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} =>
|
||||
doBlock(exprs, bindings, environment)
|
||||
doBlock(exprs, bindings, accessors)
|
||||
| list{
|
||||
ExpressionT.EValue(IEvCall("$$_lambda_$$")),
|
||||
ExpressionT.EValue(IEvArrayString(parameters)),
|
||||
|
@ -181,12 +184,12 @@ let dispatchMacroCall = (
|
|||
} =>
|
||||
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
||||
| 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
|
||||
}
|
||||
|
||||
switch macroExpression {
|
||||
| EList(aList) => expandExpressionList(aList, bindings, environment)
|
||||
| EList(aList) => expandExpressionList(aList, bindings, accessors)
|
||||
| _ => ExpressionWithContext.noContext(macroExpression)->Ok
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module T = Reducer_Dispatch_T
|
||||
module TypeChecker = Reducer_Type_TypeChecker
|
||||
open ReducerInterface_InternalExpressionValue
|
||||
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
|
||||
let makeFromTypes = jumpTable => {
|
||||
let dispatchChainPiece: T.dispatchChainPiece = ((fnName, fnArgs): functionCall, environment) => {
|
||||
let dispatchChainPiece: T.dispatchChainPiece = (
|
||||
(fnName, fnArgs): functionCall,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
) => {
|
||||
let jumpTableEntry = jumpTable->Js.Array2.find(elem => {
|
||||
let (candidName, candidType, _) = elem
|
||||
candidName == fnName && TypeChecker.checkITypeArgumentsBool(candidType, fnArgs)
|
||||
})
|
||||
switch jumpTableEntry {
|
||||
| Some((_, _, bridgeFn)) => bridgeFn(fnArgs, environment)->Some
|
||||
| Some((_, _, bridgeFn)) => bridgeFn(fnArgs, accessors)->Some
|
||||
| _ => None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
|
||||
// Each piece of the dispatch chain computes the result or returns None so that the chain can continue
|
||||
type dispatchChainPiece = (
|
||||
InternalExpressionValue.functionCall,
|
||||
InternalExpressionValue.environment,
|
||||
ProjectAccessorsT.t,
|
||||
) => option<result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>>
|
||||
|
||||
type dispatchChainPieceWithReducer = (
|
||||
InternalExpressionValue.functionCall,
|
||||
InternalExpressionValue.environment,
|
||||
ExpressionT.reducerFn,
|
||||
ProjectAccessorsT.t,
|
||||
ProjectReducerFnT.t,
|
||||
) => option<result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>>
|
||||
|
||||
// This is a switch statement case implementation: get the arguments and compute the result
|
||||
type genericIEvFunction = (
|
||||
array<InternalExpressionValue.t>,
|
||||
InternalExpressionValue.environment,
|
||||
ProjectAccessorsT.t,
|
||||
) => result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
//TODO: Do not export here but in ForTS__Types
|
||||
@gentype.import("peggy") @genType.as("LocationRange")
|
||||
type location
|
||||
type syntaxErrorLocation
|
||||
|
||||
@genType
|
||||
@genType.opaque
|
||||
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)
|
||||
| REAssignmentExpected
|
||||
| REDistributionError(DistributionTypes.error)
|
||||
|
@ -17,13 +18,13 @@ type errorValue =
|
|||
| REOperationError(Operation.operationError)
|
||||
| RERecordPropertyNotFound(string, string)
|
||||
| RESymbolNotFound(string)
|
||||
| RESyntaxError(string, option<location>)
|
||||
| RESyntaxError(string, option<syntaxErrorLocation>)
|
||||
| RETodo(string) // To do
|
||||
| REUnitNotFound(string)
|
||||
| RENeedToRun
|
||||
|
||||
type t = errorValue
|
||||
|
||||
@genType
|
||||
let errorToString = err =>
|
||||
switch err {
|
||||
| REArityError(_oFnName, arity, usedArity) =>
|
||||
|
@ -57,4 +58,5 @@ let errorToString = err =>
|
|||
| RETodo(msg) => `TODO: ${msg}`
|
||||
| REExpectedType(typeName, valueString) => `Expected type: ${typeName} but got: ${valueString}`
|
||||
| REUnitNotFound(unitName) => `Unit not found: ${unitName}`
|
||||
| RENeedToRun => "Need to run"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||
module BuiltIn = Reducer_Dispatch_BuiltIn
|
||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||
|
@ -6,30 +7,21 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|||
module Lambda = Reducer_Expression_Lambda
|
||||
module Macro = Reducer_Expression_Macro
|
||||
module MathJs = Reducer_MathJs
|
||||
module Bindings = Reducer_Bindings
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module Result = Belt.Result
|
||||
module T = Reducer_Expression_T
|
||||
|
||||
type environment = InternalExpressionValue.environment
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
type expression = T.expression
|
||||
type internalExpressionValue = InternalExpressionValue.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> =>
|
||||
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
||||
|
||||
/*
|
||||
Recursively evaluate/reduce the expression (Lisp AST)
|
||||
*/
|
||||
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
|
||||
internalExpressionValue,
|
||||
'e,
|
||||
> => {
|
||||
let rec reduceExpressionInProject = (
|
||||
expression: t,
|
||||
continuation: T.bindings,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
): result<InternalExpressionValue.t, 'e> => {
|
||||
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
||||
switch expression {
|
||||
| T.EValue(value) => value->Ok
|
||||
|
@ -38,41 +30,40 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en
|
|||
| list{EValue(IEvCall(fName)), ..._args} =>
|
||||
switch Macro.isMacroName(fName) {
|
||||
// A macro expands then reduces itself
|
||||
| true => Macro.doMacroCall(expression, bindings, environment, reduceExpression)
|
||||
| false => reduceExpressionList(list, bindings, environment)
|
||||
| true => Macro.doMacroCall(expression, continuation, accessors, reduceExpressionInProject)
|
||||
| false => reduceExpressionList(list, continuation, accessors)
|
||||
}
|
||||
| _ => reduceExpressionList(list, bindings, environment)
|
||||
| _ => reduceExpressionList(list, continuation, accessors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
and reduceExpressionList = (
|
||||
expressions: list<t>,
|
||||
bindings: T.bindings,
|
||||
environment: environment,
|
||||
): result<internalExpressionValue, 'e> => {
|
||||
continuation: T.bindings,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
): result<InternalExpressionValue.t, 'e> => {
|
||||
let racc: result<
|
||||
list<internalExpressionValue>,
|
||||
list<InternalExpressionValue.t>,
|
||||
'e,
|
||||
> = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
||||
> = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: t) =>
|
||||
racc->Result.flatMap(acc => {
|
||||
each
|
||||
->reduceExpression(bindings, environment)
|
||||
->reduceExpressionInProject(continuation, accessors)
|
||||
->Result.map(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
|
||||
*/
|
||||
and reduceValueList = (valueList: list<internalExpressionValue>, environment): result<
|
||||
internalExpressionValue,
|
||||
'e,
|
||||
> =>
|
||||
and reduceValueList = (
|
||||
valueList: list<InternalExpressionValue.t>,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
): result<InternalExpressionValue.t, 'e> =>
|
||||
switch valueList {
|
||||
| list{IEvCall(fName), ...args} => {
|
||||
let rCheckedArgs = switch fName {
|
||||
|
@ -81,7 +72,10 @@ and reduceValueList = (valueList: list<internalExpressionValue>, environment): r
|
|||
}
|
||||
|
||||
rCheckedArgs->Result.flatMap(checkedArgs =>
|
||||
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression)
|
||||
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(
|
||||
accessors,
|
||||
reduceExpressionInProject,
|
||||
)
|
||||
)
|
||||
}
|
||||
| list{IEvLambda(_)} =>
|
||||
|
@ -91,11 +85,11 @@ and reduceValueList = (valueList: list<internalExpressionValue>, environment): r
|
|||
->Result.flatMap(reducedValueList =>
|
||||
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
|
||||
)
|
||||
| list{IEvLambda(lamdaCall), ...args} =>
|
||||
| list{IEvLambda(lambdaCall), ...args} =>
|
||||
args
|
||||
->Lambda.checkIfReduced
|
||||
->Result.flatMap(checkedArgs =>
|
||||
Lambda.doLambdaCall(lamdaCall, checkedArgs, environment, reduceExpression)
|
||||
Lambda.doLambdaCall(lambdaCall, checkedArgs, accessors, reduceExpressionInProject)
|
||||
)
|
||||
|
||||
| _ =>
|
||||
|
@ -106,53 +100,27 @@ and reduceValueList = (valueList: list<internalExpressionValue>, environment): r
|
|||
)
|
||||
}
|
||||
|
||||
let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result<
|
||||
internalExpressionValue,
|
||||
'e,
|
||||
> => reduceExpression(aExpression, bindings, environment)
|
||||
|
||||
let evaluateUsingOptions = (
|
||||
~environment: option<ReducerInterface_ExternalExpressionValue.environment>,
|
||||
~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)
|
||||
let reduceReturningBindings = (
|
||||
expression: t,
|
||||
continuation: T.bindings,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
): (result<InternalExpressionValue.t, 'e>, T.bindings) => {
|
||||
let states = accessors.states
|
||||
let result = reduceExpressionInProject(expression, continuation, accessors)
|
||||
(result, states.continuation)
|
||||
}
|
||||
|
||||
/*
|
||||
IEvaluates Squiggle code and bindings via Reducer and answers the result
|
||||
*/
|
||||
let evaluate = (code: string): result<externalExpressionValue, errorValue> => {
|
||||
evaluateUsingOptions(~environment=None, ~externalBindings=None, code)
|
||||
}
|
||||
let evaluatePartialUsingExternalBindings = (
|
||||
code: string,
|
||||
externalBindings: ReducerInterface_ExternalExpressionValue.externalBindings,
|
||||
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
|
||||
module BackCompatible = {
|
||||
// Those methods are used to support the existing tests
|
||||
// If they are used outside limited testing context, error location reporting will fail
|
||||
let parse = (peggyCode: string): result<t, errorValue> =>
|
||||
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
||||
|
||||
let evaluate = (expression: t): result<InternalExpressionValue.t, errorValue> => {
|
||||
let accessors = ProjectAccessorsT.identityAccessors
|
||||
expression->reduceExpressionInProject(accessors.stdLib, accessors)
|
||||
}
|
||||
|
||||
let evaluateString = (peggyCode: string): result<InternalExpressionValue.t, errorValue> =>
|
||||
parse(peggyCode)->Result.flatMap(evaluate)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
module Result = Belt.Result
|
||||
module Bindings = Reducer_Bindings
|
||||
|
||||
type bindings = ExpressionT.bindings
|
||||
type context = bindings
|
||||
|
@ -11,7 +13,6 @@ type environment = InternalExpressionValue.environment
|
|||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
type expression = ExpressionT.expression
|
||||
type internalExpressionValue = InternalExpressionValue.t
|
||||
type reducerFn = ExpressionT.reducerFn
|
||||
|
||||
type expressionWithContext =
|
||||
| ExpressionWithContext(expression, context)
|
||||
|
@ -20,16 +21,16 @@ type expressionWithContext =
|
|||
let callReducer = (
|
||||
expressionWithContext: expressionWithContext,
|
||||
bindings: bindings,
|
||||
environment: environment,
|
||||
reducer: reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
): result<internalExpressionValue, errorValue> => {
|
||||
switch expressionWithContext {
|
||||
| ExpressionNoContext(expr) =>
|
||||
// Js.log(`callReducer: bindings ${Bindings.toString(bindings)} expr ${ExpressionT.toString(expr)}`)
|
||||
reducer(expr, bindings, environment)
|
||||
reducer(expr, bindings, accessors)
|
||||
| ExpressionWithContext(expr, context) =>
|
||||
// Js.log(`callReducer: context ${Bindings.toString(context)} expr ${ExpressionT.toString(expr)}`)
|
||||
reducer(expr, context, environment)
|
||||
reducer(expr, context, accessors)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ module Bindings = Reducer_Bindings
|
|||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
type expression = ExpressionT.expression
|
||||
type internalExpressionValue = InternalExpressionValue.t
|
||||
type externalBindings = ReducerInterface_ExternalExpressionValue.externalBindings
|
||||
|
||||
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Bindings = Reducer_Bindings
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
module Result = Belt.Result
|
||||
|
||||
type environment = ReducerInterface_InternalExpressionValue.environment
|
||||
type expression = ExpressionT.expression
|
||||
type expressionOrFFI = ExpressionT.expressionOrFFI
|
||||
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 zippedParameterList = parameterList->Belt.List.zip(args)
|
||||
let bindings = Belt.List.reduce(zippedParameterList, lambdaValue.context, (
|
||||
|
@ -52,39 +59,43 @@ let caseNotFFI = (lambdaValue: ExpressionValue.lambdaValue, expr, args, environm
|
|||
(variable, variableValue),
|
||||
) => acc->Bindings.set(variable, variableValue))
|
||||
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||
reducer(newExpression, bindings, environment)
|
||||
reducer(newExpression, bindings, accessors)
|
||||
}
|
||||
|
||||
let caseFFI = (ffiFn: ExpressionT.ffiFn, args, environment) => {
|
||||
ffiFn(args->Belt.List.toArray, environment)
|
||||
let caseFFI = (ffiFn: ExpressionT.ffiFn, args, accessors: ProjectAccessorsT.t) => {
|
||||
ffiFn(args->Belt.List.toArray, accessors.environment)
|
||||
}
|
||||
|
||||
let applyParametersToLambda = (
|
||||
lambdaValue: ExpressionValue.lambdaValue,
|
||||
args,
|
||||
environment,
|
||||
reducer: ExpressionT.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
): result<internalExpressionValue, 'e> => {
|
||||
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
||||
checkIfReduced(args)->Result.flatMap(args => {
|
||||
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
||||
switch exprOrFFI {
|
||||
| NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, environment, reducer)
|
||||
| FFI(ffiFn) => caseFFI(ffiFn, args, environment)
|
||||
| NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, accessors, reducer)
|
||||
| FFI(ffiFn) => caseFFI(ffiFn, args, accessors)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) =>
|
||||
applyParametersToLambda(lambdaValue, args, environment, reducer)
|
||||
let doLambdaCall = (
|
||||
lambdaValue: ExpressionValue.lambdaValue,
|
||||
args,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
) => applyParametersToLambda(lambdaValue, args, accessors, reducer)
|
||||
|
||||
let foreignFunctionInterface = (
|
||||
lambdaValue: ExpressionValue.lambdaValue,
|
||||
argArray: array<internalExpressionValue>,
|
||||
environment: ExpressionValue.environment,
|
||||
reducer: ExpressionT.reducerFn,
|
||||
): result<internalExpressionValue, 'e> => {
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
): result<internalExpressionValue, Reducer_ErrorValue.errorValue> => {
|
||||
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 ExpressionWithContext = Reducer_ExpressionWithContext
|
||||
module Result = Belt.Result
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
|
||||
type environment = InternalExpressionValue.environment
|
||||
type expression = ExpressionT.expression
|
||||
|
@ -11,34 +13,29 @@ type expressionWithContext = ExpressionWithContext.expressionWithContext
|
|||
let expandMacroCall = (
|
||||
macroExpression: expression,
|
||||
bindings: ExpressionT.bindings,
|
||||
environment: environment,
|
||||
reduceExpression: ExpressionT.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reduceExpression: ProjectReducerFnT.t,
|
||||
): result<expressionWithContext, 'e> =>
|
||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
||||
macroExpression,
|
||||
bindings,
|
||||
environment,
|
||||
accessors,
|
||||
reduceExpression,
|
||||
)
|
||||
|
||||
let doMacroCall = (
|
||||
macroExpression: expression,
|
||||
bindings: ExpressionT.bindings,
|
||||
environment: environment,
|
||||
reduceExpression: ExpressionT.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reduceExpression: ProjectReducerFnT.t,
|
||||
): result<internalExpressionValue, 'e> =>
|
||||
expandMacroCall(
|
||||
macroExpression,
|
||||
bindings,
|
||||
environment,
|
||||
reduceExpression,
|
||||
(accessors: ProjectAccessorsT.t),
|
||||
(reduceExpression: ProjectReducerFnT.t),
|
||||
)->Result.flatMap(expressionWithContext =>
|
||||
ExpressionWithContext.callReducer(
|
||||
expressionWithContext,
|
||||
bindings,
|
||||
environment,
|
||||
reduceExpression,
|
||||
)
|
||||
ExpressionWithContext.callReducer(expressionWithContext, bindings, accessors, reduceExpression)
|
||||
)
|
||||
|
||||
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
|
||||
and bindings = InternalExpressionValue.nameSpace
|
||||
|
||||
type t = expression
|
||||
|
||||
type reducerFn = (
|
||||
expression,
|
||||
bindings,
|
||||
|
|
|
@ -9,12 +9,25 @@ start
|
|||
|
||||
zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
|
||||
|
||||
// { return h.makeFunctionCall('$_typeOf_$', [identifier, typeExpression])}
|
||||
// {return [h.nodeVoid()];}
|
||||
outerBlock
|
||||
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
||||
{ if (finalExpression != null) { statements.push(finalExpression) }
|
||||
{ if (finalExpression != null)
|
||||
{
|
||||
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
|
||||
{ return h.nodeBlock([finalExpression])}
|
||||
{
|
||||
var newFinalExpression = h.makeFunctionCall('$_endOfOuterBlock_$', [h.nodeVoid(), finalExpression]);
|
||||
return h.nodeBlock([newFinalExpression])}
|
||||
|
||||
innerBlockOrExpression
|
||||
= quotedInnerBlock
|
||||
|
|
|
@ -5,13 +5,12 @@ type node = {"type": string}
|
|||
|
||||
@module("./Reducer_Peggy_GeneratedParser.js") external parse__: string => node = "parse"
|
||||
|
||||
type withLocation = {"location": Reducer_ErrorValue.location}
|
||||
type withLocation = {"location": Reducer_ErrorValue.syntaxErrorLocation}
|
||||
external castWithLocation: Js.Exn.t => withLocation = "%identity"
|
||||
|
||||
let syntaxErrorToLocation = (error: Js.Exn.t): Reducer_ErrorValue.location =>
|
||||
let syntaxErrorToLocation = (error: Js.Exn.t): Reducer_ErrorValue.syntaxErrorLocation =>
|
||||
castWithLocation(error)["location"]
|
||||
|
||||
@genType
|
||||
let parse = (expr: string): result<node, errorValue> =>
|
||||
try {
|
||||
Ok(parse__(expr))
|
||||
|
|
|
@ -1,47 +1,44 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module Expression = Reducer_Expression
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module Bindings = Reducer_Bindings
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
module T = Reducer_Type_T
|
||||
|
||||
let ievFromTypeExpression = (
|
||||
typeExpressionSourceCode: string,
|
||||
reducerFn: ExpressionT.reducerFn,
|
||||
reducerFn: ProjectReducerFnT.t,
|
||||
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||
let sIndex = "compiled"
|
||||
let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}`
|
||||
Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
||||
let rContext = reducerFn(
|
||||
expr,
|
||||
Bindings.emptyBindings,
|
||||
InternalExpressionValue.defaultEnvironment,
|
||||
)
|
||||
Belt.Result.map(rContext, context =>
|
||||
switch context {
|
||||
| IEvBindings(nameSpace) =>
|
||||
Reducer_Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
||||
let accessors = ProjectAccessorsT.identityAccessors
|
||||
let result = reducerFn(expr, Bindings.emptyBindings, accessors)
|
||||
let nameSpace = accessors.states.continuation
|
||||
|
||||
switch result {
|
||||
| Ok(_) =>
|
||||
switch Bindings.getType(nameSpace, sIndex) {
|
||||
| Some(value) => value
|
||||
| Some(value) => value->Ok
|
||||
| None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none"))
|
||||
}
|
||||
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-raise"))
|
||||
| err => err
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let fromTypeExpression = (
|
||||
typeExpressionSourceCode: string,
|
||||
reducerFn: ExpressionT.reducerFn,
|
||||
): result<T.t, ErrorValue.t> => {
|
||||
ievFromTypeExpression(
|
||||
(typeExpressionSourceCode: string),
|
||||
(reducerFn: ExpressionT.reducerFn),
|
||||
)->Belt.Result.map(T.fromIEvValue)
|
||||
let fromTypeExpression = (typeExpressionSourceCode: string, reducerFn: ProjectReducerFnT.t): result<
|
||||
T.t,
|
||||
ErrorValue.t,
|
||||
> => {
|
||||
ievFromTypeExpression(typeExpressionSourceCode, reducerFn)->Belt.Result.map(T.fromIEvValue)
|
||||
}
|
||||
|
||||
let fromTypeExpressionExn = (
|
||||
typeExpressionSourceCode: string,
|
||||
reducerFn: ExpressionT.reducerFn,
|
||||
reducerFn: ProjectReducerFnT.t,
|
||||
): T.t =>
|
||||
switch fromTypeExpression(typeExpressionSourceCode, reducerFn) {
|
||||
| Ok(value) => value
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
module T = Reducer_Type_T
|
||||
module TypeContracts = Reducer_Type_Contracts
|
||||
open InternalExpressionValue
|
||||
|
@ -129,7 +131,7 @@ let rec isITypeOf = (anIType: T.iType, aValue): result<bool, T.typeErrorValue> =
|
|||
let isTypeOf = (
|
||||
typeExpressionSourceCode: string,
|
||||
aValue: InternalExpressionValue.t,
|
||||
reducerFn: ExpressionT.reducerFn,
|
||||
reducerFn: ProjectReducerFnT.t,
|
||||
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
||||
| Ok(anIType) =>
|
||||
|
@ -164,7 +166,7 @@ let checkITypeArgumentsBool = (anIType: T.iType, args: array<InternalExpressionV
|
|||
let checkArguments = (
|
||||
typeExpressionSourceCode: string,
|
||||
args: array<InternalExpressionValue.t>,
|
||||
reducerFn: ExpressionT.reducerFn,
|
||||
reducerFn: ProjectReducerFnT.t,
|
||||
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
||||
| Ok(anIType) =>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||
module ExternalLibrary = ReducerInterface_ExternalLibrary
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module StdLib = ReducerInterface_StdLib
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
Irreducible values. Reducer does not know about those. Only used for external calls
|
||||
This is a configuration to to make external calls of those types
|
||||
*/
|
||||
module Extra_Array = Reducer_Extra_Array
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
@genType.opaque
|
||||
type internalCode = Object
|
||||
|
||||
@genType.opaque
|
||||
type hiddenNameSpace = Object
|
||||
|
||||
@genType
|
||||
type rec externalExpressionValue =
|
||||
| EvArray(array<externalExpressionValue>)
|
||||
| EvArrayString(array<string>)
|
||||
| EvBool(bool)
|
||||
| EvCall(string) // External function call
|
||||
| EvDistribution(DistributionTypes.genericDist)
|
||||
| EvLambda(lambdaValue)
|
||||
| EvNumber(float)
|
||||
| EvRecord(record)
|
||||
| EvString(string)
|
||||
| EvSymbol(string)
|
||||
| EvDate(Js.Date.t)
|
||||
| EvTimeDuration(float)
|
||||
| EvDeclaration(lambdaDeclaration)
|
||||
| EvTypeIdentifier(string)
|
||||
| EvModule(record)
|
||||
| EvType(record)
|
||||
| EvVoid
|
||||
and record = Js.Dict.t<externalExpressionValue>
|
||||
and lambdaValue = {
|
||||
parameters: array<string>,
|
||||
context: hiddenNameSpace,
|
||||
body: internalCode,
|
||||
}
|
||||
and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
||||
|
||||
@genType
|
||||
type externalBindings = record
|
||||
|
||||
@genType
|
||||
type t = externalExpressionValue
|
||||
|
||||
type functionCall = (string, array<externalExpressionValue>)
|
||||
|
||||
let rec toString = aValue =>
|
||||
switch aValue {
|
||||
| EvArray(anArray) => {
|
||||
let args = anArray->Js.Array2.map(each => toString(each))->Js.Array2.toString
|
||||
`[${args}]`
|
||||
}
|
||||
| EvArrayString(anArray) => {
|
||||
let args = anArray->Js.Array2.toString
|
||||
`[${args}]`
|
||||
}
|
||||
| EvBool(aBool) => Js.String.make(aBool)
|
||||
| EvCall(fName) => `:${fName}`
|
||||
| EvDate(date) => DateTime.Date.toString(date)
|
||||
| EvDeclaration(d) => Declaration.toString(d, r => toString(EvLambda(r)))
|
||||
| EvDistribution(dist) => GenericDist.toString(dist)
|
||||
| EvLambda(lambdaValue) => `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
||||
| EvModule(m) => `@${m->toStringRecord}`
|
||||
| EvNumber(aNumber) => Js.String.make(aNumber)
|
||||
| EvRecord(aRecord) => aRecord->toStringRecord
|
||||
| EvString(aString) => `'${aString}'`
|
||||
| EvSymbol(aString) => `:${aString}`
|
||||
| EvTimeDuration(t) => DateTime.Duration.toString(t)
|
||||
| EvType(t) => `type${t->toStringRecord}`
|
||||
| EvTypeIdentifier(id) => `#${id}`
|
||||
| EvVoid => `()`
|
||||
}
|
||||
and toStringRecord = aRecord => {
|
||||
let pairs =
|
||||
aRecord
|
||||
->Js.Dict.entries
|
||||
->Js.Array2.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
||||
->Js.Array2.toString
|
||||
`{${pairs}}`
|
||||
}
|
||||
|
||||
let argsToString = (args: array<externalExpressionValue>): string => {
|
||||
args->Js.Array2.map(arg => arg->toString)->Js.Array2.toString
|
||||
}
|
||||
|
||||
let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})`
|
||||
|
||||
let toStringResult = x =>
|
||||
switch x {
|
||||
| Ok(a) => `Ok(${toString(a)})`
|
||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||
}
|
||||
|
||||
@genType
|
||||
type environment = GenericDist.env
|
||||
|
||||
@genType
|
||||
let defaultEnvironment: environment = DistributionOperation.defaultEnv
|
|
@ -1,4 +1,6 @@
|
|||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||
type internalExpressionValue = InternalExpressionValue.t
|
||||
|
||||
/*
|
||||
|
@ -6,17 +8,17 @@ type internalExpressionValue = InternalExpressionValue.t
|
|||
*/
|
||||
let dispatch = (
|
||||
call: InternalExpressionValue.functionCall,
|
||||
environment,
|
||||
reducer: Reducer_Expression_T.reducerFn,
|
||||
accessors: ProjectAccessorsT.t,
|
||||
reducer: ProjectReducerFnT.t,
|
||||
chain,
|
||||
): result<internalExpressionValue, 'e> => {
|
||||
E.A.O.firstSomeFn([
|
||||
() => ReducerInterface_GenericDistribution.dispatch(call, environment),
|
||||
() => ReducerInterface_Date.dispatch(call, environment),
|
||||
() => ReducerInterface_Duration.dispatch(call, environment),
|
||||
() => ReducerInterface_Number.dispatch(call, environment),
|
||||
() => FunctionRegistry_Library.dispatch(call, environment, reducer),
|
||||
])->E.O2.defaultFn(() => chain(call, environment, reducer))
|
||||
() => ReducerInterface_GenericDistribution.dispatch(call, accessors.environment),
|
||||
() => ReducerInterface_Date.dispatch(call, accessors.environment),
|
||||
() => ReducerInterface_Duration.dispatch(call, accessors.environment),
|
||||
() => ReducerInterface_Number.dispatch(call, accessors.environment),
|
||||
() => FunctionRegistry_Library.dispatch(call, accessors, reducer),
|
||||
])->E.O2.defaultFn(() => chain(call, accessors, reducer))
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let dispatch: (
|
||||
ReducerInterface_InternalExpressionValue.functionCall,
|
||||
ReducerInterface_ExternalExpressionValue.environment,
|
||||
ReducerInterface_InternalExpressionValue.environment,
|
||||
) => option<result<ReducerInterface_InternalExpressionValue.t, Reducer_ErrorValue.errorValue>>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExternalExpressionValue = ReducerInterface_ExternalExpressionValue
|
||||
module Extra_Array = Reducer_Extra_Array
|
||||
type internalCode = ExternalExpressionValue.internalCode
|
||||
type environment = ExternalExpressionValue.environment
|
||||
type internalCode = Object
|
||||
type environment = GenericDist.env
|
||||
|
||||
let defaultEnvironment = ExternalExpressionValue.defaultEnvironment
|
||||
let defaultEnvironment: environment = DistributionOperation.defaultEnv
|
||||
|
||||
@genType.opaque
|
||||
type rec t =
|
||||
| IEvArray(array<t>) // FIXME: Convert to MapInt
|
||||
| IEvArrayString(array<string>)
|
||||
|
@ -24,42 +24,21 @@ type rec t =
|
|||
| IEvType(map)
|
||||
| IEvTypeIdentifier(string)
|
||||
| IEvVoid
|
||||
and map = Belt.Map.String.t<t>
|
||||
and nameSpace = NameSpace(Belt.Map.String.t<t>)
|
||||
@genType.opaque and squiggleArray = array<t>
|
||||
@genType.opaque and map = Belt.Map.String.t<t>
|
||||
@genType.opaque and nameSpace = NameSpace(Belt.Map.String.t<t>)
|
||||
@genType.opaque
|
||||
and lambdaValue = {
|
||||
parameters: array<string>,
|
||||
context: nameSpace,
|
||||
body: internalCode,
|
||||
}
|
||||
and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
||||
@genType.opaque and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
||||
|
||||
type internalExpressionValue = t
|
||||
|
||||
type functionCall = (string, array<t>)
|
||||
|
||||
module Internal = {
|
||||
module NameSpace = {
|
||||
external castNameSpaceToHidden: nameSpace => ExternalExpressionValue.hiddenNameSpace =
|
||||
"%identity"
|
||||
external castHiddenToNameSpace: ExternalExpressionValue.hiddenNameSpace => nameSpace =
|
||||
"%identity"
|
||||
}
|
||||
module Lambda = {
|
||||
let toInternal = (v: ExternalExpressionValue.lambdaValue): lambdaValue => {
|
||||
let p = v.parameters
|
||||
let c = v.context->NameSpace.castHiddenToNameSpace
|
||||
let b = v.body
|
||||
{parameters: p, context: c, body: b}
|
||||
}
|
||||
and toExternal = (v: lambdaValue): ExternalExpressionValue.lambdaValue => {
|
||||
let p = v.parameters
|
||||
let c = v.context->NameSpace.castNameSpaceToHidden
|
||||
let b = v.body
|
||||
{parameters: p, context: c, body: b}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let rec toString = aValue =>
|
||||
switch aValue {
|
||||
| IEvArray(anArray) => {
|
||||
|
@ -132,6 +111,12 @@ let toStringResult = x =>
|
|||
| 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 =>
|
||||
switch codeResult {
|
||||
| Ok(a) => toString(a)
|
||||
|
@ -140,7 +125,7 @@ let toStringResultOkless = (codeResult: result<t, ErrorValue.errorValue>): strin
|
|||
|
||||
let toStringResultRecord = x =>
|
||||
switch x {
|
||||
| Ok(a) => `Ok(${ExternalExpressionValue.toStringRecord(a)})`
|
||||
| Ok(a) => `Ok(${toStringMap(a)})`
|
||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||
}
|
||||
|
||||
|
@ -188,27 +173,6 @@ let valueToValueType = value =>
|
|||
| IEvVoid => EvtVoid
|
||||
}
|
||||
|
||||
let externalValueToValueType = (value: ExternalExpressionValue.t) =>
|
||||
switch value {
|
||||
| EvArray(_) => EvtArray
|
||||
| EvArrayString(_) => EvtArrayString
|
||||
| EvBool(_) => EvtBool
|
||||
| EvCall(_) => EvtCall
|
||||
| EvDate(_) => EvtDate
|
||||
| EvDeclaration(_) => EvtDeclaration
|
||||
| EvDistribution(_) => EvtDistribution
|
||||
| EvLambda(_) => EvtLambda
|
||||
| EvModule(_) => EvtModule
|
||||
| EvNumber(_) => EvtNumber
|
||||
| EvRecord(_) => EvtRecord
|
||||
| EvString(_) => EvtString
|
||||
| EvSymbol(_) => EvtSymbol
|
||||
| EvTimeDuration(_) => EvtTimeDuration
|
||||
| EvType(_) => EvtType
|
||||
| EvTypeIdentifier(_) => EvtTypeIdentifier
|
||||
| EvVoid => EvtVoid
|
||||
}
|
||||
|
||||
let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => {
|
||||
let (fn, args) = functionCall
|
||||
CallSignature(fn, args->Js.Array2.map(valueToValueType))
|
||||
|
@ -240,70 +204,18 @@ let functionCallSignatureToString = (functionCallSignature: functionCallSignatur
|
|||
`${fn}(${args->Js.Array2.map(valueTypeToString)->Js.Array2.toString})`
|
||||
}
|
||||
|
||||
let rec toExternal = (iev: t): ExternalExpressionValue.t => {
|
||||
switch iev {
|
||||
| IEvArray(v) => v->Belt.Array.map(e => toExternal(e))->EvArray
|
||||
| IEvArrayString(v) => EvArrayString(v)
|
||||
| IEvBool(v) => EvBool(v)
|
||||
| IEvCall(v) => EvCall(v)
|
||||
| IEvDeclaration(v) => {
|
||||
let fn = lambdaValueToExternal(v.fn)
|
||||
let args = v.args
|
||||
EvDeclaration({fn: fn, args: args})
|
||||
}
|
||||
| IEvDistribution(v) => EvDistribution(v)
|
||||
| IEvLambda(v) => EvLambda(lambdaValueToExternal(v))
|
||||
| IEvNumber(v) => EvNumber(v)
|
||||
| IEvRecord(v) => v->mapToExternal->EvRecord
|
||||
| IEvString(v) => EvString(v)
|
||||
| IEvSymbol(v) => EvSymbol(v)
|
||||
| IEvDate(v) => EvDate(v)
|
||||
| IEvTimeDuration(v) => EvTimeDuration(v)
|
||||
| IEvType(v) => v->mapToExternal->EvType
|
||||
| IEvTypeIdentifier(v) => EvTypeIdentifier(v)
|
||||
| IEvBindings(v) => v->nameSpaceToTypeScriptBindings->EvModule
|
||||
| IEvVoid => EvVoid
|
||||
}
|
||||
}
|
||||
and mapToExternal = v =>
|
||||
v->Belt.Map.String.map(e => toExternal(e))->Belt.Map.String.toArray->Js.Dict.fromArray
|
||||
and lambdaValueToExternal = Internal.Lambda.toExternal
|
||||
and nameSpaceToTypeScriptBindings = (
|
||||
nameSpace: nameSpace,
|
||||
): ReducerInterface_ExternalExpressionValue.externalBindings => {
|
||||
let NameSpace(container) = nameSpace
|
||||
Belt.Map.String.map(container, e => toExternal(e))->Belt.Map.String.toArray->Js.Dict.fromArray
|
||||
}
|
||||
let arrayToValueArray = (arr: array<t>): array<t> => arr
|
||||
|
||||
let rec toInternal = (ev: ExternalExpressionValue.t): t => {
|
||||
switch ev {
|
||||
| EvArray(v) => v->Belt.Array.map(e => toInternal(e))->IEvArray
|
||||
| EvArrayString(v) => IEvArrayString(v)
|
||||
| EvBool(v) => IEvBool(v)
|
||||
| EvCall(v) => IEvCall(v)
|
||||
| EvDate(v) => IEvDate(v)
|
||||
| EvDeclaration(v) => {
|
||||
let fn = lambdaValueToInternal(v.fn)
|
||||
let args = v.args
|
||||
IEvDeclaration({fn: fn, args: args})
|
||||
}
|
||||
| EvDistribution(v) => IEvDistribution(v)
|
||||
| EvLambda(v) => IEvLambda(lambdaValueToInternal(v))
|
||||
| EvModule(v) => v->nameSpaceFromTypeScriptBindings->IEvBindings
|
||||
| EvNumber(v) => IEvNumber(v)
|
||||
| EvRecord(v) => v->recordToInternal->IEvRecord
|
||||
| EvString(v) => IEvString(v)
|
||||
| EvSymbol(v) => IEvSymbol(v)
|
||||
| EvTimeDuration(v) => IEvTimeDuration(v)
|
||||
| EvType(v) => v->recordToInternal->IEvType
|
||||
| EvTypeIdentifier(v) => IEvTypeIdentifier(v)
|
||||
| EvVoid => IEvVoid
|
||||
}
|
||||
let recordToKeyValuePairs = (record: map): array<(string, t)> => record->Belt.Map.String.toArray
|
||||
|
||||
// let nameSpaceToTypeScriptBindings = (
|
||||
// nameSpace: nameSpace,
|
||||
// ) => {
|
||||
// let NameSpace(container) = nameSpace
|
||||
// Belt.Map.String.map(container, e => e->Belt.Map.String.toArray->Js.Dict.fromArray)
|
||||
// }
|
||||
|
||||
let nameSpaceToKeyValuePairs = (nameSpace: nameSpace): array<(string, t)> => {
|
||||
let NameSpace(container) = nameSpace
|
||||
container->Belt.Map.String.toArray
|
||||
}
|
||||
and recordToInternal = v =>
|
||||
v->Js.Dict.entries->Belt.Map.String.fromArray->Belt.Map.String.map(e => toInternal(e))
|
||||
and lambdaValueToInternal = Internal.Lambda.toInternal
|
||||
and nameSpaceFromTypeScriptBindings = (
|
||||
r: ReducerInterface_ExternalExpressionValue.externalBindings,
|
||||
): nameSpace =>
|
||||
r->Js.Dict.entries->Belt.Map.String.fromArray->Belt.Map.String.map(e => toInternal(e))->NameSpace
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
module Bindings = Reducer_Bindings
|
||||
|
||||
let internalStdLib =
|
||||
let internalStdLib: Bindings.t =
|
||||
Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings->SquiggleLibrary_Versions.makeBindings
|
||||
|
||||
@genType
|
||||
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,208 @@
|
|||
// TODO: Auto clean project based on topology
|
||||
|
||||
module Bindings = Reducer_Bindings
|
||||
module Continuation = ReducerInterface_Value_Continuation
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
module ProjectItem = ReducerProject_ProjectItem
|
||||
module T = ReducerProject_T
|
||||
module Topology = ReducerProject_Topology
|
||||
|
||||
type t = T.t
|
||||
|
||||
module Private = {
|
||||
type internalProject = T.Private.t
|
||||
type t = T.Private.t
|
||||
|
||||
let getSourceIds = T.Private.getSourceIds
|
||||
let getItem = T.Private.getItem
|
||||
let getDependents = Topology.getDependents
|
||||
let getDependencies = Topology.getDependencies
|
||||
let getRunOrder = Topology.getRunOrder
|
||||
let getRunOrderFor = Topology.getRunOrderFor
|
||||
|
||||
let createProject = () => {
|
||||
let project: t = {
|
||||
"tag": "reducerProject",
|
||||
"items": Belt.Map.String.empty,
|
||||
"stdLib": ReducerInterface_StdLib.internalStdLib,
|
||||
"environment": InternalExpressionValue.defaultEnvironment,
|
||||
}
|
||||
project
|
||||
}
|
||||
|
||||
let rec touchSource = (project: t, sourceId: string): unit => {
|
||||
let item = project->getItem(sourceId)
|
||||
let newItem = ProjectItem.touchSource(item)
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
touchDependents(project, sourceId)
|
||||
}
|
||||
and touchDependents = (project: t, sourceId: string): unit => {
|
||||
let _ = getDependents(project, sourceId)->Belt.Array.forEach(_, touchSource(project, _))
|
||||
}
|
||||
|
||||
let getSource = (project: t, sourceId: string): option<string> =>
|
||||
Belt.Map.String.get(project["items"], sourceId)->Belt.Option.map(ProjectItem.getSource)
|
||||
|
||||
let setSource = (project: t, sourceId: string, value: string): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.setSource(value)
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
touchDependents(project, sourceId)
|
||||
}
|
||||
|
||||
let clean = (project: t, sourceId: string): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.clean
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
}
|
||||
|
||||
let cleanAll = (project: t): unit =>
|
||||
getSourceIds(project)->Belt.Array.forEach(sourceId => clean(project, sourceId))
|
||||
|
||||
let cleanResults = (project: t, sourceId: string): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.cleanResults
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
}
|
||||
|
||||
let cleanAllResults = (project: t): unit =>
|
||||
getSourceIds(project)->Belt.Array.forEach(sourceId => cleanResults(project, sourceId))
|
||||
|
||||
let getIncludes = (project: t, sourceId: string): ProjectItem.T.includesType =>
|
||||
project->getItem(sourceId)->ProjectItem.getIncludes
|
||||
|
||||
let setContinues = (project: t, sourceId: string, continues: array<string>): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.setContinues(continues)
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
touchSource(project, sourceId)
|
||||
}
|
||||
let getContinues = (project: t, sourceId: string): array<string> =>
|
||||
ProjectItem.getContinues(project->getItem(sourceId))
|
||||
|
||||
let removeContinues = (project: t, sourceId: string): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.removeContinues
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
touchSource(project, sourceId)
|
||||
}
|
||||
|
||||
let getContinuation = (project: t, sourceId: string): ProjectItem.T.continuationArgumentType =>
|
||||
project->getItem(sourceId)->ProjectItem.getContinuation
|
||||
|
||||
let setContinuation = (
|
||||
project: t,
|
||||
sourceId: string,
|
||||
continuation: ProjectItem.T.continuationArgumentType,
|
||||
): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.setContinuation(continuation)
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
}
|
||||
|
||||
let getResultOption = (project: t, sourceId: string): ProjectItem.T.resultType =>
|
||||
project->getItem(sourceId)->ProjectItem.getResult
|
||||
|
||||
let getResult = (project: t, sourceId: string): ProjectItem.T.resultArgumentType =>
|
||||
switch getResultOption(project, sourceId) {
|
||||
| None => RENeedToRun->Error
|
||||
| Some(result) => result
|
||||
}
|
||||
|
||||
let setResult = (project: t, sourceId: string, value: ProjectItem.T.resultArgumentType): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.setResult(value)
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
}
|
||||
|
||||
let parseIncludes = (project: t, sourceId: string): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.parseIncludes
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
}
|
||||
|
||||
let rawParse = (project: t, sourceId): unit => {
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.rawParse
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
}
|
||||
|
||||
let getStdLib = (project: t): Reducer_Bindings.t => project["stdLib"]
|
||||
let setStdLib = (project: t, value: Reducer_Bindings.t): unit =>
|
||||
T.Private.setFieldStdLib(project, value)
|
||||
|
||||
let getEnvironment = (project: t): InternalExpressionValue.environment => project["environment"]
|
||||
let setEnvironment = (project: t, value: InternalExpressionValue.environment): unit =>
|
||||
T.Private.setFieldEnvironment(project, value)
|
||||
|
||||
let getBindings = (project: t, sourceId: string): ProjectItem.T.bindingsArgumentType => {
|
||||
let those = project->getContinuation(sourceId)
|
||||
let these = project->getStdLib
|
||||
let ofUser = Continuation.minus(those, these)
|
||||
ofUser
|
||||
}
|
||||
|
||||
let buildProjectAccessors = (project: t): ProjectAccessorsT.t => {
|
||||
states: {continuation: Bindings.emptyBindings},
|
||||
stdLib: getStdLib(project),
|
||||
environment: getEnvironment(project),
|
||||
}
|
||||
|
||||
let doRunWithContinuation = (
|
||||
project: t,
|
||||
sourceId: string,
|
||||
continuation: ProjectItem.T.continuation,
|
||||
): unit => {
|
||||
let accessors = buildProjectAccessors(project)
|
||||
let states = accessors.states
|
||||
let newItem = project->getItem(sourceId)->ProjectItem.run(continuation, accessors)
|
||||
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
||||
setContinuation(project, sourceId, states.continuation)
|
||||
}
|
||||
|
||||
type runState = (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation)
|
||||
|
||||
let tryRunWithContinuation = (
|
||||
project: t,
|
||||
sourceId: string,
|
||||
(rPrevResult: ProjectItem.T.resultArgumentType, continuation: ProjectItem.T.continuation),
|
||||
): (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) => {
|
||||
switch getResultOption(project, sourceId) {
|
||||
| Some(result) => (result, getContinuation(project, sourceId)) // already ran
|
||||
| None =>
|
||||
switch rPrevResult {
|
||||
| Error(error) => {
|
||||
setResult(project, sourceId, Error(error))
|
||||
(Error(error), continuation)
|
||||
}
|
||||
| Ok(_prevResult) => {
|
||||
doRunWithContinuation(project, sourceId, continuation)
|
||||
(
|
||||
getResultOption(project, sourceId)->Belt.Option.getWithDefault(rPrevResult),
|
||||
getContinuation(project, sourceId),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let runAll = (project: t): unit => {
|
||||
let runOrder = Topology.getRunOrder(project)
|
||||
let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project))
|
||||
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
||||
tryRunWithContinuation(project, currId, currState)
|
||||
)
|
||||
}
|
||||
|
||||
let run = (project: t, sourceId: string): unit => {
|
||||
let runOrder = Topology.getRunOrderFor(project, sourceId)
|
||||
let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project))
|
||||
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
||||
tryRunWithContinuation(project, currId, currState)
|
||||
)
|
||||
}
|
||||
|
||||
let evaluate = (sourceCode: string) => {
|
||||
let project = createProject()
|
||||
setSource(project, "main", sourceCode)
|
||||
runAll(project)
|
||||
let those = project->getContinuation("main")
|
||||
let these = project->getStdLib
|
||||
let ofUser = Continuation.minus(those, these)
|
||||
|
||||
(getResultOption(project, "main")->Belt.Option.getWithDefault(IEvVoid->Ok), ofUser)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,945 @@
|
|||
// 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, s4;
|
||||
|
||||
var key = peg$currPos * 10 + 0;
|
||||
var cached = peg$resultsCache[key];
|
||||
|
||||
if (cached) {
|
||||
peg$currPos = cached.nextPos;
|
||||
|
||||
return cached.result;
|
||||
}
|
||||
|
||||
s0 = peg$currPos;
|
||||
s1 = [];
|
||||
s2 = peg$parsenewLine();
|
||||
if (s2 === peg$FAILED) {
|
||||
s2 = peg$parse_();
|
||||
if (s2 === peg$FAILED) {
|
||||
s2 = peg$parsecomment();
|
||||
if (s2 === peg$FAILED) {
|
||||
s2 = peg$parsedelimitedComment();
|
||||
}
|
||||
}
|
||||
}
|
||||
while (s2 !== peg$FAILED) {
|
||||
s1.push(s2);
|
||||
s2 = peg$parsenewLine();
|
||||
if (s2 === peg$FAILED) {
|
||||
s2 = peg$parse_();
|
||||
if (s2 === peg$FAILED) {
|
||||
s2 = peg$parsecomment();
|
||||
if (s2 === peg$FAILED) {
|
||||
s2 = peg$parsedelimitedComment();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s2 = peg$parseincludes();
|
||||
if (s2 !== peg$FAILED) {
|
||||
s3 = [];
|
||||
s4 = peg$parsenewLine();
|
||||
while (s4 !== peg$FAILED) {
|
||||
s3.push(s4);
|
||||
s4 = peg$parsenewLine();
|
||||
}
|
||||
s4 = peg$parseignore();
|
||||
s0 = s2;
|
||||
} 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, s6;
|
||||
|
||||
var key = peg$currPos * 10 + 2;
|
||||
var cached = peg$resultsCache[key];
|
||||
|
||||
if (cached) {
|
||||
peg$currPos = cached.nextPos;
|
||||
|
||||
return cached.result;
|
||||
}
|
||||
|
||||
s0 = peg$currPos;
|
||||
s1 = [];
|
||||
s2 = peg$parse_();
|
||||
while (s2 !== peg$FAILED) {
|
||||
s1.push(s2);
|
||||
s2 = peg$parse_();
|
||||
}
|
||||
if (input.substr(peg$currPos, 8) === peg$c0) {
|
||||
s2 = peg$c0;
|
||||
peg$currPos += 8;
|
||||
} else {
|
||||
s2 = peg$FAILED;
|
||||
if (peg$silentFails === 0) { peg$fail(peg$e0); }
|
||||
}
|
||||
if (s2 !== peg$FAILED) {
|
||||
s3 = [];
|
||||
s4 = peg$parse_();
|
||||
while (s4 !== peg$FAILED) {
|
||||
s3.push(s4);
|
||||
s4 = peg$parse_();
|
||||
}
|
||||
s4 = peg$parsestring();
|
||||
if (s4 !== peg$FAILED) {
|
||||
s5 = [];
|
||||
s6 = peg$parse_();
|
||||
while (s6 !== peg$FAILED) {
|
||||
s5.push(s6);
|
||||
s6 = peg$parse_();
|
||||
}
|
||||
s0 = s4;
|
||||
} 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,40 @@
|
|||
// 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
|
||||
= (newLine/_/comment/delimitedComment)* @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,15 @@
|
|||
@module("./ReducerProject_IncludeParser.js") external parse__: string => array<string> = "parse"
|
||||
|
||||
let parseIncludes = (expr: string): result<array<string>, Reducer_ErrorValue.errorValue> =>
|
||||
try {
|
||||
let answer = parse__(expr)
|
||||
// let logEntry = answer->Js.Array2.joinWith(",")
|
||||
// `parseIncludes: ${logEntry} for expr: ${expr}`->Js.log
|
||||
answer->Ok
|
||||
} catch {
|
||||
| Js.Exn.Error(obj) =>
|
||||
RESyntaxError(
|
||||
Belt.Option.getExn(Js.Exn.message(obj)),
|
||||
Reducer_Peggy_Parse.syntaxErrorToLocation(obj)->Some,
|
||||
)->Error
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
module ProjectItemT = ReducerProject_ProjectItem_T
|
||||
module Bindings = Reducer_Bindings
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
|
||||
type states = {mutable continuation: ProjectItemT.continuationArgumentType}
|
||||
|
||||
type projectAccessors = {
|
||||
stdLib: Reducer_Bindings.t,
|
||||
environment: ExpressionT.environment,
|
||||
states: states,
|
||||
}
|
||||
|
||||
type t = projectAccessors
|
||||
|
||||
let identityAccessors: t = {
|
||||
// We need the states at the end of the runtime.
|
||||
// Accessors can be modified but states will stay as the same pointer
|
||||
states: {
|
||||
continuation: Bindings.emptyBindings,
|
||||
},
|
||||
stdLib: ReducerInterface_StdLib.internalStdLib,
|
||||
environment: InternalExpressionValue.defaultEnvironment,
|
||||
}
|
||||
|
||||
let identityAccessorsWithEnvironment = (environment): t => {
|
||||
states: {
|
||||
continuation: Bindings.emptyBindings,
|
||||
},
|
||||
stdLib: ReducerInterface_StdLib.internalStdLib,
|
||||
environment: environment,
|
||||
}
|
||||
|
||||
// to support change of environment in runtime
|
||||
let setEnvironment = (this: t, environment: ExpressionT.environment): t => {
|
||||
{
|
||||
...this,
|
||||
environment: environment,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
// 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 -> result
|
||||
|
||||
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 getResult = (T.ProjectItem(r)): T.resultType => r.result
|
||||
|
||||
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)
|
||||
|
||||
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,36 @@
|
|||
module Parse = Reducer_Peggy_Parse
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
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 bindingsArgumentType = InternalExpressionValue.nameSpace
|
||||
type bindingsType = option<bindingsArgumentType>
|
||||
type resultArgumentType = result<InternalExpressionValue.t, errorValue>
|
||||
type resultType = option<resultArgumentType>
|
||||
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,34 @@
|
|||
module ProjectItem = ReducerProject_ProjectItem
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||
|
||||
@genType.opaque
|
||||
type project = {"tag": string}
|
||||
//re-export
|
||||
@genType
|
||||
type t = project
|
||||
|
||||
module Private = {
|
||||
type internalProject = {
|
||||
"tag": string,
|
||||
"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"
|
||||
|
||||
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)
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
module ProjectItem = ReducerProject_ProjectItem
|
||||
module T = ReducerProject_T
|
||||
type t = T.Private.t
|
||||
|
||||
let getSourceIds = T.Private.getSourceIds
|
||||
let getItem = T.Private.getItem
|
||||
|
||||
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 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
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
open ForTS__Types
|
||||
/*
|
||||
This is meant as a file to contain @genType declarations as needed for Typescript.
|
||||
I would ultimately want to have all @genType declarations here, vs. other files, but
|
||||
|
@ -7,59 +8,32 @@ would be preferable.
|
|||
The below few seem to work fine. In the future there's definitely more work to do here.
|
||||
*/
|
||||
|
||||
@genType
|
||||
type samplingParams = GenericDist.env
|
||||
// For backwards compatibility:
|
||||
//Alternatives if one wants to keep the old habits
|
||||
@genType type samplingParams = environment
|
||||
@genType type squiggleValue_Dist = squiggleValue_Distribution //alternative
|
||||
@genType type genericDist = squiggleValue_Distribution //alternative
|
||||
@genType type sampleSetDist = sampleSetDistribution //alternative
|
||||
@genType type symbolicDist = symbolicDistribution //alternative
|
||||
@genType type resultDist = result<distribution, distributionError> //alternative
|
||||
@genType type resultFloat = result<float, distributionError> //alternative
|
||||
@genType type resultString = result<string, distributionError> //alternative
|
||||
|
||||
@genType
|
||||
type genericDist = DistributionTypes.genericDist
|
||||
let makeSampleSetDist: array<float> => result<
|
||||
sampleSetDist,
|
||||
SampleSetDist.sampleSetError,
|
||||
> = SampleSetDist.make
|
||||
|
||||
//TODO: ForTS Interface module candid
|
||||
@genType
|
||||
type sampleSetDist = SampleSetDist.t
|
||||
|
||||
@genType
|
||||
type symbolicDist = SymbolicDistTypes.symbolicDist
|
||||
|
||||
@genType
|
||||
type distributionError = DistributionTypes.error
|
||||
|
||||
@genType
|
||||
type resultDist = result<genericDist, distributionError>
|
||||
|
||||
@genType
|
||||
type resultFloat = result<float, distributionError>
|
||||
|
||||
@genType
|
||||
type resultString = result<string, distributionError>
|
||||
|
||||
@genType
|
||||
let makeSampleSetDist = SampleSetDist.make
|
||||
|
||||
@genType
|
||||
let evaluate = Reducer.evaluate
|
||||
|
||||
@genType
|
||||
let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
||||
|
||||
@genType
|
||||
let parse = Reducer_Peggy_Parse.parse
|
||||
|
||||
@genType
|
||||
let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
||||
|
||||
@genType
|
||||
type externalBindings = Reducer.externalBindings
|
||||
|
||||
@genType
|
||||
type expressionValue = ReducerInterface_ExternalExpressionValue.t
|
||||
|
||||
@genType
|
||||
type recordEV = ReducerInterface_ExternalExpressionValue.record
|
||||
|
||||
@genType
|
||||
type errorValue = Reducer_ErrorValue.errorValue
|
||||
|
||||
@genType
|
||||
let toPointSet = GenericDist.toPointSet
|
||||
let toPointSet: (
|
||||
squiggleValue_Distribution,
|
||||
~xyPointLength: int,
|
||||
~sampleCount: int,
|
||||
~xSelection: DistributionTypes.DistributionOperation.pointsetXSelection=?,
|
||||
unit,
|
||||
) => result<PointSetTypes.pointSetDist, distributionError> = GenericDist.toPointSet
|
||||
|
||||
@genType
|
||||
type mixedShape = PointSetTypes.mixedShape
|
||||
|
@ -71,31 +45,14 @@ type discreteShape = PointSetTypes.discreteShape
|
|||
type continuousShape = PointSetTypes.continuousShape
|
||||
|
||||
@genType
|
||||
let errorValueToString = Reducer_ErrorValue.errorToString
|
||||
let distributionErrorToString = ForTS_Distribution_Error.toString
|
||||
|
||||
@genType
|
||||
let distributionErrorToString = DistributionTypes.Error.toString
|
||||
let defaultSamplingEnv = ForTS_Distribution.defaultEnvironment
|
||||
|
||||
@genType
|
||||
type lambdaValue = ReducerInterface_ExternalExpressionValue.lambdaValue
|
||||
// Umur: opaqe types
|
||||
// @genType
|
||||
// type declarationArg = Declaration.arg
|
||||
|
||||
@genType
|
||||
type lambdaDeclaration = ReducerInterface_ExternalExpressionValue.lambdaDeclaration
|
||||
|
||||
@genType
|
||||
let defaultSamplingEnv = DistributionOperation.defaultEnv
|
||||
|
||||
@genType
|
||||
type environment = ReducerInterface_ExternalExpressionValue.environment
|
||||
|
||||
@genType
|
||||
let defaultEnvironment = ReducerInterface_ExternalExpressionValue.defaultEnvironment
|
||||
|
||||
@genType
|
||||
let foreignFunctionInterface = Reducer.foreignFunctionInterface
|
||||
|
||||
@genType
|
||||
type declarationArg = Declaration.arg
|
||||
|
||||
@genType
|
||||
type declaration<'a> = Declaration.declaration<'a>
|
||||
// @genType
|
||||
// type declaration<'a> = Declaration.declaration<'a>
|
||||
|
|
Loading…
Reference in New Issue
Block a user