This commit is contained in:
Umur Ozkul 2022-04-27 22:24:06 +02:00
parent 5c1ce71a40
commit 7b052ee3c3
7 changed files with 68 additions and 44 deletions

View File

@ -6,11 +6,12 @@ open Jest
open Expect open Expect
let unwrapRecord = rValue => let unwrapRecord = rValue =>
rValue->Belt.Result.flatMap(value => switch value { rValue->Belt.Result.flatMap(value =>
switch value {
| ExpressionValue.EvRecord(aRecord) => Ok(aRecord) | ExpressionValue.EvRecord(aRecord) => Ok(aRecord)
| _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error | _ => 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)
@ -25,7 +26,12 @@ 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.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=None, ~environment=None) Reducer.evaluateUsingOptions(
expr,
~externalBindings=Some(bindings),
~isPartial=None,
~environment=None,
)
->ExpressionValue.toStringResult ->ExpressionValue.toStringResult
->expect ->expect
->toBe(answer) ->toBe(answer)
@ -35,7 +41,12 @@ let expectEvalPartialBindingsToBe = (
bindings: Reducer.externalBindings, bindings: Reducer.externalBindings,
answer: string, answer: string,
) => ) =>
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=Some(true), ~environment=None) Reducer.evaluateUsingOptions(
expr,
~externalBindings=Some(bindings),
~isPartial=Some(true),
~environment=None,
)
->unwrapRecord ->unwrapRecord
->ExpressionValue.toStringResultRecord ->ExpressionValue.toStringResultRecord
->expect ->expect

View File

@ -16,12 +16,8 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings
@genType @genType
let evaluateUsingOptions: ( let evaluateUsingOptions: (
~environment: option< ~environment: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.environment>,
QuriSquiggleLang.ReducerInterface_ExpressionValue.environment, ~externalBindings: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings>,
>,
~externalBindings: option<
QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings,
>,
~isPartial: option<bool>, ~isPartial: option<bool>,
string, string,
) => result<expressionValue, errorValue> ) => result<expressionValue, errorValue>

View File

@ -60,20 +60,26 @@ 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, environment: environment): 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, environment: environment): result<t, 'e> => let doMacroCall = (list: list<t>, bindings: T.bindings, environment: environment): result<
t,
'e,
> =>
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, environment, 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 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
@ -91,9 +97,13 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en
/* /*
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>, environment): 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(environment) | 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, environment) applyParametersToLambda(internal, parameters, args, environment)
@ -153,8 +163,10 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en
) )
} }
let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result<expressionValue, 'e> => let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result<
reduceExpression(aExpression, bindings, environment) expressionValue,
'e,
> => 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.
@ -190,8 +202,8 @@ let evaluateUsingOptions = (
~environment: option<ReducerInterface_ExpressionValue.environment>, ~environment: option<ReducerInterface_ExpressionValue.environment>,
~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>, ~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>,
~isPartial: option<bool>, ~isPartial: option<bool>,
code: string): result<expressionValue, errorValue> => { code: string,
): result<expressionValue, errorValue> => {
let anEnvironment = switch environment { let anEnvironment = switch environment {
| Some(env) => env | Some(env) => env
| None => ReducerInterface_ExpressionValue.defaultEnvironment | None => ReducerInterface_ExpressionValue.defaultEnvironment

View File

@ -25,7 +25,6 @@ type externalBindings = Js.Dict.t<expressionValue>
@genType @genType
let defaultExternalBindings: externalBindings = Js.Dict.empty() let defaultExternalBindings: externalBindings = Js.Dict.empty()
type functionCall = (string, array<expressionValue>) type functionCall = (string, array<expressionValue>)
let rec toString = aValue => let rec toString = aValue =>

View File

@ -14,8 +14,13 @@ type expressionValue = ExpressionValue.expressionValue
Map external calls of Reducer Map external calls of Reducer
*/ */
let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<expressionValue, 'e> => let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<
ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default(chain(call, environment)) expressionValue,
'e,
> =>
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.

View File

@ -1,3 +1,4 @@
let dispatch: (ReducerInterface_ExpressionValue.functionCall, ReducerInterface_ExpressionValue.environment) => option< let dispatch: (
result<ReducerInterface_ExpressionValue.expressionValue, Reducer_ErrorValue.errorValue>, ReducerInterface_ExpressionValue.functionCall,
> ReducerInterface_ExpressionValue.environment,
) => option<result<ReducerInterface_ExpressionValue.expressionValue, Reducer_ErrorValue.errorValue>>