Reducer: Environment (Give environement to all function dispatches) - closes #169
This commit is contained in:
parent
7d4e3072b8
commit
54f8b10a95
|
@ -1,9 +1,17 @@
|
||||||
module Expression = Reducer.Expression
|
module Expression = Reducer.Expression
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
|
let unwrapRecord = rValue =>
|
||||||
|
rValue->Belt.Result.flatMap(value => switch value {
|
||||||
|
| ExpressionValue.EvRecord(aRecord) => Ok(aRecord)
|
||||||
|
| _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let expectParseToBe = (expr: string, answer: string) =>
|
let expectParseToBe = (expr: string, answer: string) =>
|
||||||
Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer)
|
Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
|
@ -17,7 +25,7 @@ let expectEvalToBe = (expr: string, answer: string) =>
|
||||||
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
||||||
Reducer.evaluateUsingExternalBindings(expr, bindings)
|
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=None, ~environment=None)
|
||||||
->ExpressionValue.toStringResult
|
->ExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
->toBe(answer)
|
->toBe(answer)
|
||||||
|
@ -27,7 +35,8 @@ let expectEvalPartialBindingsToBe = (
|
||||||
bindings: Reducer.externalBindings,
|
bindings: Reducer.externalBindings,
|
||||||
answer: string,
|
answer: string,
|
||||||
) =>
|
) =>
|
||||||
Reducer.evaluatePartialUsingExternalBindings(expr, bindings)
|
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=Some(true), ~environment=None)
|
||||||
|
->unwrapRecord
|
||||||
->ExpressionValue.toStringResultRecord
|
->ExpressionValue.toStringResultRecord
|
||||||
->expect
|
->expect
|
||||||
->toBe(answer)
|
->toBe(answer)
|
||||||
|
|
|
@ -5,11 +5,12 @@ module Extra = Reducer_Extra
|
||||||
module Js = Reducer_Js
|
module Js = Reducer_Js
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
|
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
let evaluate = Expression.eval
|
let evaluate = Expression.evaluate
|
||||||
let evaluateUsingExternalBindings = Expression.evalUsingExternalBindings
|
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
||||||
let evaluatePartialUsingExternalBindings = Expression.evalPartialUsingExternalBindings
|
|
||||||
let parse = Expression.parse
|
let parse = Expression.parse
|
||||||
let parseOuter = Expression.parseOuter
|
let parseOuter = Expression.parseOuter
|
||||||
let parsePartial = Expression.parsePartial
|
let parsePartial = Expression.parsePartial
|
||||||
|
|
|
@ -5,22 +5,29 @@ module Extra = Reducer_Extra
|
||||||
module Js = Reducer_Js
|
module Js = Reducer_Js
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
@genType
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
@genType
|
@genType
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
@genType
|
@genType
|
||||||
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let evaluate: string => result<expressionValue, Reducer_ErrorValue.errorValue>
|
let evaluateUsingOptions: (
|
||||||
@genType
|
~environment: option<
|
||||||
let evaluateUsingExternalBindings: (
|
QuriSquiggleLang.ReducerInterface_ExpressionValue.environment,
|
||||||
|
>,
|
||||||
|
~externalBindings: option<
|
||||||
|
QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings,
|
||||||
|
>,
|
||||||
|
~isPartial: option<bool>,
|
||||||
string,
|
string,
|
||||||
externalBindings,
|
) => result<expressionValue, errorValue>
|
||||||
) => result<expressionValue, Reducer_ErrorValue.errorValue>
|
|
||||||
@genType
|
@genType
|
||||||
let evaluatePartialUsingExternalBindings: (
|
let evaluate: string => result<expressionValue, errorValue>
|
||||||
string,
|
|
||||||
externalBindings,
|
let parse: string => result<Expression.expression, errorValue>
|
||||||
) => result<externalBindings, Reducer_ErrorValue.errorValue>
|
let parseOuter: string => result<Expression.expression, errorValue>
|
||||||
let parse: string => result<Expression.expression, ErrorValue.errorValue>
|
let parsePartial: string => result<Expression.expression, errorValue>
|
||||||
let parseOuter: string => result<Expression.expression, ErrorValue.errorValue>
|
|
||||||
let parsePartial: string => result<Expression.expression, ErrorValue.errorValue>
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ open Reducer_ErrorValue
|
||||||
|
|
||||||
exception TestRescriptException
|
exception TestRescriptException
|
||||||
|
|
||||||
let callInternal = (call: functionCall): result<'b, errorValue> => {
|
let callInternal = (call: functionCall, _environment): result<'b, errorValue> => {
|
||||||
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
||||||
switch call {
|
switch call {
|
||||||
| ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
|
| ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
|
||||||
|
@ -85,12 +85,12 @@ let callInternal = (call: functionCall): result<'b, errorValue> => {
|
||||||
/*
|
/*
|
||||||
Reducer uses Result monad while reducing expressions
|
Reducer uses Result monad while reducing expressions
|
||||||
*/
|
*/
|
||||||
let dispatch = (call: functionCall): result<expressionValue, errorValue> =>
|
let dispatch = (call: functionCall, environment): result<expressionValue, errorValue> =>
|
||||||
try {
|
try {
|
||||||
let (fn, args) = call
|
let (fn, args) = call
|
||||||
// There is a bug that prevents string match in patterns
|
// There is a bug that prevents string match in patterns
|
||||||
// So we have to recreate a copy of the string
|
// So we have to recreate a copy of the string
|
||||||
ExternalLibrary.dispatch((Js.String.make(fn), args), callInternal)
|
ExternalLibrary.dispatch((Js.String.make(fn), args), environment, callInternal)
|
||||||
} catch {
|
} catch {
|
||||||
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
||||||
| _ => RETodo("unhandled rescript exception")->Error
|
| _ => RETodo("unhandled rescript exception")->Error
|
||||||
|
|
|
@ -10,10 +10,12 @@ module Result = Belt.Result
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
|
type environment = ExpressionValue.environment
|
||||||
|
|
||||||
type reducerFn = (
|
type reducerFn = (
|
||||||
expression,
|
expression,
|
||||||
ExpressionT.bindings,
|
ExpressionT.bindings,
|
||||||
|
environment,
|
||||||
) => result<ExpressionValue.expressionValue, errorValue>
|
) => result<ExpressionValue.expressionValue, errorValue>
|
||||||
|
|
||||||
let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result<
|
let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result<
|
||||||
|
@ -101,6 +103,7 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
|
||||||
let dispatchMacroCall = (
|
let dispatchMacroCall = (
|
||||||
list: list<expression>,
|
list: list<expression>,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
|
environment,
|
||||||
reduceExpression: reducerFn,
|
reduceExpression: reducerFn,
|
||||||
): result<expression, 'e> => {
|
): result<expression, 'e> => {
|
||||||
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
|
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
|
||||||
|
@ -114,7 +117,7 @@ let dispatchMacroCall = (
|
||||||
|
|
||||||
let rNewValue =
|
let rNewValue =
|
||||||
rNewExpressionToReduce->Result.flatMap(newExpressionToReduce =>
|
rNewExpressionToReduce->Result.flatMap(newExpressionToReduce =>
|
||||||
reduceExpression(newExpressionToReduce, bindings)
|
reduceExpression(newExpressionToReduce, bindings, environment)
|
||||||
)
|
)
|
||||||
|
|
||||||
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue))
|
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue))
|
||||||
|
|
|
@ -8,9 +8,12 @@ module T = Reducer_Expression_T
|
||||||
|
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expression = T.expression
|
type expression = T.expression
|
||||||
type expressionValue = ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
type internalCode = ExpressionValue.internalCode
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
type t = expression
|
type t = expression
|
||||||
|
|
||||||
external castExpressionToInternalCode: expression => internalCode = "%identity"
|
external castExpressionToInternalCode: expression => internalCode = "%identity"
|
||||||
|
@ -57,19 +60,20 @@ let defaultBindings: T.bindings = Belt.Map.String.empty
|
||||||
/*
|
/*
|
||||||
Recursively evaluate/reduce the expression (Lisp AST)
|
Recursively evaluate/reduce the expression (Lisp AST)
|
||||||
*/
|
*/
|
||||||
let rec reduceExpression = (expression: t, bindings: T.bindings): result<expressionValue, 'e> => {
|
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<expressionValue, 'e> => {
|
||||||
/*
|
/*
|
||||||
Macros are like functions but instead of taking values as parameters,
|
Macros are like functions but instead of taking values as parameters,
|
||||||
they take expressions as parameters and return a new expression.
|
they take expressions as parameters and return a new expression.
|
||||||
Macros are used to define language building blocks. They are like Lisp macros.
|
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 doMacroCall = (list: list<t>, bindings: T.bindings, environment: environment): result<t, 'e> =>
|
||||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, reduceExpression)
|
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, environment, reduceExpression)
|
||||||
|
|
||||||
let applyParametersToLambda = (
|
let applyParametersToLambda = (
|
||||||
internal: internalCode,
|
internal: internalCode,
|
||||||
parameters: array<string>,
|
parameters: array<string>,
|
||||||
args: list<expressionValue>,
|
args: list<expressionValue>,
|
||||||
|
environment
|
||||||
): result<expressionValue, 'e> => {
|
): result<expressionValue, 'e> => {
|
||||||
let expr = castInternalCodeToExpression(internal)
|
let expr = castInternalCodeToExpression(internal)
|
||||||
let parameterList = parameters->Belt.List.fromArray
|
let parameterList = parameters->Belt.List.fromArray
|
||||||
|
@ -81,22 +85,22 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
|
||||||
"$$bindExpression",
|
"$$bindExpression",
|
||||||
list{Builder.passToFunction("$$bindings", list{}), expr},
|
list{Builder.passToFunction("$$bindings", list{}), expr},
|
||||||
)
|
)
|
||||||
reduceExpression(newExpression, bindings)
|
reduceExpression(newExpression, bindings, environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
||||||
*/
|
*/
|
||||||
let reduceValueList = (valueList: list<expressionValue>): result<expressionValue, 'e> =>
|
let reduceValueList = (valueList: list<expressionValue>, environment): result<expressionValue, 'e> =>
|
||||||
switch valueList {
|
switch valueList {
|
||||||
| list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch
|
| list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment)
|
||||||
// "(lambda(x=>internal) param)"
|
// "(lambda(x=>internal) param)"
|
||||||
| list{EvLambda((parameters, internal)), ...args} =>
|
| list{EvLambda((parameters, internal)), ...args} =>
|
||||||
applyParametersToLambda(internal, parameters, args)
|
applyParametersToLambda(internal, parameters, args, environment)
|
||||||
| _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
| _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
let rec seekMacros = (expression: t, bindings: T.bindings): result<t, 'e> =>
|
let rec seekMacros = (expression: t, bindings: T.bindings, environment): result<t, 'e> =>
|
||||||
switch expression {
|
switch expression {
|
||||||
| T.EValue(_value) => expression->Ok
|
| T.EValue(_value) => expression->Ok
|
||||||
| T.EBindings(_value) => expression->Ok
|
| T.EBindings(_value) => expression->Ok
|
||||||
|
@ -108,17 +112,17 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
|
||||||
) =>
|
) =>
|
||||||
racc->Result.flatMap(acc => {
|
racc->Result.flatMap(acc => {
|
||||||
each
|
each
|
||||||
->seekMacros(bindings)
|
->seekMacros(bindings, environment)
|
||||||
->Result.flatMap(newNode => {
|
->Result.flatMap(newNode => {
|
||||||
acc->Belt.List.add(newNode)->Ok
|
acc->Belt.List.add(newNode)->Ok
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
racc->Result.flatMap(acc => acc->doMacroCall(bindings))
|
racc->Result.flatMap(acc => acc->doMacroCall(bindings, environment))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rec reduceExpandedExpression = (expression: t): result<expressionValue, 'e> =>
|
let rec reduceExpandedExpression = (expression: t, environment): result<expressionValue, 'e> =>
|
||||||
switch expression {
|
switch expression {
|
||||||
| T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) =>
|
| T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) =>
|
||||||
EvLambda((parameters, functionDefinition->castExpressionToInternalCode))->Ok
|
EvLambda((parameters, functionDefinition->castExpressionToInternalCode))->Ok
|
||||||
|
@ -130,36 +134,36 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
|
||||||
) =>
|
) =>
|
||||||
racc->Result.flatMap(acc => {
|
racc->Result.flatMap(acc => {
|
||||||
each
|
each
|
||||||
->reduceExpandedExpression
|
->reduceExpandedExpression(environment)
|
||||||
->Result.flatMap(newNode => {
|
->Result.flatMap(newNode => {
|
||||||
acc->Belt.List.add(newNode)->Ok
|
acc->Belt.List.add(newNode)->Ok
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
racc->Result.flatMap(acc => acc->reduceValueList)
|
racc->Result.flatMap(acc => acc->reduceValueList(environment))
|
||||||
}
|
}
|
||||||
| EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error
|
| EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error
|
||||||
| EParameters(_parameters) =>
|
| EParameters(_parameters) =>
|
||||||
RETodo("Error: Lambda Parameters cannot be reduced to values")->Error
|
RETodo("Error: Lambda Parameters cannot be reduced to values")->Error
|
||||||
}
|
}
|
||||||
|
|
||||||
let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings)
|
let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings, environment)
|
||||||
rExpandedExpression->Result.flatMap(expandedExpression =>
|
rExpandedExpression->Result.flatMap(expandedExpression =>
|
||||||
expandedExpression->reduceExpandedExpression
|
expandedExpression->reduceExpandedExpression(environment)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let evalUsingExternalBindingsExpression_ = (aExpression, bindings): result<expressionValue, 'e> =>
|
let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result<expressionValue, 'e> =>
|
||||||
reduceExpression(aExpression, bindings)
|
reduceExpression(aExpression, bindings, environment)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Evaluates MathJs code via Reducer using bindings and answers the result.
|
Evaluates MathJs code via Reducer using bindings and answers the result.
|
||||||
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
||||||
Therefore all statements are assignments.
|
Therefore all statements are assignments.
|
||||||
*/
|
*/
|
||||||
let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings) => {
|
let evalPartial_ = (codeText: string, bindings: T.bindings, environment: environment) => {
|
||||||
parsePartial(codeText)->Result.flatMap(expression =>
|
parsePartial(codeText)->Result.flatMap(expression =>
|
||||||
expression->evalUsingExternalBindingsExpression_(bindings)
|
expression->evalUsingExternalBindingsExpression_(bindings, environment)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,23 +172,12 @@ let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings)
|
||||||
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
||||||
Therefore all statments are assignments.
|
Therefore all statments are assignments.
|
||||||
*/
|
*/
|
||||||
let evalOuterWBindings_ = (codeText: string, bindings: T.bindings) => {
|
let evalOuter_ = (codeText: string, bindings: T.bindings, environment: environment) => {
|
||||||
parseOuter(codeText)->Result.flatMap(expression =>
|
parseOuter(codeText)->Result.flatMap(expression =>
|
||||||
expression->evalUsingExternalBindingsExpression_(bindings)
|
expression->evalUsingExternalBindingsExpression_(bindings, environment)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Evaluates MathJs code and bindings via Reducer and answers the result
|
|
||||||
*/
|
|
||||||
let eval = (codeText: string) => {
|
|
||||||
parse(codeText)->Result.flatMap(expression =>
|
|
||||||
expression->evalUsingExternalBindingsExpression_(defaultBindings)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type externalBindings = ReducerInterface.ExpressionValue.externalBindings //Js.Dict.t<expressionValue>
|
|
||||||
|
|
||||||
let externalBindingsToBindings = (externalBindings: externalBindings): T.bindings => {
|
let externalBindingsToBindings = (externalBindings: externalBindings): T.bindings => {
|
||||||
let keys = Js.Dict.keys(externalBindings)
|
let keys = Js.Dict.keys(externalBindings)
|
||||||
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
|
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
|
||||||
|
@ -192,28 +185,41 @@ let externalBindingsToBindings = (externalBindings: externalBindings): T.binding
|
||||||
acc->Belt.Map.String.set(key, T.EValue(value))
|
acc->Belt.Map.String.set(key, T.EValue(value))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
Evaluates code with external bindings. External bindings are a record of expression values.
|
let evaluateUsingOptions = (
|
||||||
*/
|
~environment: option<ReducerInterface_ExpressionValue.environment>,
|
||||||
let evalUsingExternalBindings = (code: string, externalBindings: externalBindings) => {
|
~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>,
|
||||||
let bindings = externalBindings->externalBindingsToBindings
|
~isPartial: option<bool>,
|
||||||
evalOuterWBindings_(code, bindings)
|
code: string): result<expressionValue, errorValue> => {
|
||||||
|
|
||||||
|
let anEnvironment = switch environment {
|
||||||
|
| Some(env) => env
|
||||||
|
| None => ReducerInterface_ExpressionValue.defaultEnvironment
|
||||||
|
}
|
||||||
|
|
||||||
|
let anExternalBindings = switch externalBindings {
|
||||||
|
| Some(bindings) => bindings
|
||||||
|
| None => ReducerInterface_ExpressionValue.defaultExternalBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
let anIsPartial = switch isPartial {
|
||||||
|
| Some(isPartial) => isPartial
|
||||||
|
| None => false
|
||||||
|
}
|
||||||
|
|
||||||
|
let bindings = anExternalBindings->externalBindingsToBindings
|
||||||
|
|
||||||
|
if anIsPartial {
|
||||||
|
evalPartial_(code, bindings, anEnvironment)
|
||||||
|
} else {
|
||||||
|
evalOuter_(code, bindings, anEnvironment)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Evaluates code with external bindings. External bindings are a record of expression values.
|
Evaluates MathJs code and bindings via Reducer and answers the result
|
||||||
The code is a partial code as if it is cut from a larger code. Therefore all statments are assignments.
|
|
||||||
*/
|
*/
|
||||||
let evalPartialUsingExternalBindings = (code: string, externalBindings: externalBindings): result<
|
let evaluate = (code: string): result<expressionValue, errorValue> => {
|
||||||
externalBindings,
|
evaluateUsingOptions(~environment=None, ~externalBindings=None, ~isPartial=None, code)
|
||||||
'e,
|
|
||||||
> => {
|
|
||||||
let bindings = externalBindings->externalBindingsToBindings
|
|
||||||
let answer = evalPartialUsingExternalBindings_(code, bindings)
|
|
||||||
answer->Result.flatMap(answer =>
|
|
||||||
switch answer {
|
|
||||||
| EvRecord(aRecord) => Ok(aRecord)
|
|
||||||
| _ => RETodo("TODO: External bindings must be returned")->Error
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
let eval = evaluate
|
||||||
|
|
|
@ -22,6 +22,9 @@ type rec expressionValue =
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type externalBindings = Js.Dict.t<expressionValue>
|
type externalBindings = Js.Dict.t<expressionValue>
|
||||||
|
@genType
|
||||||
|
let defaultExternalBindings: externalBindings = Js.Dict.empty()
|
||||||
|
|
||||||
|
|
||||||
type functionCall = (string, array<expressionValue>)
|
type functionCall = (string, array<expressionValue>)
|
||||||
|
|
||||||
|
@ -84,3 +87,8 @@ let toStringResultRecord = x =>
|
||||||
| Ok(a) => `Ok(${toStringRecord(a)})`
|
| Ok(a) => `Ok(${toStringRecord(a)})`
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type environment = {dummy: int}
|
||||||
|
@genType
|
||||||
|
let defaultEnvironment: environment = {dummy: 0}
|
||||||
|
|
|
@ -14,8 +14,8 @@ type expressionValue = ExpressionValue.expressionValue
|
||||||
Map external calls of Reducer
|
Map external calls of Reducer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let dispatch = (call: ExpressionValue.functionCall, chain): result<expressionValue, 'e> =>
|
let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<expressionValue, 'e> =>
|
||||||
ReducerInterface_GenericDistribution.dispatch(call) |> E.O.default(chain(call))
|
ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default(chain(call, environment))
|
||||||
/*
|
/*
|
||||||
If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.
|
If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ module Math = {
|
||||||
let e = 2.718281828459
|
let e = 2.718281828459
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
let dispatchToGenericOutput = (call: ExpressionValue.functionCall, _environment): option<
|
||||||
DistributionOperation.outputType,
|
DistributionOperation.outputType,
|
||||||
> => {
|
> => {
|
||||||
let (fnName, args) = call
|
let (fnName, args) = call
|
||||||
|
@ -266,6 +266,6 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result<
|
||||||
| GenDistError(err) => Error(REDistributionError(err))
|
| GenDistError(err) => Error(REDistributionError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatch = call => {
|
let dispatch = (call, environment) => {
|
||||||
dispatchToGenericOutput(call)->E.O2.fmap(genericOutputToReducerValue)
|
dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
let dispatch: ReducerInterface_ExpressionValue.functionCall => option<
|
let dispatch: (ReducerInterface_ExpressionValue.functionCall, ReducerInterface_ExpressionValue.environment) => option<
|
||||||
result<ReducerInterface_ExpressionValue.expressionValue, Reducer_ErrorValue.errorValue>,
|
result<ReducerInterface_ExpressionValue.expressionValue, Reducer_ErrorValue.errorValue>,
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user