This commit is contained in:
Umur Ozkul 2022-05-19 20:25:18 +02:00
parent 57c2fba791
commit a51e4be528
9 changed files with 231 additions and 81 deletions

View File

@ -16,7 +16,11 @@ testMacro([], exampleExpression, "Ok(1)")
describe("bindStatement", () => { describe("bindStatement", () => {
// A statement is bound by the bindings created by the previous statement // A statement is bound by the bindings created by the previous statement
testMacro([], eBindStatement(eBindings([]), exampleStatementY), "Ok((:$setBindings {} :y 1) context: {})") testMacro(
[],
eBindStatement(eBindings([]), exampleStatementY),
"Ok((:$setBindings {} :y 1) context: {})",
)
// Then it answers the bindings for the next statement when reduced // Then it answers the bindings for the next statement when reduced
testMacroEval([], eBindStatement(eBindings([]), exampleStatementY), "Ok({y: 1})") testMacroEval([], eBindStatement(eBindings([]), exampleStatementY), "Ok({y: 1})")
// Now let's feed a binding to see what happens // Now let's feed a binding to see what happens
@ -31,13 +35,17 @@ describe("bindStatement", () => {
testMacro( testMacro(
[("z", EvNumber(99.))], [("z", EvNumber(99.))],
eBindStatementDefault(exampleStatementY), eBindStatementDefault(exampleStatementY),
"Ok((:$setBindings {z: 99} :y 1) context: {z: 99})", "Ok((:$setBindings {z: 99} :y 1) context: {z: 99})",
) )
}) })
describe("bindExpression", () => { describe("bindExpression", () => {
// x is simply bound in the expression // x is simply bound in the expression
testMacro([], eBindExpression(eBindings([("x", EvNumber(2.))]), eSymbol("x")), "Ok(2 context: {x: 2})") testMacro(
[],
eBindExpression(eBindings([("x", EvNumber(2.))]), eSymbol("x")),
"Ok(2 context: {x: 2})",
)
// When an let statement is the end expression then bindings are returned // When an let statement is the end expression then bindings are returned
testMacro( testMacro(
[], [],

View File

@ -60,7 +60,10 @@ describe("Peggy parse", () => {
testParse("1 * 2 - 3 / 4", "{(::subtract (::multiply 1 2) (::divide 3 4))}") testParse("1 * 2 - 3 / 4", "{(::subtract (::multiply 1 2) (::divide 3 4))}")
testParse("1 * 2 - 3 ./ 4", "{(::subtract (::multiply 1 2) (::dotDivide 3 4))}") testParse("1 * 2 - 3 ./ 4", "{(::subtract (::multiply 1 2) (::dotDivide 3 4))}")
testParse("1 * 2 - 3 * 4^5", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5)))}") testParse("1 * 2 - 3 * 4^5", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5)))}")
testParse("1 * 2 - 3 * 4^5^6", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6)))}") testParse(
"1 * 2 - 3 * 4^5^6",
"{(::subtract (::multiply 1 2) (::multiply 3 (::pow (::pow 4 5) 6)))}",
)
testParse("1 * -a[-2]", "{(::multiply 1 (::unaryMinus (::$atIndex :a (::unaryMinus 2))))}") testParse("1 * -a[-2]", "{(::multiply 1 (::unaryMinus (::$atIndex :a (::unaryMinus 2))))}")
}) })
@ -93,7 +96,7 @@ describe("Peggy parse", () => {
testParse("record.property", "{(::$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)", "{(::equal :a (::not (::b 1)))}") testParse("a==!b(1)", "{(::equal :a (::not (::b 1)))}")
testParse("a==!b[1]", "{(::equal :a (::not (::$atIndex :b 1)))}") testParse("a==!b[1]", "{(::equal :a (::not (::$atIndex :b 1)))}")
@ -105,11 +108,14 @@ describe("Peggy parse", () => {
testParse("1 // This is a line comment", "{1}") testParse("1 // This is a line comment", "{1}")
testParse("1 /* This is a multi line comment */", "{1}") testParse("1 /* This is a multi line comment */", "{1}")
testParse("/* This is a multi line comment */ 1", "{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}") 1`,
"{1}",
)
}) })
describe("ternary operator", () => { describe("ternary operator", () => {
@ -126,7 +132,7 @@ describe("Peggy parse", () => {
) //nested if ) //nested if
}) })
describe("logical", ()=> { describe("logical", () => {
testParse("true || false", "{(::or true false)}") testParse("true || false", "{(::or true false)}")
testParse("true && false", "{(::and true false)}") testParse("true && false", "{(::and true false)}")
testParse("a && b || c", "{(::and :a (::or :b :c))}") testParse("a && b || c", "{(::and :a (::or :b :c))}")
@ -144,9 +150,18 @@ describe("Peggy parse", () => {
testParse("a && b<c.i || d", "{(::and :a (::or (::smaller :b (::$atIndex :c 'i')) :d))}") testParse("a && b<c.i || d", "{(::and :a (::or (::smaller :b (::$atIndex :c 'i')) :d))}")
testParse("a && b<c(i) || d", "{(::and :a (::or (::smaller :b (::c :i)) :d))}") testParse("a && b<c(i) || d", "{(::and :a (::or (::smaller :b (::c :i)) :d))}")
testParse("a && b<1+2 || d", "{(::and :a (::or (::smaller :b (::add 1 2)) :d))}") testParse("a && b<1+2 || d", "{(::and :a (::or (::smaller :b (::add 1 2)) :d))}")
testParse("a && b<1+2*3 || d", "{(::and :a (::or (::smaller :b (::add 1 (::multiply 2 3))) :d))}") testParse(
testParse("a && b<1+2*-3+4 || d", "{(::and :a (::or (::smaller :b (::add (::add 1 (::multiply 2 (::unaryMinus 3))) 4)) :d))}") "a && b<1+2*3 || d",
testParse("a && b<1+2*3 || d ? true : false", "{(::$$ternary (::and :a (::or (::smaller :b (::add 1 (::multiply 2 3))) :d)) true false)}") "{(::and :a (::or (::smaller :b (::add 1 (::multiply 2 3))) :d))}",
)
testParse(
"a && b<1+2*-3+4 || d",
"{(::and :a (::or (::smaller :b (::add (::add 1 (::multiply 2 (::unaryMinus 3))) 4)) :d))}",
)
testParse(
"a && b<1+2*3 || d ? true : false",
"{(::$$ternary (::and :a (::or (::smaller :b (::add 1 (::multiply 2 3))) :d)) true false)}",
)
}) })
describe("pipe", () => { describe("pipe", () => {
@ -194,67 +209,111 @@ describe("Peggy parse", () => {
}) })
describe("Using lambda as value", () => { describe("Using lambda as value", () => {
testParse("myadd(x,y)=x+y; z=myadd; z", "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; :z}") testParse(
testParse("myadd(x,y)=x+y; z=[myadd]; z", "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$constructArray (:myadd))}; :z}") "myadd(x,y)=x+y; z=myadd; z",
testParse("myaddd(x,y)=x+y; z={x: myaddd}; z", "{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$constructRecord ('x': :myaddd))}; :z}") "{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {:myadd}; :z}",
)
testParse(
"myadd(x,y)=x+y; z=[myadd]; z",
"{:myadd = {|:x,:y| {(::add :x :y)}}; :z = {(::$constructArray (:myadd))}; :z}",
)
testParse(
"myaddd(x,y)=x+y; z={x: myaddd}; z",
"{:myaddd = {|:x,:y| {(::add :x :y)}}; :z = {(::$constructRecord ('x': :myaddd))}; :z}",
)
testParse("f({|x| x+1})", "{(::f {|:x| {(::add :x 1)}})}") testParse("f({|x| x+1})", "{(::f {|:x| {(::add :x 1)}})}")
testParse("map(arr, {|x| x+1})", "{(::map :arr {|:x| {(::add :x 1)}})}") testParse("map(arr, {|x| x+1})", "{(::map :arr {|:x| {(::add :x 1)}})}")
testParse("map([1,2,3], {|x| x+1})", "{(::map (::$constructArray (1 2 3)) {|:x| {(::add :x 1)}})}") testParse(
testParse("[1,2,3]->map({|x| x+1})", "{(::map (::$constructArray (1 2 3)) {|:x| {(::add :x 1)}})}") "map([1,2,3], {|x| x+1})",
"{(::map (::$constructArray (1 2 3)) {|:x| {(::add :x 1)}})}",
)
testParse(
"[1,2,3]->map({|x| x+1})",
"{(::map (::$constructArray (1 2 3)) {|:x| {(::add :x 1)}})}",
)
}) })
}) })
describe("parsing new line", ()=>{ describe("parsing new line", () => {
testParse(` testParse(
`
a + a +
b`, "{(::add :a :b)}") b`,
testParse(` "{(::add :a :b)}",
)
testParse(
`
x= x=
1`, "{:x = {1}}") 1`,
testParse(` "{:x = {1}}",
)
testParse(
`
x=1 x=1
y=2`, "{:x = {1}; :y = {2}}") y=2`,
testParse(` "{:x = {1}; :y = {2}}",
)
testParse(
`
x={ x={
y=2; y=2;
y } y }
x`, "{:x = {:y = {2}; :y}; :x}") x`,
testParse(` "{:x = {:y = {2}; :y}; :x}",
)
testParse(
`
x={ x={
y=2 y=2
y } y }
x`, "{:x = {:y = {2}; :y}; :x}") x`,
testParse(` "{:x = {:y = {2}; :y}; :x}",
)
testParse(
`
x={ x={
y=2 y=2
y y
} }
x`, "{:x = {:y = {2}; :y}; :x}") x`,
testParse(` "{:x = {:y = {2}; :y}; :x}",
)
testParse(
`
x=1 x=1
y=2 y=2
z=3 z=3
`, "{:x = {1}; :y = {2}; :z = {3}}") `,
testParse(` "{:x = {1}; :y = {2}; :z = {3}}",
)
testParse(
`
f={ f={
x=1 x=1
y=2 y=2
z=3 z=3
x+y+z x+y+z
} }
`, "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}}") `,
testParse(` "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}}",
)
testParse(
`
a |> a |>
b |> b |>
c |> c |>
d d
`, "{(::d (::c (::b :a)))}") `,
testParse(` "{(::d (::c (::b :a)))}",
)
testParse(
`
a |> a |>
b |> b |>
c |> c |>
d + d +
e e
`, "{(::add (::d (::c (::b :a))) :e)}") `,
"{(::add (::d (::c (::b :a))) :e)}",
)
}) })

View File

@ -9,27 +9,32 @@ open Jest
open Expect open Expect
let expectToExpressionToBe = (expr, answer, ~v="_", ()) => { let expectToExpressionToBe = (expr, answer, ~v="_", ()) => {
let rExpr = Parse.parse(expr) let rExpr = Parse.parse(expr)->Result.map(ToExpression.fromNode)
->Result.map(ToExpression.fromNode)
let a1 = rExpr->ExpressionT.toStringResultOkless let a1 = rExpr->ExpressionT.toStringResultOkless
if (v=="_") { if v == "_" {
a1->expect->toBe(answer) a1->expect->toBe(answer)
} else { } else {
let a2 = rExpr->Result.flatMap( let a2 =
expr => Expression.reduceExpression(expr, Belt.Map.String.empty, ExpressionValue.defaultEnvironment) rExpr
)->ExpressionValue.toStringResultOkless ->Result.flatMap(expr =>
Expression.reduceExpression(expr, Belt.Map.String.empty, ExpressionValue.defaultEnvironment)
)
->ExpressionValue.toStringResultOkless
(a1, a2)->expect->toEqual((answer, v)) (a1, a2)->expect->toEqual((answer, v))
} }
} }
let testToExpression = (expr, answer, ~v="_", ()) => test(expr, () => expectToExpressionToBe(expr, answer, ~v=v, ())) let testToExpression = (expr, answer, ~v="_", ()) =>
test(expr, () => expectToExpressionToBe(expr, answer, ~v, ()))
module MySkip = { module MySkip = {
let testToExpression = (expr, answer, ~v="_", ()) => Skip.test(expr, () => expectToExpressionToBe(expr, answer, ~v=v, ())) let testToExpression = (expr, answer, ~v="_", ()) =>
Skip.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ()))
} }
module MyOnly = { module MyOnly = {
let testToExpression = (expr, answer, ~v="_", ()) => Only.test(expr, () => expectToExpressionToBe(expr, answer, ~v=v, ())) let testToExpression = (expr, answer, ~v="_", ()) =>
Only.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ()))
} }
describe("Peggy to Expression", () => { describe("Peggy to Expression", () => {
@ -53,7 +58,12 @@ describe("Peggy to Expression", () => {
describe("multi-line", () => { describe("multi-line", () => {
testToExpression("x=1; 2", "(:$$block (:$let :x (:$$block 1)) 2)", ~v="2", ()) testToExpression("x=1; 2", "(:$$block (:$let :x (:$$block 1)) 2)", ~v="2", ())
testToExpression("x=1; y=2", "(:$$block (:$let :x (:$$block 1)) (:$let :y (:$$block 2)))", ~v="{x: 1,y: 2}", ()) testToExpression(
"x=1; y=2",
"(:$$block (:$let :x (:$$block 1)) (:$let :y (:$$block 2)))",
~v="{x: 1,y: 2}",
(),
)
}) })
describe("variables", () => { describe("variables", () => {
@ -63,22 +73,51 @@ describe("Peggy to Expression", () => {
}) })
describe("functions", () => { describe("functions", () => {
testToExpression("identity(x) = x", "(:$$block (:$let :identity (:$$lambda [x] (:$$block :x))))", ~v="{identity: lambda(x=>internal code)}", ()) // Function definitions become lambda assignments testToExpression(
"identity(x) = x",
"(:$$block (:$let :identity (:$$lambda [x] (:$$block :x))))",
~v="{identity: lambda(x=>internal code)}",
(),
) // Function definitions become lambda assignments
testToExpression("identity(x)", "(:$$block (:identity :x))", ()) // Note value returns error properly testToExpression("identity(x)", "(:$$block (:identity :x))", ()) // Note value returns error properly
}) })
describe("arrays", () => { describe("arrays", () => {
testToExpression("[]", "(:$$block (:$constructArray ()))", ~v="[]", ()) testToExpression("[]", "(:$$block (:$constructArray ()))", ~v="[]", ())
testToExpression("[0, 1, 2]", "(:$$block (:$constructArray (0 1 2)))", ~v="[0,1,2]", ()) testToExpression("[0, 1, 2]", "(:$$block (:$constructArray (0 1 2)))", ~v="[0,1,2]", ())
testToExpression("['hello', 'world']", "(:$$block (:$constructArray ('hello' 'world')))", ~v="['hello','world']", ()) testToExpression(
testToExpression("([0,1,2])[1]", "(:$$block (:$atIndex (:$constructArray (0 1 2)) 1))", ~v="1", ()) "['hello', 'world']",
"(:$$block (:$constructArray ('hello' 'world')))",
~v="['hello','world']",
(),
)
testToExpression(
"([0,1,2])[1]",
"(:$$block (:$atIndex (:$constructArray (0 1 2)) 1))",
~v="1",
(),
)
}) })
describe("records", () => { describe("records", () => {
testToExpression("{a: 1, b: 2}", "(:$$block (:$constructRecord (('a' 1) ('b' 2))))", ~v="{a: 1,b: 2}", ()) testToExpression(
testToExpression("{1+0: 1, 2+0: 2}", "(:$$block (:$constructRecord (((:add 1 0) 1) ((:add 2 0) 2))))", ()) // key can be any expression "{a: 1, b: 2}",
"(:$$block (:$constructRecord (('a' 1) ('b' 2))))",
~v="{a: 1,b: 2}",
(),
)
testToExpression(
"{1+0: 1, 2+0: 2}",
"(:$$block (:$constructRecord (((:add 1 0) 1) ((:add 2 0) 2))))",
(),
) // key can be any expression
testToExpression("record.property", "(:$$block (:$atIndex :record 'property'))", ()) testToExpression("record.property", "(:$$block (:$atIndex :record 'property'))", ())
testToExpression("record={property: 1}; record.property", "(:$$block (:$let :record (:$$block (:$constructRecord (('property' 1))))) (:$atIndex :record 'property'))", ~v="1", ()) testToExpression(
"record={property: 1}; record.property",
"(:$$block (:$let :record (:$$block (:$constructRecord (('property' 1))))) (:$atIndex :record 'property'))",
~v="1",
(),
)
}) })
describe("comments", () => { describe("comments", () => {
@ -91,16 +130,35 @@ describe("Peggy to Expression", () => {
describe("ternary operator", () => { describe("ternary operator", () => {
testToExpression("true ? 1 : 0", "(:$$block (:$$ternary true 1 0))", ~v="1", ()) testToExpression("true ? 1 : 0", "(:$$block (:$$ternary true 1 0))", ~v="1", ())
testToExpression("false ? 1 : 0", "(:$$block (:$$ternary false 1 0))", ~v="0", ()) testToExpression("false ? 1 : 0", "(:$$block (:$$ternary false 1 0))", ~v="0", ())
testToExpression("true ? 1 : false ? 2 : 0", "(:$$block (:$$ternary true 1 (:$$ternary false 2 0)))", ~v="1", ()) // nested ternary testToExpression(
testToExpression("false ? 1 : false ? 2 : 0", "(:$$block (:$$ternary false 1 (:$$ternary false 2 0)))", ~v="0", ()) // nested ternary "true ? 1 : false ? 2 : 0",
"(:$$block (:$$ternary true 1 (:$$ternary false 2 0)))",
~v="1",
(),
) // nested ternary
testToExpression(
"false ? 1 : false ? 2 : 0",
"(:$$block (:$$ternary false 1 (:$$ternary false 2 0)))",
~v="0",
(),
) // nested ternary
}) })
describe("if then else", () => { describe("if then else", () => {
testToExpression("if true then 2 else 3", "(:$$block (:$$ternary true (:$$block 2) (:$$block 3)))", ()) testToExpression(
testToExpression("if true then {2} else {3}", "(:$$block (:$$ternary true (:$$block 2) (:$$block 3)))", ()) "if true then 2 else 3",
"(:$$block (:$$ternary true (:$$block 2) (:$$block 3)))",
(),
)
testToExpression(
"if true then {2} else {3}",
"(:$$block (:$$ternary true (:$$block 2) (:$$block 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}",
"(:$$block (:$$ternary false (:$$block 2) (:$$ternary false (:$$block 4) (:$$block 5))))", () "(:$$block (:$$ternary false (:$$block 2) (:$$ternary false (:$$block 4) (:$$block 5))))",
(),
) //nested if ) //nested if
}) })
@ -119,15 +177,38 @@ describe("Peggy to Expression", () => {
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.
testToExpression("y=99; x={y=1; y}", "(:$$block (:$let :y (:$$block 99)) (:$let :x (:$$block (:$let :y (:$$block 1)) :y)))", ~v="{x: 1,y: 99}", ()) testToExpression(
"y=99; x={y=1; y}",
"(:$$block (:$let :y (:$$block 99)) (:$let :x (:$$block (:$let :y (:$$block 1)) :y)))",
~v="{x: 1,y: 99}",
(),
)
}) })
describe("lambda", () => { describe("lambda", () => {
testToExpression("{|x| x}", "(:$$block (:$$lambda [x] (:$$block :x)))", ~v="lambda(x=>internal code)", ()) testToExpression(
testToExpression("f={|x| x}", "(:$$block (:$let :f (:$$block (:$$lambda [x] (:$$block :x)))))", ~v="{f: lambda(x=>internal code)}", ()) "{|x| x}",
testToExpression("f(x)=x","(:$$block (:$let :f (:$$lambda [x] (:$$block :x))))", ~v="{f: lambda(x=>internal code)}", ()) // Function definitions are lambda assignments "(:$$block (:$$lambda [x] (:$$block :x)))",
testToExpression("f(x)=x ? 1 : 0", "(:$$block (:$let :f (:$$lambda [x] (:$$block (:$$ternary :x 1 0)))))", ~v="{f: lambda(x=>internal code)}", ()) ~v="lambda(x=>internal code)",
(),
)
testToExpression(
"f={|x| x}",
"(:$$block (:$let :f (:$$block (:$$lambda [x] (:$$block :x)))))",
~v="{f: lambda(x=>internal code)}",
(),
)
testToExpression(
"f(x)=x",
"(:$$block (:$let :f (:$$lambda [x] (:$$block :x))))",
~v="{f: lambda(x=>internal code)}",
(),
) // Function definitions are lambda assignments
testToExpression(
"f(x)=x ? 1 : 0",
"(:$$block (:$let :f (:$$lambda [x] (:$$block (:$$ternary :x 1 0)))))",
~v="{f: lambda(x=>internal code)}",
(),
)
}) })
}) })

View File

@ -9,4 +9,3 @@ describe("Eval with Bindings", () => {
testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)") testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
testEvalBindingsToBe("y = x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 2})") testEvalBindingsToBe("y = x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 2})")
}) })

View File

@ -68,21 +68,23 @@ describe("function tricks", () => {
testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})")
MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout?
MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters
testEvalToBe("myadd(x,y)=x+y; z=myadd; z", "Ok(lambda(x,y=>internal code))") testEvalToBe("myadd(x,y)=x+y; z=myadd; z", "Ok(lambda(x,y=>internal code))")
testEvalToBe("myadd(x,y)=x+y; z=myadd; z(1, 1)", "Ok(2)") testEvalToBe("myadd(x,y)=x+y; z=myadd; z(1, 1)", "Ok(2)")
}) })
describe("lambda in structures", () => { describe("lambda in structures", () => {
testEvalToBe("myadd(x,y)=x+y; z=[myadd]", "Ok({myadd: lambda(x,y=>internal code),z: [lambda(x,y=>internal code)]})") testEvalToBe(
testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0]", "Ok(lambda(x,y=>internal code))") "myadd(x,y)=x+y; z=[myadd]",
testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0](3,2)", "Ok(5)") "Ok({myadd: lambda(x,y=>internal code),z: [lambda(x,y=>internal code)]})",
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z", "Ok({x: lambda(x,y=>internal code)})") )
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z.x", "Ok(lambda(x,y=>internal code))") testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0]", "Ok(lambda(x,y=>internal code))")
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z.x(3,2)", "Ok(5)") testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0](3,2)", "Ok(5)")
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z", "Ok({x: lambda(x,y=>internal code)})")
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z.x", "Ok(lambda(x,y=>internal code))")
testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z.x(3,2)", "Ok(5)")
}) })
describe("ternary and bindings", () => { describe("ternary and bindings", () => {
testEvalToBe("f(x)=x ? 1 : 0; f(true)", "Ok(1)") testEvalToBe("f(x)=x ? 1 : 0; f(true)", "Ok(1)")
testEvalToBe("f(x)=x>2 ? 1 : 0; f(3)", "Ok(1)") testEvalToBe("f(x)=x>2 ? 1 : 0; f(3)", "Ok(1)")
}) })

View File

@ -26,7 +26,7 @@ describe("eval", () => {
test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1,b: 2})")) test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1,b: 2})"))
test("index", () => expectEvalToBe("r = {a: 1}; r.a", "Ok(1)")) test("index", () => expectEvalToBe("r = {a: 1}; r.a", "Ok(1)"))
test("index", () => expectEvalToBe("r = {a: 1}; r.b", "Error(Record property not found: b)")) test("index", () => expectEvalToBe("r = {a: 1}; r.b", "Error(Record property not found: b)"))
testEvalError("{a: 1}.b") // invalid syntax testEvalError("{a: 1}.b") // invalid syntax
}) })
describe("multi-line", () => { describe("multi-line", () => {

View File

@ -21,7 +21,9 @@ type t = expression
Converts a Squigle code to expression Converts a Squigle code to expression
*/ */
let parse = (peggyCode: string): result<t, errorValue> => let parse = (peggyCode: string): result<t, errorValue> =>
peggyCode->Reducer_Peggy_Parse.parse->Result.map(node => Reducer_Peggy_ToExpression.fromNode(node)) peggyCode
->Reducer_Peggy_Parse.parse
->Result.map(node => Reducer_Peggy_ToExpression.fromNode(node))
/* /*
Recursively evaluate/reduce the expression (Lisp AST) Recursively evaluate/reduce the expression (Lisp AST)
@ -72,7 +74,7 @@ and reduceExpressionList = (
and reduceValueList = (valueList: list<expressionValue>, environment): result< and reduceValueList = (valueList: list<expressionValue>, environment): result<
expressionValue, expressionValue,
'e, 'e,
> => > =>
switch valueList { switch valueList {
| list{EvCall(fName), ...args} => | list{EvCall(fName), ...args} =>
(fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression) (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression)

View File

@ -5,7 +5,6 @@ module Parse = Reducer_Peggy_Parse
type expression = ExpressionT.expression type expression = ExpressionT.expression
let rec fromNode = (node: Parse.node): expression => { let rec fromNode = (node: Parse.node): expression => {
let caseBlock = nodeBlock => let caseBlock = nodeBlock =>
ExpressionBuilder.eBlock(nodeBlock["statements"]->Js.Array2.map(fromNode)->Belt.List.fromArray) ExpressionBuilder.eBlock(nodeBlock["statements"]->Js.Array2.map(fromNode)->Belt.List.fromArray)

View File

@ -90,7 +90,7 @@ let toStringResult = x =>
let toStringResultOkless = codeResult => let toStringResultOkless = codeResult =>
switch codeResult { switch codeResult {
| Ok(a) => toString(a) | Ok(a) => toString(a)
| Error(m) => `Error(${ErrorValue.errorToString(m)})` | Error(m) => `Error(${ErrorValue.errorToString(m)})`
} }
let toStringResultRecord = x => let toStringResultRecord = x =>