From 84f3420369d990fdc4fbda73975cf44ceca79d3a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 22:02:06 +0200 Subject: [PATCH] parse assignment --- .../Reducer_MathJsParse_test.res | 14 +++----- .../rescript/Reducer/Reducer_ErrorValue.res | 2 ++ .../Reducer_MathJs/Reducer_MathJs_Parse.res | 33 ++++++++++++++++--- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 41ba6239..31cbeb63 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -7,17 +7,13 @@ open Expect let expectParseToBe = (expr, answer) => Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(answer) -let testParse = (expr, answer) => - test(expr, () => expectParseToBe(expr, answer)) +let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParse = (desc, expr, answer) => - test(desc, () => expectParseToBe(expr, answer)) +let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let skipTestParse = (expr, answer) => - Skip.test(expr, () => expectParseToBe(expr, answer)) +let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) -let skipDescTestParse = (desc, expr, answer) => - Skip.test(desc, () => expectParseToBe(expr, answer)) +let skipDescTestParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) describe("MathJs parse", () => { describe("literals operators paranthesis", () => { @@ -31,7 +27,7 @@ describe("MathJs parse", () => { }) describe("variables", () => { - skipTestParse("x = 1", "???") + testParse("x = 1", "x = 1") skipTestParse("x", "???") }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 4f57bc2c..70601726 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -3,6 +3,7 @@ type errorValue = | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception | RERecordPropertyNotFound(string, string) + | RESyntaxError(string) | RETodo(string) // To do type t = errorValue @@ -24,5 +25,6 @@ let errorToString = err => answer } | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}` + | RESyntaxError(desc) => `Syntax Error: ${desc}` | RETodo(msg) => `TODO: ${msg}` } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index bfd186e0..15ef6e26 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -7,7 +7,6 @@ open Reducer_ErrorValue type node = {"type": string, "isNode": bool, "comment": string} type arrayNode = {...node, "items": array} -//assignmentNode //blockNode //conditionalNode type constantNode = {...node, "value": unit} @@ -23,9 +22,15 @@ type parenthesisNode = {...node, "content": node} //rangeNode //relationalNode type symbolNode = {...node, "name": string} +type assignmentNode = {...node, "object": symbolNode, "value": node} +type assignmentNodeWAccessor = {...node, "object": accessorNode, "value": node} +type assignmentNodeWIndex = {...assignmentNodeWAccessor, "index": Js.null} external castAccessorNode: node => accessorNode = "%identity" external castArrayNode: node => arrayNode = "%identity" +external castAssignmentNode: node => assignmentNode = "%identity" +external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" +external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" external castConstantNode: node => constantNode = "%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" @@ -50,6 +55,7 @@ let parse = (expr: string): result => type mathJsNode = | MjAccessorNode(accessorNode) | MjArrayNode(arrayNode) + | MjAssignmentNode(assignmentNode) | MjConstantNode(constantNode) | MjFunctionNode(functionNode) | MjIndexNode(indexNode) @@ -58,10 +64,20 @@ type mathJsNode = | MjParenthesisNode(parenthesisNode) | MjSymbolNode(symbolNode) -let castNodeType = (node: node) => +let castNodeType = (node: node) => { + let decideAssignmentNode = node => { + let iNode = node->castAssignmentNodeWIndex + if Js.Null.test(iNode["index"]) && iNode["object"]["type"] == "SymbolNode" { + node->castAssignmentNode->MjAssignmentNode->Ok + } else { + RESyntaxError("Assignment to index or property not supported")->Error + } + } + switch node["type"] { | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok + | "AssignmentNode" => node->decideAssignmentNode | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | "IndexNode" => node->castIndexNode->MjIndexNode->Ok @@ -71,6 +87,7 @@ let castNodeType = (node: node) => | "SymbolNode" => node->castSymbolNode->MjSymbolNode->Ok | _ => RETodo(`Argg, unhandled MathJsNode: ${node["type"]}`)->Error } +} let rec toString = (mathJsNode: mathJsNode): string => { let toStringValue = (a: 'a): string => @@ -89,7 +106,8 @@ let rec toString = (mathJsNode: mathJsNode): string => { let toStringFunctionNode = (fnode: functionNode): string => `${fnode["fn"]}(${fnode["args"]->toStringNodeArray})` - let toStringObjectEntry = ((key: string, value: node)): string => `${key}: ${value->toStringMathJsNode}` + let toStringObjectEntry = ((key: string, value: node)): string => + `${key}: ${value->toStringMathJsNode}` let toStringObjectNode = (oNode: objectNode): string => `{${oNode["properties"] @@ -103,16 +121,21 @@ let rec toString = (mathJsNode: mathJsNode): string => { ->Belt.Array.map(each => toStringResult(each->castNodeType)) ->Js.String.concatMany("") + let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"] + switch mathJsNode { - | MjAccessorNode(aNode) => `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` + | MjAccessorNode(aNode) => + `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]` + | MjAssignmentNode(aNode) => + `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` | MjConstantNode(cNode) => cNode["value"]->toStringValue | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode | MjObjectNode(oNode) => oNode->toStringObjectNode | MjOperatorNode(opNode) => opNode->castOperatorNodeToFunctionNode->toStringFunctionNode | MjParenthesisNode(pNode) => `(${toStringMathJsNode(pNode["content"])})` - | MjSymbolNode(sNode) => sNode["name"] + | MjSymbolNode(sNode) => sNode->toStringSymbolNode } } and toStringResult = (rMathJsNode: result): string =>