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)
|
||||
)
|
||||
|
|
|
@ -39,15 +39,27 @@ describe("symbol not defined", () => {
|
|||
})
|
||||
|
||||
Only.describe("call and bindings", () => {
|
||||
testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})")
|
||||
testEvalToBe("f(x)=x+1; f(1)", "Ok(2)")
|
||||
testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})")
|
||||
testEvalToBe("f(x)=x+1; f(1)", "Ok(2)")
|
||||
testEvalToBe("f=1;y=2", "Ok({f: 1,y: 2})")
|
||||
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)", "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 =>
|
||||
eFunction(
|
||||
"$setBindings",
|
||||
list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, 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 =>
|
||||
eFunction(
|
||||
"$exportBindings",
|
||||
list{
|
||||
eFunction(
|
||||
"$setBindings",
|
||||
list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement},
|
||||
),
|
||||
},
|
||||
ExpressionWithContext.withContext(
|
||||
eFunction(
|
||||
"$exportBindings",
|
||||
list{
|
||||
eFunction(
|
||||
"$setBindings",
|
||||
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,10 +32,9 @@ 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}`)
|
||||
switch expression {
|
||||
> => {
|
||||
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
||||
switch expression {
|
||||
| T.EValue(value) => value->Ok
|
||||
| T.EList(list) =>
|
||||
switch 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) =>
|
||||
|
@ -80,5 +78,8 @@ and checkIfCallable = (evValue: expressionValue) =>
|
|||
| _ => ErrorValue.RENotAFunction(ExpressionValue.toString(evValue))->Error
|
||||
}
|
||||
|
||||
let toString = (bindings: ExpressionT.bindings) =>
|
||||
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