issue 234

Define partial code
This commit is contained in:
Umur Ozkul 2022-04-15 13:49:04 +02:00
parent 3f95ca455b
commit 7ab69a1708
3 changed files with 85 additions and 33 deletions

View File

@ -119,6 +119,10 @@ describe("eval", () => {
list{("x", ExpressionValue.EvNumber(1.))}->Js.Dict.fromList, list{("x", ExpressionValue.EvNumber(1.))}->Js.Dict.fromList,
"Error(JS Exception: Error: Undefined symbol x)", "Error(JS Exception: Error: Undefined symbol x)",
) )
testEvalToBe(
"x=1; y=1",
"???",
)
}) })
}) })

View File

@ -39,6 +39,9 @@ let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
let parse = (mathJsCode: string): result<t, errorValue> => let parse = (mathJsCode: string): result<t, errorValue> =>
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode) mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
let parsePartial = (mathJsCode: string): result<t, errorValue> =>
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromPartialNode)
let defaultBindings: T.bindings = Belt.Map.String.empty let defaultBindings: T.bindings = Belt.Map.String.empty
/* /*
@ -115,15 +118,18 @@ let evalWBindingsExpression_ = (aExpression, bindings): result<expressionValue,
/* /*
Evaluates MathJs code via Reducer using bindings and answers the result Evaluates MathJs code via Reducer using bindings and answers the result
When bindings are used, the code is a partial code as if it is cut from a larger code.
*/ */
let evalWBindings_ = (codeText: string, bindings: T.bindings) => { let evalWBindings_ = (codeText: string, bindings: T.bindings) => {
parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression_(bindings)) parsePartial(codeText)->Result.flatMap(expression => expression->evalWBindingsExpression_(bindings))
} }
/* /*
Evaluates MathJs code via Reducer and answers the result Evaluates MathJs code and bindings via Reducer and answers the result
*/ */
let eval = (code: string) => evalWBindings_(code, defaultBindings) let eval = (codeText: string) => {
parse(codeText)->Result.flatMap(expression => expression->evalWBindingsExpression_(defaultBindings))
}
type externalBindings = Js.Dict.t<expressionValue> type externalBindings = Js.Dict.t<expressionValue>

View File

@ -9,6 +9,22 @@ type expression = ExpressionT.expression
type expressionValue = ExpressionValue.expressionValue type expressionValue = ExpressionValue.expressionValue
type errorValue = ErrorValue.errorValue type errorValue = ErrorValue.errorValue
let passToFunction = (fName: string, rLispArgs): result<expression, errorValue> => {
let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue
let fn = fName->toEvCallValue
rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok)
}
type blockTag =
| ImportVariablesStatement
| ExportVariablesExpression
type tagOrNode =
| BlockTag(blockTag)
| BlockNode(Parse.node)
let toTagOrNode = block => BlockNode(block["node"])
let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> => let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => { Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> => let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> =>
@ -18,16 +34,9 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
) )
) )
let toEvCallValue = (name: string): expression =>
name->ExpressionValue.EvCall->ExpressionT.EValue
let toEvSymbolValue = (name: string): expression => let toEvSymbolValue = (name: string): expression =>
name->ExpressionValue.EvSymbol->ExpressionT.EValue name->ExpressionValue.EvSymbol->ExpressionT.EValue
let passToFunction = (fName: string, rLispArgs): result<expression, errorValue> => {
let fn = fName->toEvCallValue
rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok)
}
let caseFunctionNode = fNode => { let caseFunctionNode = fNode => {
let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs) passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)
@ -94,27 +103,6 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list))
} }
let caseBlockNode = (bNode): result<expression, errorValue> => {
let blocks = bNode["blocks"]
let initialBindings = passToFunction("$$bindings", list{}->Ok)
let lastIndex = Belt.Array.length(blocks) - 1
blocks->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, block, i) => {
rPreviousBindings->Result.flatMap(previousBindings => {
let node = block["node"]
let rStatement: result<expression, errorValue> = node->fromNode
let bindName = if i == lastIndex {
"$$bindExpression"
} else {
"$$bindStatement"
}
rStatement->Result.flatMap((statement: expression) => {
let lispArgs = list{previousBindings, statement}->Ok
passToFunction(bindName, lispArgs)
})
})
})
}
let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode { let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
| MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"])
| MjArrayNode(aNode) => caseArrayNode(aNode) | MjArrayNode(aNode) => caseArrayNode(aNode)
@ -124,8 +112,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
let rExpr: result<expression, errorValue> = expr->Ok let rExpr: result<expression, errorValue> = expr->Ok
rExpr rExpr
} }
| MjBlockNode(bNode) => caseBlockNode(bNode) | MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes
// | MjBlockNode(bNode) => "statement"->toEvSymbolValue->Ok
| 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)
| MjFunctionNode(fNode) => fNode->caseFunctionNode | MjFunctionNode(fNode) => fNode->caseFunctionNode
@ -136,3 +123,58 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
} }
rFinalExpression rFinalExpression
}) })
and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
let initialBindings = passToFunction("$$bindings", list{}->Ok)
let lastIndex = Belt.Array.length(tagOrNodes) - 1
tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => {
rPreviousBindings->Result.flatMap(previousBindings => {
let rStatement: result<expression, errorValue> = switch tagOrNode {
| BlockNode(node) => fromNode(node)
| BlockTag(tag) => switch tag {
| ImportVariablesStatement =>
passToFunction("$$importVariablesStatement", list{}->Ok)
| ExportVariablesExpression =>
passToFunction("$$exportVariablesExpression", list{}->Ok)
}
}
let bindName = if i == lastIndex {
"$$bindExpression"
} else {
"$$bindStatement"
}
rStatement->Result.flatMap((statement: expression) => {
let lispArgs = list{previousBindings, statement}->Ok
passToFunction(bindName, lispArgs)
})
})
})
}
let fromPartialNode = (mathJsNode: Parse.node): result<expression, errorValue> => {
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
let casePartialBlockNode = (bNode: Parse.blockNode) => {
let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode)
let completed = Js.Array2.concatMany(
[BlockTag(ImportVariablesStatement)],
[blocksOrTags, [BlockTag(ExportVariablesExpression)]],
)
completed->caseTagOrNodes
}
let casePartialExpression = (node: Parse.node) => {
let completed = Js.Array2.concatMany(
[BlockTag(ImportVariablesStatement)],
[[BlockNode(node)], [BlockTag(ExportVariablesExpression)]],
)
completed->caseTagOrNodes
}
let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
| MjBlockNode(bNode) => casePartialBlockNode(bNode)
| _ => casePartialExpression(mathJsNode)
}
rFinalExpression
})
}