commit
						263c4271bf
					
				| 
						 | 
					@ -6,15 +6,18 @@ open Expect
 | 
				
			||||||
let expectEvalToBe = (expr: string, answer: string) =>
 | 
					let expectEvalToBe = (expr: string, answer: string) =>
 | 
				
			||||||
  Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
 | 
					  Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testEval = (expr, answer) =>
 | 
				
			||||||
 | 
					  test(expr, () => expectEvalToBe(expr, answer))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("builtin", () => {
 | 
					describe("builtin", () => {
 | 
				
			||||||
  // All MathJs operators and functions are available for string, number and boolean
 | 
					  // All MathJs operators and functions are available for string, number and boolean
 | 
				
			||||||
  // .e.g + - / * > >= < <= == /= not and or
 | 
					  // .e.g + - / * > >= < <= == /= not and or
 | 
				
			||||||
  // See https://mathjs.org/docs/expressions/syntax.html
 | 
					  // See https://mathjs.org/docs/expressions/syntax.html
 | 
				
			||||||
  // See https://mathjs.org/docs/reference/functions.html
 | 
					  // See https://mathjs.org/docs/reference/functions.html
 | 
				
			||||||
  test("-1", () => expectEvalToBe("-1", "Ok(-1)"))
 | 
					  testEval("-1", "Ok(-1)")
 | 
				
			||||||
  test("1-1", () => expectEvalToBe("1-1", "Ok(0)"))
 | 
					  testEval("1-1", "Ok(0)")
 | 
				
			||||||
  test("2>1", () => expectEvalToBe("2>1", "Ok(true)"))
 | 
					  testEval("2>1", "Ok(true)")
 | 
				
			||||||
  test("concat('a','b')", () => expectEvalToBe("concat('a','b')", "Ok('ab')"))
 | 
					  testEval("concat('a','b')", "Ok('ab')")
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("builtin exception", () => {
 | 
					describe("builtin exception", () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,45 +7,60 @@ open Expect
 | 
				
			||||||
let expectParseToBe = (expr, answer) =>
 | 
					let expectParseToBe = (expr, answer) =>
 | 
				
			||||||
  Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(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))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("MathJs parse", () => {
 | 
					describe("MathJs parse", () => {
 | 
				
			||||||
  describe("literals operators paranthesis", () => {
 | 
					  describe("literals operators paranthesis", () => {
 | 
				
			||||||
    test("1", () => expectParseToBe("1", "1"))
 | 
					    testParse("1", "1")
 | 
				
			||||||
    test("'hello'", () => expectParseToBe("'hello'", "'hello'"))
 | 
					    testParse("'hello'", "'hello'")
 | 
				
			||||||
    test("true", () => expectParseToBe("true", "true"))
 | 
					    testParse("true", "true")
 | 
				
			||||||
    test("1+2", () => expectParseToBe("1+2", "add(1, 2)"))
 | 
					    testParse("1+2", "add(1, 2)")
 | 
				
			||||||
    test("add(1,2)", () => expectParseToBe("add(1,2)", "add(1, 2)"))
 | 
					    testParse("add(1,2)", "add(1, 2)")
 | 
				
			||||||
    test("(1)", () => expectParseToBe("(1)", "(1)"))
 | 
					    testParse("(1)", "(1)")
 | 
				
			||||||
    test("(1+2)", () => expectParseToBe("(1+2)", "(add(1, 2))"))
 | 
					    testParse("(1+2)", "(add(1, 2))")
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe("multi-line", () => {
 | 
				
			||||||
 | 
					    testParse("1; 2", "{1; 2}")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("variables", () => {
 | 
					  describe("variables", () => {
 | 
				
			||||||
    Skip.test("define", () => expectParseToBe("x = 1", "???"))
 | 
					    testParse("x = 1", "x = 1")
 | 
				
			||||||
    Skip.test("use", () => expectParseToBe("x", "???"))
 | 
					    testParse("x", "x")
 | 
				
			||||||
 | 
					    testParse("x = 1; x", "{x = 1; x}")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("functions", () => {
 | 
					  describe("functions", () => {
 | 
				
			||||||
    Skip.test("define", () => expectParseToBe("identity(x) = x", "???"))
 | 
					    MySkip.testParse("identity(x) = x", "???")
 | 
				
			||||||
    Skip.test("use", () => expectParseToBe("identity(x)", "???"))
 | 
					    MySkip.testParse("identity(x)", "???")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("arrays", () => {
 | 
					  describe("arrays", () => {
 | 
				
			||||||
    test("empty", () => expectParseToBe("[]", "[]"))
 | 
					    testDescriptionParse("empty", "[]", "[]")
 | 
				
			||||||
    test("define", () => expectParseToBe("[0, 1, 2]", "[0, 1, 2]"))
 | 
					    testDescriptionParse("define", "[0, 1, 2]", "[0, 1, 2]")
 | 
				
			||||||
    test("define with strings", () => expectParseToBe("['hello', 'world']", "['hello', 'world']"))
 | 
					    testDescriptionParse("define with strings", "['hello', 'world']", "['hello', 'world']")
 | 
				
			||||||
    Skip.test("range", () => expectParseToBe("range(0, 4)", "range(0, 4)"))
 | 
					    MySkip.testParse("range(0, 4)", "range(0, 4)")
 | 
				
			||||||
    test("index", () => expectParseToBe("([0,1,2])[1]", "([0, 1, 2])[1]"))
 | 
					    testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("records", () => {
 | 
					  describe("records", () => {
 | 
				
			||||||
    test("define", () => expectParseToBe("{a: 1, b: 2}", "{a: 1, b: 2}"))
 | 
					    testDescriptionParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}")
 | 
				
			||||||
    test("use", () => expectParseToBe("record.property", "record['property']"))
 | 
					    testDescriptionParse("use", "record.property", "record['property']")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("comments", () => {
 | 
					  describe("comments", () => {
 | 
				
			||||||
    Skip.test("define", () => expectParseToBe("# This is a comment", "???"))
 | 
					    MySkip.testDescriptionParse("define", "# This is a comment", "???")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("if statement", () => {
 | 
					  describe("if statement", () => { // TODO Tertiary operator instead
 | 
				
			||||||
    Skip.test("define", () => expectParseToBe("if (true) { 1 } else { 0 }", "???"))
 | 
					    MySkip.testDescriptionParse("define", "if (true) { 1 } else { 0 }", "???")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,14 @@
 | 
				
			||||||
open Jest
 | 
					open Jest
 | 
				
			||||||
open Reducer_TestHelpers
 | 
					open Reducer_TestHelpers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testDescriptionParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("reducer using mathjs parse", () => {
 | 
					describe("reducer using mathjs parse", () => {
 | 
				
			||||||
  // Test the MathJs parser compatibility
 | 
					  // Test the MathJs parser compatibility
 | 
				
			||||||
  // Those tests toString that there is a semantic mapping from MathJs to Expression
 | 
					  // Those tests toString that there is a semantic mapping from MathJs to Expression
 | 
				
			||||||
| 
						 | 
					@ -10,33 +18,39 @@ describe("reducer using mathjs parse", () => {
 | 
				
			||||||
  // Those tests toString that we are converting mathjs parse tree to what we need
 | 
					  // Those tests toString that we are converting mathjs parse tree to what we need
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("expressions", () => {
 | 
					  describe("expressions", () => {
 | 
				
			||||||
    test("1", () => expectParseToBe("1", "Ok(1)"))
 | 
					    testParseToBe("1", "Ok(1)")
 | 
				
			||||||
    test("(1)", () => expectParseToBe("(1)", "Ok(1)"))
 | 
					    testParseToBe("(1)", "Ok(1)")
 | 
				
			||||||
    test("1+2", () => expectParseToBe("1+2", "Ok((:add 1 2))"))
 | 
					    testParseToBe("1+2", "Ok((:add 1 2))")
 | 
				
			||||||
    test("(1+2)", () => expectParseToBe("1+2", "Ok((:add 1 2))"))
 | 
					    testParseToBe("1+2", "Ok((:add 1 2))")
 | 
				
			||||||
    test("add(1,2)", () => expectParseToBe("1+2", "Ok((:add 1 2))"))
 | 
					    testParseToBe("1+2", "Ok((:add 1 2))")
 | 
				
			||||||
    test("1+2*3", () => expectParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))"))
 | 
					    testParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  describe("arrays", () => {
 | 
					  describe("arrays", () => {
 | 
				
			||||||
    //Note. () is a empty list in Lisp
 | 
					    //Note. () is a empty list in Lisp
 | 
				
			||||||
    //  The only builtin structure in Lisp is list. There are no arrays
 | 
					    //  The only builtin structure in Lisp is list. There are no arrays
 | 
				
			||||||
    //  [1,2,3] becomes (1 2 3)
 | 
					    //  [1,2,3] becomes (1 2 3)
 | 
				
			||||||
    test("empty", () => expectParseToBe("[]", "Ok(())"))
 | 
					    testDescriptionParseToBe("empty", "[]", "Ok(())")
 | 
				
			||||||
    test("[1, 2, 3]", () => expectParseToBe("[1, 2, 3]", "Ok((1 2 3))"))
 | 
					    testParseToBe("[1, 2, 3]", "Ok((1 2 3))")
 | 
				
			||||||
    test("['hello', 'world']", () => expectParseToBe("['hello', 'world']", "Ok(('hello' 'world'))"))
 | 
					    testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")
 | 
				
			||||||
    test("index", () => expectParseToBe("([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))"))
 | 
					    testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  describe("records", () => {
 | 
					  describe("records", () => {
 | 
				
			||||||
    test("define", () =>
 | 
					    testDescriptionParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))")
 | 
				
			||||||
      expectParseToBe("{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))")
 | 
					    testDescriptionParseToBe(
 | 
				
			||||||
    )
 | 
					      "use",
 | 
				
			||||||
    test("use", () =>
 | 
					      "{a: 1, b: 2}.a",
 | 
				
			||||||
      expectParseToBe(
 | 
					      "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))",
 | 
				
			||||||
        "{a: 1, b: 2}.a",
 | 
					 | 
				
			||||||
        "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))",
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					  describe("multi-line", () => {
 | 
				
			||||||
 | 
					    testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))")
 | 
				
			||||||
 | 
					    testParseToBe("1+1; 2+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))")
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  describe("assignment", () => {
 | 
				
			||||||
 | 
					    testParseToBe("x=1; x", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))")
 | 
				
			||||||
 | 
					    testParseToBe("x=1+1; x+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))")
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("eval", () => {
 | 
					describe("eval", () => {
 | 
				
			||||||
| 
						 | 
					@ -45,37 +59,47 @@ describe("eval", () => {
 | 
				
			||||||
  // See https://mathjs.org/docs/expressions/syntax.html
 | 
					  // See https://mathjs.org/docs/expressions/syntax.html
 | 
				
			||||||
  // See https://mathjs.org/docs/reference/functions.html
 | 
					  // See https://mathjs.org/docs/reference/functions.html
 | 
				
			||||||
  describe("expressions", () => {
 | 
					  describe("expressions", () => {
 | 
				
			||||||
    test("1", () => expectEvalToBe("1", "Ok(1)"))
 | 
					    testEvalToBe("1", "Ok(1)")
 | 
				
			||||||
    test("1+2", () => expectEvalToBe("1+2", "Ok(3)"))
 | 
					    testEvalToBe("1+2", "Ok(3)")
 | 
				
			||||||
    test("(1+2)*3", () => expectEvalToBe("(1+2)*3", "Ok(9)"))
 | 
					    testEvalToBe("(1+2)*3", "Ok(9)")
 | 
				
			||||||
    test("2>1", () => expectEvalToBe("2>1", "Ok(true)"))
 | 
					    testEvalToBe("2>1", "Ok(true)")
 | 
				
			||||||
    test("concat('a ', 'b')", () => expectEvalToBe("concat('a ', 'b')", "Ok('a b')"))
 | 
					    testEvalToBe("concat('a ', 'b')", "Ok('a b')")
 | 
				
			||||||
    test("log(10)", () => expectEvalToBe("log(10)", "Ok(2.302585092994046)"))
 | 
					    testEvalToBe("log(10)", "Ok(2.302585092994046)")
 | 
				
			||||||
    test("cos(10)", () => expectEvalToBe("cos(10)", "Ok(-0.8390715290764524)"))
 | 
					    testEvalToBe("cos(10)", "Ok(-0.8390715290764524)")
 | 
				
			||||||
    // TODO more built ins
 | 
					    // TODO more built ins
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  describe("arrays", () => {
 | 
					  describe("arrays", () => {
 | 
				
			||||||
    test("empty array", () => expectEvalToBe("[]", "Ok([])"))
 | 
					    test("empty array", () => expectEvalToBe("[]", "Ok([])"))
 | 
				
			||||||
    test("[1, 2, 3]", () => expectEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])"))
 | 
					    testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])")
 | 
				
			||||||
    test("['hello', 'world']", () => expectEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])"))
 | 
					    testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])")
 | 
				
			||||||
    test("index", () => expectEvalToBe("([0,1,2])[1]", "Ok(1)"))
 | 
					    testEvalToBe("([0,1,2])[1]", "Ok(1)")
 | 
				
			||||||
    test("index not found", () =>
 | 
					    testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
 | 
				
			||||||
      expectEvalToBe("([0,1,2])[10]", "Error(Array index not found: 10)")
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  describe("records", () => {
 | 
					  describe("records", () => {
 | 
				
			||||||
    test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})"))
 | 
					    test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})"))
 | 
				
			||||||
    test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)"))
 | 
					    test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)"))
 | 
				
			||||||
    test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)"))
 | 
					    test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)"))
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe("multi-line", () => {
 | 
				
			||||||
 | 
					    testEvalToBe("1; 2", "Error(Assignment expected)")
 | 
				
			||||||
 | 
					    testEvalToBe("1+1; 2+1", "Error(Assignment expected)")
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  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)")
 | 
				
			||||||
 | 
					    testEvalToBe("x=1; x=1", "Error(Expression expected)")
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("test exceptions", () => {
 | 
					describe("test exceptions", () => {
 | 
				
			||||||
  test("javascript exception", () =>
 | 
					  testDescriptionEvalToBe(
 | 
				
			||||||
    expectEvalToBe("jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')")
 | 
					    "javascript exception",
 | 
				
			||||||
  )
 | 
					    "javascriptraise('div by 0')",
 | 
				
			||||||
 | 
					    "Error(JS Exception: Error: 'div by 0')",
 | 
				
			||||||
  test("rescript exception", () =>
 | 
					 | 
				
			||||||
    expectEvalToBe("resraise()", "Error(TODO: unhandled rescript exception)")
 | 
					 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					  testDescriptionEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)")
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,6 +88,7 @@ function tag<a, b>(x: a, y: b): tagged<a, b> {
 | 
				
			||||||
export type squiggleExpression =
 | 
					export type squiggleExpression =
 | 
				
			||||||
  | tagged<"symbol", string>
 | 
					  | tagged<"symbol", string>
 | 
				
			||||||
  | tagged<"string", string>
 | 
					  | tagged<"string", string>
 | 
				
			||||||
 | 
					  | tagged<"call", string>
 | 
				
			||||||
  | tagged<"array", squiggleExpression[]>
 | 
					  | tagged<"array", squiggleExpression[]>
 | 
				
			||||||
  | tagged<"boolean", boolean>
 | 
					  | tagged<"boolean", boolean>
 | 
				
			||||||
  | tagged<"distribution", Distribution>
 | 
					  | tagged<"distribution", Distribution>
 | 
				
			||||||
| 
						 | 
					@ -117,6 +118,8 @@ function createTsExport(
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    case "EvBool":
 | 
					    case "EvBool":
 | 
				
			||||||
      return tag("boolean", x.value);
 | 
					      return tag("boolean", x.value);
 | 
				
			||||||
 | 
					    case "EvCall":
 | 
				
			||||||
 | 
					      return tag("call", x.value);
 | 
				
			||||||
    case "EvDistribution":
 | 
					    case "EvDistribution":
 | 
				
			||||||
      return tag("distribution", new Distribution(x.value, sampEnv));
 | 
					      return tag("distribution", new Distribution(x.value, sampEnv));
 | 
				
			||||||
    case "EvNumber":
 | 
					    case "EvNumber":
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,8 @@ exception TestRescriptException
 | 
				
			||||||
let callInternal = (call: functionCall): result<'b, errorValue> => {
 | 
					let callInternal = (call: functionCall): result<'b, errorValue> => {
 | 
				
			||||||
  let callMathJs = (call: functionCall): result<'b, errorValue> =>
 | 
					  let callMathJs = (call: functionCall): result<'b, errorValue> =>
 | 
				
			||||||
    switch call {
 | 
					    switch call {
 | 
				
			||||||
    | ("jsraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
 | 
					    | ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
 | 
				
			||||||
    | ("resraise", _) => raise(TestRescriptException) // For Tests
 | 
					    | ("rescriptraise", _) => raise(TestRescriptException) // For Tests
 | 
				
			||||||
    | call => call->toStringFunctionCall->MathJs.Eval.eval
 | 
					    | call => call->toStringFunctionCall->MathJs.Eval.eval
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@ let callInternal = (call: functionCall): result<'b, errorValue> => {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  Lisp engine uses Result monad while reducing expressions
 | 
					  Reducer uses Result monad while reducing expressions
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
let dispatch = (call: functionCall): result<expressionValue, errorValue> =>
 | 
					let dispatch = (call: functionCall): result<expressionValue, errorValue> =>
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,14 @@
 | 
				
			||||||
@genType
 | 
					@genType
 | 
				
			||||||
type errorValue =
 | 
					type errorValue =
 | 
				
			||||||
  | REArrayIndexNotFound(string, int)
 | 
					  | REArrayIndexNotFound(string, int)
 | 
				
			||||||
 | 
					  | REAssignmentExpected
 | 
				
			||||||
 | 
					  | REExpressionExpected
 | 
				
			||||||
  | REFunctionExpected(string)
 | 
					  | REFunctionExpected(string)
 | 
				
			||||||
  | REJavaScriptExn(option<string>, option<string>) // Javascript Exception
 | 
					  | REJavaScriptExn(option<string>, option<string>) // Javascript Exception
 | 
				
			||||||
 | 
					  | REMacroNotFound(string)
 | 
				
			||||||
  | RERecordPropertyNotFound(string, string)
 | 
					  | RERecordPropertyNotFound(string, string)
 | 
				
			||||||
 | 
					  | RESymbolNotFound(string)
 | 
				
			||||||
 | 
					  | RESyntaxError(string)
 | 
				
			||||||
  | RETodo(string) // To do
 | 
					  | RETodo(string) // To do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type t = errorValue
 | 
					type t = errorValue
 | 
				
			||||||
| 
						 | 
					@ -12,6 +17,8 @@ type t = errorValue
 | 
				
			||||||
let errorToString = err =>
 | 
					let errorToString = err =>
 | 
				
			||||||
  switch err {
 | 
					  switch err {
 | 
				
			||||||
  | REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
 | 
					  | REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
 | 
				
			||||||
 | 
					  | REAssignmentExpected => "Assignment expected"
 | 
				
			||||||
 | 
					  | REExpressionExpected => "Expression expected"
 | 
				
			||||||
  | REFunctionExpected(msg) => `Function expected: ${msg}`
 | 
					  | REFunctionExpected(msg) => `Function expected: ${msg}`
 | 
				
			||||||
  | REJavaScriptExn(omsg, oname) => {
 | 
					  | REJavaScriptExn(omsg, oname) => {
 | 
				
			||||||
      let answer = "JS Exception:"
 | 
					      let answer = "JS Exception:"
 | 
				
			||||||
| 
						 | 
					@ -25,6 +32,9 @@ let errorToString = err =>
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      answer
 | 
					      answer
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  | REMacroNotFound(macro) => `Macro not found: ${macro}`
 | 
				
			||||||
  | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}`
 | 
					  | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}`
 | 
				
			||||||
 | 
					  | RESymbolNotFound(symbolName) => `${symbolName} is not defined`
 | 
				
			||||||
 | 
					  | RESyntaxError(desc) => `Syntax Error: ${desc}`
 | 
				
			||||||
  | RETodo(msg) => `TODO: ${msg}`
 | 
					  | RETodo(msg) => `TODO: ${msg}`
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,10 +11,11 @@ type expressionValue = ExpressionValue.expressionValue
 | 
				
			||||||
type t = expression
 | 
					type t = expression
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  Shows the Lisp Code as text lisp code
 | 
					  Shows the expression as text of expression
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
let rec toString = expression =>
 | 
					let rec toString = expression =>
 | 
				
			||||||
  switch expression {
 | 
					  switch expression {
 | 
				
			||||||
 | 
					  | T.EBindings(bindings) => "$$bound"
 | 
				
			||||||
  | T.EList(aList) =>
 | 
					  | T.EList(aList) =>
 | 
				
			||||||
    `(${Belt.List.map(aList, aValue => toString(aValue))
 | 
					    `(${Belt.List.map(aList, aValue => toString(aValue))
 | 
				
			||||||
      ->Extra.List.interperse(" ")
 | 
					      ->Extra.List.interperse(" ")
 | 
				
			||||||
| 
						 | 
					@ -30,7 +31,7 @@ let toStringResult = codeResult =>
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  Converts a MathJs code to Lisp Code
 | 
					  Converts a MathJs code to expression
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
 | 
					let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
 | 
				
			||||||
  expr->parser->Result.flatMap(node => converter(node))
 | 
					  expr->parser->Result.flatMap(node => converter(node))
 | 
				
			||||||
| 
						 | 
					@ -38,54 +39,141 @@ let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
 | 
				
			||||||
let parse = (mathJsCode: string): result<t, errorValue> =>
 | 
					let parse = (mathJsCode: string): result<t, errorValue> =>
 | 
				
			||||||
  mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
 | 
					  mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module MapString = Belt.Map.String
 | 
					let defaultBindings: T.bindings = Belt.Map.String.empty
 | 
				
			||||||
type bindings = MapString.t<unit>
 | 
					 | 
				
			||||||
let defaultBindings: bindings = MapString.fromArray([])
 | 
					 | 
				
			||||||
// TODO Define bindings for function execution context
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  After reducing each level of code tree, we have a value list to evaluate
 | 
					  Recursively evaluate/reduce the expression (Lisp AST)
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
let reduceValueList = (valueList: list<expressionValue>): result<expressionValue, 'e> =>
 | 
					let rec reduceExpression = (expression: t, bindings: T.bindings): result<expressionValue, 'e> => {
 | 
				
			||||||
  switch valueList {
 | 
					  /*
 | 
				
			||||||
  | list{EvSymbol(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch
 | 
					    After reducing each level of expression(Lisp AST), we have a value list to evaluate
 | 
				
			||||||
  | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
 | 
					 */
 | 
				
			||||||
  }
 | 
					  let reduceValueList = (valueList: list<expressionValue>): result<expressionValue, 'e> =>
 | 
				
			||||||
 | 
					    switch valueList {
 | 
				
			||||||
/*
 | 
					    | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch
 | 
				
			||||||
  Recursively evaluate/reduce the code tree
 | 
					    | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
let rec reduceExpression = (expression: t, bindings): result<expressionValue, 'e> =>
 | 
					 | 
				
			||||||
  switch expression {
 | 
					 | 
				
			||||||
  | T.EValue(value) => value->Ok
 | 
					 | 
				
			||||||
  | T.EList(list) => {
 | 
					 | 
				
			||||||
      let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
 | 
					 | 
				
			||||||
        racc,
 | 
					 | 
				
			||||||
        each: expression,
 | 
					 | 
				
			||||||
      ) =>
 | 
					 | 
				
			||||||
        racc->Result.flatMap(acc => {
 | 
					 | 
				
			||||||
          each
 | 
					 | 
				
			||||||
          ->reduceExpression(bindings)
 | 
					 | 
				
			||||||
          ->Result.flatMap(newNode => {
 | 
					 | 
				
			||||||
            acc->Belt.List.add(newNode)->Ok
 | 
					 | 
				
			||||||
          })
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      racc->Result.flatMap(acc => acc->reduceValueList)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					    Macros are like functions but instead of taking values as parameters,
 | 
				
			||||||
 | 
					    they take expressions as parameters and return a new expression.
 | 
				
			||||||
 | 
					    Macros are used to define language building blocks. They are like Lisp macros.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					  let doMacroCall = (list: list<t>, bindings: T.bindings): result<t, 'e> => {
 | 
				
			||||||
 | 
					    let dispatchMacroCall = (list: list<t>, bindings: T.bindings): result<t, 'e> => {
 | 
				
			||||||
 | 
					      let rec replaceSymbols = (expression: t, bindings: T.bindings): result<t, errorValue> =>
 | 
				
			||||||
 | 
					        switch expression {
 | 
				
			||||||
 | 
					        | T.EValue(EvSymbol(aSymbol)) =>
 | 
				
			||||||
 | 
					          switch bindings->Belt.Map.String.get(aSymbol) {
 | 
				
			||||||
 | 
					          | Some(boundExpression) => boundExpression->Ok
 | 
				
			||||||
 | 
					          | None => RESymbolNotFound(aSymbol)->Error
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        | T.EValue(_) => expression->Ok
 | 
				
			||||||
 | 
					        | T.EBindings(_) => expression->Ok
 | 
				
			||||||
 | 
					        | T.EList(list) => {
 | 
				
			||||||
 | 
					            let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
 | 
				
			||||||
 | 
					              racc->Result.flatMap(acc => {
 | 
				
			||||||
 | 
					                each
 | 
				
			||||||
 | 
					                ->replaceSymbols(bindings)
 | 
				
			||||||
 | 
					                ->Result.flatMap(newNode => {
 | 
				
			||||||
 | 
					                  acc->Belt.List.add(newNode)->Ok
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            racc->Result.map(acc => acc->T.EList)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let doBindStatement = (statement: t, bindings: T.bindings) => {
 | 
				
			||||||
 | 
					        switch statement {
 | 
				
			||||||
 | 
					        | T.EList(list{T.EValue(EvCall("$let")), T.EValue(EvSymbol(aSymbol)), expression}) => {
 | 
				
			||||||
 | 
					            let rNewExpression = replaceSymbols(expression, bindings)
 | 
				
			||||||
 | 
					            rNewExpression->Result.map(newExpression =>
 | 
				
			||||||
 | 
					              Belt.Map.String.set(bindings, aSymbol, newExpression)->T.EBindings
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        | _ => REAssignmentExpected->Error
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let doBindExpression = (expression: t, bindings: T.bindings) => {
 | 
				
			||||||
 | 
					        switch expression {
 | 
				
			||||||
 | 
					        | T.EList(list{T.EValue(EvCall("$let")), ..._}) => REExpressionExpected->Error
 | 
				
			||||||
 | 
					        | _ => replaceSymbols(expression, bindings)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      switch list {
 | 
				
			||||||
 | 
					      | list{T.EValue(EvCall("$$bindings"))} => bindings->EBindings->Ok
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      | list{T.EValue(EvCall("$$bindStatement")), T.EBindings(bindings), statement} =>
 | 
				
			||||||
 | 
					        doBindStatement(statement, bindings)
 | 
				
			||||||
 | 
					      | list{T.EValue(EvCall("$$bindExpression")), T.EBindings(bindings), expression} =>
 | 
				
			||||||
 | 
					        doBindExpression(expression, bindings)
 | 
				
			||||||
 | 
					      | _ => list->T.EList->Ok
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list->dispatchMacroCall(bindings)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let rec seekMacros = (expression: t, bindings: T.bindings): result<t, 'e> =>
 | 
				
			||||||
 | 
					    switch expression {
 | 
				
			||||||
 | 
					    | T.EValue(value) => expression->Ok
 | 
				
			||||||
 | 
					    | T.EList(list) => {
 | 
				
			||||||
 | 
					        let racc: result<list<t>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
 | 
				
			||||||
 | 
					          racc,
 | 
				
			||||||
 | 
					          each: expression,
 | 
				
			||||||
 | 
					        ) =>
 | 
				
			||||||
 | 
					          racc->Result.flatMap(acc => {
 | 
				
			||||||
 | 
					            each
 | 
				
			||||||
 | 
					            ->seekMacros(bindings)
 | 
				
			||||||
 | 
					            ->Result.flatMap(newNode => {
 | 
				
			||||||
 | 
					              acc->Belt.List.add(newNode)->Ok
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        racc->Result.flatMap(acc => acc->doMacroCall(bindings))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let rec reduceExpandedExpression = (expression: t): result<expressionValue, 'e> =>
 | 
				
			||||||
 | 
					    switch expression {
 | 
				
			||||||
 | 
					    | T.EValue(value) => value->Ok
 | 
				
			||||||
 | 
					    | T.EList(list) => {
 | 
				
			||||||
 | 
					        let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
 | 
				
			||||||
 | 
					          racc,
 | 
				
			||||||
 | 
					          each: expression,
 | 
				
			||||||
 | 
					        ) =>
 | 
				
			||||||
 | 
					          racc->Result.flatMap(acc => {
 | 
				
			||||||
 | 
					            each
 | 
				
			||||||
 | 
					            ->reduceExpandedExpression
 | 
				
			||||||
 | 
					            ->Result.flatMap(newNode => {
 | 
				
			||||||
 | 
					              acc->Belt.List.add(newNode)->Ok
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        racc->Result.flatMap(acc => acc->reduceValueList)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings)
 | 
				
			||||||
 | 
					  rExpandedExpression->Result.flatMap(expandedExpression =>
 | 
				
			||||||
 | 
					    expandedExpression->reduceExpandedExpression
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let evalWBindingsExpression = (aExpression, bindings): result<expressionValue, 'e> =>
 | 
					let evalWBindingsExpression = (aExpression, bindings): result<expressionValue, 'e> =>
 | 
				
			||||||
  reduceExpression(aExpression, bindings)
 | 
					  reduceExpression(aExpression, bindings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  Evaluates MathJs code via Lisp using bindings and answers the result
 | 
					  Evaluates MathJs code via Reducer using bindings and answers the result
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
let evalWBindings = (codeText: string, bindings: bindings) => {
 | 
					let evalWBindings = (codeText: string, bindings: T.bindings) => {
 | 
				
			||||||
  parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings))
 | 
					  parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  Evaluates MathJs code via Lisp and answers the result
 | 
					  Evaluates MathJs code via Reducer and answers the result
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
let eval = (code: string) => evalWBindings(code, defaultBindings)
 | 
					let eval = (code: string) => evalWBindings(code, defaultBindings)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,29 +0,0 @@
 | 
				
			||||||
module Result = Belt.Result
 | 
					 | 
				
			||||||
module T = Reducer_Expression_T
 | 
					 | 
				
			||||||
type expression = T.expression
 | 
					 | 
				
			||||||
@genType
 | 
					 | 
				
			||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
 | 
					 | 
				
			||||||
type t = expression
 | 
					 | 
				
			||||||
let toString: T.expression => Js.String.t
 | 
					 | 
				
			||||||
let toStringResult: result<T.expression, 'a> => string
 | 
					 | 
				
			||||||
let parse: string => result<expression, Reducer_ErrorValue.t>
 | 
					 | 
				
			||||||
module MapString = Belt.Map.String
 | 
					 | 
				
			||||||
type bindings = MapString.t<unit>
 | 
					 | 
				
			||||||
let defaultBindings: bindings
 | 
					 | 
				
			||||||
let reduceValueList: list<expressionValue> => result<
 | 
					 | 
				
			||||||
  expressionValue,
 | 
					 | 
				
			||||||
  Reducer_ErrorValue.t,
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
let reduceExpression: (expression, 'a) => result<
 | 
					 | 
				
			||||||
  expressionValue,
 | 
					 | 
				
			||||||
  Reducer_ErrorValue.t,
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
let evalWBindingsExpression: (expression, 'a) => result<
 | 
					 | 
				
			||||||
  expressionValue,
 | 
					 | 
				
			||||||
  Reducer_ErrorValue.t,
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
let evalWBindings: (string, bindings) => Result.t<
 | 
					 | 
				
			||||||
  expressionValue,
 | 
					 | 
				
			||||||
  Reducer_ErrorValue.t,
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
let eval: string => Result.t<expressionValue, Reducer_ErrorValue.t>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,15 @@
 | 
				
			||||||
open ReducerInterface.ExpressionValue
 | 
					open ReducerInterface.ExpressionValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  An expression is a Lisp AST. An expression is either a primitive value or a list of expressions.
 | 
				
			||||||
 | 
					  In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is
 | 
				
			||||||
 | 
					     apply e1, e2 -> apply e3 -> ... -> apply eN
 | 
				
			||||||
 | 
					  This is Lisp semantics. It holds true in both eager and lazy evaluations.
 | 
				
			||||||
 | 
					  A Lisp AST contains only expressions/primitive values to apply to their left.
 | 
				
			||||||
 | 
					  The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
type rec expression =
 | 
					type rec expression =
 | 
				
			||||||
  | EList(list<expression>) // A list to map-reduce
 | 
					  | EList(list<expression>) // A list to map-reduce
 | 
				
			||||||
  | EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
 | 
					  | EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
 | 
				
			||||||
 | 
					  | EBindings(bindings) // let/def kind of statements return bindings
 | 
				
			||||||
 | 
					and bindings = Belt.Map.String.t<expression>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,25 +7,31 @@ open Reducer_ErrorValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type node = {"type": string, "isNode": bool, "comment": string}
 | 
					type node = {"type": string, "isNode": bool, "comment": string}
 | 
				
			||||||
type arrayNode = {...node, "items": array<node>}
 | 
					type arrayNode = {...node, "items": array<node>}
 | 
				
			||||||
//assignmentNode
 | 
					type block = {"node": node}
 | 
				
			||||||
//blockNode
 | 
					type blockNode = {...node, "blocks": array<block>}
 | 
				
			||||||
//conditionalNode
 | 
					//conditionalNode
 | 
				
			||||||
type constantNode = {...node, "value": unit}
 | 
					type constantNode = {...node, "value": unit}
 | 
				
			||||||
//functionAssignmentNode
 | 
					//functionAssignmentNode
 | 
				
			||||||
type functionNode = {...node, "fn": string, "args": array<node>}
 | 
					 | 
				
			||||||
type indexNode = {...node, "dimensions": array<node>}
 | 
					type indexNode = {...node, "dimensions": array<node>}
 | 
				
			||||||
type objectNode = {...node, "properties": Js.Dict.t<node>}
 | 
					type objectNode = {...node, "properties": Js.Dict.t<node>}
 | 
				
			||||||
type accessorNode = {...node, "object": node, "index": indexNode}
 | 
					type accessorNode = {...node, "object": node, "index": indexNode, "name": string}
 | 
				
			||||||
type operatorNode = {...functionNode, "op": string}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
//parenthesisNode
 | 
					 | 
				
			||||||
type parenthesisNode = {...node, "content": node}
 | 
					type parenthesisNode = {...node, "content": node}
 | 
				
			||||||
//rangeNode
 | 
					//rangeNode
 | 
				
			||||||
//relationalNode
 | 
					//relationalNode
 | 
				
			||||||
type symbolNode = {...node, "name": string}
 | 
					type symbolNode = {...node, "name": string}
 | 
				
			||||||
 | 
					type functionNode = {...node, "fn": unit, "args": array<node>}
 | 
				
			||||||
 | 
					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<indexNode>}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
external castAccessorNode: node => accessorNode = "%identity"
 | 
					external castAccessorNode: node => accessorNode = "%identity"
 | 
				
			||||||
external castArrayNode: node => arrayNode = "%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 castConstantNode: node => constantNode = "%identity"
 | 
					external castConstantNode: node => constantNode = "%identity"
 | 
				
			||||||
external castFunctionNode: node => functionNode = "%identity"
 | 
					external castFunctionNode: node => functionNode = "%identity"
 | 
				
			||||||
external castIndexNode: node => indexNode = "%identity"
 | 
					external castIndexNode: node => indexNode = "%identity"
 | 
				
			||||||
| 
						 | 
					@ -50,6 +56,8 @@ let parse = (expr: string): result<node, errorValue> =>
 | 
				
			||||||
type mathJsNode =
 | 
					type mathJsNode =
 | 
				
			||||||
  | MjAccessorNode(accessorNode)
 | 
					  | MjAccessorNode(accessorNode)
 | 
				
			||||||
  | MjArrayNode(arrayNode)
 | 
					  | MjArrayNode(arrayNode)
 | 
				
			||||||
 | 
					  | MjAssignmentNode(assignmentNode)
 | 
				
			||||||
 | 
					  | MjBlockNode(blockNode)
 | 
				
			||||||
  | MjConstantNode(constantNode)
 | 
					  | MjConstantNode(constantNode)
 | 
				
			||||||
  | MjFunctionNode(functionNode)
 | 
					  | MjFunctionNode(functionNode)
 | 
				
			||||||
  | MjIndexNode(indexNode)
 | 
					  | MjIndexNode(indexNode)
 | 
				
			||||||
| 
						 | 
					@ -58,10 +66,21 @@ type mathJsNode =
 | 
				
			||||||
  | MjParenthesisNode(parenthesisNode)
 | 
					  | MjParenthesisNode(parenthesisNode)
 | 
				
			||||||
  | MjSymbolNode(symbolNode)
 | 
					  | MjSymbolNode(symbolNode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let castNodeType = (node: node) =>
 | 
					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"] {
 | 
					  switch node["type"] {
 | 
				
			||||||
  | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok
 | 
					  | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok
 | 
				
			||||||
  | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok
 | 
					  | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok
 | 
				
			||||||
 | 
					  | "AssignmentNode" => node->decideAssignmentNode
 | 
				
			||||||
 | 
					  | "BlockNode" => node->castBlockNode->MjBlockNode->Ok
 | 
				
			||||||
  | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok
 | 
					  | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok
 | 
				
			||||||
  | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok
 | 
					  | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok
 | 
				
			||||||
  | "IndexNode" => node->castIndexNode->MjIndexNode->Ok
 | 
					  | "IndexNode" => node->castIndexNode->MjIndexNode->Ok
 | 
				
			||||||
| 
						 | 
					@ -71,6 +90,19 @@ let castNodeType = (node: node) =>
 | 
				
			||||||
  | "SymbolNode" => node->castSymbolNode->MjSymbolNode->Ok
 | 
					  | "SymbolNode" => node->castSymbolNode->MjSymbolNode->Ok
 | 
				
			||||||
  | _ => RETodo(`Argg, unhandled MathJsNode: ${node["type"]}`)->Error
 | 
					  | _ => 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 rec toString = (mathJsNode: mathJsNode): string => {
 | 
				
			||||||
  let toStringValue = (a: 'a): string =>
 | 
					  let toStringValue = (a: 'a): string =>
 | 
				
			||||||
| 
						 | 
					@ -87,9 +119,10 @@ let rec toString = (mathJsNode: mathJsNode): string => {
 | 
				
			||||||
    ->Js.String.concatMany("")
 | 
					    ->Js.String.concatMany("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let toStringFunctionNode = (fnode: functionNode): string =>
 | 
					  let toStringFunctionNode = (fnode: functionNode): string =>
 | 
				
			||||||
    `${fnode["fn"]}(${fnode["args"]->toStringNodeArray})`
 | 
					    `${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let toStringObjectEntry = ((key: string, value: node)): string => `${key}: ${value->toStringMathJsNode}`
 | 
					  let toStringObjectEntry = ((key: string, value: node)): string =>
 | 
				
			||||||
 | 
					    `${key}: ${value->toStringMathJsNode}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let toStringObjectNode = (oNode: objectNode): string =>
 | 
					  let toStringObjectNode = (oNode: objectNode): string =>
 | 
				
			||||||
    `{${oNode["properties"]
 | 
					    `{${oNode["properties"]
 | 
				
			||||||
| 
						 | 
					@ -103,16 +136,28 @@ let rec toString = (mathJsNode: mathJsNode): string => {
 | 
				
			||||||
    ->Belt.Array.map(each => toStringResult(each->castNodeType))
 | 
					    ->Belt.Array.map(each => toStringResult(each->castNodeType))
 | 
				
			||||||
    ->Js.String.concatMany("")
 | 
					    ->Js.String.concatMany("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let toStringBlocks = (blocks: array<block>): string =>
 | 
				
			||||||
 | 
					    blocks
 | 
				
			||||||
 | 
					    ->Belt.Array.map(each => each["node"]->castNodeType->toStringResult)
 | 
				
			||||||
 | 
					    ->Extra.Array.interperse("; ")
 | 
				
			||||||
 | 
					    ->Js.String.concatMany("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch mathJsNode {
 | 
					  switch mathJsNode {
 | 
				
			||||||
  | MjAccessorNode(aNode) => `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]`
 | 
					  | MjAccessorNode(aNode) =>
 | 
				
			||||||
 | 
					    `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]`
 | 
				
			||||||
  | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]`
 | 
					  | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]`
 | 
				
			||||||
 | 
					  | MjAssignmentNode(aNode) =>
 | 
				
			||||||
 | 
					    `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}`
 | 
				
			||||||
 | 
					  | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}`
 | 
				
			||||||
  | MjConstantNode(cNode) => cNode["value"]->toStringValue
 | 
					  | MjConstantNode(cNode) => cNode["value"]->toStringValue
 | 
				
			||||||
  | MjFunctionNode(fNode) => fNode->toStringFunctionNode
 | 
					  | MjFunctionNode(fNode) => fNode->toStringFunctionNode
 | 
				
			||||||
  | MjIndexNode(iNode) => iNode->toStringIndexNode
 | 
					  | MjIndexNode(iNode) => iNode->toStringIndexNode
 | 
				
			||||||
  | MjObjectNode(oNode) => oNode->toStringObjectNode
 | 
					  | MjObjectNode(oNode) => oNode->toStringObjectNode
 | 
				
			||||||
  | MjOperatorNode(opNode) => opNode->castOperatorNodeToFunctionNode->toStringFunctionNode
 | 
					  | MjOperatorNode(opNode) => opNode->castOperatorNodeToFunctionNode->toStringFunctionNode
 | 
				
			||||||
  | MjParenthesisNode(pNode) => `(${toStringMathJsNode(pNode["content"])})`
 | 
					  | MjParenthesisNode(pNode) => `(${toStringMathJsNode(pNode["content"])})`
 | 
				
			||||||
  | MjSymbolNode(sNode) => sNode["name"]
 | 
					  | MjSymbolNode(sNode) => sNode->toStringSymbolNode
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
and toStringResult = (rMathJsNode: result<mathJsNode, errorValue>): string =>
 | 
					and toStringResult = (rMathJsNode: result<mathJsNode, errorValue>): string =>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
module ErrorValue = Reducer_ErrorValue
 | 
					module ErrorValue = Reducer_ErrorValue
 | 
				
			||||||
module ExpressionValue = ReducerInterface.ExpressionValue
 | 
					module ExpressionValue = ReducerInterface.ExpressionValue
 | 
				
			||||||
module ExtressionT = Reducer_Expression_T
 | 
					module ExpressionT = Reducer_Expression_T
 | 
				
			||||||
module JavaScript = Reducer_Js
 | 
					module JavaScript = Reducer_Js
 | 
				
			||||||
module Parse = Reducer_MathJs_Parse
 | 
					module Parse = Reducer_MathJs_Parse
 | 
				
			||||||
module Result = Belt.Result
 | 
					module Result = Belt.Result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type expression = ExtressionT.expression
 | 
					type expression = ExpressionT.expression
 | 
				
			||||||
type expressionValue = ExpressionValue.expressionValue
 | 
					type expressionValue = ExpressionValue.expressionValue
 | 
				
			||||||
type errorValue = ErrorValue.errorValue
 | 
					type errorValue = ErrorValue.errorValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,10 +18,19 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let castFunctionNode = fNode => {
 | 
					    let toEvCallValue = (name: string): expression =>
 | 
				
			||||||
      let fn = fNode["fn"]->ExpressionValue.EvSymbol->ExtressionT.EValue
 | 
					      name->ExpressionValue.EvCall->ExpressionT.EValue
 | 
				
			||||||
 | 
					    let toEvSymbolValue = (name: string): expression =>
 | 
				
			||||||
 | 
					      name->ExpressionValue.EvSymbol->ExpressionT.EValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let passToFunction = (fName: string, rLispArgs): result<expression, errorValue> => {
 | 
				
			||||||
 | 
					      let fn = fName->toEvCallValue
 | 
				
			||||||
 | 
					      rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let caseFunctionNode = fNode => {
 | 
				
			||||||
      let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
 | 
					      let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
 | 
				
			||||||
      lispArgs->Result.map(argsCode => list{fn, ...argsCode}->ExtressionT.EList)
 | 
					      passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let caseObjectNode = oNode => {
 | 
					    let caseObjectNode = oNode => {
 | 
				
			||||||
| 
						 | 
					@ -34,15 +43,16 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
 | 
				
			||||||
            fromNode(value)->Result.map(valueExpression => {
 | 
					            fromNode(value)->Result.map(valueExpression => {
 | 
				
			||||||
              let entryCode =
 | 
					              let entryCode =
 | 
				
			||||||
                list{
 | 
					                list{
 | 
				
			||||||
                  key->ExpressionValue.EvString->ExtressionT.EValue,
 | 
					                  key->ExpressionValue.EvString->ExpressionT.EValue,
 | 
				
			||||||
                  valueExpression,
 | 
					                  valueExpression,
 | 
				
			||||||
                }->ExtressionT.EList
 | 
					                }->ExpressionT.EList
 | 
				
			||||||
              list{entryCode, ...acc}
 | 
					              list{entryCode, ...acc}
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        let lispName = "$constructRecord"->ExpressionValue.EvSymbol->ExtressionT.EValue
 | 
					        rargs->Result.flatMap(args =>
 | 
				
			||||||
        rargs->Result.map(args => list{lispName, ExtressionT.EList(args)}->ExtressionT.EList)
 | 
					          passToFunction("$constructRecord", list{ExpressionT.EList(args)}->Ok)
 | 
				
			||||||
 | 
					        ) // $consturctRecord gets a single argument: List of key-value paiers
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries
 | 
					      oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries
 | 
				
			||||||
| 
						 | 
					@ -54,33 +64,75 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
 | 
				
			||||||
        Ok(list{}),
 | 
					        Ok(list{}),
 | 
				
			||||||
        (racc, currentPropertyMathJsNode) =>
 | 
					        (racc, currentPropertyMathJsNode) =>
 | 
				
			||||||
          racc->Result.flatMap(acc =>
 | 
					          racc->Result.flatMap(acc =>
 | 
				
			||||||
            fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{propertyCode, ...acc})
 | 
					            fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
 | 
				
			||||||
 | 
					              propertyCode,
 | 
				
			||||||
 | 
					              ...acc,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
      rpropertyCodeList->Result.map(propertyCodeList => ExtressionT.EList(propertyCodeList))
 | 
					      rpropertyCodeList->Result.map(propertyCodeList => ExpressionT.EList(propertyCodeList))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let caseAccessorNode = (objectNode, indexNode) => {
 | 
					    let caseAccessorNode = (objectNode, indexNode) => {
 | 
				
			||||||
      let fn = "$atIndex"->ExpressionValue.EvSymbol->ExtressionT.EValue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      caseIndexNode(indexNode)->Result.flatMap(indexCode => {
 | 
					      caseIndexNode(indexNode)->Result.flatMap(indexCode => {
 | 
				
			||||||
        fromNode(objectNode)->Result.map(objectCode =>
 | 
					        fromNode(objectNode)->Result.flatMap(objectCode =>
 | 
				
			||||||
          list{fn, objectCode, indexCode}->ExtressionT.EList
 | 
					          passToFunction("$atIndex", list{objectCode, indexCode}->Ok)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch typedMathJsNode {
 | 
					    let caseAssignmentNode = aNode => {
 | 
				
			||||||
    | MjArrayNode(aNode) =>
 | 
					      let symbol = aNode["object"]["name"]->toEvSymbolValue
 | 
				
			||||||
      aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExtressionT.EList(list))
 | 
					      let rValueExpression = fromNode(aNode["value"])
 | 
				
			||||||
    | MjConstantNode(cNode) =>
 | 
					      rValueExpression->Result.flatMap(valueExpression => {
 | 
				
			||||||
      cNode["value"]->JavaScript.Gate.jsToEv->Result.map(v => v->ExtressionT.EValue)
 | 
					        let lispArgs = list{symbol, valueExpression}->Ok
 | 
				
			||||||
    | MjFunctionNode(fNode) => fNode->castFunctionNode
 | 
					        passToFunction("$let", lispArgs)
 | 
				
			||||||
    | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->castFunctionNode
 | 
					      })
 | 
				
			||||||
    | MjParenthesisNode(pNode) => pNode["content"]->fromNode
 | 
					 | 
				
			||||||
    | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"])
 | 
					 | 
				
			||||||
    | MjObjectNode(oNode) => caseObjectNode(oNode)
 | 
					 | 
				
			||||||
    | MjSymbolNode(sNode) => sNode["name"]->ExpressionValue.EvSymbol->ExtressionT.EValue->Ok
 | 
					 | 
				
			||||||
    | MjIndexNode(iNode) => caseIndexNode(iNode)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let caseArrayNode = aNode => {
 | 
				
			||||||
 | 
					      aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let caseBlockNode = (bNode): result<expression, errorValue> => {
 | 
				
			||||||
 | 
					      let blocks = bNode["blocks"]
 | 
				
			||||||
 | 
					      let initialBindings = passToFunction("$$bindings", list{}->Ok)
 | 
				
			||||||
 | 
					      let lastIndex = Belt.Array.length(blocks) - 1
 | 
				
			||||||
 | 
					      blocks->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, block, i) => {
 | 
				
			||||||
 | 
					        rPreviousBindings->Result.flatMap(previousBindings => {
 | 
				
			||||||
 | 
					          let node = block["node"]
 | 
				
			||||||
 | 
					          let rStatement: result<expression, errorValue> = node->fromNode
 | 
				
			||||||
 | 
					          let bindName = if i == lastIndex {
 | 
				
			||||||
 | 
					            "$$bindExpression"
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            "$$bindStatement"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          rStatement->Result.flatMap((statement: expression) => {
 | 
				
			||||||
 | 
					            let lispArgs = list{previousBindings, statement}->Ok
 | 
				
			||||||
 | 
					            passToFunction(bindName, lispArgs)
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
 | 
				
			||||||
 | 
					    | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"])
 | 
				
			||||||
 | 
					    | MjArrayNode(aNode) => caseArrayNode(aNode)
 | 
				
			||||||
 | 
					    | MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
 | 
				
			||||||
 | 
					    | MjSymbolNode(sNode) => {
 | 
				
			||||||
 | 
					        let expr: expression = toEvSymbolValue(sNode["name"])
 | 
				
			||||||
 | 
					        let rExpr: result<expression, errorValue> = expr->Ok
 | 
				
			||||||
 | 
					        rExpr
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    | MjBlockNode(bNode) => caseBlockNode(bNode)
 | 
				
			||||||
 | 
					    // | MjBlockNode(bNode) => "statement"->toEvSymbolValue->Ok
 | 
				
			||||||
 | 
					    | MjConstantNode(cNode) =>
 | 
				
			||||||
 | 
					      cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
 | 
				
			||||||
 | 
					    | MjFunctionNode(fNode) => fNode->caseFunctionNode
 | 
				
			||||||
 | 
					    | MjIndexNode(iNode) => caseIndexNode(iNode)
 | 
				
			||||||
 | 
					    | MjObjectNode(oNode) => caseObjectNode(oNode)
 | 
				
			||||||
 | 
					    | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode
 | 
				
			||||||
 | 
					    | MjParenthesisNode(pNode) => pNode["content"]->fromNode
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rFinalExpression
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,25 +7,30 @@ module ErrorValue = Reducer_ErrorValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@genType
 | 
					@genType
 | 
				
			||||||
type rec expressionValue =
 | 
					type rec expressionValue =
 | 
				
			||||||
 | 
					  | EvArray(array<expressionValue>)
 | 
				
			||||||
  | EvBool(bool)
 | 
					  | EvBool(bool)
 | 
				
			||||||
 | 
					  | EvCall(string) // External function call
 | 
				
			||||||
 | 
					  | EvDistribution(GenericDist_Types.genericDist)
 | 
				
			||||||
  | EvNumber(float)
 | 
					  | EvNumber(float)
 | 
				
			||||||
 | 
					  | EvRecord(Js.Dict.t<expressionValue>)
 | 
				
			||||||
  | EvString(string)
 | 
					  | EvString(string)
 | 
				
			||||||
  | EvSymbol(string)
 | 
					  | EvSymbol(string)
 | 
				
			||||||
  | EvArray(array<expressionValue>)
 | 
					 | 
				
			||||||
  | EvRecord(Js.Dict.t<expressionValue>)
 | 
					 | 
				
			||||||
  | EvDistribution(GenericDist_Types.genericDist)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type functionCall = (string, array<expressionValue>)
 | 
					type functionCall = (string, array<expressionValue>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let rec toString = aValue =>
 | 
					let rec toString = aValue =>
 | 
				
			||||||
  switch aValue {
 | 
					  switch aValue {
 | 
				
			||||||
  | EvBool(aBool) => Js.String.make(aBool)
 | 
					  | EvBool(aBool) => Js.String.make(aBool)
 | 
				
			||||||
 | 
					  | EvCall(fName) => `:${fName}`
 | 
				
			||||||
  | EvNumber(aNumber) => Js.String.make(aNumber)
 | 
					  | EvNumber(aNumber) => Js.String.make(aNumber)
 | 
				
			||||||
  | EvString(aString) => `'${aString}'`
 | 
					  | EvString(aString) => `'${aString}'`
 | 
				
			||||||
  | EvSymbol(aString) => `:${aString}`
 | 
					  | EvSymbol(aString) => `:${aString}`
 | 
				
			||||||
  | EvArray(anArray) => {
 | 
					  | EvArray(anArray) => {
 | 
				
			||||||
      let args =
 | 
					      let args =
 | 
				
			||||||
        anArray->Belt.Array.map(each => toString(each))->Extra_Array.interperse(", ")->Js.String.concatMany("")
 | 
					        anArray
 | 
				
			||||||
 | 
					        ->Belt.Array.map(each => toString(each))
 | 
				
			||||||
 | 
					        ->Extra_Array.interperse(", ")
 | 
				
			||||||
 | 
					        ->Js.String.concatMany("")
 | 
				
			||||||
      `[${args}]`
 | 
					      `[${args}]`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  | EvRecord(aRecord) => {
 | 
					  | EvRecord(aRecord) => {
 | 
				
			||||||
| 
						 | 
					@ -37,12 +42,13 @@ let rec toString = aValue =>
 | 
				
			||||||
        ->Js.String.concatMany("")
 | 
					        ->Js.String.concatMany("")
 | 
				
			||||||
      `{${pairs}}`
 | 
					      `{${pairs}}`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  | EvDistribution(dist) => `${GenericDist.toString(dist)}`
 | 
					  | EvDistribution(dist) => GenericDist.toString(dist)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let toStringWithType = aValue =>
 | 
					let toStringWithType = aValue =>
 | 
				
			||||||
  switch aValue {
 | 
					  switch aValue {
 | 
				
			||||||
  | EvBool(_) => `Bool::${toString(aValue)}`
 | 
					  | EvBool(_) => `Bool::${toString(aValue)}`
 | 
				
			||||||
 | 
					  | EvCall(_) => `Call::${toString(aValue)}`
 | 
				
			||||||
  | EvNumber(_) => `Number::${toString(aValue)}`
 | 
					  | EvNumber(_) => `Number::${toString(aValue)}`
 | 
				
			||||||
  | EvString(_) => `String::${toString(aValue)}`
 | 
					  | EvString(_) => `String::${toString(aValue)}`
 | 
				
			||||||
  | EvSymbol(_) => `Symbol::${toString(aValue)}`
 | 
					  | EvSymbol(_) => `Symbol::${toString(aValue)}`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -128,7 +128,8 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
 | 
				
			||||||
  | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist)
 | 
					  | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist)
 | 
				
			||||||
  | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist)
 | 
					  | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist)
 | 
				
			||||||
  | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist)
 | 
					  | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist)
 | 
				
			||||||
  | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist)
 | 
					  | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) =>
 | 
				
			||||||
 | 
					    Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist)
 | 
				
			||||||
  | ("exp", [EvDistribution(a)]) =>
 | 
					  | ("exp", [EvDistribution(a)]) =>
 | 
				
			||||||
    // https://mathjs.org/docs/reference/functions/exp.html
 | 
					    // https://mathjs.org/docs/reference/functions/exp.html
 | 
				
			||||||
    Helpers.twoDiststoDistFn(Algebraic, "pow", GenericDist.fromFloat(Math.e), a)->Some
 | 
					    Helpers.twoDiststoDistFn(Algebraic, "pow", GenericDist.fromFloat(Math.e), a)->Some
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user