eval partial tested
This commit is contained in:
parent
a02bc27852
commit
5038e2c691
|
@ -14,6 +14,9 @@ describe("Parse for Bindings", () => {
|
|||
"y = x+1; y",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
||||
)
|
||||
})
|
||||
|
||||
describe("Parse for Bindings", () => {
|
||||
testParsePartialToBe(
|
||||
"x",
|
||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
||||
|
@ -50,8 +53,12 @@ describe("Eval with Bindings", () => {
|
|||
)
|
||||
})
|
||||
|
||||
/*
|
||||
Partial code is a partial code fragment that is cut out from a larger code.
|
||||
Therefore it does not end with an expression.
|
||||
*/
|
||||
Only.describe("Eval Partial", () => {
|
||||
MyOnly.testEvalPartialBindingsToBe(
|
||||
testEvalPartialBindingsToBe(
|
||||
// A partial cannot end with an expression
|
||||
"x",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
|
@ -60,17 +67,17 @@ Only.describe("Eval Partial", () => {
|
|||
testEvalPartialBindingsToBe(
|
||||
"y=x",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
"????",
|
||||
"Ok({x: 1, y: 1})",
|
||||
)
|
||||
testEvalBindingsToBe(
|
||||
testEvalPartialBindingsToBe(
|
||||
"y=x+1",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
"????",
|
||||
"Ok({x: 1, y: 2})",
|
||||
)
|
||||
testEvalBindingsToBe(
|
||||
MyOnly.testEvalPartialBindingsToBe(
|
||||
"y = x+1; z = y",
|
||||
list{("x", ExpressionValue.EvNumber(1.))},
|
||||
"????",
|
||||
"Ok({x: 1, y: 2, z: 2})",
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
/*
|
||||
Macros are like functions but instead of taking values as parameters,
|
||||
they take expressions as parameters and return a new expression.
|
||||
Macros are used to define language building blocks. They are like Lisp macros.
|
||||
*/
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
module Result = Belt.Result
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
|
||||
open Reducer_ErrorValue
|
||||
|
||||
type expression = ExpressionT.expression
|
||||
|
||||
let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings): result<
|
||||
type reducerFn = (
|
||||
expression,
|
||||
'e,
|
||||
> => {
|
||||
ExpressionT.bindings,
|
||||
) => result<ExpressionValue.expressionValue, errorValue>
|
||||
|
||||
let dispatchMacroCall = (
|
||||
list: list<expression>,
|
||||
bindings: ExpressionT.bindings,
|
||||
reduceExpression: reducerFn,
|
||||
): result<expression, 'e> => {
|
||||
let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result<
|
||||
expression,
|
||||
errorValue,
|
||||
|
@ -40,9 +52,16 @@ let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings)
|
|||
| ExpressionT.EList(list{
|
||||
ExpressionT.EValue(EvCall("$let")),
|
||||
ExpressionT.EValue(EvSymbol(aSymbol)),
|
||||
expression,
|
||||
expressionToReduce,
|
||||
}) => {
|
||||
let rNewExpression = replaceSymbols(expression, bindings)
|
||||
let rNewExpressionToReduce = replaceSymbols(expressionToReduce, bindings)
|
||||
|
||||
let rNewValue =
|
||||
rNewExpressionToReduce->Result.flatMap(newExpressionToReduce =>
|
||||
reduceExpression(newExpressionToReduce, bindings)
|
||||
)
|
||||
|
||||
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue))
|
||||
rNewExpression->Result.map(newExpression =>
|
||||
Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
|
||||
)
|
||||
|
@ -51,35 +70,37 @@ let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings)
|
|||
}
|
||||
}
|
||||
|
||||
let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) => {
|
||||
let doExportVariableExpression = (bindings: ExpressionT.bindings) => {
|
||||
let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty()
|
||||
let reducedBindings = bindings->Belt.Map.String.keep((key, value) =>
|
||||
switch value {
|
||||
| ExpressionT.EValue(_) => true
|
||||
| _ => false
|
||||
}
|
||||
)
|
||||
let externalBindings = reducedBindings->Belt.Map.String.reduce(emptyDictionary, (
|
||||
acc,
|
||||
key,
|
||||
expressionValue,
|
||||
) => {
|
||||
let value = switch expressionValue {
|
||||
| EValue(aValue) => aValue
|
||||
| _ => EvSymbol("internal")
|
||||
}
|
||||
Js.Dict.set(acc, key, value)
|
||||
acc
|
||||
})
|
||||
externalBindings->EvRecord->ExpressionT.EValue->Ok
|
||||
}
|
||||
|
||||
let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) =>
|
||||
switch expression {
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), ..._}) =>
|
||||
REExpressionExpected->Error
|
||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$exportVariablesExpression"))}) =>
|
||||
doExportVariableExpression(bindings)
|
||||
| _ => replaceSymbols(expression, bindings)
|
||||
}
|
||||
}
|
||||
|
||||
let doExportVariableExpression = (bindings: ExpressionT.bindings) => {
|
||||
let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty()
|
||||
let reducedBindings = bindings->Belt.Map.String.keep (
|
||||
(key, value) =>
|
||||
switch value {
|
||||
| ExpressionT.EValue(_) => true
|
||||
| _ => false
|
||||
}
|
||||
)
|
||||
let externalBindings = reducedBindings->Belt.Map.String.reduce(
|
||||
emptyDictionary,
|
||||
(acc, key, expressionValue) => {
|
||||
let value = switch expressionValue {
|
||||
| EValue(aValue) => aValue
|
||||
| _ => EvSymbol("internal")
|
||||
}
|
||||
Js.Dict.set(acc, key, value); acc
|
||||
}
|
||||
)
|
||||
externalBindings->EvRecord->ExpressionT.EValue->Ok
|
||||
}
|
||||
|
||||
switch list {
|
||||
| list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok
|
||||
|
@ -90,11 +111,6 @@ let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings)
|
|||
statement,
|
||||
} =>
|
||||
doBindStatement(statement, bindings)
|
||||
| list{
|
||||
ExpressionT.EValue(EvCall("$$bindExpression")),
|
||||
ExpressionT.EBindings(bindings),
|
||||
ExpressionT.EList(list{EValue(EvCall("$exportVariableExpression")), ..._}),
|
||||
} => doExportVariableExpression(bindings)
|
||||
| list{
|
||||
ExpressionT.EValue(EvCall("$$bindExpression")),
|
||||
ExpressionT.EBindings(bindings),
|
||||
|
|
|
@ -50,7 +50,15 @@ let defaultBindings: T.bindings = Belt.Map.String.empty
|
|||
/*
|
||||
Recursively evaluate/reduce the expression (Lisp AST)
|
||||
*/
|
||||
let reduceExpression = (expression: t, bindings: T.bindings): result<expressionValue, 'e> => {
|
||||
let rec reduceExpression = (expression: t, bindings: T.bindings): result<expressionValue, 'e> => {
|
||||
/*
|
||||
Macros are like functions but instead of taking values as parameters,
|
||||
they take expressions as parameters and return a new expression.
|
||||
Macros are used to define language building blocks. They are like Lisp macros.
|
||||
*/
|
||||
let doMacroCall = (list: list<t>, bindings: T.bindings): result<t, 'e> =>
|
||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, reduceExpression)
|
||||
|
||||
/*
|
||||
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
||||
*/
|
||||
|
@ -60,14 +68,6 @@ let reduceExpression = (expression: t, bindings: T.bindings): result<expressionV
|
|||
| _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
||||
}
|
||||
|
||||
/*
|
||||
Macros are like functions but instead of taking values as parameters,
|
||||
they take expressions as parameters and return a new expression.
|
||||
Macros are used to define language building blocks. They are like Lisp macros.
|
||||
*/
|
||||
let doMacroCall = (list: list<t>, bindings: T.bindings): result<t, 'e> =>
|
||||
list->Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(bindings)
|
||||
|
||||
let rec seekMacros = (expression: t, bindings: T.bindings): result<t, 'e> =>
|
||||
switch expression {
|
||||
| T.EValue(_value) => expression->Ok
|
||||
|
|
Loading…
Reference in New Issue
Block a user