immutable bindings; test fixes
This commit is contained in:
parent
89397d3584
commit
065a7aeec0
|
@ -1,27 +1,46 @@
|
||||||
@@warning("-44")
|
@@warning("-44")
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|
||||||
module Bindings = Reducer_Bindings
|
module Bindings = Reducer_Bindings
|
||||||
|
module Namespace = Reducer_Namespace
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
open Expect.Operators
|
open Expect.Operators
|
||||||
|
|
||||||
describe("Name Space", () => {
|
describe("Bindings", () => {
|
||||||
let value = Reducer_T.IEvNumber(1967.0)
|
let value = Reducer_T.IEvNumber(1967.0)
|
||||||
let nameSpace = Bindings.makeEmptyBindings()->Bindings.set("value", value)
|
let bindings = Bindings.make()->Bindings.set("value", value)
|
||||||
test("get", () => {
|
test("get", () => {
|
||||||
expect(Bindings.get(nameSpace, "value")) == Some(value)
|
expect(bindings->Bindings.get("value")) == Some(value)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("chain and get", () => {
|
test("get nonexisting value", () => {
|
||||||
let mainNameSpace = Bindings.makeEmptyBindings()->Bindings.chainTo([nameSpace])
|
expect(bindings->Bindings.get("nosuchvalue")) == None
|
||||||
expect(Bindings.get(mainNameSpace, "value")) == Some(value)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("chain and set", () => {
|
test("get on extended", () => {
|
||||||
let mainNameSpace0 = Bindings.makeEmptyBindings()->Bindings.chainTo([nameSpace])
|
expect(bindings->Bindings.extend->Bindings.get("value")) == Some(value)
|
||||||
let mainNameSpace =
|
})
|
||||||
mainNameSpace0->Bindings.set("value", Reducer_T.IEvNumber(1968.0))
|
|
||||||
expect(Bindings.get(mainNameSpace, "value")) == Some(Reducer_T.IEvNumber(1968.0))
|
test("locals", () => {
|
||||||
|
expect(bindings->Bindings.locals->Namespace.get("value")) == Some(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("locals on extendeed", () => {
|
||||||
|
expect(bindings->Bindings.extend->Bindings.locals->Namespace.get("value")) == None
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("extend", () => {
|
||||||
|
let value2 = Reducer_T.IEvNumber(5.)
|
||||||
|
let extendedBindings = bindings
|
||||||
|
->Bindings.extend
|
||||||
|
->Bindings.set("value", value2)
|
||||||
|
|
||||||
|
test("get on extended", () => {
|
||||||
|
expect(extendedBindings->Bindings.get("value")) == Some(value2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("get on original", () => {
|
||||||
|
expect(bindings->Bindings.get("value")) == Some(value)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,15 +3,7 @@ module ErrorValue = Reducer_ErrorValue
|
||||||
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface.InternalExpressionValue
|
||||||
|
|
||||||
let removeDefaultsInternal = (iev: InternalExpressionValue.t) => {
|
let removeDefaultsInternal = (iev: InternalExpressionValue.t) => {
|
||||||
Not_found->raise
|
iev // TODO - cleanup, noop
|
||||||
// switch iev {
|
|
||||||
// | Reducer_T.IEvBindings(nameSpace) =>
|
|
||||||
// Reducer_Bindings.removeOther(
|
|
||||||
// nameSpace,
|
|
||||||
// ReducerInterface.StdLib.internalStdLib,
|
|
||||||
// )->Reducer_T.IEvBindings
|
|
||||||
// | value => value
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let rRemoveDefaultsInternal = r => Belt.Result.map(r, removeDefaultsInternal)
|
let rRemoveDefaultsInternal = r => Belt.Result.map(r, removeDefaultsInternal)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
@@warning("-44")
|
||||||
|
module Namespace = Reducer_Namespace
|
||||||
|
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
open Expect.Operators
|
||||||
|
|
||||||
|
let makeValue = (v: float) => v->Reducer_T.IEvNumber
|
||||||
|
|
||||||
|
describe("Namespace", () => {
|
||||||
|
let value = makeValue(5.)
|
||||||
|
let v2 = makeValue(2.)
|
||||||
|
let ns = Namespace.make()->Namespace.set("value", value)
|
||||||
|
|
||||||
|
test("get", () => {
|
||||||
|
expect(ns->Namespace.get("value")) == Some(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("get nonexisting value", () => {
|
||||||
|
expect(ns->Namespace.get("nosuchvalue")) == None
|
||||||
|
})
|
||||||
|
|
||||||
|
test("set", () => {
|
||||||
|
let ns2 = ns->Namespace.set("v2", v2)
|
||||||
|
expect(ns2->Namespace.get("v2")) == Some(v2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("immutable", () => {
|
||||||
|
let _ = ns->Namespace.set("v2", Reducer_T.IEvNumber(2.))
|
||||||
|
expect(ns->Namespace.get("v2")) == None
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("merge many", () => {
|
||||||
|
let x1 = makeValue(10.)
|
||||||
|
let x2 = makeValue(20.)
|
||||||
|
let x3 = makeValue(30.)
|
||||||
|
let x4 = makeValue(40.)
|
||||||
|
let ns1 = Namespace.make()
|
||||||
|
->Namespace.set("x1", x1)
|
||||||
|
->Namespace.set("x2", x2)
|
||||||
|
let ns2 = Namespace.make()
|
||||||
|
->Namespace.set("x3", x3)
|
||||||
|
->Namespace.set("x4", x4)
|
||||||
|
|
||||||
|
let nsMerged = Namespace.mergeMany([ns, ns1, ns2])
|
||||||
|
|
||||||
|
test("merge many 1", () => {
|
||||||
|
expect(nsMerged->Namespace.get("x1")) == Some(x1)
|
||||||
|
})
|
||||||
|
test("merge many 2", () => {
|
||||||
|
expect(nsMerged->Namespace.get("x4")) == Some(x4)
|
||||||
|
})
|
||||||
|
test("merge many 3", () => {
|
||||||
|
expect(nsMerged->Namespace.get("value")) == Some(value)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -3,346 +3,345 @@ open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
describe("Peggy parse", () => {
|
describe("Peggy parse", () => {
|
||||||
describe("float", () => {
|
describe("float", () => {
|
||||||
testParse("1.", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("1.", "{1}")
|
||||||
testParse("1.1", "{(::$_endOfOuterBlock_$ () 1.1)}")
|
testParse("1.1", "{1.1}")
|
||||||
testParse(".1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
testParse(".1", "{0.1}")
|
||||||
testParse("0.1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
testParse("0.1", "{0.1}")
|
||||||
testParse("1e1", "{(::$_endOfOuterBlock_$ () 10)}")
|
testParse("1e1", "{10}")
|
||||||
testParse("1e-1", "{(::$_endOfOuterBlock_$ () 0.1)}")
|
testParse("1e-1", "{0.1}")
|
||||||
testParse(".1e1", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse(".1e1", "{1}")
|
||||||
testParse("0.1e1", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("0.1e1", "{1}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("literals operators parenthesis", () => {
|
describe("literals operators parenthesis", () => {
|
||||||
// Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement
|
testParse("1", "{1}")
|
||||||
testParse("1", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("'hello'", "{'hello'}")
|
||||||
testParse("'hello'", "{(::$_endOfOuterBlock_$ () 'hello')}")
|
testParse("true", "{true}")
|
||||||
testParse("true", "{(::$_endOfOuterBlock_$ () true)}")
|
testParse("1+2", "{(:add 1 2)}")
|
||||||
testParse("1+2", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
testParse("add(1,2)", "{(:add 1 2)}")
|
||||||
testParse("add(1,2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
testParse("(1)", "{1}")
|
||||||
testParse("(1)", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("(1+2)", "{(:add 1 2)}")
|
||||||
testParse("(1+2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("unary", () => {
|
describe("unary", () => {
|
||||||
testParse("-1", "{(::$_endOfOuterBlock_$ () (::unaryMinus 1))}")
|
testParse("-1", "{(:unaryMinus 1)}")
|
||||||
testParse("!true", "{(::$_endOfOuterBlock_$ () (::not true))}")
|
testParse("!true", "{(:not true)}")
|
||||||
testParse("1 + -1", "{(::$_endOfOuterBlock_$ () (::add 1 (::unaryMinus 1)))}")
|
testParse("1 + -1", "{(:add 1 (:unaryMinus 1))}")
|
||||||
testParse("-a[0]", "{(::$_endOfOuterBlock_$ () (::unaryMinus (::$_atIndex_$ :a 0)))}")
|
testParse("-a[0]", "{(:unaryMinus (:$_atIndex_$ :a 0))}")
|
||||||
testParse("!a[0]", "{(::$_endOfOuterBlock_$ () (::not (::$_atIndex_$ :a 0)))}")
|
testParse("!a[0]", "{(:not (:$_atIndex_$ :a 0))}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("multiplicative", () => {
|
describe("multiplicative", () => {
|
||||||
testParse("1 * 2", "{(::$_endOfOuterBlock_$ () (::multiply 1 2))}")
|
testParse("1 * 2", "{(:multiply 1 2)}")
|
||||||
testParse("1 / 2", "{(::$_endOfOuterBlock_$ () (::divide 1 2))}")
|
testParse("1 / 2", "{(:divide 1 2)}")
|
||||||
testParse("1 * 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::multiply 1 2) 3))}")
|
testParse("1 * 2 * 3", "{(:multiply (:multiply 1 2) 3)}")
|
||||||
testParse("1 * 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::multiply 1 2) 3))}")
|
testParse("1 * 2 / 3", "{(:divide (:multiply 1 2) 3)}")
|
||||||
testParse("1 / 2 * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::divide 1 2) 3))}")
|
testParse("1 / 2 * 3", "{(:multiply (:divide 1 2) 3)}")
|
||||||
testParse("1 / 2 / 3", "{(::$_endOfOuterBlock_$ () (::divide (::divide 1 2) 3))}")
|
testParse("1 / 2 / 3", "{(:divide (:divide 1 2) 3)}")
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 + 3 * 4",
|
"1 * 2 + 3 * 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::multiply 3 4)))}",
|
"{(:add (:multiply 1 2) (:multiply 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 * 4",
|
"1 * 2 - 3 * 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 4)))}",
|
"{(:subtract (:multiply 1 2) (:multiply 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 .+ 3 * 4",
|
"1 * 2 .+ 3 * 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::dotAdd (::multiply 1 2) (::multiply 3 4)))}",
|
"{(:dotAdd (:multiply 1 2) (:multiply 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 .- 3 * 4",
|
"1 * 2 .- 3 * 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::dotSubtract (::multiply 1 2) (::multiply 3 4)))}",
|
"{(:dotSubtract (:multiply 1 2) (:multiply 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 + 3 .* 4",
|
"1 * 2 + 3 .* 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::dotMultiply 3 4)))}",
|
"{(:add (:multiply 1 2) (:dotMultiply 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 + 3 / 4",
|
"1 * 2 + 3 / 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::divide 3 4)))}",
|
"{(:add (:multiply 1 2) (:divide 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 + 3 ./ 4",
|
"1 * 2 + 3 ./ 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::multiply 1 2) (::dotDivide 3 4)))}",
|
"{(:add (:multiply 1 2) (:dotDivide 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 .* 4",
|
"1 * 2 - 3 .* 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::dotMultiply 3 4)))}",
|
"{(:subtract (:multiply 1 2) (:dotMultiply 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 / 4",
|
"1 * 2 - 3 / 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::divide 3 4)))}",
|
"{(:subtract (:multiply 1 2) (:divide 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 ./ 4",
|
"1 * 2 - 3 ./ 4",
|
||||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::dotDivide 3 4)))}",
|
"{(:subtract (:multiply 1 2) (:dotDivide 3 4))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 * 4^5",
|
"1 * 2 - 3 * 4^5",
|
||||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5))))}",
|
"{(:subtract (:multiply 1 2) (:multiply 3 (:pow 4 5)))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * 2 - 3 * 4^5^6",
|
"1 * 2 - 3 * 4^5^6",
|
||||||
"{(::$_endOfOuterBlock_$ () (::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6))))}",
|
"{(:subtract (:multiply 1 2) (:multiply 3 (:pow (:pow 4 5) 6)))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"1 * -a[-2]",
|
"1 * -a[-2]",
|
||||||
"{(::$_endOfOuterBlock_$ () (::multiply 1 (::unaryMinus (::$_atIndex_$ :a (::unaryMinus 2)))))}",
|
"{(:multiply 1 (:unaryMinus (:$_atIndex_$ :a (:unaryMinus 2))))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("multi-line", () => {
|
describe("multi-line", () => {
|
||||||
testParse("x=1; 2", "{:x = {1}; (::$_endOfOuterBlock_$ () 2)}")
|
testParse("x=1; 2", "{:x = {1}; 2}")
|
||||||
testParse("x=1; y=2", "{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}")
|
testParse("x=1; y=2", "{:x = {1}; :y = {2}}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("variables", () => {
|
describe("variables", () => {
|
||||||
testParse("x = 1", "{:x = {1}; (::$_endOfOuterBlock_$ () ())}")
|
testParse("x = 1", "{:x = {1}}")
|
||||||
testParse("x", "{(::$_endOfOuterBlock_$ () :x)}")
|
testParse("x", "{:x}")
|
||||||
testParse("x = 1; x", "{:x = {1}; (::$_endOfOuterBlock_$ () :x)}")
|
testParse("x = 1; x", "{:x = {1}; :x}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("functions", () => {
|
describe("functions", () => {
|
||||||
testParse("identity(x) = x", "{:identity = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions become lambda assignments
|
testParse("identity(x) = x", "{:identity = {|:x| {:x}}}") // Function definitions become lambda assignments
|
||||||
testParse("identity(x)", "{(::$_endOfOuterBlock_$ () (::identity :x))}")
|
testParse("identity(x)", "{(:identity :x)}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
testParse("[]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$))}")
|
testParse("[]", "{[]}")
|
||||||
testParse("[0, 1, 2]", "{(::$_endOfOuterBlock_$ () (::$_constructArray_$ 0 1 2))}")
|
testParse("[0, 1, 2]", "{[0; 1; 2]}")
|
||||||
testParse(
|
testParse(
|
||||||
"['hello', 'world']",
|
"['hello', 'world']",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$_constructArray_$ 'hello' 'world'))}",
|
"{['hello'; 'world']}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"([0,1,2])[1]",
|
"([0,1,2])[1]",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$_atIndex_$ (::$_constructArray_$ 0 1 2) 1))}",
|
"{(:$_atIndex_$ [0; 1; 2] 1)}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"{a: 1, b: 2}",
|
"{a: 1, b: 2}",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$_constructRecord_$ ('a': 1 'b': 2)))}",
|
"{{'a': 1, 'b': 2}}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"{1+0: 1, 2+0: 2}",
|
"{1+0: 1, 2+0: 2}",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2)))}",
|
"{{(:add 1 0): 1, (:add 2 0): 2}}",
|
||||||
) // key can be any expression
|
) // key can be any expression
|
||||||
testParse("record.property", "{(::$_endOfOuterBlock_$ () (::$_atIndex_$ :record 'property'))}")
|
testParse("record.property", "{(:$_atIndex_$ :record 'property')}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("post operators", () => {
|
describe("post operators", () => {
|
||||||
//function call, array and record access are post operators with higher priority than unary operators
|
//function call, array and record access are post operators with higher priority than unary operators
|
||||||
testParse("a==!b(1)", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::b 1))))}")
|
testParse("a==!b(1)", "{(:equal :a (:not (:b 1)))}")
|
||||||
testParse("a==!b[1]", "{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 1))))}")
|
testParse("a==!b[1]", "{(:equal :a (:not (:$_atIndex_$ :b 1)))}")
|
||||||
testParse(
|
testParse(
|
||||||
"a==!b.one",
|
"a==!b.one",
|
||||||
"{(::$_endOfOuterBlock_$ () (::equal :a (::not (::$_atIndex_$ :b 'one'))))}",
|
"{(:equal :a (:not (:$_atIndex_$ :b 'one')))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("comments", () => {
|
describe("comments", () => {
|
||||||
testParse("1 # This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("1 # This is a line comment", "{1}")
|
||||||
testParse("1 // This is a line comment", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("1 // This is a line comment", "{1}")
|
||||||
testParse("1 /* This is a multi line comment */", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("1 /* This is a multi line comment */", "{1}")
|
||||||
testParse("/* This is a multi line comment */ 1", "{(::$_endOfOuterBlock_$ () 1)}")
|
testParse("/* This is a multi line comment */ 1", "{1}")
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
/* This is
|
/* This is
|
||||||
a multi line
|
a multi line
|
||||||
comment */
|
comment */
|
||||||
1`,
|
1`,
|
||||||
"{(::$_endOfOuterBlock_$ () 1)}",
|
"{1}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("ternary operator", () => {
|
describe("ternary operator", () => {
|
||||||
testParse("true ? 2 : 3", "{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true 2 3))}")
|
testParse("true ? 2 : 3", "{(::$$_ternary_$$ true 2 3)}")
|
||||||
testParse(
|
testParse(
|
||||||
"false ? 2 : false ? 4 : 5",
|
"false ? 2 : false ? 4 : 5",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5)))}",
|
"{(::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5))}",
|
||||||
) // nested ternary
|
) // nested ternary
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("if then else", () => {
|
describe("if then else", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"if true then 2 else 3",
|
"if true then 2 else 3",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ true {2} {3}))}",
|
"{(::$$_ternary_$$ true {2} {3})}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"if false then {2} else {3}",
|
"if false then {2} else {3}",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} {3}))}",
|
"{(::$$_ternary_$$ false {2} {3})}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"if false then {2} else if false then {4} else {5}",
|
"if false then {2} else if false then {4} else {5}",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5})))}",
|
"{(::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5}))}",
|
||||||
) //nested if
|
) //nested if
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("logical", () => {
|
describe("logical", () => {
|
||||||
testParse("true || false", "{(::$_endOfOuterBlock_$ () (::or true false))}")
|
testParse("true || false", "{(:or true false)}")
|
||||||
testParse("true && false", "{(::$_endOfOuterBlock_$ () (::and true false))}")
|
testParse("true && false", "{(:and true false)}")
|
||||||
testParse("a * b + c", "{(::$_endOfOuterBlock_$ () (::add (::multiply :a :b) :c))}") // for comparison
|
testParse("a * b + c", "{(:add (:multiply :a :b) :c)}") // for comparison
|
||||||
testParse("a && b || c", "{(::$_endOfOuterBlock_$ () (::or (::and :a :b) :c))}")
|
testParse("a && b || c", "{(:or (:and :a :b) :c)}")
|
||||||
testParse("a && b || c && d", "{(::$_endOfOuterBlock_$ () (::or (::and :a :b) (::and :c :d)))}")
|
testParse("a && b || c && d", "{(:or (:and :a :b) (:and :c :d))}")
|
||||||
testParse("a && !b || c", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::not :b)) :c))}")
|
testParse("a && !b || c", "{(:or (:and :a (:not :b)) :c)}")
|
||||||
testParse("a && b==c || d", "{(::$_endOfOuterBlock_$ () (::or (::and :a (::equal :b :c)) :d))}")
|
testParse("a && b==c || d", "{(:or (:and :a (:equal :b :c)) :d)}")
|
||||||
testParse(
|
testParse(
|
||||||
"a && b!=c || d",
|
"a && b!=c || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::unequal :b :c)) :d))}",
|
"{(:or (:and :a (:unequal :b :c)) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && !(b==c) || d",
|
"a && !(b==c) || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::not (::equal :b :c))) :d))}",
|
"{(:or (:and :a (:not (:equal :b :c))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b>=c || d",
|
"a && b>=c || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::largerEq :b :c)) :d))}",
|
"{(:or (:and :a (:largerEq :b :c)) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && !(b>=c) || d",
|
"a && !(b>=c) || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::not (::largerEq :b :c))) :d))}",
|
"{(:or (:and :a (:not (:largerEq :b :c))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<=c || d",
|
"a && b<=c || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smallerEq :b :c)) :d))}",
|
"{(: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", "{(:or (:and :a (:larger :b :c)) :d)}")
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<c || d",
|
"a && b<c || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b :c)) :d))}",
|
"{(:or (:and :a (:smaller :b :c)) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<c[i] || d",
|
"a && b<c[i] || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::$_atIndex_$ :c :i))) :d))}",
|
"{(:or (:and :a (:smaller :b (:$_atIndex_$ :c :i))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<c.i || d",
|
"a && b<c.i || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::$_atIndex_$ :c 'i'))) :d))}",
|
"{(:or (:and :a (:smaller :b (:$_atIndex_$ :c 'i'))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<c(i) || d",
|
"a && b<c(i) || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::c :i))) :d))}",
|
"{(:or (:and :a (:smaller :b (:c :i))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2 || d",
|
"a && b<1+2 || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::add 1 2))) :d))}",
|
"{(:or (:and :a (:smaller :b (:add 1 2))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2*3 || d",
|
"a && b<1+2*3 || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::add 1 (::multiply 2 3)))) :d))}",
|
"{(:or (:and :a (:smaller :b (:add 1 (:multiply 2 3)))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2*-3+4 || d",
|
"a && b<1+2*-3+4 || d",
|
||||||
"{(::$_endOfOuterBlock_$ () (::or (::and :a (::smaller :b (::add (::add 1 (::multiply 2 (::unaryMinus 3))) 4))) :d))}",
|
"{(:or (:and :a (:smaller :b (:add (:add 1 (:multiply 2 (:unaryMinus 3))) 4))) :d)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"a && b<1+2*3 || d ? true : false",
|
"a && b<1+2*3 || d ? true : false",
|
||||||
"{(::$_endOfOuterBlock_$ () (::$$_ternary_$$ (::or (::and :a (::smaller :b (::add 1 (::multiply 2 3)))) :d) true false))}",
|
"{(::$$_ternary_$$ (:or (:and :a (:smaller :b (:add 1 (:multiply 2 3)))) :d) true false)}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("pipe", () => {
|
describe("pipe", () => {
|
||||||
testParse("1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
testParse("1 -> add(2)", "{(:add 1 2)}")
|
||||||
testParse("-1 -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus 1) 2))}")
|
testParse("-1 -> add(2)", "{(:add (:unaryMinus 1) 2)}")
|
||||||
testParse(
|
testParse(
|
||||||
"-a[1] -> add(2)",
|
"-a[1] -> add(2)",
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::$_atIndex_$ :a 1)) 2))}",
|
"{(:add (:unaryMinus (:$_atIndex_$ :a 1)) 2)}",
|
||||||
)
|
)
|
||||||
testParse("-f(1) -> add(2)", "{(::$_endOfOuterBlock_$ () (::add (::unaryMinus (::f 1)) 2))}")
|
testParse("-f(1) -> add(2)", "{(:add (:unaryMinus (:f 1)) 2)}")
|
||||||
testParse("1 + 2 -> add(3)", "{(::$_endOfOuterBlock_$ () (::add 1 (::add 2 3)))}")
|
testParse("1 + 2 -> add(3)", "{(:add 1 (:add 2 3))}")
|
||||||
testParse("1 -> add(2) * 3", "{(::$_endOfOuterBlock_$ () (::multiply (::add 1 2) 3))}")
|
testParse("1 -> add(2) * 3", "{(:multiply (:add 1 2) 3)}")
|
||||||
testParse("1 -> subtract(2)", "{(::$_endOfOuterBlock_$ () (::subtract 1 2))}")
|
testParse("1 -> subtract(2)", "{(:subtract 1 2)}")
|
||||||
testParse("-1 -> subtract(2)", "{(::$_endOfOuterBlock_$ () (::subtract (::unaryMinus 1) 2))}")
|
testParse("-1 -> subtract(2)", "{(:subtract (:unaryMinus 1) 2)}")
|
||||||
testParse(
|
testParse(
|
||||||
"1 -> subtract(2) * 3",
|
"1 -> subtract(2) * 3",
|
||||||
"{(::$_endOfOuterBlock_$ () (::multiply (::subtract 1 2) 3))}",
|
"{(:multiply (:subtract 1 2) 3)}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("elixir pipe", () => {
|
describe("elixir pipe", () => {
|
||||||
//handled together with -> so there is no need for seperate tests
|
//handled together with -> so there is no need for seperate tests
|
||||||
testParse("1 |> add(2)", "{(::$_endOfOuterBlock_$ () (::add 1 2))}")
|
testParse("1 |> add(2)", "{(:add 1 2)}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("to", () => {
|
describe("to", () => {
|
||||||
testParse("1 to 2", "{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution 1 2))}")
|
testParse("1 to 2", "{(:credibleIntervalToDistribution 1 2)}")
|
||||||
testParse(
|
testParse(
|
||||||
"-1 to -2",
|
"-1 to -2",
|
||||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2)))}",
|
"{(:credibleIntervalToDistribution (:unaryMinus 1) (:unaryMinus 2))}",
|
||||||
) // lower than unary
|
) // lower than unary
|
||||||
testParse(
|
testParse(
|
||||||
"a[1] to a[2]",
|
"a[1] to a[2]",
|
||||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2)))}",
|
"{(:credibleIntervalToDistribution (:$_atIndex_$ :a 1) (:$_atIndex_$ :a 2))}",
|
||||||
) // lower than post
|
) // lower than post
|
||||||
testParse(
|
testParse(
|
||||||
"a.p1 to a.p2",
|
"a.p1 to a.p2",
|
||||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2')))}",
|
"{(:credibleIntervalToDistribution (:$_atIndex_$ :a 'p1') (:$_atIndex_$ :a 'p2'))}",
|
||||||
) // lower than post
|
) // lower than post
|
||||||
testParse(
|
testParse(
|
||||||
"1 to 2 + 3",
|
"1 to 2 + 3",
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::credibleIntervalToDistribution 1 2) 3))}",
|
"{(:add (:credibleIntervalToDistribution 1 2) 3)}",
|
||||||
) // higher than binary operators
|
) // higher than binary operators
|
||||||
testParse(
|
testParse(
|
||||||
"1->add(2) to 3->add(4) -> add(4)",
|
"1->add(2) to 3->add(4) -> add(4)",
|
||||||
"{(::$_endOfOuterBlock_$ () (::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4)))}",
|
"{(:credibleIntervalToDistribution (:add 1 2) (:add (:add 3 4) 4))}",
|
||||||
) // lower than chain
|
) // lower than chain
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("inner block", () => {
|
describe("inner block", () => {
|
||||||
// inner blocks are 0 argument lambdas. They can be used whenever a value is required.
|
// inner blocks are 0 argument lambdas. They can be used whenever a value is required.
|
||||||
// Like lambdas they have a local scope.
|
// Like lambdas they have a local scope.
|
||||||
testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; (::$_endOfOuterBlock_$ () :x)}")
|
testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; :x}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("lambda", () => {
|
describe("lambda", () => {
|
||||||
testParse("{|x| x}", "{(::$_endOfOuterBlock_$ () {|:x| {:x}})}")
|
testParse("{|x| x}", "{{|:x| :x}}")
|
||||||
testParse("f={|x| x}", "{:f = {{|:x| {:x}}}; (::$_endOfOuterBlock_$ () ())}")
|
testParse("f={|x| x}", "{:f = {{|:x| :x}}}")
|
||||||
testParse("f(x)=x", "{:f = {|:x| {:x}}; (::$_endOfOuterBlock_$ () ())}") // Function definitions are lambda assignments
|
testParse("f(x)=x", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments
|
||||||
testParse(
|
testParse(
|
||||||
"f(x)=x ? 1 : 0",
|
"f(x)=x ? 1 : 0",
|
||||||
"{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}; (::$_endOfOuterBlock_$ () ())}",
|
"{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}",
|
||||||
) // Function definitions are lambda assignments
|
) // Function definitions are lambda assignments
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Using lambda as value", () => {
|
describe("Using lambda as value", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"myadd(x,y)=x+y; z=myadd; z",
|
"myadd(x,y)=x+y; z=myadd; z",
|
||||||
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; (::$_endOfOuterBlock_$ () :z)}",
|
"{:myadd = {|:x,:y| {(:add :x :y)}}; :z = {:myadd}; :z}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"myadd(x,y)=x+y; z=[myadd]; z",
|
"myadd(x,y)=x+y; z=[myadd]; z",
|
||||||
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructArray_$ :myadd)}; (::$_endOfOuterBlock_$ () :z)}",
|
"{:myadd = {|:x,:y| {(:add :x :y)}}; :z = {[:myadd]}; :z}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"myaddd(x,y)=x+y; z={x: myaddd}; z",
|
"myaddd(x,y)=x+y; z={x: myaddd}; z",
|
||||||
"{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$_constructRecord_$ ('x': :myaddd))}; (::$_endOfOuterBlock_$ () :z)}",
|
"{:myaddd = {|:x,:y| {(:add :x :y)}}; :z = {{'x': :myaddd}}; :z}",
|
||||||
)
|
)
|
||||||
testParse("f({|x| x+1})", "{(::$_endOfOuterBlock_$ () (::f {|:x| {(::add :x 1)}}))}")
|
testParse("f({|x| x+1})", "{(:f {|:x| (:add :x 1)})}")
|
||||||
testParse(
|
testParse(
|
||||||
"map(arr, {|x| x+1})",
|
"map(arr, {|x| x+1})",
|
||||||
"{(::$_endOfOuterBlock_$ () (::map :arr {|:x| {(::add :x 1)}}))}",
|
"{(:map :arr {|:x| (:add :x 1)})}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"map([1,2,3], {|x| x+1})",
|
"map([1,2,3], {|x| x+1})",
|
||||||
"{(::$_endOfOuterBlock_$ () (::map (::$_constructArray_$ 1 2 3) {|:x| {(::add :x 1)}}))}",
|
"{(:map [1; 2; 3] {|:x| (:add :x 1)})}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"[1,2,3]->map({|x| x+1})",
|
"[1,2,3]->map({|x| x+1})",
|
||||||
"{(::$_endOfOuterBlock_$ () (::map (::$_constructArray_$ 1 2 3) {|:x| {(::add :x 1)}}))}",
|
"{(:map [1; 2; 3] {|:x| (:add :x 1)})}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("unit", () => {
|
describe("unit", () => {
|
||||||
testParse("1m", "{(::$_endOfOuterBlock_$ () (::fromUnit_m 1))}")
|
testParse("1m", "{(:fromUnit_m 1)}")
|
||||||
testParse("1M", "{(::$_endOfOuterBlock_$ () (::fromUnit_M 1))}")
|
testParse("1M", "{(:fromUnit_M 1)}")
|
||||||
testParse("1m+2cm", "{(::$_endOfOuterBlock_$ () (::add (::fromUnit_m 1) (::fromUnit_cm 2)))}")
|
testParse("1m+2cm", "{(:add (:fromUnit_m 1) (:fromUnit_cm 2))}")
|
||||||
})
|
})
|
||||||
describe("Module", () => {
|
describe("Module", () => {
|
||||||
testParse("x", "{(::$_endOfOuterBlock_$ () :x)}")
|
testParse("x", "{:x}")
|
||||||
testParse("Math.pi", "{(::$_endOfOuterBlock_$ () :Math.pi)}")
|
testParse("Math.pi", "{:Math.pi}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -351,19 +350,19 @@ describe("parsing new line", () => {
|
||||||
`
|
`
|
||||||
a +
|
a +
|
||||||
b`,
|
b`,
|
||||||
"{(::$_endOfOuterBlock_$ () (::add :a :b))}",
|
"{(:add :a :b)}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x=
|
x=
|
||||||
1`,
|
1`,
|
||||||
"{:x = {1}; (::$_endOfOuterBlock_$ () ())}",
|
"{:x = {1}}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
x=1
|
x=1
|
||||||
y=2`,
|
y=2`,
|
||||||
"{:x = {1}; :y = {2}; (::$_endOfOuterBlock_$ () ())}",
|
"{:x = {1}; :y = {2}}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -371,7 +370,7 @@ describe("parsing new line", () => {
|
||||||
y=2;
|
y=2;
|
||||||
y }
|
y }
|
||||||
x`,
|
x`,
|
||||||
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
"{:x = {:y = {2}; :y}; :x}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -379,7 +378,7 @@ describe("parsing new line", () => {
|
||||||
y=2
|
y=2
|
||||||
y }
|
y }
|
||||||
x`,
|
x`,
|
||||||
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
"{:x = {:y = {2}; :y}; :x}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -388,7 +387,7 @@ describe("parsing new line", () => {
|
||||||
y
|
y
|
||||||
}
|
}
|
||||||
x`,
|
x`,
|
||||||
"{:x = {:y = {2}; :y}; (::$_endOfOuterBlock_$ () :x)}",
|
"{:x = {:y = {2}; :y}; :x}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -396,7 +395,7 @@ describe("parsing new line", () => {
|
||||||
y=2
|
y=2
|
||||||
z=3
|
z=3
|
||||||
`,
|
`,
|
||||||
"{:x = {1}; :y = {2}; :z = {3}; (::$_endOfOuterBlock_$ () ())}",
|
"{:x = {1}; :y = {2}; :z = {3}}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -407,7 +406,7 @@ describe("parsing new line", () => {
|
||||||
x+y+z
|
x+y+z
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; (::$_endOfOuterBlock_$ () ())}",
|
"{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -420,7 +419,7 @@ describe("parsing new line", () => {
|
||||||
g=f+4
|
g=f+4
|
||||||
g
|
g
|
||||||
`,
|
`,
|
||||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () :g)}",
|
"{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}; :g = {(:add :f 4)}; :g}"
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -442,7 +441,7 @@ describe("parsing new line", () => {
|
||||||
p ->
|
p ->
|
||||||
q
|
q
|
||||||
`,
|
`,
|
||||||
"{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::$_endOfOuterBlock_$ () (::q (::p (::h :g))))}",
|
"{:f = {:x = {1}; :y = {2}; :z = {3}; (:add (:add :x :y) :z)}; :g = {(:add :f 4)}; (:q (:p (:h :g)))}"
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -451,7 +450,7 @@ describe("parsing new line", () => {
|
||||||
c |>
|
c |>
|
||||||
d
|
d
|
||||||
`,
|
`,
|
||||||
"{(::$_endOfOuterBlock_$ () (::d (::c (::b :a))))}",
|
"{(:d (:c (:b :a)))}",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
`
|
`
|
||||||
|
@ -461,6 +460,6 @@ describe("parsing new line", () => {
|
||||||
d +
|
d +
|
||||||
e
|
e
|
||||||
`,
|
`,
|
||||||
"{(::$_endOfOuterBlock_$ () (::add (::d (::c (::b :a))) :e))}",
|
"{(:add (:d (:c (:b :a))) :e)}"
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,18 +5,18 @@ open Jest
|
||||||
open Reducer_Peggy_TestHelpers
|
open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
describe("Peggy Outer Block", () => {
|
describe("Peggy Outer Block", () => {
|
||||||
testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
testToExpression("1", "1", ~v="1", ())
|
||||||
testToExpression("x=1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ~v="()", ())
|
testToExpression("x=1", "x = {1}", ~v="()", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"x=1; y=2",
|
"x=1; y=2",
|
||||||
"{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}",
|
"x = {1}; y = {2}",
|
||||||
~v="()",
|
~v="()",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ())
|
testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"x={a=1; a}; x",
|
"x={a=1; a}; x",
|
||||||
"{(:$_let_$ :x {(:$_let_$ :a {1}); :a}); (:$_endOfOuterBlock_$ () :x)}",
|
"x = {a = {1}; a}; x",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,69 +7,69 @@ open Reducer_Peggy_TestHelpers
|
||||||
describe("Peggy to Expression", () => {
|
describe("Peggy to Expression", () => {
|
||||||
describe("literals operators parenthesis", () => {
|
describe("literals operators parenthesis", () => {
|
||||||
// Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement
|
// Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement
|
||||||
testToExpression("1", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
testToExpression("1", "1", ~v="1", ())
|
||||||
testToExpression("'hello'", "{(:$_endOfOuterBlock_$ () 'hello')}", ~v="'hello'", ())
|
testToExpression("'hello'", "'hello'", ~v="'hello'", ())
|
||||||
testToExpression("true", "{(:$_endOfOuterBlock_$ () true)}", ~v="true", ())
|
testToExpression("true", "true", ~v="true", ())
|
||||||
testToExpression("1+2", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
testToExpression("1+2", "(add)(1, 2)", ~v="3", ())
|
||||||
testToExpression("add(1,2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
testToExpression("add(1,2)", "(add)(1, 2)", ~v="3", ())
|
||||||
testToExpression("(1)", "{(:$_endOfOuterBlock_$ () 1)}", ())
|
testToExpression("(1)", "1", ())
|
||||||
testToExpression("(1+2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ())
|
testToExpression("(1+2)", "(add)(1, 2)", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("unary", () => {
|
describe("unary", () => {
|
||||||
testToExpression("-1", "{(:$_endOfOuterBlock_$ () (:unaryMinus 1))}", ~v="-1", ())
|
testToExpression("-1", "(unaryMinus)(1)", ~v="-1", ())
|
||||||
testToExpression("!true", "{(:$_endOfOuterBlock_$ () (:not true))}", ~v="false", ())
|
testToExpression("!true", "(not)(true)", ~v="false", ())
|
||||||
testToExpression("1 + -1", "{(:$_endOfOuterBlock_$ () (:add 1 (:unaryMinus 1)))}", ~v="0", ())
|
testToExpression("1 + -1", "(add)(1, (unaryMinus)(1))", ~v="0", ())
|
||||||
testToExpression("-a[0]", "{(:$_endOfOuterBlock_$ () (:unaryMinus (:$_atIndex_$ :a 0)))}", ())
|
testToExpression("-a[0]", "(unaryMinus)(($_atIndex_$)(a, 0))", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("multi-line", () => {
|
describe("multi-line", () => {
|
||||||
testToExpression("x=1; 2", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () 2)}", ~v="2", ())
|
testToExpression("x=1; 2", "x = {1}; 2", ~v="2", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"x=1; y=2",
|
"x=1; y=2",
|
||||||
"{(:$_let_$ :x {1}); (:$_let_$ :y {2}); (:$_endOfOuterBlock_$ () ())}",
|
"x = {1}; y = {2}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("variables", () => {
|
describe("variables", () => {
|
||||||
testToExpression("x = 1", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () ())}", ())
|
testToExpression("x = 1", "x = {1}", ())
|
||||||
testToExpression("x", "{(:$_endOfOuterBlock_$ () :x)}", ~v="Error(x is not defined)", ()) //TODO: value should return error
|
testToExpression("x", "x", ~v="Error(x is not defined)", ()) //TODO: value should return error
|
||||||
testToExpression("x = 1; x", "{(:$_let_$ :x {1}); (:$_endOfOuterBlock_$ () :x)}", ~v="1", ())
|
testToExpression("x = 1; x", "x = {1}; x", ~v="1", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("functions", () => {
|
describe("functions", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"identity(x) = x",
|
"identity(x) = x",
|
||||||
"{(:$_let_$ :identity (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}",
|
"identity = {|x| {x}}",
|
||||||
(),
|
(),
|
||||||
) // Function definitions become lambda assignments
|
) // Function definitions become lambda assignments
|
||||||
testToExpression("identity(x)", "{(:$_endOfOuterBlock_$ () (:identity :x))}", ()) // Note value returns error properly
|
testToExpression("identity(x)", "(identity)(x)", ()) // Note value returns error properly
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x) = x> 2 ? 0 : 1; f(3)",
|
"f(x) = x> 2 ? 0 : 1; f(3)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ (:larger :x 2) 0 1)})); (:$_endOfOuterBlock_$ () (:f 3))}",
|
"f = {|x| {(larger)(x, 2) ? (0) : (1)}}; (f)(3)",
|
||||||
~v="0",
|
~v="0",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
testToExpression("[]", "{(:$_endOfOuterBlock_$ () (:$_constructArray_$))}", ~v="[]", ())
|
testToExpression("[]", "[]", ~v="[]", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"[0, 1, 2]",
|
"[0, 1, 2]",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$_constructArray_$ 0 1 2))}",
|
"[0, 1, 2]",
|
||||||
~v="[0,1,2]",
|
~v="[0,1,2]",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"['hello', 'world']",
|
"['hello', 'world']",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$_constructArray_$ 'hello' 'world'))}",
|
"['hello', 'world']",
|
||||||
~v="['hello','world']",
|
~v="['hello','world']",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"([0,1,2])[1]",
|
"([0,1,2])[1]",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$_atIndex_$ (:$_constructArray_$ 0 1 2) 1))}",
|
"($_atIndex_$)([0, 1, 2], 1)",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
@ -78,40 +78,40 @@ describe("Peggy to Expression", () => {
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"{a: 1, b: 2}",
|
"{a: 1, b: 2}",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (('a' 1) ('b' 2))))}",
|
"{'a': 1, 'b': 2}",
|
||||||
~v="{a: 1,b: 2}",
|
~v="{a: 1,b: 2}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"{1+0: 1, 2+0: 2}",
|
"{1+0: 1, 2+0: 2}",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$_constructRecord_$ (((:add 1 0) 1) ((:add 2 0) 2))))}",
|
"{(add)(1, 0): 1, (add)(2, 0): 2}",
|
||||||
(),
|
(),
|
||||||
) // key can be any expression
|
) // key can be any expression
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"record.property",
|
"record.property",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}",
|
"($_atIndex_$)(record, 'property')",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"record={property: 1}; record.property",
|
"record={property: 1}; record.property",
|
||||||
"{(:$_let_$ :record {(:$_constructRecord_$ (('property' 1)))}); (:$_endOfOuterBlock_$ () (:$_atIndex_$ :record 'property'))}",
|
"record = {{'property': 1}}; ($_atIndex_$)(record, 'property')",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("comments", () => {
|
describe("comments", () => {
|
||||||
testToExpression("1 # This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
testToExpression("1 # This is a line comment", "1", ~v="1", ())
|
||||||
testToExpression("1 // This is a line comment", "{(:$_endOfOuterBlock_$ () 1)}", ~v="1", ())
|
testToExpression("1 // This is a line comment", "1", ~v="1", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"1 /* This is a multi line comment */",
|
"1 /* This is a multi line comment */",
|
||||||
"{(:$_endOfOuterBlock_$ () 1)}",
|
"1",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"/* This is a multi line comment */ 1",
|
"/* This is a multi line comment */ 1",
|
||||||
"{(:$_endOfOuterBlock_$ () 1)}",
|
"1",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
@ -120,25 +120,25 @@ describe("Peggy to Expression", () => {
|
||||||
describe("ternary operator", () => {
|
describe("ternary operator", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"true ? 1 : 0",
|
"true ? 1 : 0",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 0))}",
|
"true ? (1) : (0)",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"false ? 1 : 0",
|
"false ? 1 : 0",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 0))}",
|
"false ? (1) : (0)",
|
||||||
~v="0",
|
~v="0",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"true ? 1 : false ? 2 : 0",
|
"true ? 1 : false ? 2 : 0",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 1 (:$$_ternary_$$ false 2 0)))}",
|
"true ? (1) : (false ? (2) : (0))",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
) // nested ternary
|
) // nested ternary
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"false ? 1 : false ? 2 : 0",
|
"false ? 1 : false ? 2 : 0",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0)))}",
|
"false ? (1) : (false ? (2) : (0))",
|
||||||
~v="0",
|
~v="0",
|
||||||
(),
|
(),
|
||||||
) // nested ternary
|
) // nested ternary
|
||||||
|
@ -146,21 +146,21 @@ describe("Peggy to Expression", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
// expression binding
|
// expression binding
|
||||||
"f(a) = a > 5 ? 1 : 0; f(6)",
|
"f(a) = a > 5 ? 1 : 0; f(6)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) 1 0)})); (:$_endOfOuterBlock_$ () (:f 6))}",
|
"f = {|a| {(larger)(a, 5) ? (1) : (0)}}; (f)(6)",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
// when true binding
|
// when true binding
|
||||||
"f(a) = a > 5 ? a : 0; f(6)",
|
"f(a) = a > 5 ? a : 0; f(6)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:larger :a 5) :a 0)})); (:$_endOfOuterBlock_$ () (:f 6))}",
|
"f = {|a| {(larger)(a, 5) ? (a) : (0)}}; (f)(6)",
|
||||||
~v="6",
|
~v="6",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
// when false binding
|
// when false binding
|
||||||
"f(a) = a < 5 ? 1 : a; f(6)",
|
"f(a) = a < 5 ? 1 : a; f(6)",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [a] {(:$$_ternary_$$ (:smaller :a 5) 1 :a)})); (:$_endOfOuterBlock_$ () (:f 6))}",
|
"f = {|a| {(smaller)(a, 5) ? (1) : (a)}}; (f)(6)",
|
||||||
~v="6",
|
~v="6",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
@ -170,39 +170,39 @@ describe("Peggy to Expression", () => {
|
||||||
describe("if then else", () => {
|
describe("if then else", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"if true then 2 else 3",
|
"if true then 2 else 3",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}",
|
"true ? ({2}) : ({3})",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"if true then {2} else {3}",
|
"if true then {2} else {3}",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true {2} {3}))}",
|
"true ? ({2}) : ({3})",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"if false then {2} else if false then {4} else {5}",
|
"if false then {2} else if false then {4} else {5}",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_ternary_$$ false {2} (:$$_ternary_$$ false {4} {5})))}",
|
"false ? ({2}) : (false ? ({4}) : ({5}))",
|
||||||
(),
|
(),
|
||||||
) //nested if
|
) //nested if
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("pipe", () => {
|
describe("pipe", () => {
|
||||||
testToExpression("1 -> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
testToExpression("1 -> add(2)", "(add)(1, 2)", ~v="3", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"-1 -> add(2)",
|
"-1 -> add(2)",
|
||||||
"{(:$_endOfOuterBlock_$ () (:add (:unaryMinus 1) 2))}",
|
"(add)((unaryMinus)(1), 2)",
|
||||||
~v="1",
|
~v="1",
|
||||||
(),
|
(),
|
||||||
) // note that unary has higher priority naturally
|
) // note that unary has higher priority naturally
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"1 -> add(2) * 3",
|
"1 -> add(2) * 3",
|
||||||
"{(:$_endOfOuterBlock_$ () (:multiply (:add 1 2) 3))}",
|
"(multiply)((add)(1, 2), 3)",
|
||||||
~v="9",
|
~v="9",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("elixir pipe", () => {
|
describe("elixir pipe", () => {
|
||||||
testToExpression("1 |> add(2)", "{(:$_endOfOuterBlock_$ () (:add 1 2))}", ~v="3", ())
|
testToExpression("1 |> add(2)", "(add)(1, 2)", ~v="3", ())
|
||||||
})
|
})
|
||||||
|
|
||||||
// see testParse for priorities of to and credibleIntervalToDistribution
|
// see testParse for priorities of to and credibleIntervalToDistribution
|
||||||
|
@ -212,7 +212,8 @@ describe("Peggy to Expression", () => {
|
||||||
// Like lambdas they have a local scope.
|
// Like lambdas they have a local scope.
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"y=99; x={y=1; y}",
|
"y=99; x={y=1; y}",
|
||||||
"{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y}); (:$_endOfOuterBlock_$ () ())}",
|
"y = {99}; x = {y = {1}; y}",
|
||||||
|
// "{(:$_let_$ :y {99}); (:$_let_$ :x {(:$_let_$ :y {1}); :y}); (:$_endOfOuterBlock_$ () ())}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -220,23 +221,23 @@ describe("Peggy to Expression", () => {
|
||||||
describe("lambda", () => {
|
describe("lambda", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"{|x| x}",
|
"{|x| x}",
|
||||||
"{(:$_endOfOuterBlock_$ () (:$$_lambda_$$ [x] {:x}))}",
|
"{|x| x}",
|
||||||
~v="lambda(x=>internal code)",
|
~v="lambda(x=>internal code)",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f={|x| x}",
|
"f={|x| x}",
|
||||||
"{(:$_let_$ :f {(:$$_lambda_$$ [x] {:x})}); (:$_endOfOuterBlock_$ () ())}",
|
"f = {{|x| x}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x)=x",
|
"f(x)=x",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())}",
|
"f = {|x| {x}}",
|
||||||
(),
|
(),
|
||||||
) // Function definitions are lambda assignments
|
) // Function definitions are lambda assignments
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x)=x ? 1 : 0",
|
"f(x)=x ? 1 : 0",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {(:$$_ternary_$$ :x 1 0)})); (:$_endOfOuterBlock_$ () ())}",
|
"f = {|x| {x ? (1) : (0)}}",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -250,6 +251,6 @@ describe("Peggy to Expression", () => {
|
||||||
// ->expect
|
// ->expect
|
||||||
// ->toBe("")
|
// ->toBe("")
|
||||||
// })
|
// })
|
||||||
testToExpression("Math.pi", "{(:$_endOfOuterBlock_$ () :Math.pi)}", ~v="3.141592653589793", ())
|
testToExpression("Math.pi", "Math.pi", ~v="3.141592653589793", ())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,11 +2,11 @@ open Jest
|
||||||
open Reducer_Peggy_TestHelpers
|
open Reducer_Peggy_TestHelpers
|
||||||
|
|
||||||
describe("Construct Array", () => {
|
describe("Construct Array", () => {
|
||||||
testToExpression("[1,2]", "{(:$_endOfOuterBlock_$ () (:$_constructArray_$ 1 2))}", ~v="[1,2]", ())
|
testToExpression("[1,2]", "[1, 2]", ~v="[1,2]", ())
|
||||||
testToExpression("[]", "{(:$_endOfOuterBlock_$ () (:$_constructArray_$))}", ~v="[]", ())
|
testToExpression("[]", "[]", ~v="[]", ())
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"f(x)=x; g(x)=x; [f, g]",
|
"f(x)=x; g(x)=x; [f, g]",
|
||||||
"{(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_let_$ :g (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () (:$_constructArray_$ :f :g))}",
|
"f = {|x| {x}}; g = {|x| {x}}; [f, g]",
|
||||||
~v="[lambda(x=>internal code),lambda(x=>internal code)]",
|
~v="[lambda(x=>internal code),lambda(x=>internal code)]",
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,11 +4,11 @@ open Reducer_TestHelpers
|
||||||
describe("Parse function assignment", () => {
|
describe("Parse function assignment", () => {
|
||||||
testParseToBe(
|
testParseToBe(
|
||||||
"f(x)=x",
|
"f(x)=x",
|
||||||
"Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {:x})); (:$_endOfOuterBlock_$ () ())})",
|
"Ok(f = {|x| {x}})"
|
||||||
)
|
)
|
||||||
testParseToBe(
|
testParseToBe(
|
||||||
"f(x)=2*x",
|
"f(x)=2*x",
|
||||||
"Ok({(:$_let_$ :f (:$$_lambda_$$ [x] {(:multiply 2 :x)})); (:$_endOfOuterBlock_$ () ())})",
|
"Ok(f = {|x| {(multiply)(2, x)}})"
|
||||||
)
|
)
|
||||||
//MathJs does not allow blocks in function definitions
|
//MathJs does not allow blocks in function definitions
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,7 @@ open Reducer_TestHelpers
|
||||||
describe("Parse ternary operator", () => {
|
describe("Parse ternary operator", () => {
|
||||||
testParseToBe(
|
testParseToBe(
|
||||||
"true ? 'YES' : 'NO'",
|
"true ? 'YES' : 'NO'",
|
||||||
"Ok({(:$_endOfOuterBlock_$ () (:$$_ternary_$$ true 'YES' 'NO'))})",
|
"Ok({(:$$_ternary_$$ true 'YES' 'NO')})",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -121,38 +121,38 @@ describe("parse on distribution functions", () => {
|
||||||
describe("power", () => {
|
describe("power", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"normal(5,2) ^ normal(5,1)",
|
"normal(5,2) ^ normal(5,1)",
|
||||||
"Ok({(:$_endOfOuterBlock_$ () (:pow (:normal 5 2) (:normal 5 1)))})",
|
"Ok((pow)((normal)(5, 2), (normal)(5, 1)))",
|
||||||
)
|
)
|
||||||
testParse("3 ^ normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:pow 3 (:normal 5 1)))})")
|
testParse("3 ^ normal(5,1)", "Ok((pow)(3, (normal)(5, 1)))")
|
||||||
testParse("normal(5,2) ^ 3", "Ok({(:$_endOfOuterBlock_$ () (:pow (:normal 5 2) 3))})")
|
testParse("normal(5,2) ^ 3", "Ok((pow)((normal)(5, 2), 3))")
|
||||||
})
|
})
|
||||||
describe("subtraction", () => {
|
describe("subtraction", () => {
|
||||||
testParse("10 - normal(5,1)", "Ok({(:$_endOfOuterBlock_$ () (:subtract 10 (:normal 5 1)))})")
|
testParse("10 - normal(5,1)", "Ok((subtract)(10, (normal)(5, 1)))")
|
||||||
testParse("normal(5,1) - 10", "Ok({(:$_endOfOuterBlock_$ () (:subtract (:normal 5 1) 10))})")
|
testParse("normal(5,1) - 10", "Ok((subtract)((normal)(5, 1), 10))")
|
||||||
})
|
})
|
||||||
describe("pointwise arithmetic expressions", () => {
|
describe("pointwise arithmetic expressions", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
testParse(
|
testParse(
|
||||||
~skip=true,
|
~skip=true,
|
||||||
"normal(5,2) .- normal(5,1)",
|
"normal(5,2) .- normal(5,1)",
|
||||||
"Ok((:$_endOfOuterBlock_$ () (:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1)))))",
|
"Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))",
|
||||||
// TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})"
|
// TODO: !!! returns "Ok({(:dotPow (:normal 5 2) (:normal 5 1))})"
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"normal(5,2) .* normal(5,1)",
|
"normal(5,2) .* normal(5,1)",
|
||||||
"Ok({(:$_endOfOuterBlock_$ () (:dotMultiply (:normal 5 2) (:normal 5 1)))})",
|
"Ok((dotMultiply)((normal)(5, 2), (normal)(5, 1)))",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"normal(5,2) ./ normal(5,1)",
|
"normal(5,2) ./ normal(5,1)",
|
||||||
"Ok({(:$_endOfOuterBlock_$ () (:dotDivide (:normal 5 2) (:normal 5 1)))})",
|
"Ok((dotDivide)((normal)(5, 2), (normal)(5, 1)))",
|
||||||
)
|
)
|
||||||
testParse(
|
testParse(
|
||||||
"normal(5,2) .^ normal(5,1)",
|
"normal(5,2) .^ normal(5,1)",
|
||||||
"Ok({(:$_endOfOuterBlock_$ () (:dotPow (:normal 5 2) (:normal 5 1)))})",
|
"Ok((dotPow)((normal)(5, 2), (normal)(5, 1)))",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("equality", () => {
|
describe("equality", () => {
|
||||||
testParse("5 == normal(5,2)", "Ok({(:$_endOfOuterBlock_$ () (:equal 5 (:normal 5 2)))})")
|
testParse("5 == normal(5,2)", "Ok((equal)(5, (normal)(5, 2)))")
|
||||||
})
|
})
|
||||||
describe("pointwise adding two normals", () => {
|
describe("pointwise adding two normals", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
|
|
|
@ -1,121 +1,117 @@
|
||||||
// @@warning("-44")
|
@@warning("-44")
|
||||||
// module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
// module Project = ForTS_ReducerProject
|
module Project = ForTS_ReducerProject
|
||||||
// module Bindings = Reducer_Bindings
|
module Bindings = Reducer_Bindings
|
||||||
|
|
||||||
// open Jest
|
open Jest
|
||||||
// open Expect
|
open Expect
|
||||||
// open Expect.Operators
|
open Expect.Operators
|
||||||
|
|
||||||
// describe("Parse includes", () => {
|
describe("Parse includes", () => {
|
||||||
// let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
// Project.setSource(
|
Project.setSource(
|
||||||
// project,
|
project,
|
||||||
// "main",
|
"main",
|
||||||
// `
|
`
|
||||||
// #include 'common'
|
#include 'common'
|
||||||
// x=1`,
|
x=1`,
|
||||||
// )
|
)
|
||||||
// Project.parseIncludes(project, "main")
|
Project.parseIncludes(project, "main")
|
||||||
// test("dependencies", () => {
|
test("dependencies", () => {
|
||||||
// expect(Project.getDependencies(project, "main")) == ["common"]
|
expect(Project.getDependencies(project, "main")) == ["common"]
|
||||||
// })
|
})
|
||||||
// test("dependents", () => {
|
test("dependents", () => {
|
||||||
// expect(Project.getDependents(project, "main")) == []
|
expect(Project.getDependents(project, "main")) == []
|
||||||
// })
|
})
|
||||||
// test("getIncludes", () => {
|
test("getIncludes", () => {
|
||||||
// let mainIncludes = Project.getIncludes(project, "main")
|
let mainIncludes = Project.getIncludes(project, "main")
|
||||||
// switch mainIncludes {
|
switch mainIncludes {
|
||||||
// | Ok(includes) => expect(includes) == ["common"]
|
| Ok(includes) => expect(includes) == ["common"]
|
||||||
// | Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// let internalProject = project->Project.T.Private.castToInternalProject
|
test("past chain", () => {
|
||||||
// test("past chain", () => {
|
expect(project->Project.getPastChain("main")) == ["common"]
|
||||||
// expect(Project.Private.getPastChain(internalProject, "main")) == ["common"]
|
})
|
||||||
// })
|
test("import as variables", () => {
|
||||||
// test("import as variables", () => {
|
expect(project->Project.Private.getIncludesAsVariables("main")) == []
|
||||||
// expect(Project.Private.getIncludesAsVariables(internalProject, "main")) == []
|
})
|
||||||
// })
|
})
|
||||||
// })
|
|
||||||
|
|
||||||
// describe("Parse includes", () => {
|
describe("Parse includes", () => {
|
||||||
// let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
// Project.setSource(
|
Project.setSource(
|
||||||
// project,
|
project,
|
||||||
// "main",
|
"main",
|
||||||
// `
|
`
|
||||||
// #include 'common'
|
#include 'common'
|
||||||
// #include 'myModule' as myVariable
|
#include 'myModule' as myVariable
|
||||||
// x=1`,
|
x=1`,
|
||||||
// )
|
)
|
||||||
// Project.parseIncludes(project, "main")
|
Project.parseIncludes(project, "main")
|
||||||
|
|
||||||
// test("dependencies", () => {
|
test("dependencies", () => {
|
||||||
// expect(Project.getDependencies(project, "main")) == ["common", "myModule"]
|
expect(Project.getDependencies(project, "main")) == ["common", "myModule"]
|
||||||
// })
|
})
|
||||||
|
|
||||||
// test("dependents", () => {
|
test("dependents", () => {
|
||||||
// expect(Project.getDependents(project, "main")) == []
|
expect(Project.getDependents(project, "main")) == []
|
||||||
// })
|
})
|
||||||
|
|
||||||
// test("getIncludes", () => {
|
test("getIncludes", () => {
|
||||||
// let mainIncludes = Project.getIncludes(project, "main")
|
let mainIncludes = Project.getIncludes(project, "main")
|
||||||
// switch mainIncludes {
|
switch mainIncludes {
|
||||||
// | Ok(includes) => expect(includes) == ["common", "myModule"]
|
| Ok(includes) => expect(includes) == ["common", "myModule"]
|
||||||
// | Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
|
|
||||||
// let internalProject = project->Project.T.Private.castToInternalProject
|
test("direct past chain", () => {
|
||||||
|
expect(project->Project.Private.getPastChain("main")) == ["common"]
|
||||||
|
})
|
||||||
|
|
||||||
// test("direct past chain", () => {
|
test("direct includes", () => {
|
||||||
// expect(Project.Private.getPastChain(internalProject, "main")) == ["common"]
|
expect(project->Project.Private.getDirectIncludes("main")) == ["common"]
|
||||||
// })
|
})
|
||||||
|
|
||||||
// test("direct includes", () => {
|
test("include as variables", () => {
|
||||||
// expect(Project.Private.getDirectIncludes(internalProject, "main")) == ["common"]
|
expect(project->Project.Private.getIncludesAsVariables("main")) == [
|
||||||
// })
|
("myVariable", "myModule"),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// test("include as variables", () => {
|
describe("Parse multiple direct includes", () => {
|
||||||
// expect(Project.Private.getIncludesAsVariables(internalProject, "main")) == [
|
let project = Project.createProject()
|
||||||
// ("myVariable", "myModule"),
|
Project.setSource(
|
||||||
// ]
|
project,
|
||||||
// })
|
"main",
|
||||||
// })
|
`
|
||||||
|
#include 'common'
|
||||||
// describe("Parse multiple direct includes", () => {
|
#include 'common2'
|
||||||
// let project = Project.createProject()
|
#include 'myModule' as myVariable
|
||||||
// Project.setSource(
|
x=1`,
|
||||||
// project,
|
)
|
||||||
// "main",
|
Project.parseIncludes(project, "main")
|
||||||
// `
|
test("dependencies", () => {
|
||||||
// #include 'common'
|
expect(Project.getDependencies(project, "main")) == ["common", "common2", "myModule"]
|
||||||
// #include 'common2'
|
})
|
||||||
// #include 'myModule' as myVariable
|
test("dependents", () => {
|
||||||
// x=1`,
|
expect(Project.getDependents(project, "main")) == []
|
||||||
// )
|
})
|
||||||
// Project.parseIncludes(project, "main")
|
test("getIncludes", () => {
|
||||||
// test("dependencies", () => {
|
let mainIncludes = Project.getIncludes(project, "main")
|
||||||
// expect(Project.getDependencies(project, "main")) == ["common", "common2", "myModule"]
|
switch mainIncludes {
|
||||||
// })
|
| Ok(includes) => expect(includes) == ["common", "common2", "myModule"]
|
||||||
// test("dependents", () => {
|
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
||||||
// expect(Project.getDependents(project, "main")) == []
|
}
|
||||||
// })
|
})
|
||||||
// test("getIncludes", () => {
|
test("direct past chain", () => {
|
||||||
// let mainIncludes = Project.getIncludes(project, "main")
|
expect(Project.getPastChain(project, "main")) == ["common", "common2"]
|
||||||
// switch mainIncludes {
|
})
|
||||||
// | Ok(includes) => expect(includes) == ["common", "common2", "myModule"]
|
test("include as variables", () => {
|
||||||
// | Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
expect(project->Project.Private.getIncludesAsVariables("main")) == [
|
||||||
// }
|
("myVariable", "myModule"),
|
||||||
// })
|
]
|
||||||
// let internalProject = project->Project.T.Private.castToInternalProject
|
})
|
||||||
// test("direct past chain", () => {
|
})
|
||||||
// expect(Project.getPastChain(project, "main")) == ["common", "common2"]
|
|
||||||
// })
|
|
||||||
// test("include as variables", () => {
|
|
||||||
// expect(Project.Private.getIncludesAsVariables(internalProject, "main")) == [
|
|
||||||
// ("myVariable", "myModule"),
|
|
||||||
// ]
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ open Jest
|
||||||
open Expect
|
open Expect
|
||||||
open Expect.Operators
|
open Expect.Operators
|
||||||
|
|
||||||
// test("", () => expect(1)->toBe(1))
|
|
||||||
|
|
||||||
let runFetchResult = (project, sourceId) => {
|
let runFetchResult = (project, sourceId) => {
|
||||||
Project.run(project, sourceId)
|
Project.run(project, sourceId)
|
||||||
Project.getResult(project, sourceId)->InternalExpressionValue.toStringResult
|
Project.getResult(project, sourceId)->InternalExpressionValue.toStringResult
|
||||||
|
@ -17,18 +15,9 @@ let runFetchResult = (project, sourceId) => {
|
||||||
let runFetchFlatBindings = (project, sourceId) => {
|
let runFetchFlatBindings = (project, sourceId) => {
|
||||||
Project.run(project, sourceId)
|
Project.run(project, sourceId)
|
||||||
Project.getBindings(project, sourceId)
|
Project.getBindings(project, sourceId)
|
||||||
->Bindings.removeResult
|
->InternalExpressionValue.toStringRecord
|
||||||
->InternalExpressionValue.toStringBindings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("setting continuation", () => {
|
|
||||||
let project = Project.createProject()
|
|
||||||
let sampleBindings = Bindings.makeEmptyBindings()->Bindings.set("test", IEvVoid)
|
|
||||||
ReducerProject.setContinuation(project, "main", sampleBindings)
|
|
||||||
let answer = ReducerProject.getContinuation(project, "main")
|
|
||||||
expect(answer)->toBe(sampleBindings)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("test result true", () => {
|
test("test result true", () => {
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
Project.setSource(project, "main", "true")
|
Project.setSource(project, "main", "true")
|
||||||
|
@ -50,7 +39,7 @@ test("test library", () => {
|
||||||
test("test bindings", () => {
|
test("test bindings", () => {
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
Project.setSource(project, "variables", "myVariable=666")
|
Project.setSource(project, "variables", "myVariable=666")
|
||||||
runFetchFlatBindings(project, "variables")->expect->toBe("@{myVariable: 666}")
|
runFetchFlatBindings(project, "variables")->expect->toBe("{myVariable: 666}")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("project1", () => {
|
describe("project1", () => {
|
||||||
|
@ -86,7 +75,7 @@ describe("project1", () => {
|
||||||
runFetchResult(project, "main")->expect->toBe("Ok(1)")
|
runFetchResult(project, "main")->expect->toBe("Ok(1)")
|
||||||
})
|
})
|
||||||
test("test bindings", () => {
|
test("test bindings", () => {
|
||||||
runFetchFlatBindings(project, "first")->expect->toBe("@{x: 1}")
|
runFetchFlatBindings(project, "first")->expect->toBe("{x: 1}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -96,7 +85,7 @@ describe("project2", () => {
|
||||||
Project.setContinues(project, "second", ["first"])
|
Project.setContinues(project, "second", ["first"])
|
||||||
Project.setSource(project, "first", "x=1")
|
Project.setSource(project, "first", "x=1")
|
||||||
Project.setSource(project, "second", "y=2")
|
Project.setSource(project, "second", "y=2")
|
||||||
Project.setSource(project, "main", "y")
|
Project.setSource(project, "main", "z=3;y")
|
||||||
|
|
||||||
test("runOrder", () => {
|
test("runOrder", () => {
|
||||||
expect(Project.getRunOrder(project)) == ["first", "second", "main"]
|
expect(Project.getRunOrder(project)) == ["first", "second", "main"]
|
||||||
|
@ -120,7 +109,8 @@ describe("project2", () => {
|
||||||
runFetchResult(project, "main")->expect->toBe("Ok(2)")
|
runFetchResult(project, "main")->expect->toBe("Ok(2)")
|
||||||
})
|
})
|
||||||
test("test bindings", () => {
|
test("test bindings", () => {
|
||||||
runFetchFlatBindings(project, "main")->expect->toBe("@{x: 1,y: 2}")
|
// bindings from continues are not exposed!
|
||||||
|
runFetchFlatBindings(project, "main")->expect->toBe("{z: 3}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -150,7 +140,7 @@ describe("project with include", () => {
|
||||||
)
|
)
|
||||||
Project.parseIncludes(project, "second") //The only way of setting includes
|
Project.parseIncludes(project, "second") //The only way of setting includes
|
||||||
|
|
||||||
Project.setSource(project, "main", "y")
|
Project.setSource(project, "main", "z=3; y")
|
||||||
|
|
||||||
test("runOrder", () => {
|
test("runOrder", () => {
|
||||||
expect(Project.getRunOrder(project)) == ["common", "first", "second", "main"]
|
expect(Project.getRunOrder(project)) == ["common", "first", "second", "main"]
|
||||||
|
@ -176,7 +166,8 @@ describe("project with include", () => {
|
||||||
runFetchResult(project, "main")->expect->toBe("Ok(2)")
|
runFetchResult(project, "main")->expect->toBe("Ok(2)")
|
||||||
})
|
})
|
||||||
test("test bindings", () => {
|
test("test bindings", () => {
|
||||||
runFetchFlatBindings(project, "main")->expect->toBe("@{common: 0,x: 1,y: 2}")
|
// bindings from continues are not exposed!
|
||||||
|
runFetchFlatBindings(project, "main")->expect->toBe("{z: 3}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,13 @@ Case "Running a single source".
|
||||||
/* Let's start with running a single source and getting Result as well as the Bindings
|
/* 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.
|
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.
|
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.
|
You can run any source in the project. It will be compiled and run if it hasn't happened already; otherwise 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.
|
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.
|
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()
|
let project = Project.createProject()
|
||||||
/* Every source has a name. This is used for debugging, dependencies and error messages. */
|
/* Every source has a name. This is used for debugging, dependencies and error messages. */
|
||||||
Project.setSource(project, "main", "1 + 2")
|
project->Project.setSource("main", "1 + 2")
|
||||||
/* Let's run "main" source. */
|
/* Let's run "main" source. */
|
||||||
project->Project.run("main")
|
project->Project.run("main")
|
||||||
/* Now you have a result for "main" source.
|
/* Now you have a result for "main" source.
|
||||||
|
@ -46,27 +46,27 @@ Case "Running a single source".
|
||||||
Getting None means you have forgotten to run the source.
|
Getting None means you have forgotten to run the source.
|
||||||
*/
|
*/
|
||||||
let result = project->Project.getResult("main")
|
let result = project->Project.getResult("main")
|
||||||
let bindings = project->Project.getBindings("main")->Bindings.removeResult
|
let bindings = project->Project.getBindings("main")
|
||||||
|
|
||||||
/* Let's display the result and bindings */
|
/* Let's display the result and bindings */
|
||||||
(
|
(
|
||||||
result->InternalExpressionValue.toStringResult,
|
result->InternalExpressionValue.toStringResult,
|
||||||
bindings->InternalExpressionValue.toStringBindings,
|
bindings->InternalExpressionValue.toStringRecord,
|
||||||
)->expect == ("Ok(3)", "@{}")
|
)->expect == ("Ok(3)", "{}")
|
||||||
/* You've got 3 with empty bindings. */
|
/* You've got 3 with empty bindings. */
|
||||||
})
|
})
|
||||||
|
|
||||||
test("run summary", () => {
|
test("run summary", () => {
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
Project.setSource(project, "main", "1 + 2")
|
project->Project.setSource("main", "1 + 2")
|
||||||
Project.runAll(project)
|
project->Project.runAll
|
||||||
let result = Project.getResult(project, "main")
|
let result = project->Project.getResult("main")
|
||||||
let bindings = Project.getBindings(project, "main")->Bindings.removeResult
|
let bindings = project->Project.getBindings("main")
|
||||||
/* Now you have external bindings and external result. */
|
/* Now you have external bindings and external result. */
|
||||||
(
|
(
|
||||||
result->InternalExpressionValue.toStringResult,
|
result->InternalExpressionValue.toStringResult,
|
||||||
bindings->Reducer_T.IEvBindings->InternalExpressionValue.toString,
|
bindings->Reducer_T.IEvRecord->InternalExpressionValue.toString,
|
||||||
)->expect == ("Ok(3)", "@{}")
|
)->expect == ("Ok(3)", "{}")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("run with an environment", () => {
|
test("run with an environment", () => {
|
||||||
|
@ -74,12 +74,12 @@ Case "Running a single source".
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
|
|
||||||
/* Optional. Set your custom environment anytime before running */
|
/* Optional. Set your custom environment anytime before running */
|
||||||
Project.setEnvironment(project, InternalExpressionValue.defaultEnvironment)
|
project->Project.setEnvironment(InternalExpressionValue.defaultEnvironment)
|
||||||
|
|
||||||
Project.setSource(project, "main", "1 + 2")
|
project->Project.setSource("main", "1 + 2")
|
||||||
Project.runAll(project)
|
project->Project.runAll
|
||||||
let result = Project.getResult(project, "main")
|
let result = project->Project.getResult("main")
|
||||||
let _bindings = Project.getBindings(project, "main")
|
let _bindings = project->Project.getBindings("main")
|
||||||
result->InternalExpressionValue.toStringResult->expect == "Ok(3)"
|
result->InternalExpressionValue.toStringResult->expect == "Ok(3)"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -89,12 +89,16 @@ Case "Running a single source".
|
||||||
let (result, bindings) = Project.evaluate("1+2")
|
let (result, bindings) = Project.evaluate("1+2")
|
||||||
(
|
(
|
||||||
result->InternalExpressionValue.toStringResult,
|
result->InternalExpressionValue.toStringResult,
|
||||||
bindings->Bindings.removeResult->InternalExpressionValue.toStringBindings,
|
bindings->InternalExpressionValue.toStringRecord,
|
||||||
)->expect == ("Ok(3)", "@{}")
|
)->expect == ("Ok(3)", "{}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// s1: { x = 1 } / { stdlib }
|
||||||
|
// s2 (deps=[s1]): { y = 2 } / { { x = 1 } + stdlib }
|
||||||
|
// s3 (deps=[s2]): { z = 3 } / { { y = 2 } + stdlib }
|
||||||
|
|
||||||
//TODO multiple sources
|
//TODO multiple sources
|
||||||
//TODO multiple sources with includes. Introduction to includes
|
//TODO multiple sources with includes. Introduction to includes
|
||||||
//TODO multiple sources with multi level includes. Cycle detection
|
//TODO multiple sources with multi level includes. Cycle detection
|
||||||
|
|
|
@ -14,27 +14,27 @@ describe("ReducerProject Tutorial", () => {
|
||||||
test("Chaining", () => {
|
test("Chaining", () => {
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
/* This time let's add 3 sources and chain them together */
|
/* This time let's add 3 sources and chain them together */
|
||||||
Project.setSource(project, "source1", "x=1")
|
project->Project.setSource("source1", "x=1")
|
||||||
|
|
||||||
Project.setSource(project, "source2", "y=2")
|
project->Project.setSource("source2", "y=x+1")
|
||||||
/* To run, source2 depends on source1 */
|
/* To run, source2 depends on source1 */
|
||||||
Project.setContinues(project, "source2", ["source1"])
|
project->Project.setContinues("source2", ["source1"])
|
||||||
|
|
||||||
Project.setSource(project, "source3", "z=3")
|
project->Project.setSource("source3", "z=y+1")
|
||||||
/* To run, source3 depends on source2 */
|
/* To run, source3 depends on source2 */
|
||||||
Project.setContinues(project, "source3", ["source2"])
|
project->Project.setContinues("source3", ["source2"])
|
||||||
|
|
||||||
/* Now we can run the project */
|
/* Now we can run the project */
|
||||||
Project.runAll(project)
|
project->Project.runAll
|
||||||
|
|
||||||
/* And let's check the result and bindings of source3 */
|
/* And let's check the result and bindings of source3 */
|
||||||
let result3 = Project.getResult(project, "source3")
|
let result3 = project->Project.getResult("source3")
|
||||||
let bindings3 = Project.getBindings(project, "source3")->Bindings.removeResult
|
let bindings3 = project->Project.getBindings("source3")
|
||||||
|
|
||||||
(
|
(
|
||||||
result3->InternalExpressionValue.toStringResult,
|
result3->InternalExpressionValue.toStringResult,
|
||||||
bindings3->InternalExpressionValue.toStringBindings,
|
bindings3->InternalExpressionValue.toStringRecord,
|
||||||
)->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}")
|
)->expect == ("Ok(())", "{z: 3}")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("Depending", () => {
|
test("Depending", () => {
|
||||||
|
@ -43,24 +43,24 @@ describe("ReducerProject Tutorial", () => {
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
|
|
||||||
/* This time source1 and source2 are not depending on anything */
|
/* This time source1 and source2 are not depending on anything */
|
||||||
Project.setSource(project, "source1", "x=1")
|
project->Project.setSource("source1", "x=1")
|
||||||
Project.setSource(project, "source2", "y=2")
|
project->Project.setSource("source2", "y=2")
|
||||||
|
|
||||||
Project.setSource(project, "source3", "z=3")
|
project->Project.setSource("source3", "z=x+y")
|
||||||
/* To run, source3 depends on source1 and source3 together */
|
/* To run, source3 depends on source1 and source3 together */
|
||||||
Project.setContinues(project, "source3", ["source1", "source2"])
|
project->Project.setContinues("source3", ["source1", "source2"])
|
||||||
|
|
||||||
/* Now we can run the project */
|
/* Now we can run the project */
|
||||||
Project.runAll(project)
|
project->Project.runAll
|
||||||
|
|
||||||
/* And let's check the result and bindings of source3 */
|
/* And let's check the result and bindings of source3 */
|
||||||
let result3 = Project.getResult(project, "source3")
|
let result3 = project->Project.getResult("source3")
|
||||||
let bindings3 = Project.getBindings(project, "source3")->Bindings.removeResult
|
let bindings3 = project->Project.getBindings("source3")
|
||||||
|
|
||||||
(
|
(
|
||||||
result3->InternalExpressionValue.toStringResult,
|
result3->InternalExpressionValue.toStringResult,
|
||||||
bindings3->InternalExpressionValue.toStringBindings,
|
bindings3->InternalExpressionValue.toStringRecord,
|
||||||
)->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}")
|
)->expect == ("Ok(())", "{z: 3}")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("Intro to including", () => {
|
test("Intro to including", () => {
|
||||||
|
@ -70,33 +70,32 @@ describe("ReducerProject Tutorial", () => {
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
|
|
||||||
/* This time source1 and source2 are not depending on anything */
|
/* This time source1 and source2 are not depending on anything */
|
||||||
Project.setSource(project, "source1", "x=1")
|
project->Project.setSource("source1", "x=1")
|
||||||
Project.setSource(project, "source2", "y=2")
|
project->Project.setSource("source2", "y=2")
|
||||||
|
|
||||||
Project.setSource(
|
project->Project.setSource(
|
||||||
project,
|
|
||||||
"source3",
|
"source3",
|
||||||
`
|
`
|
||||||
#include "source1"
|
#include "source1"
|
||||||
#include "source2"
|
#include "source2"
|
||||||
z=3`,
|
z=x+y`,
|
||||||
)
|
)
|
||||||
/* We need to parse the includes to set the dependencies */
|
/* We need to parse the includes to set the dependencies */
|
||||||
Project.parseIncludes(project, "source3")
|
project->Project.parseIncludes("source3")
|
||||||
|
|
||||||
/* Now we can run the project */
|
/* Now we can run the project */
|
||||||
Project.runAll(project)
|
project->Project.runAll
|
||||||
|
|
||||||
/* And let's check the result and bindings of source3
|
/* 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
|
This time you are getting all the variables because we are including the other sources
|
||||||
Behind the scenes parseIncludes is setting the dependencies */
|
Behind the scenes parseIncludes is setting the dependencies */
|
||||||
let result3 = Project.getResult(project, "source3")
|
let result3 = project->Project.getResult("source3")
|
||||||
let bindings3 = Project.getBindings(project, "source3")->Bindings.removeResult
|
let bindings3 = project->Project.getBindings("source3")
|
||||||
|
|
||||||
(
|
(
|
||||||
result3->InternalExpressionValue.toStringResult,
|
result3->InternalExpressionValue.toStringResult,
|
||||||
bindings3->InternalExpressionValue.toStringBindings,
|
bindings3->InternalExpressionValue.toStringRecord,
|
||||||
)->expect == ("Ok(())", "@{x: 1,y: 2,z: 3}")
|
)->expect == ("Ok(())", "{z: 3}")
|
||||||
/*
|
/*
|
||||||
Doing it like this is too verbose for a storybook
|
Doing it like this is too verbose for a storybook
|
||||||
But I hope you have seen the relation of setContinues and parseIncludes */
|
But I hope you have seen the relation of setContinues and parseIncludes */
|
||||||
|
|
|
@ -16,8 +16,7 @@ Here we will finally proceed to a real life scenario. */
|
||||||
/* Here we investigate the details about parseIncludes, before setting up a real life scenario in the next section. */
|
/* Here we investigate the details about parseIncludes, before setting up a real life scenario in the next section. */
|
||||||
/* Everything happens inside a project, so let's have a project */
|
/* Everything happens inside a project, so let's have a project */
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
Project.setSource(
|
project->Project.setSource(
|
||||||
project,
|
|
||||||
"main",
|
"main",
|
||||||
`
|
`
|
||||||
#include "common"
|
#include "common"
|
||||||
|
@ -25,10 +24,10 @@ Here we will finally proceed to a real life scenario. */
|
||||||
`,
|
`,
|
||||||
)
|
)
|
||||||
/* We need to parse includes after changing the source */
|
/* We need to parse includes after changing the source */
|
||||||
Project.parseIncludes(project, "main")
|
project->Project.parseIncludes("main")
|
||||||
test("getDependencies", () => {
|
test("getDependencies", () => {
|
||||||
/* Parse includes has set the dependencies */
|
/* Parse includes has set the dependencies */
|
||||||
Project.getDependencies(project, "main")->expect == ["common"]
|
project->Project.getDependencies("main")->expect == ["common"]
|
||||||
/* If there were no includes than there would be no dependencies */
|
/* 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 */
|
/* 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 */
|
/* Therefore looking at dependencies is not the right way to load includes */
|
||||||
|
@ -36,7 +35,7 @@ Here we will finally proceed to a real life scenario. */
|
||||||
})
|
})
|
||||||
test("getIncludes", () => {
|
test("getIncludes", () => {
|
||||||
/* Parse includes has set the includes */
|
/* Parse includes has set the includes */
|
||||||
switch Project.getIncludes(project, "main") {
|
switch project->Project.getIncludes("main") {
|
||||||
| Ok(includes) => includes->expect == ["common"]
|
| Ok(includes) => includes->expect == ["common"]
|
||||||
| Error(err) => err->Reducer_ErrorValue.errorToString->fail
|
| Error(err) => err->Reducer_ErrorValue.errorToString->fail
|
||||||
}
|
}
|
||||||
|
@ -50,7 +49,7 @@ Here we will finally proceed to a real life scenario. */
|
||||||
include or depend on the current source.
|
include or depend on the current source.
|
||||||
But you don't need to use this to execute the projects.
|
But you don't need to use this to execute the projects.
|
||||||
It is provided for completeness of information. */
|
It is provided for completeness of information. */
|
||||||
Project.getDependents(project, "main")->expect == []
|
project->Project.getDependents("main")->expect == []
|
||||||
/* Nothing is depending on or including main */
|
/* Nothing is depending on or including main */
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -76,29 +75,29 @@ Here we will finally proceed to a real life scenario. */
|
||||||
|
|
||||||
/* let's recursively load the sources */
|
/* let's recursively load the sources */
|
||||||
let rec loadIncludesRecursively = (project, sourceName, visited) => {
|
let rec loadIncludesRecursively = (project, sourceName, visited) => {
|
||||||
if Js.Array2.includes(visited, sourceName) {
|
if visited->Js.Array2.includes(sourceName) {
|
||||||
/* Oh we have already visited this source. There is an include cycle */
|
/* Oh we have already visited this source. There is an include cycle */
|
||||||
"Cyclic include ${sourceName}"->Js.Exn.raiseError
|
"Cyclic include ${sourceName}"->Js.Exn.raiseError
|
||||||
} else {
|
} else {
|
||||||
let newVisited = Js.Array2.copy(visited)
|
let newVisited = Js.Array2.copy(visited)
|
||||||
let _ = Js.Array2.push(newVisited, sourceName)
|
let _ = newVisited->Js.Array2.push(sourceName)
|
||||||
/* Let's parse the includes and dive into them */
|
/* Let's parse the includes and dive into them */
|
||||||
Project.parseIncludes(project, sourceName)
|
Project.parseIncludes(project, sourceName)
|
||||||
let rIncludes = Project.getIncludes(project, sourceName)
|
let rIncludes = project->Project.getIncludes(sourceName)
|
||||||
switch rIncludes {
|
switch rIncludes {
|
||||||
/* Maybe there is an include syntax error */
|
/* Maybe there is an include syntax error */
|
||||||
| Error(err) => err->Reducer_ErrorValue.errorToString->Js.Exn.raiseError
|
| Error(err) => err->Reducer_ErrorValue.errorToString->Js.Exn.raiseError
|
||||||
|
|
||||||
| Ok(includes) =>
|
| Ok(includes) =>
|
||||||
Belt.Array.forEach(includes, newIncludeName => {
|
includes->Belt.Array.forEach(newIncludeName => {
|
||||||
/* We have got one of the new includes.
|
/* We have got one of the new includes.
|
||||||
Let's load it and add it to the project */
|
Let's load it and add it to the project */
|
||||||
let newSource = loadSource(newIncludeName)
|
let newSource = loadSource(newIncludeName)
|
||||||
Project.setSource(project, newIncludeName, newSource)
|
project->Project.setSource(newIncludeName, newSource)
|
||||||
/* The new source is loaded and added to the project. */
|
/* The new source is loaded and added to the project. */
|
||||||
/* Of course the new source might have includes too. */
|
/* Of course the new source might have includes too. */
|
||||||
/* Let's recursively load them */
|
/* Let's recursively load them */
|
||||||
loadIncludesRecursively(project, newIncludeName, newVisited)
|
project->loadIncludesRecursively(newIncludeName, newVisited)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,45 +109,46 @@ Here we will finally proceed to a real life scenario. */
|
||||||
|
|
||||||
let project = Project.createProject()
|
let project = Project.createProject()
|
||||||
|
|
||||||
/* main includes source3 which includes source2 which includes source1 */
|
project->Project.setSource(
|
||||||
Project.setSource(
|
|
||||||
project,
|
|
||||||
"main",
|
"main",
|
||||||
`
|
`
|
||||||
|
#include "source1"
|
||||||
|
#include "source2"
|
||||||
#include "source3"
|
#include "source3"
|
||||||
x+y+z
|
a = x+y+z
|
||||||
|
b = doubleX
|
||||||
|
a
|
||||||
`,
|
`,
|
||||||
)
|
)
|
||||||
/* Setting source requires parsing and loading the includes recursively */
|
/* Setting source requires parsing and loading the includes recursively */
|
||||||
loadIncludesRecursively(project, "main", []) //No visited yet
|
project->loadIncludesRecursively("main", []) // Not visited yet
|
||||||
|
|
||||||
/* Let's salt it more. Let's have another source in the project which also has includes */
|
/* 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 */
|
/* doubleX includes source1 which is eventually included by main as well */
|
||||||
Project.setSource(
|
project->Project.setSource(
|
||||||
project,
|
|
||||||
"doubleX",
|
"doubleX",
|
||||||
`
|
`
|
||||||
#include "source1"
|
#include "source1"
|
||||||
doubleX = x * 2
|
doubleX = x * 2
|
||||||
`,
|
`,
|
||||||
)
|
)
|
||||||
loadIncludesRecursively(project, "doubleX", [])
|
project->loadIncludesRecursively("doubleX", [])
|
||||||
/* Remember, any time you set a source, you need to load includes recursively */
|
/* 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.
|
/* As doubleX is not included by main, it is not loaded recursively.
|
||||||
So we link it to the project as a dependency */
|
So we link it to the project as a dependency */
|
||||||
Project.setContinues(project, "main", ["doubleX"])
|
project->Project.setContinues("main", ["doubleX"])
|
||||||
|
|
||||||
/* Let's run the project */
|
/* Let's run the project */
|
||||||
Project.runAll(project)
|
project->Project.runAll
|
||||||
let result = Project.getResult(project, "main")
|
let result = project->Project.getResult("main")
|
||||||
let bindings = Project.getBindings(project, "main")
|
let bindings = project->Project.getBindings("main")
|
||||||
/* And see the result and bindings.. */
|
/* And see the result and bindings.. */
|
||||||
test("recursive includes", () => {
|
test("recursive includes", () => {
|
||||||
(
|
(
|
||||||
result->InternalExpressionValue.toStringResult,
|
result->InternalExpressionValue.toStringResult,
|
||||||
bindings->Bindings.removeResult->InternalExpressionValue.toStringBindings,
|
bindings->InternalExpressionValue.toStringRecord,
|
||||||
)->expect == ("Ok(6)", "@{doubleX: 2,x: 1,y: 2,z: 3}")
|
)->expect == ("Ok(6)", "{a: 6,b: 2}")
|
||||||
/* Everything as expected */
|
/* Everything as expected */
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
"dir": "src/rescript",
|
"dir": "src/rescript",
|
||||||
"subdirs": true
|
"subdirs": true
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// "dir": "__tests__",
|
"dir": "__tests__",
|
||||||
// "type": "dev",
|
"type": "dev",
|
||||||
// "subdirs": true
|
"subdirs": true
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
"dir": "benchmark",
|
"dir": "benchmark",
|
||||||
"type": "dev",
|
"type": "dev",
|
||||||
|
|
|
@ -35,4 +35,4 @@ const result = project.getResult("a");
|
||||||
console.log("Result:", result.tag, result.value.toString());
|
console.log("Result:", result.tag, result.value.toString());
|
||||||
|
|
||||||
const bindings = project.getBindings("a");
|
const bindings = project.getBindings("a");
|
||||||
console.log("Bindings:", bindings.asValue().toString());
|
console.log("Bindings:", bindings.toString());
|
||||||
|
|
|
@ -12,4 +12,8 @@ export class SqRecord {
|
||||||
([k, v]) => [k, wrapValue(v, this.location.extend(k))] as const
|
([k, v]) => [k, wrapValue(v, this.location.extend(k))] as const
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return RSRecord.toString(this._value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ type errorValue = Reducer_ErrorValue.errorValue
|
||||||
*/
|
*/
|
||||||
type rec frType =
|
type rec frType =
|
||||||
| FRTypeNumber
|
| FRTypeNumber
|
||||||
|
| FRTypeBool
|
||||||
| FRTypeNumeric
|
| FRTypeNumeric
|
||||||
| FRTypeDistOrNumber
|
| FRTypeDistOrNumber
|
||||||
| FRTypeDist
|
| FRTypeDist
|
||||||
|
@ -27,6 +28,7 @@ and frTypeRecordParam = (string, frType)
|
||||||
*/
|
*/
|
||||||
type rec frValue =
|
type rec frValue =
|
||||||
| FRValueNumber(float)
|
| FRValueNumber(float)
|
||||||
|
| FRValueBool(bool)
|
||||||
| FRValueDist(DistributionTypes.genericDist)
|
| FRValueDist(DistributionTypes.genericDist)
|
||||||
| FRValueArray(array<frValue>)
|
| FRValueArray(array<frValue>)
|
||||||
| FRValueDistOrNumber(frValueDistOrNumber)
|
| FRValueDistOrNumber(frValueDistOrNumber)
|
||||||
|
@ -71,6 +73,7 @@ module FRType = {
|
||||||
let rec toString = (t: t) =>
|
let rec toString = (t: t) =>
|
||||||
switch t {
|
switch t {
|
||||||
| FRTypeNumber => "number"
|
| FRTypeNumber => "number"
|
||||||
|
| FRTypeBool => "bool"
|
||||||
| FRTypeNumeric => "numeric"
|
| FRTypeNumeric => "numeric"
|
||||||
| FRTypeDist => "distribution"
|
| FRTypeDist => "distribution"
|
||||||
| FRTypeDistOrNumber => "distribution|number"
|
| FRTypeDistOrNumber => "distribution|number"
|
||||||
|
@ -107,6 +110,7 @@ module FRType = {
|
||||||
| (FRTypeAny, f) => toFrValue(f)
|
| (FRTypeAny, f) => toFrValue(f)
|
||||||
| (FRTypeString, IEvString(f)) => Some(FRValueString(f))
|
| (FRTypeString, IEvString(f)) => Some(FRValueString(f))
|
||||||
| (FRTypeNumber, IEvNumber(f)) => Some(FRValueNumber(f))
|
| (FRTypeNumber, IEvNumber(f)) => Some(FRValueNumber(f))
|
||||||
|
| (FRTypeBool, IEvBool(f)) => Some(FRValueBool(f))
|
||||||
| (FRTypeDistOrNumber, IEvNumber(f)) => Some(FRValueDistOrNumber(FRValueNumber(f)))
|
| (FRTypeDistOrNumber, IEvNumber(f)) => Some(FRValueDistOrNumber(FRValueNumber(f)))
|
||||||
| (FRTypeDistOrNumber, IEvDistribution(Symbolic(#Float(f)))) =>
|
| (FRTypeDistOrNumber, IEvDistribution(Symbolic(#Float(f)))) =>
|
||||||
Some(FRValueDistOrNumber(FRValueNumber(f)))
|
Some(FRValueDistOrNumber(FRValueNumber(f)))
|
||||||
|
@ -142,6 +146,7 @@ module FRType = {
|
||||||
let rec matchReverse = (e: frValue): internalExpressionValue =>
|
let rec matchReverse = (e: frValue): internalExpressionValue =>
|
||||||
switch e {
|
switch e {
|
||||||
| FRValueNumber(f) => IEvNumber(f)
|
| FRValueNumber(f) => IEvNumber(f)
|
||||||
|
| FRValueBool(f) => IEvBool(f)
|
||||||
| FRValueDistOrNumber(FRValueNumber(n)) => IEvNumber(n)
|
| FRValueDistOrNumber(FRValueNumber(n)) => IEvNumber(n)
|
||||||
| FRValueDistOrNumber(FRValueDist(n)) => IEvDistribution(n)
|
| FRValueDistOrNumber(FRValueDist(n)) => IEvDistribution(n)
|
||||||
| FRValueDist(dist) => IEvDistribution(dist)
|
| FRValueDist(dist) => IEvDistribution(dist)
|
||||||
|
|
|
@ -72,5 +72,25 @@ let library = [
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
|
makeFn(
|
||||||
|
"not",
|
||||||
|
[FRTypeNumber],
|
||||||
|
inputs => {
|
||||||
|
switch inputs {
|
||||||
|
| [IEvNumber(x)] => IEvBool(x != 0.)->Ok
|
||||||
|
| _ => Error(impossibleError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
makeFn(
|
||||||
|
"not",
|
||||||
|
[FRTypeBool],
|
||||||
|
inputs => {
|
||||||
|
switch inputs {
|
||||||
|
| [IEvBool(x)] => IEvBool(!x)->Ok
|
||||||
|
| _ => Error(impossibleError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,15 +18,11 @@ let rec get = ({ namespace, parent }: t, id: string) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let getWithDefault = (namespace: t, id: string, default) =>
|
|
||||||
switch namespace->get(id) {
|
|
||||||
| Some(v) => Some(v)
|
|
||||||
| None => default
|
|
||||||
}
|
|
||||||
|
|
||||||
let set = ({ namespace } as bindings: t, id: string, value): t => {
|
let set = ({ namespace } as bindings: t, id: string, value): t => {
|
||||||
let _ = namespace->Reducer_Namespace.set(id, value)
|
{
|
||||||
bindings
|
...bindings,
|
||||||
|
namespace: namespace->Reducer_Namespace.set(id, value),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rec toString = ({ namespace, parent }: t) => {
|
let rec toString = ({ namespace, parent }: t) => {
|
||||||
|
@ -43,8 +39,8 @@ let extend = (bindings: t): t => { namespace: Reducer_Namespace.make(), parent:
|
||||||
let make = (): t => { namespace: Reducer_Namespace.make(), parent: None }
|
let make = (): t => { namespace: Reducer_Namespace.make(), parent: None }
|
||||||
|
|
||||||
let removeResult = ({ namespace } as bindings: t): t => {
|
let removeResult = ({ namespace } as bindings: t): t => {
|
||||||
namespace->Belt.MutableMap.String.remove("__result__")
|
...bindings,
|
||||||
bindings
|
namespace: namespace->Belt.Map.String.remove("__result__"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let locals = ({ namespace }: t): Reducer_T.namespace => namespace
|
let locals = ({ namespace }: t): Reducer_T.namespace => namespace
|
||||||
|
@ -92,16 +88,6 @@ let fromNamespace = (namespace: Reducer_Namespace.t): t => { namespace, parent:
|
||||||
// NameSpace(Belt.Map.String.set(container, typeReferencesKey, r2))
|
// NameSpace(Belt.Map.String.set(container, typeReferencesKey, r2))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// let removeOther = (NameSpace(container): t, NameSpace(otherContainer): t): t => {
|
|
||||||
// let keys = Belt.Map.String.keysToArray(otherContainer)
|
|
||||||
// NameSpace(
|
|
||||||
// Belt.Map.String.keep(container, (key, _value) => {
|
|
||||||
// let removeThis = Js.Array2.includes(keys, key)
|
|
||||||
// !removeThis
|
|
||||||
// }),
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let functionNotFoundError = (call: functionCall) =>
|
// let functionNotFoundError = (call: functionCall) =>
|
||||||
// REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)->Error
|
// REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)->Error
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ type t = Reducer_T.context
|
||||||
|
|
||||||
let createContext = (stdLib: Reducer_Namespace.t, environment: Reducer_T.environment): t => {
|
let createContext = (stdLib: Reducer_Namespace.t, environment: Reducer_T.environment): t => {
|
||||||
{
|
{
|
||||||
bindings: stdLib->Reducer_Bindings.fromNamespace,
|
bindings: stdLib->Reducer_Bindings.fromNamespace->Reducer_Bindings.extend,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,36 +34,6 @@ let callInternal = (
|
||||||
| call => call->IEV.toStringFunctionCall->MathJs.Eval.eval
|
| call => call->IEV.toStringFunctionCall->MathJs.Eval.eval
|
||||||
}
|
}
|
||||||
|
|
||||||
// let constructRecord = arrayOfPairs => {
|
|
||||||
// Belt.Array.map(arrayOfPairs, pairValue =>
|
|
||||||
// switch pairValue {
|
|
||||||
// | Reducer_T.IEvArray([IEvString(key), valueValue]) => (key, valueValue)
|
|
||||||
// | _ => ("wrong key type", pairValue->IEV.toStringWithType->IEvString)
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// ->Belt.Map.String.fromArray
|
|
||||||
// ->Reducer_T.IEvRecord
|
|
||||||
// ->Ok
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let arrayAtIndex = (aValueArray: array<Reducer_T.value>, fIndex: float) =>
|
|
||||||
// switch Belt.Array.get(aValueArray, Belt.Int.fromFloat(fIndex)) {
|
|
||||||
// | Some(value) => value->Ok
|
|
||||||
// | None => REArrayIndexNotFound("Array index not found", Belt.Int.fromFloat(fIndex))->Error
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let moduleAtIndex = (nameSpace: Reducer_T.nameSpace, sIndex) =>
|
|
||||||
// switch Bindings.get(nameSpace, sIndex) {
|
|
||||||
// | Some(value) => value->Ok
|
|
||||||
// | None => RERecordPropertyNotFound("Bindings property not found", sIndex)->Error
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let recordAtIndex = (dict: Belt.Map.String.t<Reducer_T.value>, sIndex) =>
|
|
||||||
// switch Belt.Map.String.get(dict, sIndex) {
|
|
||||||
// | Some(value) => value->Ok
|
|
||||||
// | None => RERecordPropertyNotFound("Record property not found", sIndex)->Error
|
|
||||||
// }
|
|
||||||
|
|
||||||
let doAddArray = (originalA, b) => {
|
let doAddArray = (originalA, b) => {
|
||||||
let a = originalA->Js.Array2.copy
|
let a = originalA->Js.Array2.copy
|
||||||
let _ = Js.Array2.pushMany(a, b)
|
let _ = Js.Array2.pushMany(a, b)
|
||||||
|
@ -84,10 +54,6 @@ let callInternal = (
|
||||||
value->Ok
|
value->Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// let doSetBindings = (bindings: Reducer_T.nameSpace, symbol: string, value: Reducer_T.value) => {
|
|
||||||
// Bindings.set(bindings, symbol, value)->IEvBindings->Ok
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let doSetTypeAliasBindings = (
|
// let doSetTypeAliasBindings = (
|
||||||
// bindings: nameSpace,
|
// bindings: nameSpace,
|
||||||
// symbol: string,
|
// symbol: string,
|
||||||
|
|
|
@ -8,55 +8,74 @@ type errorValue = Reducer_ErrorValue.errorValue
|
||||||
/*
|
/*
|
||||||
Recursively evaluate the expression
|
Recursively evaluate the expression
|
||||||
*/
|
*/
|
||||||
let rec evaluate: T.reducerFn = (expression, context) => {
|
let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
// Js.log(`reduce: ${expression->Reducer_Expression_T.toString}`)
|
// Js.log(`reduce: ${expression->Reducer_Expression_T.toString}`)
|
||||||
switch expression {
|
switch expression {
|
||||||
| T.EBlock(statements) => {
|
| T.EBlock(statements) => {
|
||||||
let innerContext = {...context, bindings: context.bindings->Bindings.extend}
|
let innerContext = {...context, bindings: context.bindings->Bindings.extend}
|
||||||
statements->Js.Array2.reduce((_, statement) => statement->evaluate(innerContext), T.IEvVoid)
|
let (value, _) = statements->Belt.Array.reduce(
|
||||||
|
(T.IEvVoid, innerContext),
|
||||||
|
((_, currentContext), statement) => statement->evaluate(currentContext)
|
||||||
|
)
|
||||||
|
(value, context) // inner context can be dropped
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.EProgram(statements) => {
|
| T.EProgram(statements) => {
|
||||||
// Js.log(`bindings: ${context.bindings->Reducer_Bindings.toString}`)
|
// Js.log(`bindings: ${context.bindings->Bindings.locals->Reducer_Namespace.toString}`)
|
||||||
let res =
|
let (value, finalContext) = statements->Belt.Array.reduce(
|
||||||
statements->Js.Array2.reduce((_, statement) => statement->evaluate(context), T.IEvVoid)
|
(T.IEvVoid, context),
|
||||||
|
((_, currentContext), statement) => statement->evaluate(currentContext))
|
||||||
|
|
||||||
// Js.log(`bindings after: ${context.bindings->Reducer_Bindings.toString}`)
|
// Js.log(`bindings after: ${finalContext.bindings->Bindings.locals->Reducer_Namespace.toString}`)
|
||||||
res
|
(value, finalContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.EArray(elements) => elements->Js.Array2.map(element => evaluate(element, context))->T.IEvArray
|
| T.EArray(elements) => {
|
||||||
|
let value = elements->Belt.Array.map(element => {
|
||||||
|
let (value, _) = evaluate(element, context)
|
||||||
|
value
|
||||||
|
})->T.IEvArray
|
||||||
|
(value, context)
|
||||||
|
}
|
||||||
|
|
||||||
| T.ERecord(pairs) =>
|
| T.ERecord(pairs) => {
|
||||||
pairs
|
let value =
|
||||||
->Js.Array2.map(((eKey, eValue)) => {
|
pairs
|
||||||
let key = eKey->evaluate(context)
|
->Belt.Array.map(((eKey, eValue)) => {
|
||||||
let keyString = switch key {
|
let (key, _) = eKey->evaluate(context)
|
||||||
| IEvString(s) => s
|
let keyString = switch key {
|
||||||
| _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise
|
| IEvString(s) => s
|
||||||
}
|
| _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise
|
||||||
let value = eValue->evaluate(context)
|
}
|
||||||
(keyString, value)
|
let (value, _) = eValue->evaluate(context)
|
||||||
})
|
(keyString, value)
|
||||||
->Belt.Map.String.fromArray
|
})
|
||||||
->IEvRecord
|
->Belt.Map.String.fromArray
|
||||||
|
->T.IEvRecord
|
||||||
|
(value, context)
|
||||||
|
}
|
||||||
|
|
||||||
| T.EAssign(left, right) => {
|
| T.EAssign(left, right) => {
|
||||||
let result = right->evaluate(context)
|
let (result, _) = right->evaluate(context)
|
||||||
let _ = context.bindings->Bindings.set(left, result)
|
(
|
||||||
T.IEvVoid
|
T.IEvVoid,
|
||||||
|
{
|
||||||
|
...context,
|
||||||
|
bindings: context.bindings->Bindings.set(left, result),
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.ESymbol(name) =>
|
| T.ESymbol(name) =>
|
||||||
switch context.bindings->Bindings.get(name) {
|
switch context.bindings->Bindings.get(name) {
|
||||||
| Some(v) => v
|
| Some(v) => (v, context)
|
||||||
| None => Reducer_ErrorValue.RESymbolNotFound(name)->Reducer_ErrorValue.ErrorException->raise
|
| None => Reducer_ErrorValue.RESymbolNotFound(name)->Reducer_ErrorValue.ErrorException->raise
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.EValue(value) => value
|
| T.EValue(value) => (value, context)
|
||||||
|
|
||||||
| T.ETernary(predicate, trueCase, falseCase) => {
|
| T.ETernary(predicate, trueCase, falseCase) => {
|
||||||
let predicateResult = predicate->evaluate(context)
|
let (predicateResult, _) = predicate->evaluate(context)
|
||||||
switch predicateResult {
|
switch predicateResult {
|
||||||
| T.IEvBool(value) => (value ? trueCase : falseCase)->evaluate(context)
|
| T.IEvBool(value) => (value ? trueCase : falseCase)->evaluate(context)
|
||||||
| _ => REExpectedType("Boolean", "")->Reducer_ErrorValue.ErrorException->raise
|
| _ => REExpectedType("Boolean", "")->Reducer_ErrorValue.ErrorException->raise
|
||||||
|
@ -64,13 +83,16 @@ let rec evaluate: T.reducerFn = (expression, context) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.ELambda(parameters, body) =>
|
| T.ELambda(parameters, body) =>
|
||||||
Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda
|
(Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda, context)
|
||||||
|
|
||||||
| T.ECall(fn, args) => {
|
| T.ECall(fn, args) => {
|
||||||
let lambda = fn->evaluate(context)
|
let (lambda, _) = fn->evaluate(context)
|
||||||
let argValues = Js.Array2.map(args, arg => arg->evaluate(context))
|
let argValues = Js.Array2.map(args, arg => {
|
||||||
|
let (argValue, _) = arg->evaluate(context)
|
||||||
|
argValue
|
||||||
|
})
|
||||||
switch lambda {
|
switch lambda {
|
||||||
| T.IEvLambda(lambda) => Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate)
|
| T.IEvLambda(lambda) => (Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate), context)
|
||||||
| _ => REExpectedType("Lambda", "")->Reducer_ErrorValue.ErrorException->raise
|
| _ => REExpectedType("Lambda", "")->Reducer_ErrorValue.ErrorException->raise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,18 +102,19 @@ let rec evaluate: T.reducerFn = (expression, context) => {
|
||||||
module BackCompatible = {
|
module BackCompatible = {
|
||||||
// Those methods are used to support the existing tests
|
// Those methods are used to support the existing tests
|
||||||
// If they are used outside limited testing context, error location reporting will fail
|
// If they are used outside limited testing context, error location reporting will fail
|
||||||
let parse = (peggyCode: string): result<Reducer_T.expression, errorValue> =>
|
let parse = (peggyCode: string): result<T.expression, errorValue> =>
|
||||||
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
||||||
|
|
||||||
let evaluate = (expression: Reducer_T.expression): result<Reducer_T.value, errorValue> => {
|
let evaluate = (expression: T.expression): result<T.value, errorValue> => {
|
||||||
let context = Reducer_Context.createDefaultContext()
|
let context = Reducer_Context.createDefaultContext()
|
||||||
try {
|
try {
|
||||||
expression->evaluate(context)->Ok
|
let (value, _) = expression->evaluate(context)
|
||||||
|
value->Ok
|
||||||
} catch {
|
} catch {
|
||||||
| exn => Reducer_ErrorValue.fromException(exn)->Error
|
| exn => Reducer_ErrorValue.fromException(exn)->Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluateString = (peggyCode: string): result<Reducer_T.value, errorValue> =>
|
let evaluateString = (peggyCode: string): result<T.value, errorValue> =>
|
||||||
parse(peggyCode)->Result.flatMap(evaluate)
|
parse(peggyCode)->Result.flatMap(evaluate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,14 @@ let makeLambda = (
|
||||||
}
|
}
|
||||||
|
|
||||||
let localBindings = bindings->Reducer_Bindings.extend
|
let localBindings = bindings->Reducer_Bindings.extend
|
||||||
parameters->Js.Array2.forEachi((parameter, index) => {
|
let localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex(
|
||||||
let _ = localBindings->Reducer_Bindings.set(parameter, arguments[index])
|
localBindings,
|
||||||
|
(currentBindings, parameter, index) => {
|
||||||
|
currentBindings->Reducer_Bindings.set(parameter, arguments[index])
|
||||||
})
|
})
|
||||||
|
|
||||||
reducer(body, {bindings: localBindings, environment: environment})
|
let (value, _) = reducer(body, {bindings: localBindingsWithParameters, environment: environment})
|
||||||
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,36 +1,23 @@
|
||||||
/*
|
/*
|
||||||
An expression is a Lisp AST. An expression is either a primitive value or a list of expressions.
|
An expression is an intermediate representation of a Squiggle code.
|
||||||
In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is
|
Expressions are evaluated by `Reducer_Expression.evaluate` function.
|
||||||
apply e1, e2 -> apply e3 -> ... -> apply eN
|
|
||||||
This is Lisp semantics. It holds true in both eager and lazy evaluations.
|
|
||||||
A Lisp AST contains only expressions/primitive values to apply to their left.
|
|
||||||
The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
|
|
||||||
*/
|
*/
|
||||||
module Extra = Reducer_Extra
|
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
|
||||||
type internalExpressionValue = Reducer_T.value
|
type t = Reducer_T.expression
|
||||||
type environment = Reducer_T.environment
|
|
||||||
|
|
||||||
type expression = Reducer_T.expression
|
|
||||||
|
|
||||||
type t = expression
|
|
||||||
|
|
||||||
type context = Reducer_T.context
|
|
||||||
|
|
||||||
type reducerFn = Reducer_T.reducerFn
|
|
||||||
|
|
||||||
let commaJoin = values => values->Reducer_Extra_Array.intersperse(", ")->Js.String.concatMany("")
|
let commaJoin = values => values->Reducer_Extra_Array.intersperse(", ")->Js.String.concatMany("")
|
||||||
|
let semicolonJoin = values => values->Reducer_Extra_Array.intersperse("; ")->Js.String.concatMany("")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Converts the expression to String
|
Converts the expression to String
|
||||||
*/
|
*/
|
||||||
let rec toString = (expression: expression) =>
|
let rec toString = (expression: t) =>
|
||||||
switch expression {
|
switch expression {
|
||||||
| EBlock(statements) => `{${Js.Array2.map(statements, aValue => toString(aValue))->commaJoin}}`
|
| EBlock(statements) => `{${Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin}}`
|
||||||
| EProgram(statements) => `<${Js.Array2.map(statements, aValue => toString(aValue))->commaJoin}>`
|
| EProgram(statements) => Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin
|
||||||
| EArray(aList) => `[${Js.Array2.map(aList, aValue => toString(aValue))->commaJoin}]`
|
| EArray(aList) => `[${Js.Array2.map(aList, aValue => toString(aValue))->commaJoin}]`
|
||||||
| ERecord(map) => `{${map->Belt.Array.map(((key, value)) => `${key->toString}: ${value->toString}`)->Js.Array2.toString}}`
|
| ERecord(map) => `{${map->Belt.Array.map(((key, value)) => `${key->toString}: ${value->toString}`)->commaJoin}}`
|
||||||
| ESymbol(name) => name
|
| ESymbol(name) => name
|
||||||
| ETernary(predicate, trueCase, falseCase) =>
|
| ETernary(predicate, trueCase, falseCase) =>
|
||||||
`${predicate->toString} ? (${trueCase->toString}) : (${falseCase->toString})`
|
`${predicate->toString} ? (${trueCase->toString}) : (${falseCase->toString})`
|
||||||
|
@ -52,30 +39,19 @@ let toStringResultOkless = codeResult =>
|
||||||
| Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
let inspect = (expr: expression): expression => {
|
let inspect = (expr: t): t => {
|
||||||
Js.log(toString(expr))
|
Js.log(toString(expr))
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
let inspectResult = (r: result<expression, Reducer_ErrorValue.errorValue>): result<
|
let inspectResult = (r: result<t, Reducer_ErrorValue.errorValue>): result<
|
||||||
expression,
|
t,
|
||||||
Reducer_ErrorValue.errorValue,
|
Reducer_ErrorValue.errorValue,
|
||||||
> => {
|
> => {
|
||||||
Js.log(toStringResult(r))
|
Js.log(toStringResult(r))
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
type ffiFn = (
|
|
||||||
array<internalExpressionValue>,
|
|
||||||
environment,
|
|
||||||
) => result<internalExpressionValue, Reducer_ErrorValue.errorValue>
|
|
||||||
|
|
||||||
type optionFfiFn = (array<internalExpressionValue>, environment) => option<internalExpressionValue>
|
|
||||||
type optionFfiFnReturningResult = (
|
|
||||||
array<internalExpressionValue>,
|
|
||||||
environment,
|
|
||||||
) => option<result<internalExpressionValue, Reducer_ErrorValue.errorValue>>
|
|
||||||
|
|
||||||
let resultToValue = (rExpression: result<t, Reducer_ErrorValue.t>): t =>
|
let resultToValue = (rExpression: result<t, Reducer_ErrorValue.t>): t =>
|
||||||
switch rExpression {
|
switch rExpression {
|
||||||
| Ok(expression) => expression
|
| Ok(expression) => expression
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
type t = Reducer_T.namespace
|
type t = Reducer_T.namespace
|
||||||
|
|
||||||
let make = (): t => Belt.MutableMap.String.make()
|
let make = (): t => Belt.Map.String.empty
|
||||||
|
|
||||||
let get = (namespace: t, id: string): option<Reducer_T.value> =>
|
let get = (namespace: t, id: string): option<Reducer_T.value> =>
|
||||||
namespace->Belt.MutableMap.String.get(id)
|
namespace->Belt.Map.String.get(id)
|
||||||
|
|
||||||
let set = (namespace: t, id: string, value): t => {
|
let set = (namespace: t, id: string, value): t => {
|
||||||
namespace->Belt.MutableMap.String.set(id, value)
|
namespace->Belt.Map.String.set(id, value)
|
||||||
namespace
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mergeFrom = (from: t, to: t): t => {
|
let mergeFrom = (from: t, to: t): t => {
|
||||||
to->Belt.MutableMap.String.reduce(from, (namespace, key, value) => {
|
to->Belt.Map.String.reduce(from, (namespace, key, value) => {
|
||||||
if key != "__result__" {
|
if key != "__result__" {
|
||||||
namespace->Belt.MutableMap.String.set(key, value)
|
namespace->set(key, value)
|
||||||
|
} else {
|
||||||
|
namespace
|
||||||
}
|
}
|
||||||
namespace
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,15 +24,15 @@ let mergeMany = (namespaces: array<t>): t =>
|
||||||
|
|
||||||
let toString = (namespace: t) =>
|
let toString = (namespace: t) =>
|
||||||
namespace
|
namespace
|
||||||
->Belt.MutableMap.String.toArray
|
->Belt.Map.String.toArray
|
||||||
->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${eachValue->ReducerInterface_InternalExpressionValue.toString}`)
|
->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${eachValue->ReducerInterface_InternalExpressionValue.toString}`)
|
||||||
->Js.Array2.toString
|
->Js.Array2.toString
|
||||||
|
|
||||||
let fromArray = (a): t =>
|
let fromArray = (a): t =>
|
||||||
Belt.MutableMap.String.fromArray(a)
|
Belt.Map.String.fromArray(a)
|
||||||
|
|
||||||
let toMap = (namespace: t): Reducer_T.map =>
|
let toMap = (namespace: t): Reducer_T.map =>
|
||||||
namespace->Belt.MutableMap.String.toArray->Belt.Map.String.fromArray
|
namespace
|
||||||
|
|
||||||
let toRecord = (namespace: t): Reducer_T.value =>
|
let toRecord = (namespace: t): Reducer_T.value =>
|
||||||
namespace->toMap->IEvRecord
|
namespace->toMap->IEvRecord
|
||||||
|
|
|
@ -38,7 +38,7 @@ and expression =
|
||||||
| ELambda(array<string>, expression)
|
| ELambda(array<string>, expression)
|
||||||
| EValue(value)
|
| EValue(value)
|
||||||
|
|
||||||
and namespace = Belt.MutableMap.String.t<value>
|
and namespace = Belt.Map.String.t<value>
|
||||||
and bindings = {
|
and bindings = {
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
parent: option<bindings>,
|
parent: option<bindings>,
|
||||||
|
@ -49,4 +49,4 @@ and context = {
|
||||||
environment: environment,
|
environment: environment,
|
||||||
}
|
}
|
||||||
|
|
||||||
and reducerFn = (expression, context) => value
|
and reducerFn = (expression, context) => (value, context)
|
||||||
|
|
|
@ -6,7 +6,7 @@ let internalStdLib: Reducer_T.namespace = {
|
||||||
->Reducer_Namespace.mergeFrom(SquiggleLibrary_Math.make())
|
->Reducer_Namespace.mergeFrom(SquiggleLibrary_Math.make())
|
||||||
->Reducer_Namespace.mergeFrom(SquiggleLibrary_Versions.make())
|
->Reducer_Namespace.mergeFrom(SquiggleLibrary_Versions.make())
|
||||||
|
|
||||||
let _ = res->Reducer_Namespace.set(
|
let res = res->Reducer_Namespace.set(
|
||||||
"$_atIndex_$",
|
"$_atIndex_$",
|
||||||
Reducer_Expression_Lambda.makeFFILambda((inputs, _, _) => {
|
Reducer_Expression_Lambda.makeFFILambda((inputs, _, _) => {
|
||||||
switch inputs {
|
switch inputs {
|
||||||
|
@ -29,9 +29,10 @@ let internalStdLib: Reducer_T.namespace = {
|
||||||
})->Reducer_T.IEvLambda,
|
})->Reducer_T.IEvLambda,
|
||||||
)
|
)
|
||||||
|
|
||||||
FunctionRegistry_Library.nonRegistryLambdas->Js.Array2.forEach(
|
let res = FunctionRegistry_Library.nonRegistryLambdas->Belt.Array.reduce(
|
||||||
((name, lambda)) => {
|
res,
|
||||||
let _ = res->Reducer_Namespace.set(name, lambda->Reducer_T.IEvLambda)
|
(cur, (name, lambda)) => {
|
||||||
|
cur->Reducer_Namespace.set(name, lambda->Reducer_T.IEvLambda)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,10 +60,10 @@ let internalStdLib: Reducer_T.namespace = {
|
||||||
// [ ] | (_, [IEvNumber(_), IEvNumber(_)])
|
// [ ] | (_, [IEvNumber(_), IEvNumber(_)])
|
||||||
// [ ] | (_, [IEvString(_), IEvString(_)]) => callMathJs(call)
|
// [ ] | (_, [IEvString(_), IEvString(_)]) => callMathJs(call)
|
||||||
|
|
||||||
FunctionRegistry_Library.registry.fnNameDict
|
let res = FunctionRegistry_Library.registry.fnNameDict
|
||||||
->Js.Dict.keys
|
->Js.Dict.keys
|
||||||
->Js.Array2.forEach(name => {
|
->Belt.Array.reduce(res, (cur, name) => {
|
||||||
let _ = res->Reducer_Namespace.set(
|
cur->Reducer_Namespace.set(
|
||||||
name,
|
name,
|
||||||
Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => {
|
Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => {
|
||||||
switch FunctionRegistry_Library.call(name, arguments, environment, reducer) {
|
switch FunctionRegistry_Library.call(name, arguments, environment, reducer) {
|
||||||
|
|
|
@ -194,17 +194,17 @@ let tryRunWithResult = (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
rPrevResult: ProjectItem.T.resultArgumentType,
|
rPrevResult: ProjectItem.T.resultArgumentType,
|
||||||
): ProjectItem.T.resultArgumentType => {
|
): ProjectItem.T.resultArgumentType => {
|
||||||
switch getResultOption(project, sourceId) {
|
switch project->getResultOption(sourceId) {
|
||||||
| Some(result) => result // already ran
|
| Some(result) => result // already ran
|
||||||
| None =>
|
| None =>
|
||||||
switch rPrevResult {
|
switch rPrevResult {
|
||||||
| Error(error) => {
|
| Error(error) => {
|
||||||
setResult(project, sourceId, Error(error))
|
project->setResult(sourceId, Error(error))
|
||||||
Error(error)
|
Error(error)
|
||||||
}
|
}
|
||||||
| Ok(_prevResult) => {
|
| Ok(_prevResult) => {
|
||||||
doLinkAndRun(project, sourceId)
|
project->doLinkAndRun(sourceId)
|
||||||
getResultOption(project, sourceId)->Belt.Option.getWithDefault(rPrevResult)
|
project->getResultOption(sourceId)->Belt.Option.getWithDefault(rPrevResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ let runAll = (project: t): unit => {
|
||||||
let runOrder = Topology.getRunOrder(project)
|
let runOrder = Topology.getRunOrder(project)
|
||||||
let initialState = Ok(Reducer_T.IEvVoid)
|
let initialState = Ok(Reducer_T.IEvVoid)
|
||||||
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
||||||
tryRunWithResult(project, currId, currState)
|
project->tryRunWithResult(currId, currState)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,17 +222,17 @@ let run = (project: t, sourceId: string): unit => {
|
||||||
let runOrder = Topology.getRunOrderFor(project, sourceId)
|
let runOrder = Topology.getRunOrderFor(project, sourceId)
|
||||||
let initialState = Ok(Reducer_T.IEvVoid)
|
let initialState = Ok(Reducer_T.IEvVoid)
|
||||||
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
||||||
tryRunWithResult(project, currId, currState)
|
project->tryRunWithResult(currId, currState)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluate = (sourceCode: string) => {
|
let evaluate = (sourceCode: string) => {
|
||||||
let project = createProject()
|
let project = createProject()
|
||||||
setSource(project, "main", sourceCode)
|
project->setSource("main", sourceCode)
|
||||||
runAll(project)
|
project->runAll
|
||||||
|
|
||||||
(
|
(
|
||||||
getResultOption(project, "main")->Belt.Option.getWithDefault(Reducer_T.IEvVoid->Ok),
|
project->getResultOption("main")->Belt.Option.getWithDefault(Reducer_T.IEvVoid->Ok),
|
||||||
project->getBindings("main")->Reducer_Namespace.toMap,
|
project->getBindings("main")->Reducer_Namespace.toMap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,8 +174,8 @@ let doRun = (this: t, context: Reducer_T.context): t =>
|
||||||
switch this->getExpression {
|
switch this->getExpression {
|
||||||
| Some(expressionResult) => switch expressionResult {
|
| Some(expressionResult) => switch expressionResult {
|
||||||
| Ok(expression) => try {
|
| Ok(expression) => try {
|
||||||
let result = Reducer_Expression.evaluate(expression, context)
|
let (result, contextAfterEvaluation) = Reducer_Expression.evaluate(expression, context)
|
||||||
this->setResult(result->Ok)->setContinuation(context.bindings->Reducer_Bindings.locals)
|
this->setResult(result->Ok)->setContinuation(contextAfterEvaluation.bindings->Reducer_Bindings.locals)
|
||||||
} catch {
|
} catch {
|
||||||
| Reducer_ErrorValue.ErrorException(e) => this->failRun(e)
|
| Reducer_ErrorValue.ErrorException(e) => this->failRun(e)
|
||||||
| _ => this->failRun(RETodo("unhandled rescript exception"))
|
| _ => this->failRun(RETodo("unhandled rescript exception"))
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
module ProjectItem = ReducerProject_ProjectItem
|
module ProjectItem = ReducerProject_ProjectItem
|
||||||
module ExpressionT = Reducer_Expression_T
|
|
||||||
|
|
||||||
@genType.opaque
|
@genType.opaque
|
||||||
type project = {
|
type project = {
|
||||||
items: Belt.MutableMap.String.t<ProjectItem.t>,
|
items: Belt.MutableMap.String.t<ProjectItem.t>,
|
||||||
mutable stdLib: Reducer_Namespace.t,
|
mutable stdLib: Reducer_Namespace.t,
|
||||||
mutable environment: ExpressionT.environment,
|
mutable environment: Reducer_T.environment,
|
||||||
mutable previousRunOrder: array<string>,
|
mutable previousRunOrder: array<string>,
|
||||||
}
|
}
|
||||||
type t = project
|
type t = project
|
||||||
|
|
Loading…
Reference in New Issue
Block a user