diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index e6183ba0..45492433 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -9,3 +9,6 @@ let expectParseToBe = (expr: string, answer: string) => let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) + +let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => + Reducer.evaluateWBindings(expr, bindings)->ExpressionValue.toStringResult->expect->toBe(answer) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index bd9101a2..62c0358a 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -10,6 +10,9 @@ let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answe let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) +let testEvalBindingsToBe = (expr, bindings, answer) => + test(expr, () => expectEvalBindingsToBe(expr, bindings, answer)) + describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility // Those tests toString that there is a semantic mapping from MathJs to Expression @@ -102,6 +105,21 @@ describe("eval", () => { testEvalToBe("1; 1", "Error(Assignment expected)") testEvalToBe("x=1; x=1", "Error(Expression expected)") }) + describe("external bindings", () => { + testEvalBindingsToBe( + "y=1; x+1", + list{("x", ExpressionValue.EvNumber(1.))}->Js.Dict.fromList, + "Ok(2)", + ) + testEvalBindingsToBe( + // This will go away when we have a proper parser + // x+1 is an expression not a block! + // Bindings are done for blocks only + "x+1", + list{("x", ExpressionValue.EvNumber(1.))}->Js.Dict.fromList, + "Error(JS Exception: Error: Undefined symbol x)", + ) + }) }) describe("test exceptions", () => { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index 7e93f367..2e4ac32e 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -6,5 +6,7 @@ module Js = Reducer_Js module MathJs = Reducer_MathJs type expressionValue = Reducer_Expression.expressionValue +type externalBindings = Expression.externalBindings let evaluate = Expression.eval +let evaluateWBindings = Expression.evalWBindings let parse = Expression.parse diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index 6f6a55a8..c20fce48 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -7,7 +7,10 @@ module MathJs = Reducer_MathJs @genType type expressionValue = ReducerInterface_ExpressionValue.expressionValue - +@genType +type externalBindings = Expression.externalBindings @genType let evaluate: string => result +@genType +let evaluateWBindings: (string, externalBindings) => result let parse: string => result 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 b2b90633..0bf8c201 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 @@ -110,17 +110,31 @@ let reduceExpression = (expression: t, bindings: T.bindings): result => +let evalWBindingsExpression_ = (aExpression, bindings): result => reduceExpression(aExpression, bindings) /* Evaluates MathJs code via Reducer using bindings and answers the result */ -let evalWBindings = (codeText: string, bindings: T.bindings) => { - parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings)) +let evalWBindings_ = (codeText: string, bindings: T.bindings) => { + parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression_(bindings)) } /* Evaluates MathJs code via Reducer and answers the result */ -let eval = (code: string) => evalWBindings(code, defaultBindings) +let eval = (code: string) => evalWBindings_(code, defaultBindings) + +type externalBindings = Js.Dict.t + +/* + Evaluates code with external bindings. External bindings are a record of expression values. +*/ +let evalWBindings = (code: string, externalBindings: externalBindings) => { + let keys = Js.Dict.keys(externalBindings) + let bindings = keys->Belt.Array.reduce(defaultBindings, (acc, key) => { + let value = Js.Dict.unsafeGet(externalBindings, key) + acc->Belt.Map.String.set(key, T.EValue(value)) + }) + evalWBindings_(code, bindings) +}