format
This commit is contained in:
parent
57c2fba791
commit
a51e4be528
|
@ -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(
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -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)}",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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)}",
|
||||||
|
(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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})")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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)")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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 =>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user