Compare commits
1 Commits
develop
...
bindings-r
Author | SHA1 | Date | |
---|---|---|---|
|
d4025e7f02 |
|
@ -20,49 +20,11 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
|
|||
expression,
|
||||
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 {
|
||||
| ExpressionT.EValue(EvSymbol(aSymbol)) => {
|
||||
let parameters = getParameters(bindings)
|
||||
answerBindingIfNotParameter(aSymbol, expression, parameters, bindings)
|
||||
}
|
||||
| ExpressionT.EValue(EvCall(aSymbol)) => {
|
||||
let parameters = getParameters(bindings)
|
||||
answerCallBindingIfNotParameter(aSymbol, expression, parameters, bindings)
|
||||
}
|
||||
| ExpressionT.EValue(EvSymbol(aSymbol)) =>
|
||||
ExpressionT.Bindings.getResultIfNotInParameters(bindings, aSymbol)->E.O2.default(Ok(expression))
|
||||
| ExpressionT.EValue(EvCall(aSymbol)) =>
|
||||
ExpressionT.Bindings.getIfNotInParameters(bindings, aSymbol)->E.O2.default(expression)->Ok
|
||||
| ExpressionT.EValue(_) => expression->Ok
|
||||
| ExpressionT.EBindings(_) => expression->Ok
|
||||
| ExpressionT.EParameters(_) => expression->Ok
|
||||
|
@ -71,9 +33,7 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings
|
|||
ExpressionT.EParameters(parameters),
|
||||
expr,
|
||||
}) => {
|
||||
let oldParameters = getParameters(bindings)
|
||||
let newParameters = oldParameters->Js.Array2.concat(parameters)
|
||||
let newBindings = putParameters(bindings, newParameters)
|
||||
let newBindings = ExpressionT.Bindings.Parameters.setArray(bindings, parameters)
|
||||
let rNewExpr = replaceSymbols(expr, newBindings)
|
||||
rNewExpr->Result.flatMap(newExpr =>
|
||||
ExpressionT.EList(list{
|
||||
|
@ -119,7 +79,7 @@ let dispatchMacroCall = (
|
|||
|
||||
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue))
|
||||
rNewExpression->Result.map(newExpression =>
|
||||
Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
|
||||
ExpressionT.Bindings.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
|
||||
)
|
||||
}
|
||||
| _ => REAssignmentExpected->Error
|
||||
|
|
|
@ -6,11 +6,14 @@ module Result = Belt.Result
|
|||
type errorValue = ErrorValue.errorValue
|
||||
type expression = ExpressionT.expression
|
||||
|
||||
let passToFunction = (fName: string, lispArgs: list<expression>): expression => {
|
||||
let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue
|
||||
let fn = fName->toEvCallValue
|
||||
list{fn, ...lispArgs}->ExpressionT.EList
|
||||
}
|
||||
let toEvCallValue = (name: string): expression => ExpressionT.EValue(ExpressionValue.EvCall(name))
|
||||
|
||||
let toEvSymbolValue = (name: string): expression =>
|
||||
name->ExpressionValue.EvSymbol->ExpressionT.EValue
|
||||
let toEvSymbolValue = (name: string): expression => 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})
|
||||
}
|
|
@ -8,9 +8,60 @@ open ReducerInterface.ExpressionValue
|
|||
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.
|
||||
*/
|
||||
|
||||
type rec expression =
|
||||
| EList(list<expression>) // A list to map-reduce
|
||||
| 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
|
||||
| EParameters(array<string>) // for $defun; for internal use only
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module Builder = Reducer_Expression_Builder
|
||||
module ExpressionBuilder = Reducer_Expression_Builder
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
|
@ -31,7 +31,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
let caseFunctionNode = fNode => {
|
||||
let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
|
||||
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 =>
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -78,27 +78,27 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
let caseAccessorNode = (objectNode, indexNode) => {
|
||||
caseIndexNode(indexNode)->Result.flatMap(indexCode => {
|
||||
fromNode(objectNode)->Result.flatMap(objectCode =>
|
||||
Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok
|
||||
ExpressionBuilder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let caseAssignmentNode = aNode => {
|
||||
let symbol = aNode["object"]["name"]->Builder.toEvSymbolValue
|
||||
let symbol = aNode["object"]["name"]->ExpressionBuilder.toEvSymbolValue
|
||||
let rValueExpression = fromNode(aNode["value"])
|
||||
rValueExpression->Result.flatMap(valueExpression =>
|
||||
Builder.passToFunction("$let", list{symbol, valueExpression})->Ok
|
||||
ExpressionBuilder.passToFunction("$let", list{symbol, valueExpression})->Ok
|
||||
)
|
||||
}
|
||||
|
||||
let caseFunctionAssignmentNode = faNode => {
|
||||
let symbol = faNode["name"]->Builder.toEvSymbolValue
|
||||
let symbol = faNode["name"]->ExpressionBuilder.toEvSymbolValue
|
||||
let rValueExpression = fromNode(faNode["expr"])
|
||||
|
||||
rValueExpression->Result.flatMap(valueExpression => {
|
||||
let lispParams = faNode["params"]->ExpressionT.EParameters
|
||||
let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression})
|
||||
Builder.passToFunction("$let", list{symbol, lambda})->Ok
|
||||
let lambda = ExpressionBuilder.passToFunction("$lambda", list{lispParams, valueExpression})
|
||||
ExpressionBuilder.passToFunction("$let", list{symbol, lambda})->Ok
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
| MjArrayNode(aNode) => caseArrayNode(aNode)
|
||||
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
|
||||
| MjSymbolNode(sNode) => {
|
||||
let expr: expression = Builder.toEvSymbolValue(sNode["name"])
|
||||
let expr: expression = ExpressionBuilder.toEvSymbolValue(sNode["name"])
|
||||
let rExpr: result<expression, errorValue> = expr->Ok
|
||||
rExpr
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|||
rFinalExpression
|
||||
})
|
||||
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
|
||||
tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => {
|
||||
rPreviousBindings->Result.flatMap(previousBindings => {
|
||||
|
@ -137,9 +137,9 @@ and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
|
|||
| BlockTag(tag) =>
|
||||
switch tag {
|
||||
| ImportVariablesStatement =>
|
||||
Builder.passToFunction("$importVariablesStatement", list{})->Ok
|
||||
ExpressionBuilder.passToFunction("$importVariablesStatement", list{})->Ok
|
||||
| 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) => {
|
||||
Builder.passToFunction(bindName, list{previousBindings, statement})->Ok
|
||||
ExpressionBuilder.passToFunction(bindName, list{previousBindings, statement})->Ok
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -338,6 +338,7 @@ module A = {
|
|||
let getBy = Belt.Array.getBy
|
||||
let last = a => get(a, length(a) - 1)
|
||||
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 fold_left = Array.fold_left
|
||||
let fold_right = Array.fold_right
|
||||
|
|
Loading…
Reference in New Issue
Block a user