squiggle/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res
Umur Ozkul 660c0c70ae variables and statements
format only reducer

reformat lint

multi-line test

spelling

multi-line semantic mapping

todo multi-line eval

multi-line tests todo

change context to bindings

simplify tests

rename exception test methods

bindings is an expression value

make bindings callable

reformat

Emphasize the nature of Lisp AST

Initial definition of macros

make functions private

fixed functionNode type casting

macro call skeleton

sort ReducerInterface

fix test

macros skeleton

bindings is not a value

assignment semantics

let semantics defined

format

reformat

reformat

TODO function calls and list hd variables are confused

reformat

tmp

works

reformat

reformat

add test

reformat

add test
2022-04-11 16:31:10 +02:00

106 lines
4.2 KiB
Plaintext

open Jest
open Reducer_TestHelpers
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
let testDescParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer))
let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer))
let testDescEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
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(1)")
testParseToBe("(1)", "Ok(1)")
testParseToBe("1+2", "Ok((:add 1 2))")
testParseToBe("1+2", "Ok((:add 1 2))")
testParseToBe("1+2", "Ok((:add 1 2))")
testParseToBe("1+2*3", "Ok((: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)
testDescParseToBe("empty", "[]", "Ok(())")
testParseToBe("[1, 2, 3]", "Ok((1 2 3))")
testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")
testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")
})
describe("records", () => {
testDescParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))")
testDescParseToBe(
"use",
"{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", () => {
// 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)")
testDescEvalToBe("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", "Error(Expression expected)")
})
})
describe("test exceptions", () => {
testDescEvalToBe(
"javascript exception",
"javascriptraise('div by 0')",
"Error(JS Exception: Error: 'div by 0')",
)
testDescEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)")
})