Compare commits
1 Commits
develop
...
bindings-r
Author | SHA1 | Date | |
---|---|---|---|
|
d4025e7f02 |
|
@ -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
|
||||||
|
|
|
@ -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})
|
||||||
|
}
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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)})`
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user