Attempt of refactor for Bindings and Paramaters

This commit is contained in:
Ozzie Gooen 2022-04-25 16:26:23 -04:00
parent 7d4e3072b8
commit d4025e7f02
6 changed files with 83 additions and 68 deletions

View File

@ -20,49 +20,11 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
expression, expression,
errorValue, errorValue,
> => { > => {
let getParameters = (bindings: ExpressionT.bindings): array<string> => {
let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([]))
switch eParameters {
| EParameters(parameters) => parameters
| _ => []
}
}
let putParameters = (
bindings: ExpressionT.bindings,
parameters: array<string>,
): ExpressionT.bindings =>
Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters))
let answerBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) =>
switch Js.Array2.some(parameters, a => a == aSymbol) {
| true => defaultExpression->Ok // We cannot bind the parameters with global values
| false =>
switch bindings->Belt.Map.String.get(aSymbol) {
| Some(boundExpression) => boundExpression->Ok
| None => RESymbolNotFound(aSymbol)->Error
}
}
let answerCallBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) =>
switch Js.Array2.some(parameters, a => a == aSymbol) {
| true => defaultExpression->Ok // We cannot bind the parameters with global values
| false =>
switch bindings->Belt.Map.String.get(aSymbol) {
| Some(boundExpression) => boundExpression->Ok
| None => defaultExpression->Ok
}
}
switch expression { switch expression {
| ExpressionT.EValue(EvSymbol(aSymbol)) => { | ExpressionT.EValue(EvSymbol(aSymbol)) =>
let parameters = getParameters(bindings) ExpressionT.Bindings.getResultIfNotInParameters(bindings, aSymbol)->E.O2.default(Ok(expression))
answerBindingIfNotParameter(aSymbol, expression, parameters, bindings) | ExpressionT.EValue(EvCall(aSymbol)) =>
} ExpressionT.Bindings.getIfNotInParameters(bindings, aSymbol)->E.O2.default(expression)->Ok
| ExpressionT.EValue(EvCall(aSymbol)) => {
let parameters = getParameters(bindings)
answerCallBindingIfNotParameter(aSymbol, expression, parameters, bindings)
}
| ExpressionT.EValue(_) => expression->Ok | ExpressionT.EValue(_) => expression->Ok
| ExpressionT.EBindings(_) => expression->Ok | ExpressionT.EBindings(_) => expression->Ok
| ExpressionT.EParameters(_) => expression->Ok | ExpressionT.EParameters(_) => expression->Ok
@ -71,9 +33,7 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
ExpressionT.EParameters(parameters), ExpressionT.EParameters(parameters),
expr, expr,
}) => { }) => {
let oldParameters = getParameters(bindings) let newBindings = ExpressionT.Bindings.Parameters.setArray(bindings, parameters)
let newParameters = oldParameters->Js.Array2.concat(parameters)
let newBindings = putParameters(bindings, newParameters)
let rNewExpr = replaceSymbols(expr, newBindings) let rNewExpr = replaceSymbols(expr, newBindings)
rNewExpr->Result.flatMap(newExpr => rNewExpr->Result.flatMap(newExpr =>
ExpressionT.EList(list{ ExpressionT.EList(list{
@ -119,7 +79,7 @@ let dispatchMacroCall = (
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue)) 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 ExpressionT.Bindings.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
) )
} }
| _ => REAssignmentExpected->Error | _ => REAssignmentExpected->Error

View File

@ -6,11 +6,14 @@ module Result = Belt.Result
type errorValue = ErrorValue.errorValue type errorValue = ErrorValue.errorValue
type expression = ExpressionT.expression type expression = ExpressionT.expression
let passToFunction = (fName: string, lispArgs: list<expression>): expression => { let toEvCallValue = (name: string): expression => ExpressionT.EValue(ExpressionValue.EvCall(name))
let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue
let fn = fName->toEvCallValue
list{fn, ...lispArgs}->ExpressionT.EList
}
let toEvSymbolValue = (name: string): expression => let toEvSymbolValue = (name: string): expression => ExpressionT.EValue(
name->ExpressionValue.EvSymbol->ExpressionT.EValue ExpressionValue.EvSymbol(name),
)
//From Ozzie: I think this could really use a more descriptive name.
let passToFunction = (fName: string, lispArgs: list<expression>): expression => {
let fn = toEvCallValue(fName)
ExpressionT.EList(list{fn, ...lispArgs})
}

View File

@ -8,9 +8,60 @@ open ReducerInterface.ExpressionValue
A Lisp AST contains only expressions/primitive values to apply to their left. A Lisp AST contains only expressions/primitive values to apply to their left.
The act of defining the semantics of a functional language is to write it in terms of Lisp AST. The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
*/ */
type rec expression = type rec expression =
| EList(list<expression>) // A list to map-reduce | EList(list<expression>) // A list to map-reduce
| EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible | EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
| EBindings(bindings) // $let kind of statements return bindings; for internal use only | EBindings(bindings) // $let kind of statements return bindings; for internal use only
| EParameters(array<string>) // for $defun; for internal use only | EParameters(array<string>) // for $defun; for internal use only
and bindings = Belt.Map.String.t<expression> and bindings = Belt.Map.String.t<expression>
module Bindings = {
type t = bindings
let get = (t: t, str: string) => Belt.Map.String.get(t, str)
let set = (t: t, key: string, value: expression): t => {
Belt.Map.String.set(t, key, value)
}
let getResult = (t: t, str: string): result<expression, Reducer_ErrorValue.errorValue> =>
get(t, str) |> E.O.toResult(Reducer_ErrorValue.RESymbolNotFound(str))
module Parameters = {
let parametersKey = "$parameters"
let default = EParameters([])
let get = (t: t): array<string> => {
let expressionParameters = Belt.Map.String.getWithDefault(t, parametersKey, default)
switch expressionParameters {
| EParameters(parameters) => parameters
| _ => []
}
}
let has = (t: t, s: string): bool => E.A.has(get(t), s)
let setArray = (t: t, newParameters: array<string>): t => {
let oldParameters = get(t)
let updatedParameters = Js.Array2.concat(oldParameters, newParameters)
Belt.Map.String.set(t, parametersKey, EParameters(updatedParameters))
}
}
// We cannot bind the parameters with global values
let getIfNotInParameters = (t: t, aSymbol: string):option<expression> => {
if Parameters.has(t, aSymbol) {
None
} else {
get(t, aSymbol)
}
}
// We cannot bind the parameters with global values
let getResultIfNotInParameters = (t: t, aSymbol: string) => {
if Parameters.has(t, aSymbol) {
None
} else {
Some(getResult(t, aSymbol))
}
}
}

View File

@ -1,4 +1,4 @@
module Builder = Reducer_Expression_Builder module ExpressionBuilder = Reducer_Expression_Builder
module ErrorValue = Reducer_ErrorValue module ErrorValue = Reducer_ErrorValue
module ExpressionT = Reducer_Expression_T module ExpressionT = Reducer_Expression_T
module ExpressionValue = ReducerInterface.ExpressionValue module ExpressionValue = ReducerInterface.ExpressionValue
@ -31,7 +31,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
let caseFunctionNode = fNode => { let caseFunctionNode = fNode => {
let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
rLispArgs->Result.flatMap(lispArgs => rLispArgs->Result.flatMap(lispArgs =>
Builder.passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)->Ok ExpressionBuilder.passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)->Ok
) )
} }
@ -53,7 +53,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
) )
) )
rargs->Result.flatMap(args => rargs->Result.flatMap(args =>
Builder.passToFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok ExpressionBuilder.passToFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok
) // $constructRecord gets a single argument: List of key-value paiers ) // $constructRecord gets a single argument: List of key-value paiers
} }
@ -78,27 +78,27 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
let caseAccessorNode = (objectNode, indexNode) => { let caseAccessorNode = (objectNode, indexNode) => {
caseIndexNode(indexNode)->Result.flatMap(indexCode => { caseIndexNode(indexNode)->Result.flatMap(indexCode => {
fromNode(objectNode)->Result.flatMap(objectCode => fromNode(objectNode)->Result.flatMap(objectCode =>
Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok ExpressionBuilder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok
) )
}) })
} }
let caseAssignmentNode = aNode => { let caseAssignmentNode = aNode => {
let symbol = aNode["object"]["name"]->Builder.toEvSymbolValue let symbol = aNode["object"]["name"]->ExpressionBuilder.toEvSymbolValue
let rValueExpression = fromNode(aNode["value"]) let rValueExpression = fromNode(aNode["value"])
rValueExpression->Result.flatMap(valueExpression => rValueExpression->Result.flatMap(valueExpression =>
Builder.passToFunction("$let", list{symbol, valueExpression})->Ok ExpressionBuilder.passToFunction("$let", list{symbol, valueExpression})->Ok
) )
} }
let caseFunctionAssignmentNode = faNode => { let caseFunctionAssignmentNode = faNode => {
let symbol = faNode["name"]->Builder.toEvSymbolValue let symbol = faNode["name"]->ExpressionBuilder.toEvSymbolValue
let rValueExpression = fromNode(faNode["expr"]) let rValueExpression = fromNode(faNode["expr"])
rValueExpression->Result.flatMap(valueExpression => { rValueExpression->Result.flatMap(valueExpression => {
let lispParams = faNode["params"]->ExpressionT.EParameters let lispParams = faNode["params"]->ExpressionT.EParameters
let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression}) let lambda = ExpressionBuilder.passToFunction("$lambda", list{lispParams, valueExpression})
Builder.passToFunction("$let", list{symbol, lambda})->Ok ExpressionBuilder.passToFunction("$let", list{symbol, lambda})->Ok
}) })
} }
@ -111,7 +111,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
| MjArrayNode(aNode) => caseArrayNode(aNode) | MjArrayNode(aNode) => caseArrayNode(aNode)
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode) | MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
| MjSymbolNode(sNode) => { | MjSymbolNode(sNode) => {
let expr: expression = Builder.toEvSymbolValue(sNode["name"]) let expr: expression = ExpressionBuilder.toEvSymbolValue(sNode["name"])
let rExpr: result<expression, errorValue> = expr->Ok let rExpr: result<expression, errorValue> = expr->Ok
rExpr rExpr
} }
@ -128,7 +128,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
rFinalExpression rFinalExpression
}) })
and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => { and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
let initialBindings = Builder.passToFunction("$$bindings", list{})->Ok let initialBindings = ExpressionBuilder.passToFunction("$$bindings", list{})->Ok
let lastIndex = Belt.Array.length(tagOrNodes) - 1 let lastIndex = Belt.Array.length(tagOrNodes) - 1
tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => { tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => {
rPreviousBindings->Result.flatMap(previousBindings => { rPreviousBindings->Result.flatMap(previousBindings => {
@ -137,9 +137,9 @@ and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
| BlockTag(tag) => | BlockTag(tag) =>
switch tag { switch tag {
| ImportVariablesStatement => | ImportVariablesStatement =>
Builder.passToFunction("$importVariablesStatement", list{})->Ok ExpressionBuilder.passToFunction("$importVariablesStatement", list{})->Ok
| ExportVariablesExpression => | ExportVariablesExpression =>
Builder.passToFunction("$exportVariablesExpression", list{})->Ok ExpressionBuilder.passToFunction("$exportVariablesExpression", list{})->Ok
} }
} }
@ -150,7 +150,7 @@ and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
} }
rStatement->Result.flatMap((statement: expression) => { rStatement->Result.flatMap((statement: expression) => {
Builder.passToFunction(bindName, list{previousBindings, statement})->Ok ExpressionBuilder.passToFunction(bindName, list{previousBindings, statement})->Ok
}) })
}) })
}) })

View File

@ -83,4 +83,4 @@ let toStringResultRecord = x =>
switch x { switch x {
| Ok(a) => `Ok(${toStringRecord(a)})` | Ok(a) => `Ok(${toStringRecord(a)})`
| Error(m) => `Error(${ErrorValue.errorToString(m)})` | Error(m) => `Error(${ErrorValue.errorToString(m)})`
} }

View File

@ -338,6 +338,7 @@ module A = {
let getBy = Belt.Array.getBy let getBy = Belt.Array.getBy
let last = a => get(a, length(a) - 1) let last = a => get(a, length(a) - 1)
let first = get(_, 0) let first = get(_, 0)
let has = (r, el) => Belt.Array.some(r, (x) => x == el)
let hasBy = (r, fn) => Belt.Array.getBy(r, fn) |> O.isSome let hasBy = (r, fn) => Belt.Array.getBy(r, fn) |> O.isSome
let fold_left = Array.fold_left let fold_left = Array.fold_left
let fold_right = Array.fold_right let fold_right = Array.fold_right