fixed function f not bound
This commit is contained in:
		
							parent
							
								
									5a0b436932
								
							
						
					
					
						commit
						6a3b35eb4a
					
				|  | @ -1,10 +1,11 @@ | |||
| open Jest | ||||
| open Expect | ||||
| 
 | ||||
| module Macro = Reducer_Expression_Macro | ||||
| module Bindings = Reducer_Expression_Bindings | ||||
| module Expression = Reducer_Expression | ||||
| module ExpressionValue = ReducerInterface_ExpressionValue | ||||
| module ExpressionWithContext = Reducer_ExpressionWithContext | ||||
| module Macro = Reducer_Expression_Macro | ||||
| module T = Reducer_Expression_T | ||||
| 
 | ||||
| let testMacro_ = ( | ||||
|  | @ -21,7 +22,7 @@ let testMacro_ = ( | |||
|       ExpressionValue.defaultEnvironment, | ||||
|       Expression.reduceExpression, | ||||
|     ) | ||||
|     ->T.toStringResult | ||||
|     ->ExpressionWithContext.toStringResult | ||||
|     ->expect | ||||
|     ->toEqual(expectedCode) | ||||
|   ) | ||||
|  |  | |||
|  | @ -45,9 +45,21 @@ Only.describe("call and bindings", () => { | |||
|   testEvalToBe("f(x)=x+1; y=f(1)", "Ok({f: lambda(x=>internal code),y: 2})") | ||||
|   testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)") | ||||
|   testEvalToBe("f(x)=x+1; y=f(1); z=f(1)", "Ok({f: lambda(x=>internal code),y: 2,z: 2})") | ||||
|   testEvalToBe("f(x)=x+1; g(x)=f(x)+1", "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code)})") //TODO: f is not found | ||||
|   MyOnly.testEvalToBe("f(x)=x+1; g(x)=f(x)+1; y=g(2)", "????") //TODO: f is not found | ||||
|   MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "????") //TODO: f is not found | ||||
|   testEvalToBe( | ||||
|     "f(x)=x+1; g(x)=f(x)+1", | ||||
|     "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code)})", | ||||
|   ) | ||||
|   testParseToBe( | ||||
|     "f=99; g(x)=f; g(2)", | ||||
|     "Ok((:$$block (:$$block (:$let :f 99) (:$let :g (:$$lambda [x] (:$$block :f))) (:g 2))))", | ||||
|   ) | ||||
|   testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)") | ||||
|   testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)") | ||||
|   testEvalToBe( | ||||
|     "f(x)=x+1; g(x)=f(x)+1; y=g(2)", | ||||
|     "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code),y: 4})", | ||||
|   ) | ||||
|   testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)") | ||||
| }) | ||||
| 
 | ||||
