squiggle/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res

159 lines
5.3 KiB
Plaintext
Raw Normal View History

module BindingsReplacer = Reducer_Expression_BindingsReplacer
2022-03-29 09:09:59 +00:00
module BuiltIn = Reducer_Dispatch_BuiltIn
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
2022-03-29 09:09:59 +00:00
module Extra = Reducer_Extra
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
module Lambda = Reducer_Expression_Lambda
module Macro = Reducer_Expression_Macro
2022-03-29 09:09:59 +00:00
module MathJs = Reducer_MathJs
module Module = Reducer_Category_Module
2022-03-29 09:09:59 +00:00
module Result = Belt.Result
module T = Reducer_Expression_T
2022-04-25 06:33:48 +00:00
type environment = InternalExpressionValue.environment
type errorValue = Reducer_ErrorValue.errorValue
2022-03-29 09:09:59 +00:00
type expression = T.expression
2022-06-24 10:15:38 +00:00
type internalExpressionValue = InternalExpressionValue.t
type externalExpressionValue = ReducerInterface_ExternalExpressionValue.t
2022-03-30 09:45:30 +00:00
type t = expression
2022-03-29 09:09:59 +00:00
/*
parser toFunction additive multiplicative compact whitespace pow relational equality boolean whitespace separator left associative operators expression not identifier function call array constructor string indexed values ident priority block outerBlock optional final expression statement separator outerBlock innerBlock better errors note xor white space and record unary minus inner/outer block statement lambda sort lambda is a value constructor lambdaCall ternary ternary basicValue cleanup quotes chained Functions dot operators unify unary operators unify unary operatos notes notes notes notes parser priorities set white space or newline defined allow newlines notes function call has become a post operator recordElement recursive index postOperatorToFunction better integer comments notes record priority comment atom finalComment generated parser type cast format initiate test file test initiated; todo nodeCall; nodeExpression callIdentifier recover extra initiate testing initial tests pass tests pass remove function node ternary test parse passed to tests pass notes sort toExpression format notes remove unused modules remove unnecessary nodeLambdaCall notes note fix construct array comment test todo elixir pipe fix toString notes initial to expression test value test parsing records records comments ternary ifthenelse inner block passed inner block lambda lambda new parser tested now test tricks ternary in expression to test lambda as argument to test lambda in structures Use peggy Parser expectEvalError macros tested remove mathjs parse reducer test comparison operator
2022-05-05 19:45:25 +00:00
Converts a Squigle code to expression
2022-03-29 09:09:59 +00:00
*/
parser toFunction additive multiplicative compact whitespace pow relational equality boolean whitespace separator left associative operators expression not identifier function call array constructor string indexed values ident priority block outerBlock optional final expression statement separator outerBlock innerBlock better errors note xor white space and record unary minus inner/outer block statement lambda sort lambda is a value constructor lambdaCall ternary ternary basicValue cleanup quotes chained Functions dot operators unify unary operators unify unary operatos notes notes notes notes parser priorities set white space or newline defined allow newlines notes function call has become a post operator recordElement recursive index postOperatorToFunction better integer comments notes record priority comment atom finalComment generated parser type cast format initiate test file test initiated; todo nodeCall; nodeExpression callIdentifier recover extra initiate testing initial tests pass tests pass remove function node ternary test parse passed to tests pass notes sort toExpression format notes remove unused modules remove unnecessary nodeLambdaCall notes note fix construct array comment test todo elixir pipe fix toString notes initial to expression test value test parsing records records comments ternary ifthenelse inner block passed inner block lambda lambda new parser tested now test tricks ternary in expression to test lambda as argument to test lambda in structures Use peggy Parser expectEvalError macros tested remove mathjs parse reducer test comparison operator
2022-05-05 19:45:25 +00:00
let parse = (peggyCode: string): result<t, errorValue> =>
2022-05-22 17:02:20 +00:00
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
2022-03-29 09:09:59 +00:00
/*
Recursively evaluate/reduce the expression (Lisp AST)
2022-03-29 09:09:59 +00:00
*/
2022-04-27 20:24:06 +00:00
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
2022-06-24 10:15:38 +00:00
internalExpressionValue,
2022-04-27 20:24:06 +00:00
'e,
2022-05-02 16:44:35 +00:00
> => {
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
switch expression {
| T.EValue(value) => value->Ok
| T.EList(list) =>
switch list {
2022-06-23 18:38:07 +00:00
| list{EValue(IEvCall(fName)), ..._args} =>
switch Macro.isMacroName(fName) {
// A macro expands then reduces itself
| true => Macro.doMacroCall(expression, bindings, environment, reduceExpression)
| false => reduceExpressionList(list, bindings, environment)
}
| _ => reduceExpressionList(list, bindings, environment)
}
2022-05-02 16:44:35 +00:00
}
}
2022-04-29 16:14:02 +00:00
and reduceExpressionList = (
expressions: list<t>,
bindings: T.bindings,
environment: environment,
2022-06-24 10:15:38 +00:00
): result<internalExpressionValue, 'e> => {
let racc: result<
list<internalExpressionValue>,
'e,
> = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
racc->Result.flatMap(acc => {
each
->reduceExpression(bindings, environment)
->Result.map(newNode => {
acc->Belt.List.add(newNode)
})
})
)
racc->Result.flatMap(acc => acc->reduceValueList(environment))
}
2022-03-29 09:09:59 +00:00
/*
After reducing each level of expression(Lisp AST), we have a value list to evaluate
*/
2022-06-24 10:15:38 +00:00
and reduceValueList = (valueList: list<internalExpressionValue>, environment): result<
internalExpressionValue,
2022-04-27 20:24:06 +00:00
'e,
2022-05-19 18:25:18 +00:00
> =>
switch valueList {
2022-06-23 18:38:07 +00:00
| list{IEvCall(fName), ...args} => {
let rCheckedArgs = switch fName {
| "$_setBindings_$" | "$_setTypeOfBindings_$" | "$_setTypeAliasBindings_$" => args->Ok
| _ => args->Lambda.checkIfReduced
}
2022-04-17 17:24:39 +00:00
rCheckedArgs->Result.flatMap(checkedArgs =>
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(environment, reduceExpression)
)
}
2022-06-23 18:38:07 +00:00
| list{IEvLambda(_)} =>
// TODO: remove on solving issue#558
parser toFunction additive multiplicative compact whitespace pow relational equality boolean whitespace separator left associative operators expression not identifier function call array constructor string indexed values ident priority block outerBlock optional final expression statement separator outerBlock innerBlock better errors note xor white space and record unary minus inner/outer block statement lambda sort lambda is a value constructor lambdaCall ternary ternary basicValue cleanup quotes chained Functions dot operators unify unary operators unify unary operatos notes notes notes notes parser priorities set white space or newline defined allow newlines notes function call has become a post operator recordElement recursive index postOperatorToFunction better integer comments notes record priority comment atom finalComment generated parser type cast format initiate test file test initiated; todo nodeCall; nodeExpression callIdentifier recover extra initiate testing initial tests pass tests pass remove function node ternary test parse passed to tests pass notes sort toExpression format notes remove unused modules remove unnecessary nodeLambdaCall notes note fix construct array comment test todo elixir pipe fix toString notes initial to expression test value test parsing records records comments ternary ifthenelse inner block passed inner block lambda lambda new parser tested now test tricks ternary in expression to test lambda as argument to test lambda in structures Use peggy Parser expectEvalError macros tested remove mathjs parse reducer test comparison operator
2022-05-05 19:45:25 +00:00
valueList
->Lambda.checkIfReduced
->Result.flatMap(reducedValueList =>
2022-06-23 18:38:07 +00:00
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
parser toFunction additive multiplicative compact whitespace pow relational equality boolean whitespace separator left associative operators expression not identifier function call array constructor string indexed values ident priority block outerBlock optional final expression statement separator outerBlock innerBlock better errors note xor white space and record unary minus inner/outer block statement lambda sort lambda is a value constructor lambdaCall ternary ternary basicValue cleanup quotes chained Functions dot operators unify unary operators unify unary operatos notes notes notes notes parser priorities set white space or newline defined allow newlines notes function call has become a post operator recordElement recursive index postOperatorToFunction better integer comments notes record priority comment atom finalComment generated parser type cast format initiate test file test initiated; todo nodeCall; nodeExpression callIdentifier recover extra initiate testing initial tests pass tests pass remove function node ternary test parse passed to tests pass notes sort toExpression format notes remove unused modules remove unnecessary nodeLambdaCall notes note fix construct array comment test todo elixir pipe fix toString notes initial to expression test value test parsing records records comments ternary ifthenelse inner block passed inner block lambda lambda new parser tested now test tricks ternary in expression to test lambda as argument to test lambda in structures Use peggy Parser expectEvalError macros tested remove mathjs parse reducer test comparison operator
2022-05-05 19:45:25 +00:00
)
2022-06-23 18:38:07 +00:00
| list{IEvLambda(lamdaCall), ...args} =>
args
->Lambda.checkIfReduced
->Result.flatMap(checkedArgs =>
Lambda.doLambdaCall(lamdaCall, checkedArgs, environment, reduceExpression)
)
| _ =>
valueList
->Lambda.checkIfReduced
->Result.flatMap(reducedValueList =>
2022-06-23 18:38:07 +00:00
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
)
}
2022-03-29 09:09:59 +00:00
let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result<
2022-06-24 10:15:38 +00:00
internalExpressionValue,
'e,
> => reduceExpression(aExpression, bindings, environment)
let evaluateUsingOptions = (
2022-06-24 10:15:38 +00:00
~environment: option<ReducerInterface_ExternalExpressionValue.environment>,
~externalBindings: option<ReducerInterface_ExternalExpressionValue.externalBindings>,
2022-04-27 20:24:06 +00:00
code: string,
): result<externalExpressionValue, errorValue> => {
2022-06-13 16:54:48 +00:00
let anEnvironment = Belt.Option.getWithDefault(
environment,
2022-06-24 10:15:38 +00:00
ReducerInterface_ExternalExpressionValue.defaultEnvironment,
2022-06-13 16:54:48 +00:00
)
let mergedBindings: InternalExpressionValue.nameSpace = Module.merge(
ReducerInterface_StdLib.internalStdLib,
Belt.Option.map(externalBindings, Module.fromTypeScriptBindings)->Belt.Option.getWithDefault(
Module.emptyModule,
),
)
parse(code)
->Result.flatMap(expr => evalUsingBindingsExpression_(expr, mergedBindings, anEnvironment))
->Result.map(ReducerInterface_InternalExpressionValue.toExternal)
2022-04-17 17:24:39 +00:00
}
/*
2022-06-23 18:38:07 +00:00
IEvaluates Squiggle code and bindings via Reducer and answers the result
2022-04-17 17:24:39 +00:00
*/
let evaluate = (code: string): result<externalExpressionValue, errorValue> => {
evaluateUsingOptions(~environment=None, ~externalBindings=None, code)
2022-04-15 06:56:48 +00:00
}
let evaluatePartialUsingExternalBindings = (
code: string,
2022-06-24 10:15:38 +00:00
externalBindings: ReducerInterface_ExternalExpressionValue.externalBindings,
environment: ReducerInterface_ExternalExpressionValue.environment,
): result<ReducerInterface_ExternalExpressionValue.externalBindings, errorValue> => {
2022-04-29 17:31:34 +00:00
let rAnswer = evaluateUsingOptions(
~environment=Some(environment),
~externalBindings=Some(externalBindings),
code,
)
switch rAnswer {
2022-06-23 01:54:37 +00:00
| Ok(EvModule(externalBindings)) => Ok(externalBindings)
2022-04-29 17:31:34 +00:00
| Ok(_) =>
Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`))
| Error(err) => err->Error
}
}