removed some extra array references rename Builder to ExpressionBuilder Expression Builder Trash Warning remove parsePartial/Outer, add context to lambda format module Bindings simplify types module Macro reduceValueList do macro call result map bindings stop replacing on macro calls Macro Test doBindStatement bind a statement bindings tested. TODO bind shadowing in lambda block tests defined block tests defined blocks tested macro lambda test defined
		
			
				
	
	
		
			103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 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)")
 | |
|     testEvalToBe("1+2", "Ok(3)")
 | |
|     testEvalToBe("(1+2)*3", "Ok(9)")
 | |
|     testEvalToBe("2>1", "Ok(true)")
 | |
|     testEvalToBe("concat('a ', 'b')", "Ok('a b')")
 | |
|     testEvalToBe("log(10)", "Ok(2.302585092994046)")
 | |
|     testEvalToBe("cos(10)", "Ok(-0.8390715290764524)")
 | |
|     // TODO more built ins
 | |
|   })
 | |
|   describe("arrays", () => {
 | |
|     test("empty array", () => expectEvalToBe("[]", "Ok([])"))
 | |
|     testEvalToBe("[1, 2, 3]", "Ok([1,2,3])")
 | |
|     testEvalToBe("['hello', 'world']", "Ok(['hello','world'])")
 | |
|     testEvalToBe("([0,1,2])[1]", "Ok(1)")
 | |
|     testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
 | |
|   })
 | |
|   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)"))
 | |
|   })
 | |
| 
 | |
|   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", "Ok({x: 1})")
 | |
|   })
 | |
| })
 | |
| 
 | |
| describe("test exceptions", () => {
 | |
|   testDescriptionEvalToBe(
 | |
|     "javascript exception",
 | |
|     "javascriptraise('div by 0')",
 | |
|     "Error(JS Exception: Error: 'div by 0')",
 | |
|   )
 | |
|   testDescriptionEvalToBe(
 | |
|     "rescript exception",
 | |
|     "rescriptraise()",
 | |
|     "Error(TODO: unhandled rescript exception)",
 | |
|   )
 | |
| })
 |