diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res index 7bbc43dd..f1acfd3a 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res @@ -16,33 +16,41 @@ testMacro([], exampleExpression, "Ok(1)") describe("bindStatement", () => { // A statement is bound by the bindings created by the previous statement - testMacro([], eBindStatement(eBindings([]), exampleStatementY), "Ok((:$setBindings {} :y 1))") + testMacro( + [], + eBindStatement(eBindings([]), exampleStatementY), + "Ok((:$_setBindings_$ {} :y 1) context: {})", + ) // Then it answers the bindings for the next statement when reduced testMacroEval([], eBindStatement(eBindings([]), exampleStatementY), "Ok({y: 1})") // Now let's feed a binding to see what happens testMacro( [], eBindStatement(eBindings([("x", EvNumber(2.))]), exampleStatementX), - "Ok((:$setBindings {x: 2} :y 2))", + "Ok((:$_setBindings_$ {x: 2} :y 2) context: {x: 2})", ) // An expression does not return a binding, thus error - testMacro([], eBindStatement(eBindings([]), exampleExpression), "Error(Assignment expected)") + testMacro([], eBindStatement(eBindings([]), exampleExpression), "Assignment expected") // When bindings from previous statement are missing the context is injected. This must be the first statement of a block testMacro( [("z", EvNumber(99.))], eBindStatementDefault(exampleStatementY), - "Ok((:$setBindings {z: 99} :y 1))", + "Ok((:$_setBindings_$ {z: 99} :y 1) context: {z: 99})", ) }) describe("bindExpression", () => { // x is simply bound in the expression - testMacro([], eBindExpression(eBindings([("x", EvNumber(2.))]), eSymbol("x")), "Ok(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 testMacro( [], eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY), - "Ok((:$exportBindings (:$setBindings {x: 2} :y 1)))", + "Ok((:$_exportBindings_$ (:$_setBindings_$ {x: 2} :y 1)) context: {x: 2})", ) // Now let's reduce that expression testMacroEval( @@ -60,37 +68,37 @@ describe("bindExpression", () => { describe("block", () => { // Block with a single expression - testMacro([], eBlock(list{exampleExpression}), "Ok((:$$bindExpression 1))") + testMacro([], eBlock(list{exampleExpression}), "Ok((:$$_bindExpression_$$ 1))") testMacroEval([], eBlock(list{exampleExpression}), "Ok(1)") // Block with a single statement - testMacro([], eBlock(list{exampleStatementY}), "Ok((:$$bindExpression (:$let :y 1)))") + testMacro([], eBlock(list{exampleStatementY}), "Ok((:$$_bindExpression_$$ (:$_let_$ :y 1)))") testMacroEval([], eBlock(list{exampleStatementY}), "Ok({y: 1})") // Block with a statement and an expression testMacro( [], eBlock(list{exampleStatementY, exampleExpressionY}), - "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) :y))", + "Ok((:$$_bindExpression_$$ (:$$_bindStatement_$$ (:$_let_$ :y 1)) :y))", ) testMacroEval([], eBlock(list{exampleStatementY, exampleExpressionY}), "Ok(1)") // Block with a statement and another statement testMacro( [], eBlock(list{exampleStatementY, exampleStatementZ}), - "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) (:$let :z :y)))", + "Ok((:$$_bindExpression_$$ (:$$_bindStatement_$$ (:$_let_$ :y 1)) (:$_let_$ :z :y)))", ) testMacroEval([], eBlock(list{exampleStatementY, exampleStatementZ}), "Ok({y: 1,z: 1})") // Block inside a block testMacro( [], eBlock(list{eBlock(list{exampleExpression})}), - "Ok((:$$bindExpression (:$$block 1)))", + "Ok((:$$_bindExpression_$$ (:$$_block_$$ 1)))", ) testMacroEval([], eBlock(list{eBlock(list{exampleExpression})}), "Ok(1)") // Block assigned to a variable testMacro( [], eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}), - "Ok((:$$bindExpression (:$let :z (:$$block (:$$block :y)))))", + "Ok((:$$_bindExpression_$$ (:$_let_$ :z (:$$_block_$$ (:$$_block_$$ :y)))))", ) testMacroEval( [], @@ -99,7 +107,7 @@ describe("block", () => { ) // Empty block testMacro([], eBlock(list{}), "Ok(:undefined block)") //TODO: should be an error - // :$$block (:$$block (:$let :y (:add :x 1)) :y)" + // :$$_block_$$ (:$$_block_$$ (:$_let_$ :y (:add :x 1)) :y)" testMacro( [], eBlock(list{ @@ -108,9 +116,9 @@ describe("block", () => { eSymbol("y"), }), }), - "Ok((:$$bindExpression (:$$block (:$let :y (:add :x 1)) :y)))", + "Ok((:$$_bindExpression_$$ (:$$_block_$$ (:$_let_$ :y (:add :x 1)) :y)))", ) - MyOnly.testMacroEval( + testMacroEval( [("x", EvNumber(1.))], eBlock(list{ eBlock(list{ @@ -124,17 +132,17 @@ describe("block", () => { describe("lambda", () => { // assign a lambda to a variable - let lambdaExpression = eFunction("$$lambda", list{eArrayString(["y"]), exampleExpressionY}) - testMacro([], lambdaExpression, "Ok(lambda(y=>internal))") + let lambdaExpression = eFunction("$$_lambda_$$", list{eArrayString(["y"]), exampleExpressionY}) + testMacro([], lambdaExpression, "Ok(lambda(y=>internal code))") // call a lambda let callLambdaExpression = list{lambdaExpression, eNumber(1.)}->ExpressionT.EList - testMacro([], callLambdaExpression, "Ok(((:$$lambda [y] :y) 1))") + testMacro([], callLambdaExpression, "Ok(((:$$_lambda_$$ [y] :y) 1))") testMacroEval([], callLambdaExpression, "Ok(1)") // Parameters shadow the outer scope testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(1)") // When not shadowed by the parameters, the outer scope variables are available let lambdaExpression = eFunction( - "$$lambda", + "$$_lambda_$$", list{eArrayString(["z"]), eFunction("add", list{eSymbol("y"), eSymbol("z")})}, ) let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res index 398530e3..682e1737 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res @@ -26,6 +26,16 @@ describe("builtin", () => { describe("builtin exception", () => { //It's a pity that MathJs does not return error position test("MathJs Exception", () => - expectEvalToBe("testZadanga()", "Error(JS Exception: Error: Undefined function testZadanga)") + expectEvalToBe("testZadanga(1)", "Error(JS Exception: Error: Undefined function testZadanga)") ) }) + +describe("error reporting from collection functions", () => { + testEval("arr=[1,2,3]; map(arr, {|x| x*2})", "Ok([2,4,6])") + testEval( + "arr = [normal(3,2)]; map(arr, zarathsuzaWasHere)", + "Error(zarathsuzaWasHere is not defined)", + ) + // FIXME: returns "Error(Function not found: map(Array,Symbol))" + // Actually this error is correct but not informative +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res deleted file mode 100644 index b6c8c290..00000000 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ /dev/null @@ -1,74 +0,0 @@ -module Parse = Reducer_MathJs.Parse -module Result = Belt.Result - -open Jest -open Expect - -let expectParseToBe = (expr, answer) => - Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(answer) - -let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) - -let testDescriptionParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) - -module MySkip = { - let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) - - let testDescriptionParse = (desc, expr, answer) => - Skip.test(desc, () => expectParseToBe(expr, answer)) -} - -module MyOnly = { - let testParse = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) - let testDescriptionParse = (desc, expr, answer) => - Only.test(desc, () => expectParseToBe(expr, answer)) -} - -describe("MathJs parse", () => { - describe("literals operators parenthesis", () => { - testParse("1", "1") - testParse("'hello'", "'hello'") - testParse("true", "true") - testParse("1+2", "add(1, 2)") - testParse("add(1,2)", "add(1, 2)") - testParse("(1)", "(1)") - testParse("(1+2)", "(add(1, 2))") - }) - - describe("multi-line", () => { - testParse("1; 2", "{1; 2}") - }) - - describe("variables", () => { - testParse("x = 1", "x = 1") - testParse("x", "x") - testParse("x = 1; x", "{x = 1; x}") - }) - - describe("functions", () => { - testParse("identity(x) = x", "identity = (x) => x") - testParse("identity(x)", "identity(x)") - }) - - describe("arrays", () => { - testDescriptionParse("empty", "[]", "[]") - testDescriptionParse("define", "[0, 1, 2]", "[0, 1, 2]") - testDescriptionParse("define with strings", "['hello', 'world']", "['hello', 'world']") - testParse("range(0, 4)", "range(0, 4)") - testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") - }) - - describe("records", () => { - testDescriptionParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") - testDescriptionParse("use", "record.property", "record['property']") - }) - - describe("comments", () => { - testDescriptionParse("define", "1 # This is a comment", "1") - }) - - describe("ternary operator", () => { - testParse("1 ? 2 : 3", "ternary(1, 2, 3)") - testParse("1 ? 2 : 3 ? 4 : 5", "ternary(1, 2, ternary(3, 4, 5))") - }) -}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res new file mode 100644 index 00000000..168be4d8 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res @@ -0,0 +1,373 @@ +module Parse = Reducer_Peggy_Parse +module Result = Belt.Result + +open Jest +open Expect + +let expectParseToBe = (expr, answer) => + Parse.parse(expr)->Parse.toStringResult->expect->toBe(answer) + +let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) + +module MySkip = { + let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) + + let testDescriptionParse = (desc, expr, answer) => + Skip.test(desc, () => expectParseToBe(expr, answer)) +} + +module MyOnly = { + let testParse = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) + let testDescriptionParse = (desc, expr, answer) => + Only.test(desc, () => expectParseToBe(expr, answer)) +} + +describe("Peggy parse", () => { + describe("float", () => { + testParse("1.", "{1}") + testParse("1.1", "{1.1}") + testParse(".1", "{0.1}") + testParse("0.1", "{0.1}") + testParse("1e1", "{10}") + testParse("1e-1", "{0.1}") + testParse(".1e1", "{1}") + testParse("0.1e1", "{1}") + }) + + describe("literals operators parenthesis", () => { + // Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement + testParse("1", "{1}") + testParse("'hello'", "{'hello'}") + testParse("true", "{true}") + testParse("1+2", "{(::add 1 2)}") + testParse("add(1,2)", "{(::add 1 2)}") + testParse("(1)", "{1}") + testParse("(1+2)", "{(::add 1 2)}") + }) + + describe("unary", () => { + testParse("-1", "{(::unaryMinus 1)}") + testParse("!true", "{(::not true)}") + testParse("1 + -1", "{(::add 1 (::unaryMinus 1))}") + testParse("-a[0]", "{(::unaryMinus (::$_atIndex_$ :a 0))}") + testParse("!a[0]", "{(::not (::$_atIndex_$ :a 0))}") + }) + + describe("multiplicative", () => { + testParse("1 * 2", "{(::multiply 1 2)}") + testParse("1 / 2", "{(::divide 1 2)}") + testParse("1 * 2 * 3", "{(::multiply (::multiply 1 2) 3)}") + testParse("1 * 2 / 3", "{(::divide (::multiply 1 2) 3)}") + testParse("1 / 2 * 3", "{(::multiply (::divide 1 2) 3)}") + testParse("1 / 2 / 3", "{(::divide (::divide 1 2) 3)}") + testParse("1 * 2 + 3 * 4", "{(::add (::multiply 1 2) (::multiply 3 4))}") + testParse("1 * 2 - 3 * 4", "{(::subtract (::multiply 1 2) (::multiply 3 4))}") + testParse("1 * 2 .+ 3 * 4", "{(::dotAdd (::multiply 1 2) (::multiply 3 4))}") + testParse("1 * 2 .- 3 * 4", "{(::dotSubtract (::multiply 1 2) (::multiply 3 4))}") + testParse("1 * 2 + 3 .* 4", "{(::add (::multiply 1 2) (::dotMultiply 3 4))}") + testParse("1 * 2 + 3 / 4", "{(::add (::multiply 1 2) (::divide 3 4))}") + testParse("1 * 2 + 3 ./ 4", "{(::add (::multiply 1 2) (::dotDivide 3 4))}") + testParse("1 * 2 - 3 .* 4", "{(::subtract (::multiply 1 2) (::dotMultiply 3 4))}") + testParse("1 * 2 - 3 / 4", "{(::subtract (::multiply 1 2) (::divide 3 4))}") + testParse("1 * 2 - 3 ./ 4", "{(::subtract (::multiply 1 2) (::dotDivide 3 4))}") + testParse("1 * 2 - 3 * 4^5", "{(::subtract (::multiply 1 2) (::multiply 3 (::pow 4 5)))}") + testParse( + "1 * 2 - 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))))}") + }) + + describe("multi-line", () => { + testParse("x=1; 2", "{:x = {1}; 2}") + testParse("x=1; y=2", "{:x = {1}; :y = {2}}") + }) + + describe("variables", () => { + testParse("x = 1", "{:x = {1}}") + testParse("x", "{:x}") + testParse("x = 1; x", "{:x = {1}; :x}") + }) + + describe("functions", () => { + testParse("identity(x) = x", "{:identity = {|:x| {:x}}}") // Function definitions become lambda assignments + testParse("identity(x)", "{(::identity :x)}") + }) + + describe("arrays", () => { + testParse("[]", "{(::$_constructArray_$ ())}") + testParse("[0, 1, 2]", "{(::$_constructArray_$ (0 1 2))}") + testParse("['hello', 'world']", "{(::$_constructArray_$ ('hello' 'world'))}") + testParse("([0,1,2])[1]", "{(::$_atIndex_$ (::$_constructArray_$ (0 1 2)) 1)}") + }) + + describe("records", () => { + testParse("{a: 1, b: 2}", "{(::$_constructRecord_$ ('a': 1 'b': 2))}") + testParse("{1+0: 1, 2+0: 2}", "{(::$_constructRecord_$ ((::add 1 0): 1 (::add 2 0): 2))}") // key can be any expression + testParse("record.property", "{(::$_atIndex_$ :record 'property')}") + }) + + describe("post operators", () => { + //function call, array and record access are post operators with higher priority than unary operators + testParse("a==!b(1)", "{(::equal :a (::not (::b 1)))}") + testParse("a==!b[1]", "{(::equal :a (::not (::$_atIndex_$ :b 1)))}") + testParse("a==!b.one", "{(::equal :a (::not (::$_atIndex_$ :b 'one')))}") + }) + + describe("comments", () => { + testParse("1 # This is a line comment", "{1}") + testParse("1 // This is a line comment", "{1}") + testParse("1 /* This is a multi line comment */", "{1}") + testParse("/* This is a multi line comment */ 1", "{1}") + testParse( + ` + /* This is + a multi line + comment */ + 1`, + "{1}", + ) + }) + + describe("ternary operator", () => { + testParse("true ? 2 : 3", "{(::$$_ternary_$$ true 2 3)}") + testParse( + "false ? 2 : false ? 4 : 5", + "{(::$$_ternary_$$ false 2 (::$$_ternary_$$ false 4 5))}", + ) // nested ternary + }) + + describe("if then else", () => { + testParse("if true then 2 else 3", "{(::$$_ternary_$$ true {2} {3})}") + testParse("if false then {2} else {3}", "{(::$$_ternary_$$ false {2} {3})}") + testParse( + "if false then {2} else if false then {4} else {5}", + "{(::$$_ternary_$$ false {2} (::$$_ternary_$$ false {4} {5}))}", + ) //nested if + }) + + describe("logical", () => { + testParse("true || false", "{(::or true false)}") + testParse("true && false", "{(::and true false)}") + testParse("a * b + c", "{(::add (::multiply :a :b) :c)}") // for comparison + testParse("a && b || c", "{(::or (::and :a :b) :c)}") + testParse("a && b || c && d", "{(::or (::and :a :b) (::and :c :d))}") + testParse("a && !b || c", "{(::or (::and :a (::not :b)) :c)}") + testParse("a && b==c || d", "{(::or (::and :a (::equal :b :c)) :d)}") + testParse("a && b!=c || d", "{(::or (::and :a (::unequal :b :c)) :d)}") + testParse("a && !(b==c) || d", "{(::or (::and :a (::not (::equal :b :c))) :d)}") + testParse("a && b>=c || d", "{(::or (::and :a (::largerEq :b :c)) :d)}") + testParse("a && !(b>=c) || d", "{(::or (::and :a (::not (::largerEq :b :c))) :d)}") + testParse("a && b<=c || d", "{(::or (::and :a (::smallerEq :b :c)) :d)}") + testParse("a && b>c || d", "{(::or (::and :a (::larger :b :c)) :d)}") + testParse("a && b { + testParse("1 -> add(2)", "{(::add 1 2)}") + testParse("-1 -> add(2)", "{(::add (::unaryMinus 1) 2)}") + testParse("-a[1] -> add(2)", "{(::add (::unaryMinus (::$_atIndex_$ :a 1)) 2)}") + testParse("-f(1) -> add(2)", "{(::add (::unaryMinus (::f 1)) 2)}") + testParse("1 + 2 -> add(3)", "{(::add 1 (::add 2 3))}") + testParse("1 -> add(2) * 3", "{(::multiply (::add 1 2) 3)}") + testParse("1 -> subtract(2)", "{(::subtract 1 2)}") + testParse("-1 -> subtract(2)", "{(::subtract (::unaryMinus 1) 2)}") + testParse("1 -> subtract(2) * 3", "{(::multiply (::subtract 1 2) 3)}") + }) + + describe("elixir pipe", () => { + //handled together with -> so there is no need for seperate tests + testParse("1 |> add(2)", "{(::add 1 2)}") + }) + + describe("to", () => { + testParse("1 to 2", "{(::credibleIntervalToDistribution 1 2)}") + testParse("-1 to -2", "{(::credibleIntervalToDistribution (::unaryMinus 1) (::unaryMinus 2))}") // lower than unary + testParse( + "a[1] to a[2]", + "{(::credibleIntervalToDistribution (::$_atIndex_$ :a 1) (::$_atIndex_$ :a 2))}", + ) // lower than post + testParse( + "a.p1 to a.p2", + "{(::credibleIntervalToDistribution (::$_atIndex_$ :a 'p1') (::$_atIndex_$ :a 'p2'))}", + ) // lower than post + testParse("1 to 2 + 3", "{(::add (::credibleIntervalToDistribution 1 2) 3)}") // higher than binary operators + testParse( + "1->add(2) to 3->add(4) -> add(4)", + "{(::credibleIntervalToDistribution (::add 1 2) (::add (::add 3 4) 4))}", + ) // lower than chain + }) + + describe("inner block", () => { + // inner blocks are 0 argument lambdas. They can be used whenever a value is required. + // Like lambdas they have a local scope. + testParse("x={y=1; y}; x", "{:x = {:y = {1}; :y}; :x}") + }) + + describe("lambda", () => { + testParse("{|x| x}", "{{|:x| {:x}}}") + testParse("f={|x| x}", "{:f = {{|:x| {:x}}}}") + testParse("f(x)=x", "{:f = {|:x| {:x}}}") // Function definitions are lambda assignments + testParse("f(x)=x ? 1 : 0", "{:f = {|:x| {(::$$_ternary_$$ :x 1 0)}}}") // Function definitions are lambda assignments + }) + + describe("Using lambda as value", () => { + testParse( + "myadd(x,y)=x+y; z=myadd; 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("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( + "[1,2,3]->map({|x| x+1})", + "{(::map (::$_constructArray_$ (1 2 3)) {|:x| {(::add :x 1)}})}", + ) + }) +}) + +describe("parsing new line", () => { + testParse( + ` + a + + b`, + "{(::add :a :b)}", + ) + testParse( + ` + x= + 1`, + "{:x = {1}}", + ) + testParse( + ` + x=1 + y=2`, + "{:x = {1}; :y = {2}}", + ) + testParse( + ` + x={ + y=2; + y } + x`, + "{:x = {:y = {2}; :y}; :x}", + ) + testParse( + ` + x={ + y=2 + y } + x`, + "{:x = {:y = {2}; :y}; :x}", + ) + testParse( + ` + x={ + y=2 + y + } + x`, + "{:x = {:y = {2}; :y}; :x}", + ) + testParse( + ` + x=1 + y=2 + z=3 + `, + "{:x = {1}; :y = {2}; :z = {3}}", + ) + testParse( + ` + f={ + x=1 + y=2 + z=3 + x+y+z + } + `, + "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}}", + ) + testParse( + ` + f={ + x=1 + y=2 + z=3 + x+y+z + } + g=f+4 + g + `, + "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; :g}", + ) + testParse( + ` + f = + { + x=1; //x + y=2 //y + z= + 3 + x+ + y+ + z + } + g = + f + + 4 + g -> + h -> + p -> + q + `, + "{:f = {:x = {1}; :y = {2}; :z = {3}; (::add (::add :x :y) :z)}; :g = {(::add :f 4)}; (::q (::p (::h :g)))}", + ) + testParse( + ` + a |> + b |> + c |> + d + `, + "{(::d (::c (::b :a)))}", + ) + testParse( + ` + a |> + b |> + c |> + d + + e + `, + "{(::add (::d (::c (::b :a))) :e)}", + ) +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res new file mode 100644 index 00000000..81bafd97 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res @@ -0,0 +1,220 @@ +module Expression = Reducer_Expression +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface_ExpressionValue +module Parse = Reducer_Peggy_Parse +module ToExpression = Reducer_Peggy_ToExpression +module Result = Belt.Result + +open Jest +open Expect + +let expectToExpressionToBe = (expr, answer, ~v="_", ()) => { + let rExpr = Parse.parse(expr)->Result.map(ToExpression.fromNode) + let a1 = rExpr->ExpressionT.toStringResultOkless + if v == "_" { + a1->expect->toBe(answer) + } else { + let a2 = + rExpr + ->Result.flatMap(expr => + Expression.reduceExpression(expr, Belt.Map.String.empty, ExpressionValue.defaultEnvironment) + ) + ->ExpressionValue.toStringResultOkless + (a1, a2)->expect->toEqual((answer, v)) + } +} + +let testToExpression = (expr, answer, ~v="_", ()) => + test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) + +module MySkip = { + let testToExpression = (expr, answer, ~v="_", ()) => + Skip.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) +} + +module MyOnly = { + let testToExpression = (expr, answer, ~v="_", ()) => + Only.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) +} + +describe("Peggy to Expression", () => { + describe("literals operators parenthesis", () => { + // Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement + testToExpression("1", "(:$$_block_$$ 1)", ~v="1", ()) + testToExpression("'hello'", "(:$$_block_$$ 'hello')", ~v="'hello'", ()) + testToExpression("true", "(:$$_block_$$ true)", ~v="true", ()) + testToExpression("1+2", "(:$$_block_$$ (:add 1 2))", ~v="3", ()) + testToExpression("add(1,2)", "(:$$_block_$$ (:add 1 2))", ~v="3", ()) + testToExpression("(1)", "(:$$_block_$$ 1)", ()) + testToExpression("(1+2)", "(:$$_block_$$ (:add 1 2))", ()) + }) + + describe("unary", () => { + testToExpression("-1", "(:$$_block_$$ (:unaryMinus 1))", ~v="-1", ()) + testToExpression("!true", "(:$$_block_$$ (:not true))", ~v="false", ()) + testToExpression("1 + -1", "(:$$_block_$$ (:add 1 (:unaryMinus 1)))", ~v="0", ()) + testToExpression("-a[0]", "(:$$_block_$$ (:unaryMinus (:$_atIndex_$ :a 0)))", ()) + }) + + describe("multi-line", () => { + 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}", + (), + ) + }) + + describe("variables", () => { + testToExpression("x = 1", "(:$$_block_$$ (:$_let_$ :x (:$$_block_$$ 1)))", ~v="{x: 1}", ()) + testToExpression("x", "(:$$_block_$$ :x)", ~v=":x", ()) //TODO: value should return error + testToExpression("x = 1; x", "(:$$_block_$$ (:$_let_$ :x (:$$_block_$$ 1)) :x)", ~v="1", ()) + }) + + 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)", "(:$$_block_$$ (:identity :x))", ()) // Note value returns error properly + testToExpression( + "f(x) = x> 2 ? 0 : 1; f(3)", + "(:$$_block_$$ (:$_let_$ :f (:$$_lambda_$$ [x] (:$$_block_$$ (:$$_ternary_$$ (:larger :x 2) 0 1)))) (:f 3))", + ~v="0", + (), + ) + }) + + describe("arrays", () => { + testToExpression("[]", "(:$$_block_$$ (:$_constructArray_$ ()))", ~v="[]", ()) + testToExpression("[0, 1, 2]", "(:$$_block_$$ (:$_constructArray_$ (0 1 2)))", ~v="[0,1,2]", ()) + testToExpression( + "['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", () => { + testToExpression( + "{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: 1}; record.property", + "(:$$_block_$$ (:$_let_$ :record (:$$_block_$$ (:$_constructRecord_$ (('property' 1))))) (:$_atIndex_$ :record 'property'))", + ~v="1", + (), + ) + }) + + describe("comments", () => { + testToExpression("1 # This is a line comment", "(:$$_block_$$ 1)", ~v="1", ()) + testToExpression("1 // This is a line comment", "(:$$_block_$$ 1)", ~v="1", ()) + testToExpression("1 /* This is a multi line comment */", "(:$$_block_$$ 1)", ~v="1", ()) + testToExpression("/* This is a multi line comment */ 1", "(:$$_block_$$ 1)", ~v="1", ()) + }) + + describe("ternary operator", () => { + testToExpression("true ? 1 : 0", "(:$$_block_$$ (:$$_ternary_$$ true 1 0))", ~v="1", ()) + 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( + "false ? 1 : false ? 2 : 0", + "(:$$_block_$$ (:$$_ternary_$$ false 1 (:$$_ternary_$$ false 2 0)))", + ~v="0", + (), + ) // nested ternary + }) + + describe("if then else", () => { + testToExpression( + "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( + "if false then {2} else if false then {4} else {5}", + "(:$$_block_$$ (:$$_ternary_$$ false (:$$_block_$$ 2) (:$$_ternary_$$ false (:$$_block_$$ 4) (:$$_block_$$ 5))))", + (), + ) //nested if + }) + + describe("pipe", () => { + testToExpression("1 -> add(2)", "(:$$_block_$$ (:add 1 2))", ~v="3", ()) + testToExpression("-1 -> add(2)", "(:$$_block_$$ (:add (:unaryMinus 1) 2))", ~v="1", ()) // note that unary has higher priority naturally + testToExpression("1 -> add(2) * 3", "(:$$_block_$$ (:multiply (:add 1 2) 3))", ~v="9", ()) + }) + + describe("elixir pipe", () => { + testToExpression("1 |> add(2)", "(:$$_block_$$ (:add 1 2))", ~v="3", ()) + }) + + // see testParse for priorities of to and credibleIntervalToDistribution + + describe("inner block", () => { + // inner blocks are 0 argument lambdas. They can be used whenever a value is required. + // Like lambdas they have a local scope. + 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", () => { + testToExpression( + "{|x| x}", + "(:$$_block_$$ (:$$_lambda_$$ [x] (:$$_block_$$ :x)))", + ~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)}", + (), + ) + }) +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index 766acd43..6ec9930c 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -19,6 +19,9 @@ let expectParseToBe = (expr: string, answer: string) => let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) +let expectEvalError = (expr: string) => + Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toMatch("Error\(") + let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None) ->ExpressionValue.toStringResult @@ -29,6 +32,7 @@ let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, ans let testDescriptionParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) +let testEvalError = expr => test(expr, () => expectEvalError(expr)) let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) let testEvalBindingsToBe = (expr, bindingsList, answer) => diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res index 3a903343..c47879b3 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res @@ -2,62 +2,10 @@ open Jest open Reducer_TestHelpers -// describe("Parse for Bindings", () => { -// testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))") -// testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))") -// testParseOuterToBe( -// "y = x+1; y", -// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))", -// ) -// }) - -// describe("Parse Partial", () => { -// testParsePartialToBe( -// "x", -// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))", -// ) -// testParsePartialToBe( -// "y=x", -// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))", -// ) -// testParsePartialToBe( -// "y=x+1", -// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))", -// ) -// testParsePartialToBe( -// "y = x+1; z = y", -// "Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))", -// ) -// }) - describe("Eval with Bindings", () => { testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)") testEvalBindingsToBe("x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)") - testParseToBe("y = x+1; y", "Ok((:$$block (:$$block (:$let :y (:add :x 1)) :y)))") + testParseToBe("y = x+1; y", "Ok((:$$_block_$$ (:$_let_$ :y (:$$_block_$$ (:add :x 1))) :y))") 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})") }) - -/* - Partial code is a partial code fragment that is cut out from a larger code. - Therefore it does not end with an expression. -*/ -// describe("Eval Partial", () => { -// testEvalPartialBindingsToBe( -// // A partial cannot end with an expression -// "x", -// list{("x", ExpressionValue.EvNumber(1.))}, -// "Error(Assignment expected)", -// ) -// testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 1})") -// testEvalPartialBindingsToBe( -// "y=x+1", -// list{("x", ExpressionValue.EvNumber(1.))}, -// "Ok({x: 1,y: 2})", -// ) -// testEvalPartialBindingsToBe( -// "y = x+1; z = y", -// list{("x", ExpressionValue.EvNumber(1.))}, -// "Ok({x: 1,y: 2,z: 2})", -// ) -// }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res index bb3e2220..0f280265 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res @@ -2,8 +2,11 @@ open Jest open Reducer_TestHelpers describe("Parse function assignment", () => { - testParseToBe("f(x)=x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block :x)))))") - testParseToBe("f(x)=2*x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block (:multiply 2 :x))))))") + testParseToBe("f(x)=x", "Ok((:$$_block_$$ (:$_let_$ :f (:$$_lambda_$$ [x] (:$$_block_$$ :x)))))") + testParseToBe( + "f(x)=2*x", + "Ok((:$$_block_$$ (:$_let_$ :f (:$$_lambda_$$ [x] (:$$_block_$$ (:multiply 2 :x))))))", + ) //MathJs does not allow blocks in function definitions }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index d9f7e7c8..fd7485eb 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -25,7 +25,7 @@ describe("Arity check", () => { ) testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))") testEvalToBe( - "f(x,y)=x(y); f(z)", + "f(x,y)=x(y); f(1)", "Error(2 arguments expected. Instead 1 argument(s) were passed.)", ) }) @@ -51,7 +51,7 @@ describe("call and bindings", () => { ) testParseToBe( "f=99; g(x)=f; g(2)", - "Ok((:$$block (:$$block (:$let :f 99) (:$let :g (:$$lambda [x] (:$$block :f))) (:g 2))))", + "Ok((:$$_block_$$ (:$_let_$ :f (:$$_block_$$ 99)) (:$_let_$ :g (:$$_lambda_$$ [x] (:$$_block_$$ :f))) (:g 2)))", ) testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)") testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)") @@ -63,15 +63,28 @@ describe("call and bindings", () => { }) describe("function tricks", () => { - testParseToBe( - "f(x)=f(y)=2; f(2)", - "Ok((:$$block (:$$block (:$let :f (:$$lambda [x] (:$$block (:$let :f (:$$lambda [y] (:$$block 2)))))) (:f 2))))", - ) - testEvalToBe("f(x)=f(y)=2; f(2)", "Ok({f: lambda(y=>internal code),x: 2})") + testEvalError("f(x)=f(y)=2; f(2)") //Error because chain assignment is not allowed testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") 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("myadd(x,y)=x+y; z=[add]; z[0](3,2)", "????") //TODO: to fix with new parser - MySkip.testEvalToBe("myaddd(x,y)=x+y; z={x: add}; z.x(3,2)", "????") //TODO: to fix with new parser + 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)") +}) + +describe("lambda in structures", () => { + testEvalToBe( + "myadd(x,y)=x+y; z=[myadd]", + "Ok({myadd: lambda(x,y=>internal code),z: [lambda(x,y=>internal code)]})", + ) + testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0]", "Ok(lambda(x,y=>internal code))") + testEvalToBe("myadd(x,y)=x+y; z=[myadd]; z[0](3,2)", "Ok(5)") + testEvalToBe("myaddd(x,y)=x+y; z={x: myaddd}; z", "Ok({x: lambda(x,y=>internal code)})") + 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", () => { + testEvalToBe("f(x)=x ? 1 : 0; f(true)", "Ok(1)") + testEvalToBe("f(x)=x>2 ? 1 : 0; f(3)", "Ok(1)") }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res index c0311450..57b44156 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res @@ -2,7 +2,7 @@ open Jest open Reducer_TestHelpers describe("Parse ternary operator", () => { - testParseToBe("true ? 'YES' : 'NO'", "Ok((:$$block (:$$ternary true 'YES' 'NO')))") + testParseToBe("true ? 'YES' : 'NO'", "Ok((:$$_block_$$ (:$$_ternary_$$ true 'YES' 'NO')))") }) describe("Evaluate ternary operator", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 80468c0f..32aad5d3 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,55 +1,9 @@ open Jest open Reducer_TestHelpers -describe("reducer using mathjs parse", () => { - // Test the MathJs parser compatibility - // Those tests toString that there is a semantic mapping from MathJs to Expression - // Reducer.parse is called by Reducer.eval - // See https://mathjs.org/docs/expressions/syntax.html - // See https://mathjs.org/docs/reference/functions.html - // Those tests toString that we are converting mathjs parse tree to what we need - - describe("expressions", () => { - testParseToBe("1", "Ok((:$$block 1))") - testParseToBe("(1)", "Ok((:$$block 1))") - testParseToBe("1+2", "Ok((:$$block (:add 1 2)))") - testParseToBe("1+2*3", "Ok((:$$block (:add 1 (:multiply 2 3))))") - }) - describe("arrays", () => { - //Note. () is a empty list in Lisp - // The only builtin structure in Lisp is list. There are no arrays - // [1,2,3] becomes (1 2 3) - testDescriptionParseToBe("empty", "[]", "Ok((:$$block ()))") - testParseToBe("[1, 2, 3]", "Ok((:$$block (1 2 3)))") - testParseToBe("['hello', 'world']", "Ok((:$$block ('hello' 'world')))") - testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$$block (:$atIndex (0 1 2) (1))))") - }) - describe("records", () => { - testDescriptionParseToBe( - "define", - "{a: 1, b: 2}", - "Ok((:$$block (:$constructRecord (('a' 1) ('b' 2)))))", - ) - testDescriptionParseToBe( - "use", - "{a: 1, b: 2}.a", - "Ok((:$$block (:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a'))))", - ) - }) - describe("multi-line", () => { - testParseToBe("1; 2", "Ok((:$$block (:$$block 1 2)))") - testParseToBe("1+1; 2+1", "Ok((:$$block (:$$block (:add 1 1) (:add 2 1))))") - }) - describe("assignment", () => { - testParseToBe("x=1; x", "Ok((:$$block (:$$block (:$let :x 1) :x)))") - testParseToBe("x=1+1; x+1", "Ok((:$$block (:$$block (:$let :x (:add 1 1)) (:add :x 1))))") - }) -}) - describe("eval", () => { // All MathJs operators and functions are builtin for string, float and boolean // .e.g + - / * > >= < <= == /= not and or - // See https://mathjs.org/docs/expressions/syntax.html // See https://mathjs.org/docs/reference/functions.html describe("expressions", () => { testEvalToBe("1", "Ok(1)") @@ -70,20 +24,21 @@ describe("eval", () => { }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1,b: 2})")) - test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)")) - test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)")) + test("index", () => expectEvalToBe("r = {a: 1}; r.a", "Ok(1)")) + test("index", () => expectEvalToBe("r = {a: 1}; r.b", "Error(Record property not found: b)")) + testEvalError("{a: 1}.b") // invalid syntax }) describe("multi-line", () => { - testEvalToBe("1; 2", "Error(Assignment expected)") - testEvalToBe("1+1; 2+1", "Error(Assignment expected)") + testEvalError("1; 2") + testEvalError("1+1; 2+1") }) describe("assignment", () => { testEvalToBe("x=1; x", "Ok(1)") testEvalToBe("x=1+1; x+1", "Ok(3)") testEvalToBe("x=1; y=x+1; y+1", "Ok(3)") - testEvalToBe("1; x=1", "Error(Assignment expected)") - testEvalToBe("1; 1", "Error(Assignment expected)") + testEvalError("1; x=1") + testEvalError("1; 1") testEvalToBe("x=1; x=1", "Ok({x: 1})") }) }) @@ -94,9 +49,9 @@ describe("test exceptions", () => { "javascriptraise('div by 0')", "Error(JS Exception: Error: 'div by 0')", ) - testDescriptionEvalToBe( - "rescript exception", - "rescriptraise()", - "Error(TODO: unhandled rescript exception)", - ) + // testDescriptionEvalToBe( + // "rescript exception", + // "rescriptraise()", + // "Error(TODO: unhandled rescript exception)", + // ) }) diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 48bdcaa5..bc95f160 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -123,34 +123,37 @@ describe("eval on distribution functions", () => { describe("parse on distribution functions", () => { describe("power", () => { - testParse("normal(5,2) ^ normal(5,1)", "Ok((:$$block (:pow (:normal 5 2) (:normal 5 1))))") - testParse("3 ^ normal(5,1)", "Ok((:$$block (:pow 3 (:normal 5 1))))") - testParse("normal(5,2) ^ 3", "Ok((:$$block (:pow (:normal 5 2) 3)))") + testParse("normal(5,2) ^ normal(5,1)", "Ok((:$$_block_$$ (:pow (:normal 5 2) (:normal 5 1))))") + testParse("3 ^ normal(5,1)", "Ok((:$$_block_$$ (:pow 3 (:normal 5 1))))") + testParse("normal(5,2) ^ 3", "Ok((:$$_block_$$ (:pow (:normal 5 2) 3)))") }) describe("subtraction", () => { - testParse("10 - normal(5,1)", "Ok((:$$block (:subtract 10 (:normal 5 1))))") - testParse("normal(5,1) - 10", "Ok((:$$block (:subtract (:normal 5 1) 10)))") + testParse("10 - normal(5,1)", "Ok((:$$_block_$$ (:subtract 10 (:normal 5 1))))") + testParse("normal(5,1) - 10", "Ok((:$$_block_$$ (:subtract (:normal 5 1) 10)))") }) describe("pointwise arithmetic expressions", () => { testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))") testParse( ~skip=true, "normal(5,2) .- normal(5,1)", - "Ok((:$$block (:dotSubtract (:normal 5 2) (:normal 5 1))))", - // TODO: !!! returns "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))" + "Ok((:$$_block_$$ (:dotSubtract (:normal 5 2) (:normal 5 1))))", + // TODO: !!! returns "Ok((:$$_block_$$ (:dotPow (:normal 5 2) (:normal 5 1))))" ) testParse( "normal(5,2) .* normal(5,1)", - "Ok((:$$block (:dotMultiply (:normal 5 2) (:normal 5 1))))", + "Ok((:$$_block_$$ (:dotMultiply (:normal 5 2) (:normal 5 1))))", ) testParse( "normal(5,2) ./ normal(5,1)", - "Ok((:$$block (:dotDivide (:normal 5 2) (:normal 5 1))))", + "Ok((:$$_block_$$ (:dotDivide (:normal 5 2) (:normal 5 1))))", + ) + testParse( + "normal(5,2) .^ normal(5,1)", + "Ok((:$$_block_$$ (:dotPow (:normal 5 2) (:normal 5 1))))", ) - testParse("normal(5,2) .^ normal(5,1)", "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))") }) describe("equality", () => { - testParse("5 == normal(5,2)", "Ok((:$$block (:equal 5 (:normal 5 2))))") + testParse("5 == normal(5,2)", "Ok((:$$_block_$$ (:equal 5 (:normal 5 2))))") }) describe("pointwise adding two normals", () => { testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))") diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 579a5f31..bf76709a 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -4,6 +4,8 @@ "homepage": "https://squiggle-language.com", "license": "MIT", "scripts": { + "peggy": "peggy --cache ", + "build:peggy": "find . -type f -name *.peggy -exec yarn run peggy {} \\;", "build": "yarn build:rescript && yarn build:typescript", "build:rescript": "rescript build -with-deps", "build:typescript": "tsc", @@ -54,6 +56,7 @@ "lodash": "^4.17.21", "moduleserve": "^0.9.1", "nyc": "^15.1.0", + "peggy": "^1.2.0", "reanalyze": "^2.19.0", "rescript-fast-check": "^1.1.1", "ts-jest": "^27.1.4", diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res index cd16e1fe..141b4a37 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res @@ -13,6 +13,8 @@ open Reducer_ErrorValue DO NOT try to add external function mapping here! */ +//TODO: pow to xor + exception TestRescriptException let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< @@ -128,12 +130,12 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce } switch call { - | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => - arrayAtIndex(aValueArray, fIndex) - | ("$atIndex", [EvRecord(dict), EvArray([EvString(sIndex)])]) => recordAtIndex(dict, sIndex) - | ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) - | ("$exportBindings", [EvRecord(externalBindings)]) => doExportBindings(externalBindings) - | ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) => + | ("$_atIndex_$", [EvArray(aValueArray), EvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex) + | ("$_atIndex_$", [EvRecord(dict), EvString(sIndex)]) => recordAtIndex(dict, sIndex) + | ("$_constructArray_$", [EvArray(aValueArray)]) => EvArray(aValueArray)->Ok + | ("$_constructRecord_$", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) + | ("$_exportBindings_$", [EvRecord(externalBindings)]) => doExportBindings(externalBindings) + | ("$_setBindings_$", [EvRecord(externalBindings), EvSymbol(symbol), value]) => doSetBindings(externalBindings, symbol, value) | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) | ("inspect", [value]) => inspect(value) @@ -147,7 +149,15 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce | ("reduceReverse", [EvArray(aValueArray), initialValue, EvLambda(aLambdaValue)]) => doReduceReverseArray(aValueArray, initialValue, aLambdaValue) | ("reverse", [EvArray(aValueArray)]) => aValueArray->Belt.Array.reverse->EvArray->Ok - | call => callMathJs(call) + | (_, [EvBool(_)]) + | (_, [EvNumber(_)]) + | (_, [EvString(_)]) + | (_, [EvBool(_), EvBool(_)]) + | (_, [EvNumber(_), EvNumber(_)]) + | (_, [EvString(_), EvString(_)]) => + callMathJs(call) + | call => + Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) // Report full type signature as error } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index a771dd32..1fba533f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -4,6 +4,7 @@ Macros are used to define language building blocks. They are like Lisp macros. */ module Bindings = Reducer_Expression_Bindings +module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue module ExpressionWithContext = Reducer_ExpressionWithContext @@ -24,7 +25,7 @@ let dispatchMacroCall = ( ): result => { let doBindStatement = (bindingExpr: expression, statement: expression, environment) => switch statement { - | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { + | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$_let_$")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) rExternalBindingsValue->Result.flatMap(externalBindingsValue => { @@ -33,7 +34,7 @@ let dispatchMacroCall = ( // Js.log( // `bindStatement ${Bindings.toString(newBindings)}<==${ExpressionT.toString( // bindingExpr, - // )} statement: $let ${ExpressionT.toString(symbolExpr)}=${ExpressionT.toString( + // )} statement: $_let_$ ${ExpressionT.toString(symbolExpr)}=${ExpressionT.toString( // statement, // )}`, // ) @@ -42,7 +43,7 @@ let dispatchMacroCall = ( rNewStatement->Result.map(newStatement => ExpressionWithContext.withContext( eFunction( - "$setBindings", + "$_setBindings_$", list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, ), newBindings, @@ -58,7 +59,7 @@ let dispatchMacroCall = ( errorValue, > => switch statement { - | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { + | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$_let_$")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) rExternalBindingsValue->Result.flatMap(externalBindingsValue => { @@ -67,10 +68,10 @@ let dispatchMacroCall = ( rNewStatement->Result.map(newStatement => ExpressionWithContext.withContext( eFunction( - "$exportBindings", + "$_exportBindings_$", list{ eFunction( - "$setBindings", + "$_setBindings_$", list{ newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, @@ -139,7 +140,8 @@ let dispatchMacroCall = ( bindings: ExpressionT.bindings, environment, ): result => { - let rCondition = reduceExpression(condition, bindings, environment) + let blockCondition = ExpressionBuilder.eBlock(list{condition}) + let rCondition = reduceExpression(blockCondition, bindings, environment) rCondition->Result.flatMap(conditionValue => switch conditionValue { | ExpressionValue.EvBool(false) => ExpressionWithContext.noContext(ifFalse)->Ok @@ -155,31 +157,32 @@ let dispatchMacroCall = ( > => switch aList { | list{ - ExpressionT.EValue(EvCall("$$bindStatement")), + ExpressionT.EValue(EvCall("$$_bindStatement_$$")), bindingExpr: ExpressionT.expression, statement, } => doBindStatement(bindingExpr, statement, environment) - | list{ExpressionT.EValue(EvCall("$$bindStatement")), statement} => + | list{ExpressionT.EValue(EvCall("$$_bindStatement_$$")), statement} => // bindings of the context are used when there is no binding expression doBindStatement(eRecord(Bindings.toExternalBindings(bindings)), statement, environment) | list{ - ExpressionT.EValue(EvCall("$$bindExpression")), + ExpressionT.EValue(EvCall("$$_bindExpression_$$")), bindingExpr: ExpressionT.expression, expression, } => doBindExpression(bindingExpr, expression, environment) - | list{ExpressionT.EValue(EvCall("$$bindExpression")), expression} => + | list{ExpressionT.EValue(EvCall("$$_bindExpression_$$")), expression} => // bindings of the context are used when there is no binding expression doBindExpression(eRecord(Bindings.toExternalBindings(bindings)), expression, environment) - | list{ExpressionT.EValue(EvCall("$$block")), ...exprs} => doBlock(exprs, bindings, environment) + | list{ExpressionT.EValue(EvCall("$$_block_$$")), ...exprs} => + doBlock(exprs, bindings, environment) | list{ - ExpressionT.EValue(EvCall("$$lambda")), + ExpressionT.EValue(EvCall("$$_lambda_$$")), ExpressionT.EValue(EvArrayString(parameters)), lambdaDefinition, } => doLambdaDefinition(bindings, parameters, lambdaDefinition) - | list{ExpressionT.EValue(EvCall("$$ternary")), condition, ifTrue, ifFalse} => + | list{ExpressionT.EValue(EvCall("$$_ternary_$$")), condition, ifTrue, ifFalse} => doTernary(condition, ifTrue, ifFalse, bindings, environment) | _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index d36ca5c4..fc2f86f1 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -7,6 +7,7 @@ type errorValue = | REOperationError(Operation.operationError) | REExpressionExpected | REFunctionExpected(string) + | REFunctionNotFound(string) | REJavaScriptExn(option, option) // Javascript Exception | REMacroNotFound(string) | RENotAFunction(string) @@ -29,6 +30,7 @@ let errorToString = err => | REAssignmentExpected => "Assignment expected" | REExpressionExpected => "Expression expected" | REFunctionExpected(msg) => `Function expected: ${msg}` + | REFunctionNotFound(msg) => `Function not found: ${msg}` | REDistributionError(err) => `Distribution Math Error: ${DistributionTypes.Error.toString(err)}` | REOperationError(err) => `Math Error: ${Operation.Error.toString(err)}` | REJavaScriptExn(omsg, oname) => { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 81830e84..64faa43b 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -18,13 +18,10 @@ type internalCode = ReducerInterface_ExpressionValue.internalCode type t = expression /* - Converts a MathJs code to expression + Converts a Squigle code to expression */ -let parse_ = (expr: string, parser, converter): result => - expr->parser->Result.flatMap(node => converter(node)) - -let parse = (mathJsCode: string): result => - mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode) +let parse = (peggyCode: string): result => + peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode) /* Recursively evaluate/reduce the expression (Lisp AST) @@ -77,11 +74,30 @@ and reduceValueList = (valueList: list, environment): result< 'e, > => switch valueList { - | list{EvCall(fName), ...args} => - (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression) + | list{EvCall(fName), ...args} => { + let rCheckedArgs = switch fName == "$_setBindings_$" { + | false => args->Lambda.checkIfReduced + | true => args->Ok + } + rCheckedArgs->Result.flatMap(checkedArgs => + (fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression) + ) + } + | list{EvLambda(_)} => + // TODO: remove on solving issue#558 + valueList + ->Lambda.checkIfReduced + ->Result.flatMap(reducedValueList => + reducedValueList->Belt.List.toArray->ExpressionValue.EvArray->Ok + ) | list{EvLambda(lamdaCall), ...args} => - Lambda.doLambdaCall(lamdaCall, args, environment, reduceExpression) + args + ->Lambda.checkIfReduced + ->Result.flatMap(checkedArgs => + Lambda.doLambdaCall(lamdaCall, checkedArgs, environment, reduceExpression) + ) + | _ => valueList ->Lambda.checkIfReduced @@ -116,7 +132,7 @@ let evaluateUsingOptions = ( } /* - Evaluates MathJs code and bindings via Reducer and answers the result + Evaluates Squiggle code and bindings via Reducer and answers the result */ let evaluate = (code: string): result => { evaluateUsingOptions(~environment=None, ~externalBindings=None, code) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res index 7ccea9fc..cdf3425b 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -48,19 +48,19 @@ let eSymbol = (name: string): expression => name->BExpressionValue.EvSymbol->BEx let eList = (list: list): expression => list->BExpressionT.EList -let eBlock = (exprs: list): expression => eFunction("$$block", exprs) +let eBlock = (exprs: list): expression => eFunction("$$_block_$$", exprs) let eLetStatement = (symbol: string, valueExpression: expression): expression => - eFunction("$let", list{eSymbol(symbol), valueExpression}) + eFunction("$_let_$", list{eSymbol(symbol), valueExpression}) let eBindStatement = (bindingExpr: expression, letStatement: expression): expression => - eFunction("$$bindStatement", list{bindingExpr, letStatement}) + eFunction("$$_bindStatement_$$", list{bindingExpr, letStatement}) let eBindStatementDefault = (letStatement: expression): expression => - eFunction("$$bindStatement", list{letStatement}) + eFunction("$$_bindStatement_$$", list{letStatement}) let eBindExpression = (bindingExpr: expression, expression: expression): expression => - eFunction("$$bindExpression", list{bindingExpr, expression}) + eFunction("$$_bindExpression_$$", list{bindingExpr, expression}) let eBindExpressionDefault = (expression: expression): expression => - eFunction("$$bindExpression", list{expression}) + eFunction("$$_bindExpression_$$", list{expression}) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res index b21ba8b7..65ba4c96 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res @@ -42,6 +42,12 @@ let toStringResult = codeResult => | Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})` } +let toStringResultOkless = codeResult => + switch codeResult { + | Ok(a) => toString(a) + | Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})` + } + let inspect = (expr: expression): expression => { Js.log(toString(expr)) expr diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs.res index 38033109..640f010a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs.res @@ -1,3 +1 @@ module Eval = Reducer_MathJs_Eval -module Parse = Reducer_MathJs_Parse -module ToExpression = Reducer_MathJs_ToExpression diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res deleted file mode 100644 index 704d1d38..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ /dev/null @@ -1,182 +0,0 @@ -/* - MathJs Nodes - We make MathJs Nodes strong-typed -*/ -module Extra = Reducer_Extra -open Reducer_ErrorValue - -type node = {"type": string, "isNode": bool, "comment": string} -type arrayNode = {...node, "items": array} -type block = {"node": node} -type blockNode = {...node, "blocks": array} -type conditionalNode = {...node, "condition": node, "trueExpr": node, "falseExpr": node} -type constantNode = {...node, "value": unit} -type functionAssignmentNode = {...node, "name": string, "params": array, "expr": node} -type indexNode = {...node, "dimensions": array} -type objectNode = {...node, "properties": Js.Dict.t} -type accessorNode = {...node, "object": node, "index": indexNode, "name": string} -type parenthesisNode = {...node, "content": node} -//rangeNode -//relationalNode -type symbolNode = {...node, "name": string} -type functionNode = {...node, "fn": unit, "args": array} -type operatorNode = {...functionNode, "op": string} -type assignmentNode = {...node, "object": symbolNode, "value": node} -type assignmentNodeWAccessor = {...node, "object": accessorNode, "value": node} -type assignmentNodeWIndex = {...assignmentNodeWAccessor, "index": Js.null} - -external castAccessorNode: node => accessorNode = "%identity" -external castArrayNode: node => arrayNode = "%identity" -external castAssignmentNode: node => assignmentNode = "%identity" -external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" -external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" -external castBlockNode: node => blockNode = "%identity" -external castConditionalNode: node => conditionalNode = "%identity" -external castConstantNode: node => constantNode = "%identity" -external castFunctionAssignmentNode: node => functionAssignmentNode = "%identity" -external castFunctionNode: node => functionNode = "%identity" -external castIndexNode: node => indexNode = "%identity" -external castObjectNode: node => objectNode = "%identity" -external castOperatorNode: node => operatorNode = "%identity" -external castOperatorNodeToFunctionNode: operatorNode => functionNode = "%identity" -external castParenthesisNode: node => parenthesisNode = "%identity" -external castSymbolNode: node => symbolNode = "%identity" - -/* - MathJs Parser -*/ -@module("mathjs") external parse__: string => node = "parse" - -let parse = (expr: string): result => - try { - Ok(parse__(expr)) - } catch { - | Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error - } - -type mathJsNode = - | MjAccessorNode(accessorNode) - | MjArrayNode(arrayNode) - | MjAssignmentNode(assignmentNode) - | MjBlockNode(blockNode) - | MjConditionalNode(conditionalNode) - | MjConstantNode(constantNode) - | MjFunctionAssignmentNode(functionAssignmentNode) - | MjFunctionNode(functionNode) - | MjIndexNode(indexNode) - | MjObjectNode(objectNode) - | MjOperatorNode(operatorNode) - | MjParenthesisNode(parenthesisNode) - | MjSymbolNode(symbolNode) - -let castNodeType = (node: node) => { - let decideAssignmentNode = node => { - let iNode = node->castAssignmentNodeWIndex - if Js.null == iNode["index"] && iNode["object"]["type"] == "SymbolNode" { - node->castAssignmentNode->MjAssignmentNode->Ok - } else { - RESyntaxError("Assignment to index or property not supported")->Error - } - } - - switch node["type"] { - | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok - | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok - | "AssignmentNode" => node->decideAssignmentNode - | "BlockNode" => node->castBlockNode->MjBlockNode->Ok - | "ConditionalNode" => node->castConditionalNode->MjConditionalNode->Ok - | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok - | "FunctionAssignmentNode" => node->castFunctionAssignmentNode->MjFunctionAssignmentNode->Ok - | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok - | "IndexNode" => node->castIndexNode->MjIndexNode->Ok - | "ObjectNode" => node->castObjectNode->MjObjectNode->Ok - | "OperatorNode" => node->castOperatorNode->MjOperatorNode->Ok - | "ParenthesisNode" => node->castParenthesisNode->MjParenthesisNode->Ok - | "SymbolNode" => node->castSymbolNode->MjSymbolNode->Ok - | _ => RETodo(`Argg, unhandled MathJsNode: ${node["type"]}`)->Error - } -} - -external unitAsSymbolNode: unit => symbolNode = "%identity" -external unitAsString: unit => string = "%identity" - -let nameOfFunctionNode = (fNode: functionNode): string => { - let name = fNode["fn"] - if Js.typeof(name) == "string" { - name->unitAsString - } else { - (name->unitAsSymbolNode)["name"] - } -} - -let rec toString = (mathJsNode: mathJsNode): string => { - let toStringValue = (a: 'a): string => - if Js.typeof(a) == "string" { - `'${Js.String.make(a)}'` - } else { - Js.String.make(a) - } - - let toStringNodeArray = (nodeArray: array): string => - nodeArray - ->Belt.Array.map(a => toStringMathJsNode(a)) - ->Extra.Array.interperse(", ") - ->Js.String.concatMany("") - - let toStringFunctionAssignmentNode = (faNode: functionAssignmentNode): string => { - let paramNames = Js.Array2.toString(faNode["params"]) - `${faNode["name"]} = (${paramNames}) => ${toStringMathJsNode(faNode["expr"])}` - } - let toStringFunctionNode = (fnode: functionNode): string => - `${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})` - - let toStringObjectEntry = ((key: string, value: node)): string => - `${key}: ${value->toStringMathJsNode}` - - let toStringObjectNode = (oNode: objectNode): string => - `{${oNode["properties"] - ->Js.Dict.entries - ->Belt.Array.map(entry => entry->toStringObjectEntry) - ->Extra.Array.interperse(", ") - ->Js.String.concatMany("")}}` - - let toStringIndexNode = (iNode: indexNode): string => - iNode["dimensions"] - ->Belt.Array.map(each => toStringResult(each->castNodeType)) - ->Js.String.concatMany("") - - let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"] - - let toStringBlocks = (blocks: array): string => - blocks - ->Belt.Array.map(each => each["node"]->castNodeType->toStringResult) - ->Extra.Array.interperse("; ") - ->Js.String.concatMany("") - - switch mathJsNode { - | MjAccessorNode(aNode) => - `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` - | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]` - | MjAssignmentNode(aNode) => - `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` - | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}` - | MjConditionalNode(cNode) => - `ternary(${toStringMathJsNode(cNode["condition"])}, ${toStringMathJsNode( - cNode["trueExpr"], - )}, ${toStringMathJsNode(cNode["falseExpr"])})` - | MjConstantNode(cNode) => cNode["value"]->toStringValue - | MjFunctionAssignmentNode(faNode) => faNode->toStringFunctionAssignmentNode - | MjFunctionNode(fNode) => fNode->toStringFunctionNode - | MjIndexNode(iNode) => iNode->toStringIndexNode - | MjObjectNode(oNode) => oNode->toStringObjectNode - | MjOperatorNode(opNode) => opNode->castOperatorNodeToFunctionNode->toStringFunctionNode - | MjParenthesisNode(pNode) => `(${toStringMathJsNode(pNode["content"])})` - | MjSymbolNode(sNode) => sNode->toStringSymbolNode - } -} -and toStringResult = (rMathJsNode: result): string => - switch rMathJsNode { - | Error(e) => errorToString(e) - | Ok(mathJsNode) => toString(mathJsNode) - } -and toStringMathJsNode = node => node->castNodeType->toStringResult diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res deleted file mode 100644 index 6355de88..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res +++ /dev/null @@ -1,154 +0,0 @@ -/* * WARNING. DO NOT EDIT, BEAUTIFY, COMMENT ON OR REFACTOR THIS CODE. -We will stop using MathJs parser and -this whole file will go to trash -**/ -module ErrorValue = Reducer_ErrorValue -module ExpressionBuilder = Reducer_Expression_ExpressionBuilder -module ExpressionT = Reducer_Expression_T -module ExpressionValue = ReducerInterface.ExpressionValue -module JavaScript = Reducer_Js -module Parse = Reducer_MathJs_Parse -module Result = Belt.Result - -type errorValue = ErrorValue.errorValue -type expression = ExpressionT.expression -type expressionValue = ExpressionValue.expressionValue - -let blockToNode = block => block["node"] - -let rec fromInnerNode = (mathJsNode: Parse.node): result => - Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => { - let fromNodeList = (nodeList: list): result, 'e> => - Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) => - racc->Result.flatMap(acc => - fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc}) - ) - ) - - let caseFunctionNode = fNode => { - let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList - rLispArgs->Result.map(lispArgs => - ExpressionBuilder.eFunction(fNode->Parse.nameOfFunctionNode, lispArgs) - ) - } - - let caseObjectNode = oNode => { - let fromObjectEntries = entryList => { - let rargs = Belt.List.reduceReverse(entryList, Ok(list{}), ( - racc, - (key: string, value: Parse.node), - ) => - racc->Result.flatMap(acc => - fromInnerNode(value)->Result.map(valueExpression => { - let entryCode = - list{ExpressionBuilder.eString(key), valueExpression}->ExpressionT.EList - list{entryCode, ...acc} - }) - ) - ) - rargs->Result.flatMap(args => - ExpressionBuilder.eFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok - ) // $constructRecord gets a single argument: List of key-value paiers - } - - oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries - } - - let caseIndexNode = iNode => { - let rpropertyCodeList = Belt.List.reduceReverse( - iNode["dimensions"]->Belt.List.fromArray, - Ok(list{}), - (racc, currentPropertyMathJsNode) => - racc->Result.flatMap(acc => - fromInnerNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{ - propertyCode, - ...acc, - }) - ), - ) - rpropertyCodeList->Result.map(propertyCodeList => ExpressionT.EList(propertyCodeList)) - } - - let caseAccessorNode = (objectNode, indexNode) => { - caseIndexNode(indexNode)->Result.flatMap(indexCode => { - fromInnerNode(objectNode)->Result.flatMap(objectCode => - ExpressionBuilder.eFunction("$atIndex", list{objectCode, indexCode})->Ok - ) - }) - } - - let caseBlock = (nodesArray: array): result => { - let rStatements: result, 'a> = - nodesArray - ->Belt.List.fromArray - ->Belt.List.reduceReverse(Ok(list{}), (racc, currNode) => - racc->Result.flatMap(acc => - fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc}) - ) - ) - rStatements->Result.map(statements => ExpressionBuilder.eBlock(statements)) - } - - let caseAssignmentNode = aNode => { - let symbolName = aNode["object"]["name"] - let rValueExpression = fromInnerNode(aNode["value"]) - rValueExpression->Result.map(valueExpression => - ExpressionBuilder.eLetStatement(symbolName, valueExpression) - ) - } - - let caseFunctionAssignmentNode = faNode => { - let symbol = faNode["name"]->ExpressionBuilder.eSymbol - let rValueExpression = fromInnerNode(faNode["expr"]) - - rValueExpression->Result.flatMap(valueExpression => { - let lispParams = ExpressionBuilder.eArrayString(faNode["params"]) - let valueBlock = ExpressionBuilder.eBlock(list{valueExpression}) - let lambda = ExpressionBuilder.eFunction("$$lambda", list{lispParams, valueBlock}) - ExpressionBuilder.eFunction("$let", list{symbol, lambda})->Ok - }) - } - - let caseArrayNode = aNode => { - aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) - } - - let caseConditionalNode = cndNode => { - let rCondition = fromInnerNode(cndNode["condition"]) - let rTrueExpr = fromInnerNode(cndNode["trueExpr"]) - let rFalse = fromInnerNode(cndNode["falseExpr"]) - - rCondition->Result.flatMap(condition => - rTrueExpr->Result.flatMap(trueExpr => - rFalse->Result.flatMap(falseExpr => - ExpressionBuilder.eFunction("$$ternary", list{condition, trueExpr, falseExpr})->Ok - ) - ) - ) - } - - let rFinalExpression: result = switch typedMathJsNode { - | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) - | MjArrayNode(aNode) => caseArrayNode(aNode) - | MjAssignmentNode(aNode) => caseAssignmentNode(aNode) - | MjSymbolNode(sNode) => { - let expr: expression = ExpressionBuilder.eSymbol(sNode["name"]) - let rExpr: result = expr->Ok - rExpr - } - | MjBlockNode(bNode) => bNode["blocks"]->Js.Array2.map(blockToNode)->caseBlock - | MjConditionalNode(cndNode) => caseConditionalNode(cndNode) - | MjConstantNode(cNode) => - cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) - | MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode) - | MjFunctionNode(fNode) => fNode->caseFunctionNode - | MjIndexNode(iNode) => caseIndexNode(iNode) - | MjObjectNode(oNode) => caseObjectNode(oNode) - | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode - | MjParenthesisNode(pNode) => pNode["content"]->fromInnerNode - } - rFinalExpression - }) - -let fromNode = (node: Parse.node): result => - fromInnerNode(node)->Result.map(expr => ExpressionBuilder.eBlock(list{expr})) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js new file mode 100644 index 00000000..3a34dfb2 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js @@ -0,0 +1,5151 @@ +// Generated by Peggy 1.2.0. +// +// https://peggyjs.org/ + +"use strict"; + +var toFunction = { + "-": "subtract", + "->": "pipe", + "!=": "unequal", + ".-": "dotSubtract", + ".*": "dotMultiply", + "./": "dotDivide", + ".^": "dotPow", + ".+": "dotAdd", + "*": "multiply", + "/": "divide", + "&&": "and", + "^": "pow", // or xor + "+": "add", + "<": "smaller", + "<=": "smallerEq", + "==": "equal", + ">": "larger", + ">=": "largerEq", + "||": "or", + to: "credibleIntervalToDistribution", +}; + +var unaryToFunction = { + "-": "unaryMinus", + "!": "not", + ".-": "unaryDotMinus", +}; + +var postOperatorToFunction = { + ".": "$_atIndex_$", + "()": "$$_applyAll_$$", + "[]": "$_atIndex_$", +}; + +function nodeBlock(statements) { + return { type: "Block", statements: statements }; +} +function nodeBoolean(value) { + return { type: "Boolean", value: value }; +} +function nodeCallIndentifier(value) { + return { type: "CallIdentifier", value: value }; +} +function nodeExpression(args) { + return { type: "Expression", nodes: args }; +} +function nodeFloat(value) { + return { type: "Float", value: value }; +} +function makeFunctionCall(fn, args) { + if (fn === "$$_applyAll_$$") { + // Any list of values is applied from left to right anyway. + // Like in Haskell and Lisp. + // So we remove the redundant $$_applyAll_$$. + if (args[0].type === "Identifier") { + args[0].type = "CallIdentifier"; + } + return nodeExpression(args); + } else { + return nodeExpression([nodeCallIndentifier(fn), ...args]); + } +} +function nodeIdentifier(value) { + return { type: "Identifier", value: value }; +} +function nodeInteger(value) { + return { type: "Integer", value: value }; +} +function nodeKeyValue(key, value) { + if (key.type === "Identifier") { + key.type = "String"; + } + return { type: "KeyValue", key: key, value: value }; +} +function nodeLambda(args, body) { + return { type: "Lambda", args: args, body: body }; +} +function nodeLetStatment(variable, value) { + return { type: "LetStatement", variable: variable, value: value }; +} +function nodeString(value) { + return { type: "String", value: value }; +} +function nodeTernary(condition, trueExpression, falseExpression) { + return { + type: "Ternary", + condition: condition, + trueExpression: trueExpression, + falseExpression: falseExpression, + }; +} + +function peg$subclass(child, parent) { + function C() { + this.constructor = child; + } + C.prototype = parent.prototype; + child.prototype = new C(); +} + +function peg$SyntaxError(message, expected, found, location) { + var self = Error.call(this, message); + if (Object.setPrototypeOf) { + Object.setPrototypeOf(self, peg$SyntaxError.prototype); + } + self.expected = expected; + self.found = found; + self.location = location; + self.name = "SyntaxError"; + return self; +} + +peg$subclass(peg$SyntaxError, Error); + +function peg$padEnd(str, targetLength, padString) { + padString = padString || " "; + if (str.length > targetLength) { + return str; + } + targetLength -= str.length; + padString += padString.repeat(targetLength); + return str + padString.slice(0, targetLength); +} + +peg$SyntaxError.prototype.format = function (sources) { + var str = "Error: " + this.message; + if (this.location) { + var src = null; + var k; + for (k = 0; k < sources.length; k++) { + if (sources[k].source === this.location.source) { + src = sources[k].text.split(/\r\n|\n|\r/g); + break; + } + } + var s = this.location.start; + var loc = this.location.source + ":" + s.line + ":" + s.column; + if (src) { + var e = this.location.end; + var filler = peg$padEnd("", s.line.toString().length); + var line = src[s.line - 1]; + var last = s.line === e.line ? e.column : line.length + 1; + str += + "\n --> " + + loc + + "\n" + + filler + + " |\n" + + s.line + + " | " + + line + + "\n" + + filler + + " | " + + peg$padEnd("", s.column - 1) + + peg$padEnd("", last - s.column, "^"); + } else { + str += "\n at " + loc; + } + } + return str; +}; + +peg$SyntaxError.buildMessage = function (expected, found) { + var DESCRIBE_EXPECTATION_FNS = { + literal: function (expectation) { + return '"' + literalEscape(expectation.text) + '"'; + }, + + class: function (expectation) { + var escapedParts = expectation.parts.map(function (part) { + return Array.isArray(part) + ? classEscape(part[0]) + "-" + classEscape(part[1]) + : classEscape(part); + }); + + return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; + }, + + any: function () { + return "any character"; + }, + + end: function () { + return "end of input"; + }, + + other: function (expectation) { + return expectation.description; + }, + }; + + function hex(ch) { + return ch.charCodeAt(0).toString(16).toUpperCase(); + } + + function literalEscape(s) { + return s + .replace(/\\/g, "\\\\") + .replace(/"/g, '\\"') + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, function (ch) { + return "\\x0" + hex(ch); + }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { + return "\\x" + hex(ch); + }); + } + + function classEscape(s) { + return s + .replace(/\\/g, "\\\\") + .replace(/\]/g, "\\]") + .replace(/\^/g, "\\^") + .replace(/-/g, "\\-") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, function (ch) { + return "\\x0" + hex(ch); + }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { + return "\\x" + hex(ch); + }); + } + + function describeExpectation(expectation) { + return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); + } + + function describeExpected(expected) { + var descriptions = expected.map(describeExpectation); + var i, j; + + descriptions.sort(); + + if (descriptions.length > 0) { + for (i = 1, j = 1; i < descriptions.length; i++) { + if (descriptions[i - 1] !== descriptions[i]) { + descriptions[j] = descriptions[i]; + j++; + } + } + descriptions.length = j; + } + + switch (descriptions.length) { + case 1: + return descriptions[0]; + + case 2: + return descriptions[0] + " or " + descriptions[1]; + + default: + return ( + descriptions.slice(0, -1).join(", ") + + ", or " + + descriptions[descriptions.length - 1] + ); + } + } + + function describeFound(found) { + return found ? '"' + literalEscape(found) + '"' : "end of input"; + } + + return ( + "Expected " + + describeExpected(expected) + + " but " + + describeFound(found) + + " found." + ); +}; + +function peg$parse(input, options) { + options = options !== undefined ? options : {}; + + var peg$FAILED = {}; + var peg$source = options.grammarSource; + + var peg$startRuleFunctions = { start: peg$parsestart }; + var peg$startRuleFunction = peg$parsestart; + + var peg$c0 = "{"; + var peg$c1 = "}"; + var peg$c2 = "("; + var peg$c3 = ")"; + var peg$c4 = "="; + var peg$c5 = ","; + var peg$c6 = "if"; + var peg$c7 = "then"; + var peg$c8 = "else"; + var peg$c9 = "?"; + var peg$c10 = ":"; + var peg$c11 = "||"; + var peg$c12 = "&&"; + var peg$c13 = "=="; + var peg$c14 = "!="; + var peg$c15 = "<="; + var peg$c16 = "<"; + var peg$c17 = ">="; + var peg$c18 = ">"; + var peg$c19 = "+"; + var peg$c20 = "-"; + var peg$c21 = ".+"; + var peg$c22 = ".-"; + var peg$c23 = "*"; + var peg$c24 = "/"; + var peg$c25 = ".*"; + var peg$c26 = "./"; + var peg$c27 = "^"; + var peg$c28 = ".^"; + var peg$c29 = "to"; + var peg$c30 = "->"; + var peg$c31 = "|>"; + var peg$c32 = "!"; + var peg$c33 = "["; + var peg$c34 = "."; + var peg$c35 = "]"; + var peg$c36 = "'"; + var peg$c37 = '"'; + var peg$c38 = "true"; + var peg$c39 = "false"; + var peg$c40 = "|"; + var peg$c41 = ";"; + var peg$c42 = "//"; + var peg$c43 = "#"; + var peg$c44 = "/*"; + var peg$c45 = "*/"; + + var peg$r0 = /^[_a-z]/; + var peg$r1 = /^[_a-z0-9]/i; + var peg$r2 = /^[$_a-z]/; + var peg$r3 = /^[$_a-z0-9]/i; + var peg$r4 = /^[^']/; + var peg$r5 = /^[^"]/; + var peg$r6 = /^[e]/i; + var peg$r7 = /^[0-9]/; + var peg$r8 = /^[^\r\n]/; + var peg$r9 = /^[^*]/; + var peg$r10 = /^[ \t]/; + var peg$r11 = /^[\n\r]/; + + var peg$e0 = peg$literalExpectation("{", false); + var peg$e1 = peg$literalExpectation("}", false); + var peg$e2 = peg$literalExpectation("(", false); + var peg$e3 = peg$literalExpectation(")", false); + var peg$e4 = peg$otherExpectation("assignment"); + var peg$e5 = peg$literalExpectation("=", false); + var peg$e6 = peg$literalExpectation(",", false); + var peg$e7 = peg$literalExpectation("if", false); + var peg$e8 = peg$literalExpectation("then", false); + var peg$e9 = peg$literalExpectation("else", false); + var peg$e10 = peg$literalExpectation("?", false); + var peg$e11 = peg$literalExpectation(":", false); + var peg$e12 = peg$otherExpectation("operator"); + var peg$e13 = peg$literalExpectation("||", false); + var peg$e14 = peg$literalExpectation("&&", false); + var peg$e15 = peg$literalExpectation("==", false); + var peg$e16 = peg$literalExpectation("!=", false); + var peg$e17 = peg$literalExpectation("<=", false); + var peg$e18 = peg$literalExpectation("<", false); + var peg$e19 = peg$literalExpectation(">=", false); + var peg$e20 = peg$literalExpectation(">", false); + var peg$e21 = peg$literalExpectation("+", false); + var peg$e22 = peg$literalExpectation("-", false); + var peg$e23 = peg$literalExpectation(".+", false); + var peg$e24 = peg$literalExpectation(".-", false); + var peg$e25 = peg$literalExpectation("*", false); + var peg$e26 = peg$literalExpectation("/", false); + var peg$e27 = peg$literalExpectation(".*", false); + var peg$e28 = peg$literalExpectation("./", false); + var peg$e29 = peg$literalExpectation("^", false); + var peg$e30 = peg$literalExpectation(".^", false); + var peg$e31 = peg$literalExpectation("to", false); + var peg$e32 = peg$literalExpectation("->", false); + var peg$e33 = peg$literalExpectation("|>", false); + var peg$e34 = peg$otherExpectation("unary operator"); + var peg$e35 = peg$literalExpectation("!", false); + var peg$e36 = peg$literalExpectation("[", false); + var peg$e37 = peg$literalExpectation(".", false); + var peg$e38 = peg$literalExpectation("]", false); + var peg$e39 = peg$otherExpectation("identifier"); + var peg$e40 = peg$classExpectation(["_", ["a", "z"]], false, false); + var peg$e41 = peg$classExpectation( + ["_", ["a", "z"], ["0", "9"]], + false, + true + ); + var peg$e42 = peg$otherExpectation("$identifier"); + var peg$e43 = peg$classExpectation(["$", "_", ["a", "z"]], false, false); + var peg$e44 = peg$classExpectation( + ["$", "_", ["a", "z"], ["0", "9"]], + false, + true + ); + var peg$e45 = peg$otherExpectation("string"); + var peg$e46 = peg$literalExpectation("'", false); + var peg$e47 = peg$classExpectation(["'"], true, false); + var peg$e48 = peg$literalExpectation('"', false); + var peg$e49 = peg$classExpectation(['"'], true, false); + var peg$e50 = peg$otherExpectation("integer"); + var peg$e51 = peg$classExpectation(["e"], false, true); + var peg$e52 = peg$otherExpectation("float"); + var peg$e53 = peg$classExpectation([["0", "9"]], false, false); + var peg$e54 = peg$otherExpectation("boolean"); + var peg$e55 = peg$literalExpectation("true", false); + var peg$e56 = peg$literalExpectation("false", false); + var peg$e57 = peg$literalExpectation("|", false); + var peg$e58 = peg$otherExpectation("array"); + var peg$e59 = peg$otherExpectation("record"); + var peg$e60 = peg$otherExpectation("whitespace"); + var peg$e61 = peg$otherExpectation("optional whitespace or newline"); + var peg$e62 = peg$otherExpectation("whitespace or newline"); + var peg$e63 = peg$otherExpectation("statement separator"); + var peg$e64 = peg$literalExpectation(";", false); + var peg$e65 = peg$otherExpectation("line comment"); + var peg$e66 = peg$literalExpectation("//", false); + var peg$e67 = peg$literalExpectation("#", false); + var peg$e68 = peg$classExpectation(["\r", "\n"], true, false); + var peg$e69 = peg$otherExpectation("comment"); + var peg$e70 = peg$literalExpectation("/*", false); + var peg$e71 = peg$classExpectation(["*"], true, false); + var peg$e72 = peg$literalExpectation("*/", false); + var peg$e73 = peg$classExpectation([" ", "\t"], false, false); + var peg$e74 = peg$otherExpectation("newline"); + var peg$e75 = peg$classExpectation(["\n", "\r"], false, false); + + var peg$f0 = function (start) { + return start; + }; + var peg$f1 = function (statements, finalExpression) { + if (finalExpression != null) { + statements.push(finalExpression); + } + return nodeBlock(statements); + }; + var peg$f2 = function (finalExpression) { + return nodeBlock([finalExpression]); + }; + var peg$f3 = function (statements, finalExpression) { + statements.push(finalExpression); + return nodeBlock(statements); + }; + var peg$f4 = function (finalExpression) { + return nodeBlock([finalExpression]); + }; + var peg$f5 = function (head, tail) { + return [head, ...tail]; + }; + var peg$f6 = function (head) { + return [head]; + }; + var peg$f7 = function (variable, value) { + return nodeLetStatment(variable, value); + }; + var peg$f8 = function (variable, args, body) { + var value = nodeLambda(args, body); + return nodeLetStatment(variable, value); + }; + var peg$f9 = function (head, tail) { + return [head, ...tail]; + }; + var peg$f10 = function (condition, trueExpression, falseExpression) { + return nodeTernary(condition, trueExpression, falseExpression); + }; + var peg$f11 = function (head, operator, arg) { + return { operator: operator, right: arg }; + }; + var peg$f12 = function (head, tail) { + return tail.reduce(function (result, element) { + return makeFunctionCall(toFunction[element.operator], [ + result, + element.right, + ]); + }, head); + }; + var peg$f13 = function (left, operator, right) { + return makeFunctionCall(toFunction[operator], [left, right]); + }; + var peg$f14 = function (head, chained) { + return chained; + }; + var peg$f15 = function (head, tail) { + return tail.reduce(function (result, element) { + return makeFunctionCall(element.fnName, [result, ...element.args]); + }, head); + }; + var peg$f16 = function (fn, args) { + return { fnName: fn.value, args: args }; + }; + var peg$f17 = function (fn) { + return { fnName: fn.value, args: [] }; + }; + var peg$f18 = function (unaryOperator, right) { + return makeFunctionCall(unaryToFunction[unaryOperator], [right]); + }; + var peg$f19 = function (head, arg) { + return { fn: postOperatorToFunction["[]"], args: [arg] }; + }; + var peg$f20 = function (head, args) { + return { fn: postOperatorToFunction["()"], args: args }; + }; + var peg$f21 = function (head, arg) { + return { fn: postOperatorToFunction["[]"], args: [nodeString(arg)] }; + }; + var peg$f22 = function (head, tail) { + return tail.reduce(function (result, element) { + return makeFunctionCall(element.fn, [result, ...element.args]); + }, head); + }; + var peg$f23 = function (head, arg) { + return { fn: postOperatorToFunction["."], args: [nodeString(arg)] }; + }; + var peg$f24 = function (head, tail) { + return tail.reduce(function (result, element) { + return makeFunctionCall(element.fn, [result, ...element.args]); + }, head); + }; + var peg$f25 = function (expression) { + return expression; + }; + var peg$f26 = function () { + return nodeIdentifier(text()); + }; + var peg$f27 = function (characters) { + return nodeString(characters.join("")); + }; + var peg$f28 = function () { + return nodeInteger(parseInt(text())); + }; + var peg$f29 = function () { + return nodeFloat(parseFloat(text())); + }; + var peg$f30 = function () { + return nodeBoolean(text() === "true"); + }; + var peg$f31 = function (args, statements, finalExpression) { + statements.push(finalExpression); + return nodeLambda(args, nodeBlock(statements)); + }; + var peg$f32 = function (args, finalExpression) { + return nodeLambda(args, nodeBlock([finalExpression])); + }; + var peg$f33 = function () { + return makeFunctionCall("$_constructArray_$", [nodeExpression([])]); + }; + var peg$f34 = function (args) { + return makeFunctionCall("$_constructArray_$", [nodeExpression(args)]); + }; + var peg$f35 = function (args) { + return makeFunctionCall("$_constructRecord_$", [nodeExpression(args)]); + }; + var peg$f36 = function (key, value) { + return nodeKeyValue(key, value); + }; + + var peg$currPos = 0; + var peg$savedPos = 0; + var peg$posDetailsCache = [{ line: 1, column: 1 }]; + var peg$maxFailPos = 0; + var peg$maxFailExpected = []; + var peg$silentFails = 0; + + var peg$resultsCache = {}; + + var peg$result; + + if ("startRule" in options) { + if (!(options.startRule in peg$startRuleFunctions)) { + throw new Error( + "Can't start parsing from rule \"" + options.startRule + '".' + ); + } + + peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; + } + + function text() { + return input.substring(peg$savedPos, peg$currPos); + } + + function offset() { + return peg$savedPos; + } + + function range() { + return { + source: peg$source, + start: peg$savedPos, + end: peg$currPos, + }; + } + + function location() { + return peg$computeLocation(peg$savedPos, peg$currPos); + } + + function expected(description, location) { + location = + location !== undefined + ? location + : peg$computeLocation(peg$savedPos, peg$currPos); + + throw peg$buildStructuredError( + [peg$otherExpectation(description)], + input.substring(peg$savedPos, peg$currPos), + location + ); + } + + function error(message, location) { + location = + location !== undefined + ? location + : peg$computeLocation(peg$savedPos, peg$currPos); + + throw peg$buildSimpleError(message, location); + } + + function peg$literalExpectation(text, ignoreCase) { + return { type: "literal", text: text, ignoreCase: ignoreCase }; + } + + function peg$classExpectation(parts, inverted, ignoreCase) { + return { + type: "class", + parts: parts, + inverted: inverted, + ignoreCase: ignoreCase, + }; + } + + function peg$anyExpectation() { + return { type: "any" }; + } + + function peg$endExpectation() { + return { type: "end" }; + } + + function peg$otherExpectation(description) { + return { type: "other", description: description }; + } + + function peg$computePosDetails(pos) { + var details = peg$posDetailsCache[pos]; + var p; + + if (details) { + return details; + } else { + p = pos - 1; + while (!peg$posDetailsCache[p]) { + p--; + } + + details = peg$posDetailsCache[p]; + details = { + line: details.line, + column: details.column, + }; + + while (p < pos) { + if (input.charCodeAt(p) === 10) { + details.line++; + details.column = 1; + } else { + details.column++; + } + + p++; + } + + peg$posDetailsCache[pos] = details; + + return details; + } + } + + function peg$computeLocation(startPos, endPos) { + var startPosDetails = peg$computePosDetails(startPos); + var endPosDetails = peg$computePosDetails(endPos); + + return { + source: peg$source, + start: { + offset: startPos, + line: startPosDetails.line, + column: startPosDetails.column, + }, + end: { + offset: endPos, + line: endPosDetails.line, + column: endPosDetails.column, + }, + }; + } + + function peg$fail(expected) { + if (peg$currPos < peg$maxFailPos) { + return; + } + + if (peg$currPos > peg$maxFailPos) { + peg$maxFailPos = peg$currPos; + peg$maxFailExpected = []; + } + + peg$maxFailExpected.push(expected); + } + + function peg$buildSimpleError(message, location) { + return new peg$SyntaxError(message, null, null, location); + } + + function peg$buildStructuredError(expected, found, location) { + return new peg$SyntaxError( + peg$SyntaxError.buildMessage(expected, found), + expected, + found, + location + ); + } + + function peg$parsestart() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 0; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parse_nl(); + s2 = peg$parseouterBlock(); + if (s2 !== peg$FAILED) { + s3 = peg$parse_nl(); + s4 = peg$parsefinalComment(); + if (s4 === peg$FAILED) { + s4 = null; + } + peg$savedPos = s0; + s0 = peg$f0(s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsezeroOMoreArgumentsBlockOrExpression() { + var s0; + + var key = peg$currPos * 67 + 1; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parseinnerBlockOrExpression(); + if (s0 === peg$FAILED) { + s0 = peg$parselambda(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseouterBlock() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 2; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsearray_statements(); + if (s1 !== peg$FAILED) { + s2 = peg$currPos; + s3 = peg$parsestatementSeparator(); + if (s3 !== peg$FAILED) { + s4 = peg$parseexpression(); + if (s4 !== peg$FAILED) { + s2 = s4; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + if (s2 === peg$FAILED) { + s2 = null; + } + peg$savedPos = s0; + s0 = peg$f1(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parseexpression(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f2(s1); + } + s0 = s1; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseinnerBlockOrExpression() { + var s0, s1; + + var key = peg$currPos * 67 + 3; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsequotedInnerBlock(); + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parseexpression(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f2(s1); + } + s0 = s1; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsequotedInnerBlock() { + var s0, s1, s2, s3, s4, s5, s6; + + var key = peg$currPos * 67 + 4; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 123) { + s1 = peg$c0; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e0); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + s3 = peg$parsearray_statements(); + if (s3 !== peg$FAILED) { + s4 = peg$currPos; + s5 = peg$parsestatementSeparator(); + if (s5 !== peg$FAILED) { + s6 = peg$parseexpression(); + if (s6 !== peg$FAILED) { + s4 = s6; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + if (s4 !== peg$FAILED) { + s5 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 125) { + s6 = peg$c1; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e1); + } + } + if (s6 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f3(s3, s4); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 123) { + s1 = peg$c0; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e0); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + s3 = peg$parseexpression(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 125) { + s5 = peg$c1; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e1); + } + } + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f4(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearray_statements() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 5; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsestatement(); + if (s1 !== peg$FAILED) { + s2 = peg$currPos; + s3 = peg$parsestatementSeparator(); + if (s3 !== peg$FAILED) { + s4 = peg$parsearray_statements(); + if (s4 !== peg$FAILED) { + s2 = s4; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f5(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsestatement(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f6(s1); + } + s0 = s1; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsestatement() { + var s0; + + var key = peg$currPos * 67 + 6; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parseletStatement(); + if (s0 === peg$FAILED) { + s0 = peg$parsedefunStatement(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseletStatement() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 7; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseidentifier(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + s3 = peg$parseassignmentOp(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parsezeroOMoreArgumentsBlockOrExpression(); + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f7(s1, s5); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsedefunStatement() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; + + var key = peg$currPos * 67 + 8; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseidentifier(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 40) { + s2 = peg$c2; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_nl(); + s4 = peg$parsearray_parameters(); + if (s4 !== peg$FAILED) { + s5 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 41) { + s6 = peg$c3; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e3); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_(); + s8 = peg$parseassignmentOp(); + if (s8 !== peg$FAILED) { + s9 = peg$parse_nl(); + s10 = peg$parseinnerBlockOrExpression(); + if (s10 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f8(s1, s4, s10); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseassignmentOp() { + var s0, s1; + + var key = peg$currPos * 67 + 9; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 61) { + s0 = peg$c4; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e5); + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e4); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearray_parameters() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 10; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsedollarIdentifier(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsedollarIdentifier(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsedollarIdentifier(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f9(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseexpression() { + var s0; + + var key = peg$currPos * 67 + 11; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parseifthenelse(); + if (s0 === peg$FAILED) { + s0 = peg$parseternary(); + if (s0 === peg$FAILED) { + s0 = peg$parselogicalAdditive(); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseifthenelse() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; + + var key = peg$currPos * 67 + 12; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c6) { + s1 = peg$c6; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e7); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse__nl(); + if (s2 !== peg$FAILED) { + s3 = peg$parselogicalAdditive(); + if (s3 !== peg$FAILED) { + s4 = peg$parse__nl(); + if (s4 !== peg$FAILED) { + if (input.substr(peg$currPos, 4) === peg$c7) { + s5 = peg$c7; + peg$currPos += 4; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e8); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse__nl(); + if (s6 !== peg$FAILED) { + s7 = peg$parseinnerBlockOrExpression(); + if (s7 !== peg$FAILED) { + s8 = peg$parse__nl(); + if (s8 !== peg$FAILED) { + if (input.substr(peg$currPos, 4) === peg$c8) { + s9 = peg$c8; + peg$currPos += 4; + } else { + s9 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e9); + } + } + if (s9 !== peg$FAILED) { + s10 = peg$parse__nl(); + if (s10 !== peg$FAILED) { + s11 = peg$parseifthenelse(); + if (s11 === peg$FAILED) { + s11 = peg$parseinnerBlockOrExpression(); + } + if (s11 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f10(s3, s7, s11); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseternary() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; + + var key = peg$currPos * 67 + 13; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parselogicalAdditive(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 63) { + s3 = peg$c9; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e10); + } + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parselogicalAdditive(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 58) { + s7 = peg$c10; + peg$currPos++; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e11); + } + } + if (s7 !== peg$FAILED) { + s8 = peg$parse_nl(); + s9 = peg$parseternary(); + if (s9 === peg$FAILED) { + s9 = peg$parselogicalAdditive(); + } + if (s9 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f10(s1, s5, s9); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parselogicalAdditive() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 14; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parselogicalMultiplicative(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parselogicalAdditiveOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parselogicalMultiplicative(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parselogicalAdditiveOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parselogicalMultiplicative(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f12(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parselogicalAdditiveOp() { + var s0, s1; + + var key = peg$currPos * 67 + 15; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.substr(peg$currPos, 2) === peg$c11) { + s0 = peg$c11; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e13); + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parselogicalMultiplicative() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 16; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseequality(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parselogicalMultiplicativeOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parseequality(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parselogicalMultiplicativeOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parseequality(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f12(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parselogicalMultiplicativeOp() { + var s0, s1; + + var key = peg$currPos * 67 + 17; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.substr(peg$currPos, 2) === peg$c12) { + s0 = peg$c12; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e14); + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseequality() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 18; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parserelational(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + s3 = peg$parseequalityOp(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parserelational(); + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f13(s1, s3, s5); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parserelational(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseequalityOp() { + var s0, s1; + + var key = peg$currPos * 67 + 19; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.substr(peg$currPos, 2) === peg$c13) { + s0 = peg$c13; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e15); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c14) { + s0 = peg$c14; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e16); + } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parserelational() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 20; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseadditive(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + s3 = peg$parserelationalOp(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parseadditive(); + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f13(s1, s3, s5); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parseadditive(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parserelationalOp() { + var s0, s1; + + var key = peg$currPos * 67 + 21; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.substr(peg$currPos, 2) === peg$c15) { + s0 = peg$c15; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e17); + } + } + if (s0 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 60) { + s0 = peg$c16; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e18); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c17) { + s0 = peg$c17; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e19); + } + } + if (s0 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 62) { + s0 = peg$c18; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e20); + } + } + } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseadditive() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 22; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsemultiplicative(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parseadditiveOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsemultiplicative(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parseadditiveOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsemultiplicative(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f12(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseadditiveOp() { + var s0, s1; + + var key = peg$currPos * 67 + 23; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 43) { + s0 = peg$c19; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e21); + } + } + if (s0 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 45) { + s0 = peg$c20; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e22); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c21) { + s0 = peg$c21; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e23); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c22) { + s0 = peg$c22; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e24); + } + } + } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsemultiplicative() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 24; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsepower(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parsemultiplicativeOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsepower(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parsemultiplicativeOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsepower(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f12(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsemultiplicativeOp() { + var s0, s1; + + var key = peg$currPos * 67 + 25; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 42) { + s0 = peg$c23; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e25); + } + } + if (s0 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 47) { + s0 = peg$c24; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e26); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c25) { + s0 = peg$c25; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e27); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c26) { + s0 = peg$c26; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e28); + } + } + } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsepower() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 26; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsecredibleInterval(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parsepowerOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsecredibleInterval(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + s5 = peg$parsepowerOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsecredibleInterval(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f12(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsepowerOp() { + var s0, s1; + + var key = peg$currPos * 67 + 27; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 94) { + s0 = peg$c27; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e29); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c28) { + s0 = peg$c28; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e30); + } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecredibleInterval() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 28; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsechainFunctionCall(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse__(); + if (s4 !== peg$FAILED) { + s5 = peg$parsecredibleIntervalOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse__nl(); + if (s6 !== peg$FAILED) { + s7 = peg$parsechainFunctionCall(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse__(); + if (s4 !== peg$FAILED) { + s5 = peg$parsecredibleIntervalOp(); + if (s5 !== peg$FAILED) { + s6 = peg$parse__nl(); + if (s6 !== peg$FAILED) { + s7 = peg$parsechainFunctionCall(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f11(s1, s5, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f12(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecredibleIntervalOp() { + var s0, s1; + + var key = peg$currPos * 67 + 29; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.substr(peg$currPos, 2) === peg$c29) { + s0 = peg$c29; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e31); + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e12); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsechainFunctionCall() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 30; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseunary(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.substr(peg$currPos, 2) === peg$c30) { + s5 = peg$c30; + peg$currPos += 2; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e32); + } + } + if (s5 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c31) { + s5 = peg$c31; + peg$currPos += 2; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e33); + } + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsechainedFunction(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f14(s1, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.substr(peg$currPos, 2) === peg$c30) { + s5 = peg$c30; + peg$currPos += 2; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e32); + } + } + if (s5 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c31) { + s5 = peg$c31; + peg$currPos += 2; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e33); + } + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsechainedFunction(); + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s3 = peg$f14(s1, s7); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f15(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsechainedFunction() { + var s0, s1, s2, s3, s4, s5, s6; + + var key = peg$currPos * 67 + 31; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsedollarIdentifier(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 40) { + s2 = peg$c2; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_nl(); + s4 = peg$parsearray_functionArguments(); + if (s4 !== peg$FAILED) { + s5 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 41) { + s6 = peg$c3; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e3); + } + } + if (s6 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f16(s1, s4); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsedollarIdentifier(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 40) { + s2 = peg$c2; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 41) { + s4 = peg$c3; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e3); + } + } + if (s4 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f17(s1); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsedollarIdentifier(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f17(s1); + } + s0 = s1; + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseunary() { + var s0, s1, s2, s3; + + var key = peg$currPos * 67 + 32; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseunaryOperator(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + s3 = peg$parseunary(); + if (s3 === peg$FAILED) { + s3 = peg$parseindexedValue(); + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f18(s1, s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parseindexedValue(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseunaryOperator() { + var s0, s1; + + var key = peg$currPos * 67 + 33; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 45) { + s0 = peg$c20; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e22); + } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c22) { + s0 = peg$c22; + peg$currPos += 2; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e24); + } + } + if (s0 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 33) { + s0 = peg$c32; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e35); + } + } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e34); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseindexedValue() { + var s0; + + var key = peg$currPos * 67 + 34; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsecollectionElement(); + if (s0 === peg$FAILED) { + s0 = peg$parserecordElement(); + if (s0 === peg$FAILED) { + s0 = peg$parseatom(); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecollectionElement() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; + + var key = peg$currPos * 67 + 35; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseatom(); + if (s1 !== peg$FAILED) { + s2 = peg$currPos; + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 91) { + s3 = peg$c33; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e36); + } + } + if (s3 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 40) { + s3 = peg$c2; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s3 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 46) { + s3 = peg$c34; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + } + } + peg$silentFails--; + if (s3 !== peg$FAILED) { + peg$currPos = s2; + s2 = undefined; + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 91) { + s6 = peg$c33; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e36); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_nl(); + s8 = peg$parseexpression(); + if (s8 !== peg$FAILED) { + s9 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 93) { + s10 = peg$c35; + peg$currPos++; + } else { + s10 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e38); + } + } + if (s10 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f19(s1, s8); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + if (s4 === peg$FAILED) { + s4 = peg$currPos; + s5 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 40) { + s6 = peg$c2; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_nl(); + s8 = peg$parsearray_functionArguments(); + if (s8 !== peg$FAILED) { + s9 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 41) { + s10 = peg$c3; + peg$currPos++; + } else { + s10 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e3); + } + } + if (s10 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f20(s1, s8); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + if (s4 === peg$FAILED) { + s4 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 46) { + s5 = peg$c34; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$currPos; + s7 = peg$parsedollarIdentifier(); + if (s7 !== peg$FAILED) { + s6 = input.substring(s6, peg$currPos); + } else { + s6 = s7; + } + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f21(s1, s6); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 91) { + s6 = peg$c33; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e36); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_nl(); + s8 = peg$parseexpression(); + if (s8 !== peg$FAILED) { + s9 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 93) { + s10 = peg$c35; + peg$currPos++; + } else { + s10 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e38); + } + } + if (s10 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f19(s1, s8); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + if (s4 === peg$FAILED) { + s4 = peg$currPos; + s5 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 40) { + s6 = peg$c2; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_nl(); + s8 = peg$parsearray_functionArguments(); + if (s8 !== peg$FAILED) { + s9 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 41) { + s10 = peg$c3; + peg$currPos++; + } else { + s10 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e3); + } + } + if (s10 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f20(s1, s8); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + if (s4 === peg$FAILED) { + s4 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 46) { + s5 = peg$c34; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$currPos; + s7 = peg$parsedollarIdentifier(); + if (s7 !== peg$FAILED) { + s6 = input.substring(s6, peg$currPos); + } else { + s6 = s7; + } + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f21(s1, s6); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + } + } + peg$savedPos = s0; + s0 = peg$f22(s1, s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearray_functionArguments() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 36; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseexpression(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parseexpression(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parseexpression(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f9(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parserecordElement() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; + + var key = peg$currPos * 67 + 37; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsedollarIdentifier(); + if (s1 !== peg$FAILED) { + s2 = peg$currPos; + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 46) { + s3 = peg$c34; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + peg$silentFails--; + if (s3 !== peg$FAILED) { + peg$currPos = s2; + s2 = undefined; + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 46) { + s6 = peg$c34; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_nl(); + s8 = peg$currPos; + s9 = peg$parsedollarIdentifier(); + if (s9 !== peg$FAILED) { + s8 = input.substring(s8, peg$currPos); + } else { + s8 = s9; + } + if (s8 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f23(s1, s8); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 46) { + s6 = peg$c34; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + if (s6 !== peg$FAILED) { + s7 = peg$parse_nl(); + s8 = peg$currPos; + s9 = peg$parsedollarIdentifier(); + if (s9 !== peg$FAILED) { + s8 = input.substring(s8, peg$currPos); + } else { + s8 = s9; + } + if (s8 !== peg$FAILED) { + peg$savedPos = s4; + s4 = peg$f23(s1, s8); + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f24(s1, s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseatom() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 38; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 40) { + s1 = peg$c2; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e2); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + s3 = peg$parseexpression(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 41) { + s5 = peg$c3; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e3); + } + } + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f25(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parsebasicValue(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsebasicValue() { + var s0; + + var key = peg$currPos * 67 + 39; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsevalueConstructor(); + if (s0 === peg$FAILED) { + s0 = peg$parsebasicLiteral(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsebasicLiteral() { + var s0; + + var key = peg$currPos * 67 + 40; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsestring(); + if (s0 === peg$FAILED) { + s0 = peg$parsefloat(); + if (s0 === peg$FAILED) { + s0 = peg$parseinteger(); + if (s0 === peg$FAILED) { + s0 = peg$parseboolean(); + if (s0 === peg$FAILED) { + s0 = peg$parsedollarIdentifier(); + } + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseidentifier() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 41; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$currPos; + s2 = []; + if (peg$r0.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e40); + } + } + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + if (peg$r0.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e40); + } + } + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r1.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e41); + } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r1.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e41); + } + } + } + s2 = [s2, s3]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f26(); + } + s0 = s1; + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e39); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsedollarIdentifier() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 42; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$currPos; + s2 = []; + if (peg$r2.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e43); + } + } + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + if (peg$r2.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e43); + } + } + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r3.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e44); + } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r3.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e44); + } + } + } + s2 = [s2, s3]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f26(); + } + s0 = s1; + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e42); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsestring() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 43; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 39) { + s2 = peg$c36; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e46); + } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r4.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e47); + } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r4.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e47); + } + } + } + if (input.charCodeAt(peg$currPos) === 39) { + s4 = peg$c36; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e46); + } + } + if (s4 !== peg$FAILED) { + s1 = s3; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f27(s1); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 34) { + s2 = peg$c37; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e48); + } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r5.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e49); + } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r5.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e49); + } + } + } + if (input.charCodeAt(peg$currPos) === 34) { + s4 = peg$c37; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e48); + } + } + if (s4 !== peg$FAILED) { + s1 = s3; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f27(s1); + } + s0 = s1; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e45); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseinteger() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 44; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = []; + s2 = peg$parsed(); + if (s2 !== peg$FAILED) { + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = peg$parsed(); + } + } else { + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + s2 = peg$currPos; + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 46) { + s3 = peg$c34; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + peg$silentFails--; + if (s3 === peg$FAILED) { + s2 = undefined; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$currPos; + peg$silentFails++; + if (peg$r6.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e51); + } + } + peg$silentFails--; + if (s4 === peg$FAILED) { + s3 = undefined; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f28(); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e50); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsefloat() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 45; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$currPos; + s2 = peg$currPos; + s3 = peg$currPos; + s4 = []; + s5 = peg$parsed(); + if (s5 !== peg$FAILED) { + while (s5 !== peg$FAILED) { + s4.push(s5); + s5 = peg$parsed(); + } + } else { + s4 = peg$FAILED; + } + if (s4 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 46) { + s5 = peg$c34; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + if (s5 !== peg$FAILED) { + s6 = []; + s7 = peg$parsed(); + while (s7 !== peg$FAILED) { + s6.push(s7); + s7 = peg$parsed(); + } + s4 = [s4, s5, s6]; + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + if (s3 === peg$FAILED) { + s3 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 46) { + s4 = peg$c34; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e37); + } + } + if (s4 !== peg$FAILED) { + s5 = []; + s6 = peg$parsed(); + if (s6 !== peg$FAILED) { + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = peg$parsed(); + } + } else { + s5 = peg$FAILED; + } + if (s5 !== peg$FAILED) { + s4 = [s4, s5]; + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + s4 = peg$parsefloatExponent(); + if (s4 === peg$FAILED) { + s4 = null; + } + s3 = [s3, s4]; + s2 = s3; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + if (s2 === peg$FAILED) { + s2 = peg$currPos; + s3 = []; + s4 = peg$parsed(); + if (s4 !== peg$FAILED) { + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$parsed(); + } + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s4 = peg$parsefloatExponent(); + if (s4 !== peg$FAILED) { + s3 = [s3, s4]; + s2 = s3; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } + if (s2 !== peg$FAILED) { + s1 = input.substring(s1, peg$currPos); + } else { + s1 = s2; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f29(); + } + s0 = s1; + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e52); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsefloatExponent() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 46; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (peg$r6.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e51); + } + } + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 45) { + s2 = peg$c20; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e22); + } + } + if (s2 === peg$FAILED) { + s2 = null; + } + s3 = []; + s4 = peg$parsed(); + if (s4 !== peg$FAILED) { + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$parsed(); + } + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsed() { + var s0; + + var key = peg$currPos * 67 + 47; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (peg$r7.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e53); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseboolean() { + var s0, s1; + + var key = peg$currPos * 67 + 48; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + if (input.substr(peg$currPos, 4) === peg$c38) { + s1 = peg$c38; + peg$currPos += 4; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e55); + } + } + if (s1 === peg$FAILED) { + if (input.substr(peg$currPos, 5) === peg$c39) { + s1 = peg$c39; + peg$currPos += 5; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e56); + } + } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f30(); + } + s0 = s1; + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e54); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsevalueConstructor() { + var s0; + + var key = peg$currPos * 67 + 49; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parserecordConstructor(); + if (s0 === peg$FAILED) { + s0 = peg$parsearrayConstructor(); + if (s0 === peg$FAILED) { + s0 = peg$parselambda(); + if (s0 === peg$FAILED) { + s0 = peg$parsequotedInnerBlock(); + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parselambda() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12; + + var key = peg$currPos * 67 + 50; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 123) { + s1 = peg$c0; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e0); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 124) { + s3 = peg$c40; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e57); + } + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parsearray_parameters(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 124) { + s7 = peg$c40; + peg$currPos++; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e57); + } + } + if (s7 !== peg$FAILED) { + s8 = peg$parse_nl(); + s9 = peg$parsearray_statements(); + if (s9 !== peg$FAILED) { + s10 = peg$currPos; + s11 = peg$parsestatementSeparator(); + if (s11 !== peg$FAILED) { + s12 = peg$parseexpression(); + if (s12 !== peg$FAILED) { + s10 = s12; + } else { + peg$currPos = s10; + s10 = peg$FAILED; + } + } else { + peg$currPos = s10; + s10 = peg$FAILED; + } + if (s10 !== peg$FAILED) { + s11 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 125) { + s12 = peg$c1; + peg$currPos++; + } else { + s12 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e1); + } + } + if (s12 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f31(s5, s9, s10); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 123) { + s1 = peg$c0; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e0); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 124) { + s3 = peg$c40; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e57); + } + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parsearray_parameters(); + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 124) { + s7 = peg$c40; + peg$currPos++; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e57); + } + } + if (s7 !== peg$FAILED) { + s8 = peg$parse_nl(); + s9 = peg$parseexpression(); + if (s9 !== peg$FAILED) { + s10 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 125) { + s11 = peg$c1; + peg$currPos++; + } else { + s11 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e1); + } + } + if (s11 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f32(s5, s9); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearrayConstructor() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 51; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 91) { + s1 = peg$c33; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e36); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 93) { + s3 = peg$c35; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e38); + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f33(); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 91) { + s1 = peg$c33; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e36); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + s3 = peg$parsearray_elements(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 93) { + s5 = peg$c35; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e38); + } + } + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f34(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e58); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearray_elements() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 52; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseexpression(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parseexpression(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parseexpression(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f9(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parserecordConstructor() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 53; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 123) { + s1 = peg$c0; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e0); + } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_nl(); + s3 = peg$parsearray_recordArguments(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + if (input.charCodeAt(peg$currPos) === 125) { + s5 = peg$c1; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e1); + } + } + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f35(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e59); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearray_recordArguments() { + var s0, s1, s2, s3, s4, s5, s6, s7; + + var key = peg$currPos * 67 + 54; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsekeyValuePair(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsekeyValuePair(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c5; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e6); + } + } + if (s5 !== peg$FAILED) { + s6 = peg$parse_nl(); + s7 = peg$parsekeyValuePair(); + if (s7 !== peg$FAILED) { + s3 = s7; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + peg$savedPos = s0; + s0 = peg$f9(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsekeyValuePair() { + var s0, s1, s2, s3, s4, s5; + + var key = peg$currPos * 67 + 55; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseexpression(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 58) { + s3 = peg$c10; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e11); + } + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_nl(); + s5 = peg$parseexpression(); + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f36(s1, s5); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parse_() { + var s0, s1; + + var key = peg$currPos * 67 + 56; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = []; + s1 = peg$parsewhiteSpaceCharactersOrComment(); + while (s1 !== peg$FAILED) { + s0.push(s1); + s1 = peg$parsewhiteSpaceCharactersOrComment(); + } + peg$silentFails--; + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e60); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parse_nl() { + var s0, s1; + + var key = peg$currPos * 67 + 57; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = []; + s1 = peg$parsewhiteSpaceCharactersOrComment(); + if (s1 === peg$FAILED) { + s1 = peg$parsecommentOrNewLine(); + } + while (s1 !== peg$FAILED) { + s0.push(s1); + s1 = peg$parsewhiteSpaceCharactersOrComment(); + if (s1 === peg$FAILED) { + s1 = peg$parsecommentOrNewLine(); + } + } + peg$silentFails--; + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e61); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parse__() { + var s0, s1; + + var key = peg$currPos * 67 + 58; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = []; + s1 = peg$parsewhiteSpaceCharactersOrComment(); + if (s1 !== peg$FAILED) { + while (s1 !== peg$FAILED) { + s0.push(s1); + s1 = peg$parsewhiteSpaceCharactersOrComment(); + } + } else { + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e60); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parse__nl() { + var s0, s1; + + var key = peg$currPos * 67 + 59; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = []; + s1 = peg$parsewhiteSpaceCharactersOrComment(); + if (s1 === peg$FAILED) { + s1 = peg$parsecommentOrNewLine(); + } + if (s1 !== peg$FAILED) { + while (s1 !== peg$FAILED) { + s0.push(s1); + s1 = peg$parsewhiteSpaceCharactersOrComment(); + if (s1 === peg$FAILED) { + s1 = peg$parsecommentOrNewLine(); + } + } + } else { + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e62); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsestatementSeparator() { + var s0, s1, s2, s3; + + var key = peg$currPos * 67 + 60; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$parse_(); + s2 = []; + if (input.charCodeAt(peg$currPos) === 59) { + s3 = peg$c41; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e64); + } + } + if (s3 === peg$FAILED) { + s3 = peg$parsecommentOrNewLine(); + } + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + if (input.charCodeAt(peg$currPos) === 59) { + s3 = peg$c41; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e64); + } + } + if (s3 === peg$FAILED) { + s3 = peg$parsecommentOrNewLine(); + } + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_nl(); + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e63); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecommentOrNewLine() { + var s0, s1, s2; + + var key = peg$currPos * 67 + 61; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefinalComment(); + if (s1 === peg$FAILED) { + s1 = null; + } + s2 = peg$parsenewLine(); + if (s2 !== peg$FAILED) { + s1 = [s1, s2]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsefinalComment() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 67 + 62; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$parse_(); + if (input.substr(peg$currPos, 2) === peg$c42) { + s2 = peg$c42; + peg$currPos += 2; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e66); + } + } + if (s2 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 35) { + s2 = peg$c43; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e67); + } + } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r8.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e68); + } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r8.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e68); + } + } + } + s0 = s3; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e65); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsewhiteSpaceCharactersOrComment() { + var s0; + + var key = peg$currPos * 67 + 63; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsewhiteSpaceCharacters(); + if (s0 === peg$FAILED) { + s0 = peg$parsedelimitedComment(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsedelimitedComment() { + var s0, s1, s2, s3; + + var key = peg$currPos * 67 + 64; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c44) { + s1 = peg$c44; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e70); + } + } + if (s1 !== peg$FAILED) { + s2 = []; + if (peg$r9.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e71); + } + } + while (s3 !== peg$FAILED) { + s2.push(s3); + if (peg$r9.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e71); + } + } + } + if (input.substr(peg$currPos, 2) === peg$c45) { + s3 = peg$c45; + peg$currPos += 2; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e72); + } + } + if (s3 !== peg$FAILED) { + s0 = s2; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e69); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsewhiteSpaceCharacters() { + var s0; + + var key = peg$currPos * 67 + 65; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (peg$r10.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e73); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsenewLine() { + var s0, s1; + + var key = peg$currPos * 67 + 66; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + if (peg$r11.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e75); + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e74); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + peg$result = peg$startRuleFunction(); + + if (peg$result !== peg$FAILED && peg$currPos === input.length) { + return peg$result; + } else { + if (peg$result !== peg$FAILED && peg$currPos < input.length) { + peg$fail(peg$endExpectation()); + } + + throw peg$buildStructuredError( + peg$maxFailExpected, + peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, + peg$maxFailPos < input.length + ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) + : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) + ); + } +} + +module.exports = { + SyntaxError: peg$SyntaxError, + parse: peg$parse, +}; diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy new file mode 100644 index 00000000..5d3392b3 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy @@ -0,0 +1,346 @@ +// Try in https://peggyjs.org/online + +{{ + var toFunction = { + '-': 'subtract', + '->': 'pipe', + '!=': 'unequal', + '.-': 'dotSubtract', + '.*': 'dotMultiply', + './': 'dotDivide', + '.^': 'dotPow', + '.+': 'dotAdd', + '*': 'multiply', + '/': 'divide', + '&&': 'and', + '^': 'pow', // or xor + '+': 'add', + '<': 'smaller', + '<=': 'smallerEq', + '==': 'equal', + '>': 'larger', + '>=': 'largerEq', + '||': 'or', + 'to': 'credibleIntervalToDistribution', + } + + var unaryToFunction = { + '-': 'unaryMinus', + '!': 'not', + '.-': 'unaryDotMinus', + } + + var postOperatorToFunction = { + '.': '$_atIndex_$', + '()': '$$_applyAll_$$', + '[]': '$_atIndex_$', + } + + function nodeBlock(statements) {return{type: 'Block', statements: statements}} + function nodeBoolean(value) {return {type: 'Boolean', value: value}} + function nodeCallIndentifier(value) {return {type: 'CallIdentifier', value: value}} + function nodeExpression(args) {return {type: 'Expression', nodes: args}} + function nodeFloat(value) {return {type: 'Float', value: value}} + function makeFunctionCall(fn, args) { + if (fn === '$$_applyAll_$$') { + // Any list of values is applied from left to right anyway. + // Like in Haskell and Lisp. + // So we remove the redundant $$_applyAll_$$. + if (args[0].type === "Identifier") {args[0].type = "CallIdentifier"} + return nodeExpression(args) + } else { + return nodeExpression([nodeCallIndentifier(fn), ...args]) + } + } + function nodeIdentifier(value) {return {type: 'Identifier', value: value}} + function nodeInteger(value) {return {type: 'Integer', value: value}} + function nodeKeyValue(key, value) { + if (key.type === 'Identifier') {key.type = 'String'} + return {type: 'KeyValue', key: key, value: value}} + function nodeLambda(args, body) {return {type: 'Lambda', args: args, body: body}} + function nodeLetStatment(variable, value) {return {type: 'LetStatement', variable: variable, value: value}} + function nodeString(value) {return {type: 'String', value: value}} + function nodeTernary(condition, trueExpression, falseExpression) {return {type: 'Ternary', condition: condition, trueExpression: trueExpression, falseExpression: falseExpression}} +}} + +start + = _nl start:outerBlock _nl finalComment? {return start} + +zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda + +outerBlock + = statements:array_statements finalExpression: (statementSeparator @expression)? + { if (finalExpression != null) { statements.push(finalExpression) } + return nodeBlock(statements) } + / finalExpression: expression + { return nodeBlock([finalExpression])} + +innerBlockOrExpression + = quotedInnerBlock + / finalExpression: expression + { return nodeBlock([finalExpression])} + +quotedInnerBlock + = '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}' + { statements.push(finalExpression) + return nodeBlock(statements) } + / '{' _nl finalExpression: expression _nl '}' + { return nodeBlock([finalExpression]) } + +array_statements + = head:statement tail:(statementSeparator @array_statements ) + { return [head, ...tail] } + / head:statement + { return [head] } + +statement + = letStatement + / defunStatement + +letStatement + = variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression + { return nodeLetStatment(variable, value) } + +defunStatement + = variable:identifier '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression + { var value = nodeLambda(args, body) + return nodeLetStatment(variable, value) } + + assignmentOp "assignment" = '=' + +array_parameters + = head:dollarIdentifier tail:(_ ',' _nl @dollarIdentifier)* + { return [head, ...tail]; } + +expression = ifthenelse / ternary / logicalAdditive + +ifthenelse + = 'if' __nl condition:logicalAdditive + __nl 'then' __nl trueExpression:innerBlockOrExpression + __nl 'else' __nl falseExpression:(ifthenelse/innerBlockOrExpression) + { return nodeTernary(condition, trueExpression, falseExpression) } + +ternary + = condition:logicalAdditive _ '?' _nl trueExpression:logicalAdditive _ ':' _nl falseExpression:(ternary/logicalAdditive) + { return nodeTernary(condition, trueExpression, falseExpression) } + +logicalAdditive + = head:logicalMultiplicative tail:(_ operator:logicalAdditiveOp _nl arg:logicalMultiplicative {return {operator: operator, right: arg}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(toFunction[element.operator], [result, element.right]) + }, head)} + + logicalAdditiveOp "operator" = '||' + +// start binary operators +logicalMultiplicative + = head:equality tail:(_ operator:logicalMultiplicativeOp _nl arg:equality {return {operator: operator, right: arg}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(toFunction[element.operator], [result, element.right]) + }, head)} + + logicalMultiplicativeOp "operator" = '&&' + +equality + = left:relational _ operator:equalityOp _nl right:relational + { return makeFunctionCall(toFunction[operator], [left, right])} + / relational + + equalityOp "operator" = '=='/'!=' + +relational + = left:additive _ operator:relationalOp _nl right:additive + { return makeFunctionCall(toFunction[operator], [left, right])} + / additive + + relationalOp "operator" = '<='/'<'/'>='/'>' + +additive + = head:multiplicative tail:(_ operator:additiveOp _nl arg:multiplicative {return {operator: operator, right: arg}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(toFunction[element.operator], [result, element.right]) + }, head)} + + additiveOp "operator" = '+' / '-' / '.+' / '.-' + +multiplicative + = head:power tail:(_ operator:multiplicativeOp _nl arg:power {return {operator: operator, right: arg}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(toFunction[element.operator], [result, element.right]) + }, head)} + + multiplicativeOp "operator" = '*' / '/' / '.*' / './' + +power + = head:credibleInterval tail:(_ operator:powerOp _nl arg:credibleInterval {return {operator: operator, right: arg}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(toFunction[element.operator], [result, element.right]) + }, head)} + + powerOp "operator" = '^' / '.^' + +credibleInterval + = head:chainFunctionCall tail:(__ operator:credibleIntervalOp __nl arg:chainFunctionCall {return {operator: operator, right: arg}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(toFunction[element.operator], [result, element.right]) + }, head)} + + credibleIntervalOp "operator" = 'to' + +chainFunctionCall + = head:unary tail:(_ ('->'/'|>') _nl chained:chainedFunction {return chained})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(element.fnName, [result, ...element.args]) + }, head)} + + chainedFunction + = fn:dollarIdentifier '(' _nl args:array_functionArguments _nl ')' + { return {fnName: fn.value, args: args}} + / fn:dollarIdentifier '(' _nl ')' + { return {fnName: fn.value, args: []}} + / fn:dollarIdentifier + { return {fnName: fn.value, args: []}} + +// end of binary operators + +unary + = unaryOperator:unaryOperator _nl right:(unary/postOperator) + { return makeFunctionCall(unaryToFunction[unaryOperator], [right])} + / postOperator + + unaryOperator "unary operator" + = ('-' / '.-' / '!' ) + +postOperator = indexedValue + +indexedValue + = collectionElement + / recordElement + / atom + + collectionElement + = head:atom &('['/'('/'.') + tail:( + _ '[' _nl arg:expression _nl ']' {return {fn: postOperatorToFunction['[]'], args: [arg]}} + / _ '(' _nl args:array_functionArguments _nl ')' {return {fn: postOperatorToFunction['()'], args: args}} + / '.' arg:$dollarIdentifier {return {fn: postOperatorToFunction['[]'], args: [nodeString(arg)]}} + )* + { return tail.reduce(function(result, element) { + return makeFunctionCall(element.fn, [result, ...element.args]) + }, head)} + + array_functionArguments + = head:expression tail:(_ ',' _nl @expression)* + { return [head, ...tail]; } + +recordElement + = head:dollarIdentifier &'.' + tail:(_ '.' _nl arg:$dollarIdentifier {return {fn: postOperatorToFunction['.'], args: [nodeString(arg)]}})* + { return tail.reduce(function(result, element) { + return makeFunctionCall(element.fn, [result, ...element.args]) + }, head)} + +atom + = '(' _nl expression:expression _nl ')' {return expression} + / basicValue + +basicValue = valueConstructor / basicLiteral + +basicLiteral + = string + / float + / integer + / boolean + / dollarIdentifier + +identifier 'identifier' + = ([_a-z]+[_a-z0-9]i*) {return nodeIdentifier(text())} + +dollarIdentifier '$identifier' + = ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())} + +string 'string' + = characters:("'" @([^'])* "'") {return nodeString(characters.join(''))} + / characters:('"' @([^"])* '"') {return nodeString(characters.join(''))} + +integer 'integer' + = d+ !"\." ![e]i + { return nodeInteger(parseInt(text()))} + +float 'float' + = $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent) + { return nodeFloat(parseFloat(text()))} + + floatExponent = [e]i '-'? d+ + d = [0-9] + +boolean 'boolean' + = ('true'/'false') + { return nodeBoolean(text() === 'true')} + +valueConstructor + = recordConstructor + / arrayConstructor + / lambda + / quotedInnerBlock + +lambda + = '{' _nl '|' _nl args:array_parameters _nl '|' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}' + { statements.push(finalExpression) + return nodeLambda(args, nodeBlock(statements)) } + / '{' _nl '|' _nl args:array_parameters _nl '|' _nl finalExpression: expression _nl '}' + { return nodeLambda(args, nodeBlock([finalExpression])) } + +arrayConstructor 'array' + = '[' _nl ']' + { return makeFunctionCall('$_constructArray_$', [nodeExpression([])])} + / '[' _nl args:array_elements _nl ']' + { return makeFunctionCall('$_constructArray_$', [nodeExpression(args)])} + + array_elements + = head:expression tail:(_ ',' _nl @expression)* + { return [head, ...tail]; } + +recordConstructor 'record' + = '{' _nl args:array_recordArguments _nl '}' + { return makeFunctionCall('$_constructRecord_$', [nodeExpression(args)])} + + array_recordArguments + = head:keyValuePair tail:(_ ',' _nl @keyValuePair)* + { return [head, ...tail]; } + + keyValuePair + = key:expression _ ':' _nl value:expression + { return nodeKeyValue(key, value)} + +_ 'whitespace' + = whiteSpaceCharactersOrComment* + +_nl 'optional whitespace or newline' + = (whiteSpaceCharactersOrComment / commentOrNewLine)* + +__ 'whitespace' + = whiteSpaceCharactersOrComment+ + +__nl 'whitespace or newline' + = (whiteSpaceCharactersOrComment / commentOrNewLine )+ + +statementSeparator 'statement separator' + = _ (';'/ commentOrNewLine)+ _nl + + commentOrNewLine = finalComment? newLine + + finalComment "line comment" + = _ ('//'/'#') @([^\r\n]*) + + whiteSpaceCharactersOrComment = whiteSpaceCharacters / delimitedComment + + delimitedComment "comment" + = '/*' @([^*]*) '*/' + + whiteSpaceCharacters = [ \t] + + newLine "newline" + = [\n\r] + + \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res new file mode 100644 index 00000000..313639fb --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res @@ -0,0 +1,109 @@ +module Extra = Reducer_Extra +open Reducer_ErrorValue + +type node = {"type": string} + +@module("./Reducer_Peggy_GeneratedParser.js") external parse__: string => node = "parse" + +let parse = (expr: string): result => + try { + Ok(parse__(expr)) + } catch { + | Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error + } + +type nodeBlock = {...node, "statements": array} +type nodeBoolean = {...node, "value": bool} +type nodeCallIdentifier = {...node, "value": string} +type nodeExpression = {...node, "nodes": array} +type nodeFloat = {...node, "value": float} +type nodeIdentifier = {...node, "value": string} +type nodeInteger = {...node, "value": int} +type nodeKeyValue = {...node, "key": node, "value": node} +type nodeLambda = {...node, "args": array, "body": nodeBlock} +type nodeLetStatement = {...node, "variable": nodeIdentifier, "value": node} +type nodeString = {...node, "value": string} +type nodeTernary = {...node, "condition": node, "trueExpression": node, "falseExpression": node} + +type peggyNode = + | PgNodeBlock(nodeBlock) + | PgNodeBoolean(nodeBoolean) + | PgNodeCallIdentifier(nodeCallIdentifier) + | PgNodeExpression(nodeExpression) + | PgNodeFloat(nodeFloat) + | PgNodeIdentifier(nodeIdentifier) + | PgNodeInteger(nodeInteger) + | PgNodeKeyValue(nodeKeyValue) + | PgNodeLambda(nodeLambda) + | PgNodeLetStatement(nodeLetStatement) + | PgNodeString(nodeString) + | PgNodeTernary(nodeTernary) + +external castNodeBlock: node => nodeBlock = "%identity" +external castNodeBoolean: node => nodeBoolean = "%identity" +external castNodeCallIdentifier: node => nodeCallIdentifier = "%identity" +external castNodeExpression: node => nodeExpression = "%identity" +external castNodeFloat: node => nodeFloat = "%identity" +external castNodeIdentifier: node => nodeIdentifier = "%identity" +external castNodeInteger: node => nodeInteger = "%identity" +external castNodeKeyValue: node => nodeKeyValue = "%identity" +external castNodeLambda: node => nodeLambda = "%identity" +external castNodeLetStatement: node => nodeLetStatement = "%identity" +external castNodeString: node => nodeString = "%identity" +external castNodeTernary: node => nodeTernary = "%identity" + +exception UnsupportedPeggyNodeType(string) // This should never happen; programming error +let castNodeType = (node: node) => + switch node["type"] { + | "Block" => node->castNodeBlock->PgNodeBlock + | "Boolean" => node->castNodeBoolean->PgNodeBoolean + | "CallIdentifier" => node->castNodeCallIdentifier->PgNodeCallIdentifier + | "Expression" => node->castNodeExpression->PgNodeExpression + | "Float" => node->castNodeFloat->PgNodeFloat + | "Identifier" => node->castNodeIdentifier->PgNodeIdentifier + | "Integer" => node->castNodeInteger->PgNodeInteger + | "KeyValue" => node->castNodeKeyValue->PgNodeKeyValue + | "Lambda" => node->castNodeLambda->PgNodeLambda + | "LetStatement" => node->castNodeLetStatement->PgNodeLetStatement + | "String" => node->castNodeString->PgNodeString + | "Ternary" => node->castNodeTernary->PgNodeTernary + | _ => raise(UnsupportedPeggyNodeType(node["type"])) + } + +let rec pgToString = (peggyNode: peggyNode): string => { + let argsToString = (args: array): string => + args->Js.Array2.map(arg => PgNodeIdentifier(arg)->pgToString)->Js.Array2.toString + + let nodesToStringUsingSeparator = (nodes: array, separator: string): string => + nodes->Js.Array2.map(toString)->Extra.Array.interperse(separator)->Js.String.concatMany("") + + switch peggyNode { + | PgNodeBlock(node) => "{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}" + | PgNodeBoolean(node) => node["value"]->Js.String.make + | PgNodeCallIdentifier(node) => `::${Js.String.make(node["value"])}` // This is an identifier also but for function names + | PgNodeExpression(node) => "(" ++ node["nodes"]->nodesToStringUsingSeparator(" ") ++ ")" + | PgNodeFloat(node) => node["value"]->Js.String.make + | PgNodeIdentifier(node) => `:${node["value"]}` + | PgNodeInteger(node) => node["value"]->Js.String.make + | PgNodeKeyValue(node) => toString(node["key"]) ++ ": " ++ toString(node["value"]) + | PgNodeLambda(node) => + "{|" ++ node["args"]->argsToString ++ "| " ++ pgToString(PgNodeBlock(node["body"])) ++ "}" + | PgNodeLetStatement(node) => + pgToString(PgNodeIdentifier(node["variable"])) ++ " = " ++ toString(node["value"]) + | PgNodeString(node) => `'${node["value"]->Js.String.make}'` + | PgNodeTernary(node) => + "(::$$_ternary_$$ " ++ + toString(node["condition"]) ++ + " " ++ + toString(node["trueExpression"]) ++ + " " ++ + toString(node["falseExpression"]) ++ ")" + } +} +and toString = (node: node): string => node->castNodeType->pgToString + +let toStringResult = (rNode: result): string => + switch rNode { + | Ok(node) => toString(node) + | Error(error) => `Error(${errorToString(error)})` + } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res new file mode 100644 index 00000000..a9d4fb22 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res @@ -0,0 +1,48 @@ +module ExpressionBuilder = Reducer_Expression_ExpressionBuilder +module ExpressionT = Reducer_Expression_T +module Parse = Reducer_Peggy_Parse + +type expression = ExpressionT.expression + +let rec fromNode = (node: Parse.node): expression => { + let caseBlock = nodeBlock => + ExpressionBuilder.eBlock(nodeBlock["statements"]->Js.Array2.map(fromNode)->Belt.List.fromArray) + + let caseLambda = (nodeLambda: Parse.nodeLambda): expression => { + let args = + nodeLambda["args"] + ->Js.Array2.map((argNode: Parse.nodeIdentifier) => argNode["value"]) + ->ExpressionBuilder.eArrayString + let body = nodeLambda["body"]->caseBlock + ExpressionBuilder.eFunction("$$_lambda_$$", list{args, body}) + } + + switch Parse.castNodeType(node) { + | PgNodeBlock(nodeBlock) => caseBlock(nodeBlock) + | PgNodeBoolean(nodeBoolean) => ExpressionBuilder.eBool(nodeBoolean["value"]) + | PgNodeCallIdentifier(nodeCallIdentifier) => ExpressionBuilder.eCall(nodeCallIdentifier["value"]) + | PgNodeExpression(nodeExpression) => + ExpressionT.EList(nodeExpression["nodes"]->Js.Array2.map(fromNode)->Belt.List.fromArray) + | PgNodeFloat(nodeFloat) => ExpressionBuilder.eNumber(nodeFloat["value"]) + | PgNodeIdentifier(nodeIdentifier) => ExpressionBuilder.eSymbol(nodeIdentifier["value"]) + | PgNodeInteger(nodeInteger) => ExpressionBuilder.eNumber(Belt.Int.toFloat(nodeInteger["value"])) + | PgNodeKeyValue(nodeKeyValue) => + ExpressionT.EList(list{fromNode(nodeKeyValue["key"]), fromNode(nodeKeyValue["value"])}) + | PgNodeLambda(nodeLambda) => caseLambda(nodeLambda) + | PgNodeLetStatement(nodeLetStatement) => + ExpressionBuilder.eLetStatement( + nodeLetStatement["variable"]["value"], + fromNode(nodeLetStatement["value"]), + ) + | PgNodeString(nodeString) => ExpressionBuilder.eString(nodeString["value"]) + | PgNodeTernary(nodeTernary) => + ExpressionBuilder.eFunction( + "$$_ternary_$$", + list{ + fromNode(nodeTernary["condition"]), + fromNode(nodeTernary["trueExpression"]), + fromNode(nodeTernary["falseExpression"]), + }, + ) + } +} diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 5c9ee4b7..7b896509 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -87,6 +87,12 @@ let toStringResult = x => | Error(m) => `Error(${ErrorValue.errorToString(m)})` } +let toStringResultOkless = (codeResult: result): string => + switch codeResult { + | Ok(a) => toString(a) + | Error(m) => `Error(${ErrorValue.errorToString(m)})` + } + let toStringResultRecord = x => switch x { | Ok(a) => `Ok(${toStringRecord(a)})` @@ -98,3 +104,57 @@ type environment = DistributionOperation.env @genType let defaultEnvironment: environment = DistributionOperation.defaultEnv + +type expressionValueType = + | EvtArray + | EvtArrayString + | EvtBool + | EvtCall + | EvtDistribution + | EvtLambda + | EvtNumber + | EvtRecord + | EvtString + | EvtSymbol + +type functionCallSignature = CallSignature(string, array) +type functionDefinitionSignature = + FunctionDefinitionSignature(functionCallSignature, expressionValueType) + +let valueToValueType = value => + switch value { + | EvArray(_) => EvtArray + | EvArrayString(_) => EvtArray + | EvBool(_) => EvtBool + | EvCall(_) => EvtCall + | EvDistribution(_) => EvtDistribution + | EvLambda(_) => EvtLambda + | EvNumber(_) => EvtNumber + | EvRecord(_) => EvtRecord + | EvString(_) => EvtArray + | EvSymbol(_) => EvtSymbol + } + +let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => { + let (fn, args) = functionCall + CallSignature(fn, args->Js.Array2.map(valueToValueType)) +} + +let valueTypeToString = (valueType: expressionValueType): string => + switch valueType { + | EvtArray => `Array` + | EvtArrayString => `ArrayString` + | EvtBool => `Bool` + | EvtCall => `Call` + | EvtDistribution => `Distribution` + | EvtLambda => `Lambda` + | EvtNumber => `Number` + | EvtRecord => `Record` + | EvtString => `String` + | EvtSymbol => `Symbol` + } + +let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => { + let CallSignature(fn, args) = functionCallSignature + `${fn}(${args->Js.Array2.map(valueTypeToString)->Js.Array2.toString})` +} diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 8366818a..fa152c6f 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -188,14 +188,15 @@ module SymbolicConstructors = { let twoFloat = name => switch name { - | "normal" => Ok(SymbolicDist.Normal.make) - | "uniform" => Ok(SymbolicDist.Uniform.make) | "beta" => Ok(SymbolicDist.Beta.make) - | "lognormal" => Ok(SymbolicDist.Lognormal.make) - | "logistic" => Ok(SymbolicDist.Logistic.make) | "cauchy" => Ok(SymbolicDist.Cauchy.make) + | "credibleIntervalToDistribution" => Ok(SymbolicDist.From90thPercentile.make) | "gamma" => Ok(SymbolicDist.Gamma.make) - | "to" => Ok(SymbolicDist.From90thPercentile.make) + | "logistic" => Ok(SymbolicDist.Logistic.make) + | "lognormal" => Ok(SymbolicDist.Lognormal.make) + | "normal" => Ok(SymbolicDist.Normal.make) + | "to" => Ok(SymbolicDist.From90thPercentile.make) // as credibleIntervalToDistribution is defined "to" might be redundant + | "uniform" => Ok(SymbolicDist.Uniform.make) | _ => Error("Unreachable state") } @@ -233,6 +234,7 @@ let dispatchToGenericOutput = ( | "lognormal" | "cauchy" | "gamma" + | "credibleIntervalToDistribution" | "to" | "logistic") as fnName, [EvNumber(f1), EvNumber(f2)], diff --git a/yarn.lock b/yarn.lock index 1a8f9e89..3ba8e213 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13102,6 +13102,11 @@ pdfast@^0.2.0: resolved "https://registry.yarnpkg.com/pdfast/-/pdfast-0.2.0.tgz#8cbc556e1bf2522177787c0de2e0d4373ba885c9" integrity sha1-jLxVbhvyUiF3eHwN4uDUNzuohck= +peggy@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/peggy/-/peggy-1.2.0.tgz#657ba45900cbef1dc9f52356704bdbb193c2021c" + integrity sha512-PQ+NKpAobImfMprYQtc4Egmyi29bidRGEX0kKjCU5uuW09s0Cthwqhfy7mLkwcB4VcgacE5L/ZjruD/kOPCUUw== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"