function definition parse (tested)

This commit is contained in:
Umur Ozkul 2022-04-23 21:13:43 +02:00
parent a915e68049
commit 88b6d49ad3
5 changed files with 32 additions and 1 deletions

View File

@ -0,0 +1,12 @@
open Jest
open Reducer_TestHelpers
describe("Parse function assignment", () => {
testParseToBe("f(x)=x", "Ok((:$let :f (:$lambda (x) :x)))")
testParseToBe("f(x)=2*x", "Ok((:$let :f (:$lambda (x) (:multiply 2 :x))))")
//MathJs does not allow blocks in function definitions
})
Skip.describe("Evaluate function assignment", () => {
testParseToBe("f(x)=x; f(1)", "Ok(1)")
})

View File

@ -33,6 +33,7 @@ let dispatchMacroCall = (
} }
| ExpressionT.EValue(_) => expression->Ok | ExpressionT.EValue(_) => expression->Ok
| ExpressionT.EBindings(_) => expression->Ok | ExpressionT.EBindings(_) => expression->Ok
| ExpressionT.EParameters(_) => expression->Ok
| ExpressionT.EList(list) => { | ExpressionT.EList(list) => {
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
racc->Result.flatMap(acc => { racc->Result.flatMap(acc => {

View File

@ -16,6 +16,7 @@ type t = expression
let rec toString = expression => let rec toString = expression =>
switch expression { switch expression {
| T.EBindings(_) => "$$bound" | T.EBindings(_) => "$$bound"
| T.EParameters(params) => `(${Js.Array2.toString(params->Belt.List.toArray)})`
| T.EList(aList) => | T.EList(aList) =>
`(${Belt.List.map(aList, aValue => toString(aValue)) `(${Belt.List.map(aList, aValue => toString(aValue))
->Extra.List.interperse(" ") ->Extra.List.interperse(" ")
@ -72,6 +73,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
switch expression { switch expression {
| T.EValue(_value) => expression->Ok | T.EValue(_value) => expression->Ok
| T.EBindings(_value) => expression->Ok | T.EBindings(_value) => expression->Ok
| T.EParameters(_value) => expression->Ok
| T.EList(list) => { | T.EList(list) => {
let racc: result<list<t>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( let racc: result<list<t>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
racc, racc,
@ -108,6 +110,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result<express
racc->Result.flatMap(acc => acc->reduceValueList) racc->Result.flatMap(acc => acc->reduceValueList)
} }
| EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error | EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error
| EParameters(_parameters) => RETodo("Error: Lambda Parameters cannot be reduced to values")->Error
} }
let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings) let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings)

View File

@ -11,5 +11,6 @@ open ReducerInterface.ExpressionValue
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/def kind of statements return bindings | EBindings(bindings) // $let kind of statements return bindings; for internal use only
| EParameters(list<string>) // for $defun; for internal use only
and bindings = Belt.Map.String.t<expression> and bindings = Belt.Map.String.t<expression>

View File

@ -99,6 +99,19 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
}) })
} }
let caseFunctionAssignmentNode = faNode => {
let symbol = faNode["name"]->toEvSymbolValue
let rValueExpression = fromNode(faNode["expr"])
rValueExpression->Result.flatMap(valueExpression => {
let lispParams = faNode["params"]->Belt.List.fromArray->ExpressionT.EParameters
let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok)
rLambda -> Result.flatMap( lambda => {
passToFunction("$let", list{symbol, lambda}->Ok)
})
})
}
let caseArrayNode = aNode => { let caseArrayNode = aNode => {
aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list))
} }
@ -115,6 +128,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
| MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes | MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes
| MjConstantNode(cNode) => | MjConstantNode(cNode) =>
cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
| MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode)
| MjFunctionNode(fNode) => fNode->caseFunctionNode | MjFunctionNode(fNode) => fNode->caseFunctionNode
| MjIndexNode(iNode) => caseIndexNode(iNode) | MjIndexNode(iNode) => caseIndexNode(iNode)
| MjObjectNode(oNode) => caseObjectNode(oNode) | MjObjectNode(oNode) => caseObjectNode(oNode)