From d4025e7f0212be570aafd40e8128200ec60e17f7 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 25 Apr 2022 16:26:23 -0400 Subject: [PATCH] Attempt of refactor for Bindings and Paramaters --- .../Reducer_Dispatch_BuiltInMacros.res | 52 +++---------------- .../Reducer_Expression_Builder.res | 17 +++--- .../Reducer_Expression_T.res | 51 ++++++++++++++++++ .../Reducer_MathJs_ToExpression.res | 28 +++++----- .../ReducerInterface_ExpressionValue.res | 2 +- .../squiggle-lang/src/rescript/Utility/E.res | 1 + 6 files changed, 83 insertions(+), 68 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 5facc9e7..2f6b45dd 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -20,49 +20,11 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings expression, errorValue, > => { - let getParameters = (bindings: ExpressionT.bindings): array => { - let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([])) - switch eParameters { - | EParameters(parameters) => parameters - | _ => [] - } - } - - let putParameters = ( - bindings: ExpressionT.bindings, - parameters: array, - ): 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 { - | ExpressionT.EValue(EvSymbol(aSymbol)) => { - let parameters = getParameters(bindings) - answerBindingIfNotParameter(aSymbol, expression, parameters, bindings) - } - | ExpressionT.EValue(EvCall(aSymbol)) => { - let parameters = getParameters(bindings) - answerCallBindingIfNotParameter(aSymbol, expression, parameters, bindings) - } + | ExpressionT.EValue(EvSymbol(aSymbol)) => + ExpressionT.Bindings.getResultIfNotInParameters(bindings, aSymbol)->E.O2.default(Ok(expression)) + | ExpressionT.EValue(EvCall(aSymbol)) => + ExpressionT.Bindings.getIfNotInParameters(bindings, aSymbol)->E.O2.default(expression)->Ok | ExpressionT.EValue(_) => expression->Ok | ExpressionT.EBindings(_) => expression->Ok | ExpressionT.EParameters(_) => expression->Ok @@ -71,9 +33,7 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings ExpressionT.EParameters(parameters), expr, }) => { - let oldParameters = getParameters(bindings) - let newParameters = oldParameters->Js.Array2.concat(parameters) - let newBindings = putParameters(bindings, newParameters) + let newBindings = ExpressionT.Bindings.Parameters.setArray(bindings, parameters) let rNewExpr = replaceSymbols(expr, newBindings) rNewExpr->Result.flatMap(newExpr => ExpressionT.EList(list{ @@ -119,7 +79,7 @@ let dispatchMacroCall = ( let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue)) rNewExpression->Result.map(newExpression => - Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings + ExpressionT.Bindings.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings ) } | _ => REAssignmentExpected->Error diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res index 4e5a988e..8daffb86 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res @@ -6,11 +6,14 @@ module Result = Belt.Result type errorValue = ErrorValue.errorValue type expression = ExpressionT.expression -let passToFunction = (fName: string, lispArgs: list): expression => { - let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue - let fn = fName->toEvCallValue - list{fn, ...lispArgs}->ExpressionT.EList -} +let toEvCallValue = (name: string): expression => ExpressionT.EValue(ExpressionValue.EvCall(name)) -let toEvSymbolValue = (name: string): expression => - name->ExpressionValue.EvSymbol->ExpressionT.EValue +let toEvSymbolValue = (name: string): expression => ExpressionT.EValue( + ExpressionValue.EvSymbol(name), +) + +//From Ozzie: I think this could really use a more descriptive name. +let passToFunction = (fName: string, lispArgs: list): expression => { + let fn = toEvCallValue(fName) + ExpressionT.EList(list{fn, ...lispArgs}) +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res index c3fd822c..190dd03f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res @@ -8,9 +8,60 @@ open ReducerInterface.ExpressionValue 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. */ + type rec expression = | EList(list) // A list to map-reduce | 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 | EParameters(array) // for $defun; for internal use only and bindings = Belt.Map.String.t + +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 => + get(t, str) |> E.O.toResult(Reducer_ErrorValue.RESymbolNotFound(str)) + + module Parameters = { + let parametersKey = "$parameters" + let default = EParameters([]) + let get = (t: t): array => { + 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): 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 => { + 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)) + } + } +} diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res index 5dc53413..56339a8f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res @@ -1,4 +1,4 @@ -module Builder = Reducer_Expression_Builder +module ExpressionBuilder = Reducer_Expression_Builder module ErrorValue = Reducer_ErrorValue module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue @@ -31,7 +31,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => let caseFunctionNode = fNode => { let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList 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 => ) ) 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 } @@ -78,27 +78,27 @@ let rec fromNode = (mathJsNode: Parse.node): result => let caseAccessorNode = (objectNode, indexNode) => { caseIndexNode(indexNode)->Result.flatMap(indexCode => { fromNode(objectNode)->Result.flatMap(objectCode => - Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok + ExpressionBuilder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok ) }) } let caseAssignmentNode = aNode => { - let symbol = aNode["object"]["name"]->Builder.toEvSymbolValue + let symbol = aNode["object"]["name"]->ExpressionBuilder.toEvSymbolValue let rValueExpression = fromNode(aNode["value"]) rValueExpression->Result.flatMap(valueExpression => - Builder.passToFunction("$let", list{symbol, valueExpression})->Ok + ExpressionBuilder.passToFunction("$let", list{symbol, valueExpression})->Ok ) } let caseFunctionAssignmentNode = faNode => { - let symbol = faNode["name"]->Builder.toEvSymbolValue + let symbol = faNode["name"]->ExpressionBuilder.toEvSymbolValue let rValueExpression = fromNode(faNode["expr"]) rValueExpression->Result.flatMap(valueExpression => { let lispParams = faNode["params"]->ExpressionT.EParameters - let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression}) - Builder.passToFunction("$let", list{symbol, lambda})->Ok + let lambda = ExpressionBuilder.passToFunction("$lambda", list{lispParams, valueExpression}) + ExpressionBuilder.passToFunction("$let", list{symbol, lambda})->Ok }) } @@ -111,7 +111,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => | MjArrayNode(aNode) => caseArrayNode(aNode) | MjAssignmentNode(aNode) => caseAssignmentNode(aNode) | MjSymbolNode(sNode) => { - let expr: expression = Builder.toEvSymbolValue(sNode["name"]) + let expr: expression = ExpressionBuilder.toEvSymbolValue(sNode["name"]) let rExpr: result = expr->Ok rExpr } @@ -128,7 +128,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => rFinalExpression }) and caseTagOrNodes = (tagOrNodes): result => { - let initialBindings = Builder.passToFunction("$$bindings", list{})->Ok + let initialBindings = ExpressionBuilder.passToFunction("$$bindings", list{})->Ok let lastIndex = Belt.Array.length(tagOrNodes) - 1 tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => { rPreviousBindings->Result.flatMap(previousBindings => { @@ -137,9 +137,9 @@ and caseTagOrNodes = (tagOrNodes): result => { | BlockTag(tag) => switch tag { | ImportVariablesStatement => - Builder.passToFunction("$importVariablesStatement", list{})->Ok + ExpressionBuilder.passToFunction("$importVariablesStatement", list{})->Ok | ExportVariablesExpression => - Builder.passToFunction("$exportVariablesExpression", list{})->Ok + ExpressionBuilder.passToFunction("$exportVariablesExpression", list{})->Ok } } @@ -150,7 +150,7 @@ and caseTagOrNodes = (tagOrNodes): result => { } rStatement->Result.flatMap((statement: expression) => { - Builder.passToFunction(bindName, list{previousBindings, statement})->Ok + ExpressionBuilder.passToFunction(bindName, list{previousBindings, statement})->Ok }) }) }) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 6c15536b..a7c4ebca 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -83,4 +83,4 @@ let toStringResultRecord = x => switch x { | Ok(a) => `Ok(${toStringRecord(a)})` | Error(m) => `Error(${ErrorValue.errorToString(m)})` - } + } \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 78c872ff..3f919e0a 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -338,6 +338,7 @@ module A = { let getBy = Belt.Array.getBy let last = a => get(a, length(a) - 1) 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 fold_left = Array.fold_left let fold_right = Array.fold_right