Merge pull request #484 from quantified-uncertainty/reducer-dev
Reducer: Ternary operator (if then else)
This commit is contained in:
		
						commit
						b29ba9162f
					
				|  | @ -66,4 +66,9 @@ describe("MathJs parse", () => { | |||
|   describe("comments", () => { | ||||
|     testDescriptionParse("define", "1 # This is a comment", "1") | ||||
|   }) | ||||
| 
 | ||||
|   describe("ternary operator", () => { | ||||
|     testParse("1 ? 2 : 3", "ternary(1, 2, 3)") | ||||
|     testParse("1 ? 2 : 3 ? 4 : 5", "ternary(1, 2, ternary(3, 4, 5))") | ||||
|   }) | ||||
| }) | ||||
|  |  | |||
|  | @ -62,7 +62,7 @@ describe("call and bindings", () => { | |||
|   testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)") | ||||
| }) | ||||
| 
 | ||||
| describe("function trics", () => { | ||||
| describe("function tricks", () => { | ||||
|   testParseToBe( | ||||
|     "f(x)=f(y)=2; f(2)", | ||||
|     "Ok((:$$block (:$$block (:$let :f (:$$lambda [x] (:$$block (:$let :f (:$$lambda [y] (:$$block 2)))))) (:f 2))))", | ||||
|  |  | |||
|  | @ -1,12 +1,14 @@ | |||
| open Jest | ||||
| open Reducer_TestHelpers | ||||
| 
 | ||||
| Skip.describe("Parse ternary operator", () => { | ||||
|   testParseToBe("true ? 'YES' : 'NO'", "Ok('YES')") | ||||
|   testParseToBe("false ? 'YES' : 'NO'", "Ok('NO')") | ||||
| describe("Parse ternary operator", () => { | ||||
|   testParseToBe("true ? 'YES' : 'NO'", "Ok((:$$block (:$$ternary true 'YES' 'NO')))") | ||||
| }) | ||||
| 
 | ||||
| Skip.describe("Evaluate ternary operator", () => { | ||||
| describe("Evaluate ternary operator", () => { | ||||
|   testEvalToBe("true ? 'YES' : 'NO'", "Ok('YES')") | ||||
|   testEvalToBe("false ? 'YES' : 'NO'", "Ok('NO')") | ||||
|   testEvalToBe("2 > 1 ? 'YES' : 'NO'", "Ok('YES')") | ||||
|   testEvalToBe("2 <= 1 ? 'YES' : 'NO'", "Ok('NO')") | ||||
|   testEvalToBe("1+1 ? 'YES' : 'NO'", "Error(Expected type: Boolean)") | ||||
| }) | ||||
|  |  | |||
|  | @ -132,6 +132,23 @@ let dispatchMacroCall = ( | |||
|       eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition), | ||||
|     )->Ok | ||||
| 
 | ||||
|   let doTernary = ( | ||||
|     condition: expression, | ||||
|     ifTrue: expression, | ||||
|     ifFalse: expression, | ||||
|     bindings: ExpressionT.bindings, | ||||
|     environment, | ||||
|   ): result<expressionWithContext, errorValue> => { | ||||
|     let rCondition = reduceExpression(condition, bindings, environment) | ||||
|     rCondition->Result.flatMap(conditionValue => | ||||
|       switch conditionValue { | ||||
|       | ExpressionValue.EvBool(false) => ExpressionWithContext.noContext(ifFalse)->Ok | ||||
|       | ExpressionValue.EvBool(true) => ExpressionWithContext.noContext(ifTrue)->Ok | ||||
|       | _ => REExpectedType("Boolean")->Error | ||||
|       } | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment): result< | ||||
|     expressionWithContext, | ||||
|     errorValue, | ||||
|  | @ -162,6 +179,8 @@ let dispatchMacroCall = ( | |||
|         lambdaDefinition, | ||||
|       } => | ||||
|       doLambdaDefinition(bindings, parameters, lambdaDefinition) | ||||
|     | list{ExpressionT.EValue(EvCall("$$ternary")), condition, ifTrue, ifFalse} => | ||||
|       doTernary(condition, ifTrue, ifFalse, bindings, environment) | ||||
|     | _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ type errorValue = | |||
|   | RESymbolNotFound(string) | ||||
|   | RESyntaxError(string) | ||||
|   | RETodo(string) // To do | ||||
|   | REExpectedType(string) | ||||
| 
 | ||||
| type t = errorValue | ||||
| 
 | ||||
|  | @ -46,4 +47,5 @@ let errorToString = err => | |||
|   | RESymbolNotFound(symbolName) => `${symbolName} is not defined` | ||||
|   | RESyntaxError(desc) => `Syntax Error: ${desc}` | ||||
|   | RETodo(msg) => `TODO: ${msg}` | ||||
|   | REExpectedType(typeName) => `Expected type: ${typeName}` | ||||
|   } | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ type node = {"type": string, "isNode": bool, "comment": string} | |||
| type arrayNode = {...node, "items": array<node>} | ||||
| type block = {"node": node} | ||||
| type blockNode = {...node, "blocks": array<block>} | ||||
| //conditionalNode | ||||
| type conditionalNode = {...node, "condition": node, "trueExpr": node, "falseExpr": node} | ||||
| type constantNode = {...node, "value": unit} | ||||
| type functionAssignmentNode = {...node, "name": string, "params": array<string>, "expr": node} | ||||
| type indexNode = {...node, "dimensions": array<node>} | ||||
|  | @ -31,6 +31,7 @@ external castAssignmentNode: node => assignmentNode = "%identity" | |||
| external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" | ||||
| external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" | ||||
| external castBlockNode: node => blockNode = "%identity" | ||||
| external castConditionalNode: node => conditionalNode = "%identity" | ||||
| external castConstantNode: node => constantNode = "%identity" | ||||
| external castFunctionAssignmentNode: node => functionAssignmentNode = "%identity" | ||||
| external castFunctionNode: node => functionNode = "%identity" | ||||
|  | @ -58,6 +59,7 @@ type mathJsNode = | |||
|   | MjArrayNode(arrayNode) | ||||
|   | MjAssignmentNode(assignmentNode) | ||||
|   | MjBlockNode(blockNode) | ||||
|   | MjConditionalNode(conditionalNode) | ||||
|   | MjConstantNode(constantNode) | ||||
|   | MjFunctionAssignmentNode(functionAssignmentNode) | ||||
|   | MjFunctionNode(functionNode) | ||||
|  | @ -82,6 +84,7 @@ let castNodeType = (node: node) => { | |||
|   | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok | ||||
|   | "AssignmentNode" => node->decideAssignmentNode | ||||
|   | "BlockNode" => node->castBlockNode->MjBlockNode->Ok | ||||
|   | "ConditionalNode" => node->castConditionalNode->MjConditionalNode->Ok | ||||
|   | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok | ||||
|   | "FunctionAssignmentNode" => node->castFunctionAssignmentNode->MjFunctionAssignmentNode->Ok | ||||
|   | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | ||||
|  | @ -157,6 +160,10 @@ let rec toString = (mathJsNode: mathJsNode): string => { | |||
|   | MjAssignmentNode(aNode) => | ||||
|     `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` | ||||
|   | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}` | ||||
|   | MjConditionalNode(cNode) => | ||||
|     `ternary(${toStringMathJsNode(cNode["condition"])}, ${toStringMathJsNode( | ||||
|         cNode["trueExpr"], | ||||
|       )}, ${toStringMathJsNode(cNode["falseExpr"])})` | ||||
|   | MjConstantNode(cNode) => cNode["value"]->toStringValue | ||||
|   | MjFunctionAssignmentNode(faNode) => faNode->toStringFunctionAssignmentNode | ||||
|   | MjFunctionNode(fNode) => fNode->toStringFunctionNode | ||||
|  |  | |||
|  | @ -113,6 +113,20 @@ let rec fromInnerNode = (mathJsNode: Parse.node): result<expression, errorValue> | |||
|       aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) | ||||
|     } | ||||
| 
 | ||||
|     let caseConditionalNode = cndNode => { | ||||
|       let rCondition = fromInnerNode(cndNode["condition"]) | ||||
|       let rTrueExpr = fromInnerNode(cndNode["trueExpr"]) | ||||
|       let rFalse = fromInnerNode(cndNode["falseExpr"]) | ||||
| 
 | ||||
|       rCondition->Result.flatMap(condition => | ||||
|         rTrueExpr->Result.flatMap(trueExpr => | ||||
|           rFalse->Result.flatMap(falseExpr => | ||||
|             ExpressionBuilder.eFunction("$$ternary", list{condition, trueExpr, falseExpr})->Ok | ||||
|           ) | ||||
|         ) | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode { | ||||
|     | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) | ||||
|     | MjArrayNode(aNode) => caseArrayNode(aNode) | ||||
|  | @ -123,6 +137,7 @@ let rec fromInnerNode = (mathJsNode: Parse.node): result<expression, errorValue> | |||
|         rExpr | ||||
|       } | ||||
|     | MjBlockNode(bNode) => bNode["blocks"]->Js.Array2.map(blockToNode)->caseBlock | ||||
|     | MjConditionalNode(cndNode) => caseConditionalNode(cndNode) | ||||
|     | MjConstantNode(cNode) => | ||||
|       cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) | ||||
|     | MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user