| Skip.describe("function trics", () => { | ||||
|  |  | |||
|  | @ -6,19 +6,22 @@ | |||
| module Bindings = Reducer_Expression_Bindings | ||||
| module ExpressionT = Reducer_Expression_T | ||||
| module ExpressionValue = ReducerInterface.ExpressionValue | ||||
| module ExpressionWithContext = Reducer_ExpressionWithContext | ||||
| module Result = Belt.Result | ||||
| open Reducer_Expression_ExpressionBuilder | ||||
| 
 | ||||
| type expression = ExpressionT.expression | ||||
| type environment = ExpressionValue.environment | ||||
| type errorValue = Reducer_ErrorValue.errorValue | ||||
| type expression = ExpressionT.expression | ||||
| type expressionValue = ExpressionValue.expressionValue | ||||
| type expressionWithContext = ExpressionWithContext.expressionWithContext | ||||
| 
 | ||||
| let dispatchMacroCall = ( | ||||
|   macroExpression: expression, | ||||
|   bindings: ExpressionT.bindings, | ||||
|   environment, | ||||
|   reduceExpression: ExpressionT.reducerFn, | ||||
| ): result<expression, errorValue> => { | ||||
| ): result<expressionWithContext, errorValue> => { | ||||
|   let doBindStatement = (bindingExpr: expression, statement: expression, environment) => | ||||
|     switch statement { | ||||
|     | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { | ||||
|  | @ -26,11 +29,23 @@ let dispatchMacroCall = ( | |||
| 
 | ||||
|         rExternalBindingsValue->Result.flatMap(externalBindingsValue => { | ||||
|           let newBindings = Bindings.fromValue(externalBindingsValue) | ||||
| 
 | ||||
|           // Js.log( | ||||
|           //   `bindStatement ${Bindings.toString(newBindings)}<==${ExpressionT.toString( | ||||
|           //       bindingExpr, | ||||
|           //     )} statement: $let ${ExpressionT.toString(symbolExpr)}=${ExpressionT.toString( | ||||
|           //       statement, | ||||
|           //     )}`, | ||||
|           // ) | ||||
| 
 | ||||
|           let rNewStatement = Bindings.replaceSymbols(newBindings, statement) | ||||
|           rNewStatement->Result.map(newStatement => | ||||
|             ExpressionWithContext.withContext( | ||||
|               eFunction( | ||||
|                 "$setBindings", | ||||
|                 list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, | ||||
|               ), | ||||
|               newBindings, | ||||
|             ) | ||||
|           ) | ||||
|         }) | ||||
|  | @ -38,7 +53,10 @@ let dispatchMacroCall = ( | |||
|     | _ => REAssignmentExpected->Error | ||||
|     } | ||||
| 
 | ||||
|   let doBindExpression = (bindingExpr: expression, statement: expression, environment) => | ||||
|   let doBindExpression = (bindingExpr: expression, statement: expression, environment): result< | ||||
|     expressionWithContext, | ||||
|     errorValue, | ||||
|   > => | ||||
|     switch statement { | ||||
|     | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { | ||||
|         let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) | ||||
|  | @ -47,35 +65,49 @@ let dispatchMacroCall = ( | |||
|           let newBindings = Bindings.fromValue(externalBindingsValue) | ||||
|           let rNewStatement = Bindings.replaceSymbols(newBindings, statement) | ||||
|           rNewStatement->Result.map(newStatement => | ||||
|             ExpressionWithContext.withContext( | ||||
|               eFunction( | ||||
|                 "$exportBindings", | ||||
|                 list{ | ||||
|                   eFunction( | ||||
|                     "$setBindings", | ||||
|                   list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, | ||||
|                     list{ | ||||
|                       newBindings->Bindings.toExternalBindings->eRecord, | ||||
|                       symbolExpr, | ||||
|                       newStatement, | ||||
|                     }, | ||||
|                   ), | ||||
|                 }, | ||||
|               ), | ||||
|               newBindings, | ||||
|             ) | ||||
|           ) | ||||
|         }) | ||||
|       } | ||||
|     | _ => { | ||||
|         let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) | ||||
|         let rExternalBindingsValue: result<expressionValue, errorValue> = reduceExpression( | ||||
|           bindingExpr, | ||||
|           bindings, | ||||
|           environment, | ||||
|         ) | ||||
| 
 | ||||
|         rExternalBindingsValue->Result.flatMap(externalBindingsValue => { | ||||
|           let newBindings = Bindings.fromValue(externalBindingsValue) | ||||
|           let rNewStatement = Bindings.replaceSymbols(newBindings, statement) | ||||
|           rNewStatement | ||||
|           rNewStatement->Result.map(newStatement => | ||||
|             ExpressionWithContext.withContext(newStatement, newBindings) | ||||
|           ) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _environment): result< | ||||
|     expression, | ||||
|     expressionWithContext, | ||||
|     errorValue, | ||||
|   > => { | ||||
|     let exprsArray = Belt.List.toArray(exprs) | ||||
|     let maxIndex = Js.Array2.length(exprsArray) - 1 | ||||
|     exprsArray->Js.Array2.reducei((acc, statement, index) => | ||||
|     let newStatement = exprsArray->Js.Array2.reducei((acc, statement, index) => | ||||
|       if index == 0 { | ||||
|         if index == maxIndex { | ||||
|           eBindExpressionDefault(statement) | ||||
|  | @ -87,16 +119,23 @@ let dispatchMacroCall = ( | |||
|       } else { | ||||
|         eBindStatement(acc, statement) | ||||
|       } | ||||
|     , eSymbol("undefined block"))->Ok | ||||
|     , eSymbol("undefined block")) | ||||
|     ExpressionWithContext.noContext(newStatement)->Ok | ||||
|   } | ||||
| 
 | ||||
|   let doLambdaDefinition = ( | ||||
|     bindings: ExpressionT.bindings, | ||||
|     parameters: array<string>, | ||||
|     lambdaDefinition: ExpressionT.expression, | ||||
|   ) => eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition)->Ok | ||||
|   ) => | ||||
|     ExpressionWithContext.noContext( | ||||
|       eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition), | ||||
|     )->Ok | ||||
| 
 | ||||
|   let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment) => | ||||
|   let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment): result< | ||||
|     expressionWithContext, | ||||
|     errorValue, | ||||
|   > => | ||||
|     switch aList { | ||||
|     | list{ | ||||
|         ExpressionT.EValue(EvCall("$$bindStatement")), | ||||
|  | @ -123,11 +162,11 @@ let dispatchMacroCall = ( | |||
|         lambdaDefinition, | ||||
|       } => | ||||
|       doLambdaDefinition(bindings, parameters, lambdaDefinition) | ||||
|     | _ => ExpressionT.EList(aList)->Ok | ||||
|     | _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok | ||||
|     } | ||||
| 
 | ||||
|   switch macroExpression { | ||||
|   | EList(aList) => expandExpressionList(aList, bindings, environment) | ||||
|   | _ => macroExpression->Ok | ||||
|   | _ => ExpressionWithContext.noContext(macroExpression)->Ok | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -32,9 +32,8 @@ let parse = (mathJsCode: string): result<t, errorValue> => | |||
| let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< | ||||
|   expressionValue, | ||||
|   'e, | ||||
| > => | ||||
|   { | ||||
|     Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`) | ||||
| > => { | ||||
|   // Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`) | ||||
|   switch expression { | ||||
|   | T.EValue(value) => value->Ok | ||||
|   | T.EList(list) => | ||||
|  | @ -47,7 +46,8 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en | |||
|       } | ||||
|     | _ => reduceExpressionList(list, bindings, environment) | ||||
|     } | ||||
|   }} | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| and reduceExpressionList = ( | ||||
|   expressions: list<t>, | ||||
|  |  | |||
|  | @ -0,0 +1,45 @@ | |||
| module Bindings = Reducer_Expression_Bindings | ||||
| module ErrorValue = Reducer_ErrorValue | ||||
| module ExpressionT = Reducer_Expression_T | ||||
| module ExpressionValue = ReducerInterface.ExpressionValue | ||||
| module Result = Belt.Result | ||||
| 
 | ||||
| type bindings = ExpressionT.bindings | ||||
| type context = bindings | ||||
| type environment = ExpressionValue.environment | ||||
| type errorValue = Reducer_ErrorValue.errorValue | ||||
| type expression = ExpressionT.expression | ||||
| type expressionValue = ExpressionValue.expressionValue | ||||
| type externalBindings = ReducerInterface_ExpressionValue.externalBindings | ||||
| type reducerFn = ExpressionT.reducerFn | ||||
| 
 | ||||
| type expressionWithContext = | ||||
|   | ExpressionWithContext(expression, context) | ||||
|   | ExpressionNoContext(expression) | ||||
| 
 | ||||
| let callReducer = ( | ||||
|   expressionWithContext: expressionWithContext, | ||||
|   bindings: bindings, | ||||
|   environment: environment, | ||||
|   reducer: reducerFn, | ||||
| ): result<expressionValue, errorValue> => | ||||
|   switch expressionWithContext { | ||||
|   | ExpressionNoContext(expr) => reducer(expr, bindings, environment) | ||||
|   | ExpressionWithContext(expr, context) => reducer(expr, context, environment) | ||||
|   } | ||||
| 
 | ||||
| let withContext = (expression, context) => ExpressionWithContext(expression, context) | ||||
| let noContext = expression => ExpressionNoContext(expression) | ||||
| 
 | ||||
| let toString = expressionWithContext => | ||||
|   switch expressionWithContext { | ||||
|   | ExpressionNoContext(expr) => ExpressionT.toString(expr) | ||||
|   | ExpressionWithContext(expr, context) => | ||||
|     `${ExpressionT.toString(expr)} context: ${Bindings.toString(context)}` | ||||
|   } | ||||
| 
 | ||||
| let toStringResult = rExpressionWithContext => | ||||
|   switch rExpressionWithContext { | ||||
|   | Ok(expressionWithContext) => `Ok(${toString(expressionWithContext)})` | ||||
|   | Error(errorValue) => ErrorValue.errorToString(errorValue) | ||||
|   } | ||||
|  | @ -68,10 +68,8 @@ and replaceSymbolsOnExpressionList = (bindings, list) => { | |||
| } | ||||
| and replaceSymbolOnValue = (bindings, evValue: expressionValue) => | ||||
|   switch evValue { | ||||
|   | EvSymbol(symbol) => | ||||
|     Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok | ||||
|   | EvCall(symbol) => | ||||
|     Belt.Map.String.getWithDefault(bindings, symbol, evValue)->checkIfCallable | ||||
|   | EvSymbol(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok | ||||
|   | EvCall(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->checkIfCallable | ||||
|   | _ => evValue->Ok | ||||
|   } | ||||
| and checkIfCallable = (evValue: expressionValue) => | ||||
|  | @ -82,3 +80,6 @@ and checkIfCallable = (evValue: expressionValue) => | |||
| 
 | ||||
| let toString = (bindings: ExpressionT.bindings) => | ||||
|   bindings->toExternalBindings->ExpressionValue.EvRecord->ExpressionValue.toString | ||||
| 
 | ||||
| let externalBindingsToString = (externalBindings: externalBindings) => | ||||
|   externalBindings->ExpressionValue.EvRecord->ExpressionValue.toString | ||||
|  |  | |||
|  | @ -25,12 +25,18 @@ let eFunction = (fName: string, lispArgs: list<expression>): expression => { | |||
|   list{fn, ...lispArgs}->BExpressionT.EList | ||||
| } | ||||
| 
 | ||||
| let eLambda = (parameters: array<string>, context, expr) => | ||||
| let eLambda = ( | ||||
|   parameters: array<string>, | ||||
|   context: BExpressionValue.externalBindings, | ||||
|   expr: expression, | ||||
| ) => { | ||||
|   // Js.log(`eLambda context ${BBindings.externalBindingsToString(context)}`) | ||||
|   BExpressionValue.EvLambda({ | ||||
|     parameters: parameters, | ||||
|     context: context, | ||||
|     body: expr->castExpressionToInternalCode, | ||||
|   })->BExpressionT.EValue | ||||
| } | ||||
| 
 | ||||
| let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,17 +1,19 @@ | |||
| module ExpressionT = Reducer_Expression_T | ||||
| module ExpressionValue = ReducerInterface.ExpressionValue | ||||
| module ExpressionWithContext = Reducer_ExpressionWithContext | ||||
| module Result = Belt.Result | ||||
| 
 | ||||
| type environment = ExpressionValue.environment | ||||
| type expression = ExpressionT.expression | ||||
| type expressionValue = ExpressionValue.expressionValue | ||||
| type expressionWithContext = ExpressionWithContext.expressionWithContext | ||||
| 
 | ||||
| let expandMacroCall = ( | ||||
|   macroExpression: expression, | ||||
|   bindings: ExpressionT.bindings, | ||||
|   environment: environment, | ||||
|   reduceExpression: ExpressionT.reducerFn, | ||||
| ): result<expression, 'e> => | ||||
| ): result<expressionWithContext, 'e> => | ||||
|   Reducer_Dispatch_BuiltInMacros.dispatchMacroCall( | ||||
|     macroExpression, | ||||
|     bindings, | ||||
|  | @ -30,6 +32,13 @@ let doMacroCall = ( | |||
|     bindings, | ||||
|     environment, | ||||
|     reduceExpression, | ||||
|   )->Result.flatMap(expression => reduceExpression(expression, bindings, environment)) | ||||
|   )->Result.flatMap(expressionWithContext => | ||||
|     ExpressionWithContext.callReducer( | ||||
|       expressionWithContext, | ||||
|       bindings, | ||||
|       environment, | ||||
|       reduceExpression, | ||||
|     ) | ||||
|   ) | ||||
| 
 | ||||
| let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$") | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user