eval partial tested

This commit is contained in:
Umur Ozkul 2022-04-21 22:56:06 +02:00
parent a02bc27852
commit 5038e2c691
3 changed files with 73 additions and 50 deletions

View File

@ -14,6 +14,9 @@ describe("Parse for Bindings", () => {
"y = x+1; y", "y = x+1; y",
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
) )
})
describe("Parse for Bindings", () => {
testParsePartialToBe( testParsePartialToBe(
"x", "x",
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))", "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", () => { Only.describe("Eval Partial", () => {
MyOnly.testEvalPartialBindingsToBe( testEvalPartialBindingsToBe(
// A partial cannot end with an expression // A partial cannot end with an expression
"x", "x",
list{("x", ExpressionValue.EvNumber(1.))}, list{("x", ExpressionValue.EvNumber(1.))},
@ -60,17 +67,17 @@ Only.describe("Eval Partial", () => {
testEvalPartialBindingsToBe( testEvalPartialBindingsToBe(
"y=x", "y=x",
list{("x", ExpressionValue.EvNumber(1.))}, list{("x", ExpressionValue.EvNumber(1.))},
"????", "Ok({x: 1, y: 1})",
) )
testEvalBindingsToBe( testEvalPartialBindingsToBe(
"y=x+1", "y=x+1",
list{("x", ExpressionValue.EvNumber(1.))}, list{("x", ExpressionValue.EvNumber(1.))},
"????", "Ok({x: 1, y: 2})",
) )
testEvalBindingsToBe( MyOnly.testEvalPartialBindingsToBe(
"y = x+1; z = y", "y = x+1; z = y",
list{("x", ExpressionValue.EvNumber(1.))}, list{("x", ExpressionValue.EvNumber(1.))},
"????", "Ok({x: 1, y: 2, z: 2})",
) )
}) })

View File

@ -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 ExpressionValue = ReducerInterface.ExpressionValue
module Result = Belt.Result module Result = Belt.Result
module ExpressionT = Reducer_Expression_T
open Reducer_ErrorValue open Reducer_ErrorValue
type expression = ExpressionT.expression type expression = ExpressionT.expression
let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings): result< type reducerFn = (
expression, 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< let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result<
expression, expression,
errorValue, errorValue,
@ -40,9 +52,16 @@ let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings)
| ExpressionT.EList(list{ | ExpressionT.EList(list{
ExpressionT.EValue(EvCall("$let")), ExpressionT.EValue(EvCall("$let")),
ExpressionT.EValue(EvSymbol(aSymbol)), 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 => rNewExpression->Result.map(newExpression =>
Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
) )
@ -51,36 +70,38 @@ let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings)
} }
} }
let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) => {
switch expression {
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), ..._}) =>
REExpressionExpected->Error
| _ => replaceSymbols(expression, bindings)
}
}
let doExportVariableExpression = (bindings: ExpressionT.bindings) => { let doExportVariableExpression = (bindings: ExpressionT.bindings) => {
let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty() let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty()
let reducedBindings = bindings->Belt.Map.String.keep ( let reducedBindings = bindings->Belt.Map.String.keep((key, value) =>
(key, value) =>
switch value { switch value {
| ExpressionT.EValue(_) => true | ExpressionT.EValue(_) => true
| _ => false | _ => false
} }
) )
let externalBindings = reducedBindings->Belt.Map.String.reduce( let externalBindings = reducedBindings->Belt.Map.String.reduce(emptyDictionary, (
emptyDictionary, acc,
(acc, key, expressionValue) => { key,
expressionValue,
) => {
let value = switch expressionValue { let value = switch expressionValue {
| EValue(aValue) => aValue | EValue(aValue) => aValue
| _ => EvSymbol("internal") | _ => EvSymbol("internal")
} }
Js.Dict.set(acc, key, value); acc Js.Dict.set(acc, key, value)
} acc
) })
externalBindings->EvRecord->ExpressionT.EValue->Ok 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)
}
switch list { switch list {
| list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok | list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok
@ -90,11 +111,6 @@ let dispatchMacroCall = (list: list<expression>, bindings: ExpressionT.bindings)
statement, statement,
} => } =>
doBindStatement(statement, bindings) doBindStatement(statement, bindings)
| list{
ExpressionT.EValue(EvCall("$$bindExpression")),
ExpressionT.EBindings(bindings),
ExpressionT.EList(list{EValue(EvCall("$exportVariableExpression")), ..._}),
} => doExportVariableExpression(bindings)
| list{ | list{
ExpressionT.EValue(EvCall("$$bindExpression")), ExpressionT.EValue(EvCall("$$bindExpression")),
ExpressionT.EBindings(bindings), ExpressionT.EBindings(bindings),

View File

@ -50,7 +50,15 @@ let defaultBindings: T.bindings = Belt.Map.String.empty
/* /*
Recursively evaluate/reduce the expression (Lisp AST) 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 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 | _ => 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> => let rec seekMacros = (expression: t, bindings: T.bindings): result<t, 'e> =>
switch expression { switch expression {
| T.EValue(_value) => expression->Ok | T.EValue(_value) => expression->Ok