arity error
This commit is contained in:
parent
806ff93983
commit
c68138e5f6
|
@ -1,17 +1,42 @@
|
||||||
open Jest
|
open Jest
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
Skip.describe("function trics", () => {
|
describe("Arity check", () => {
|
||||||
testEvalToBe("f(x,y)=x(y); f(f)", "????")
|
testEvalToBe("f(x,y) = x + y; f(1,2)", "Ok(3)")
|
||||||
testEvalToBe("f(x)=x(y); f(f)", "????")
|
testEvalToBe(
|
||||||
testEvalToBe("f(x)=x; f(f)", "????")
|
"f(x,y) = x + y; f(1)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
testEvalToBe("f(x,y)=x(y); f(z)", "????")
|
)
|
||||||
testEvalToBe("f(x,y)=x(y); f(2)", "????") //prevent js error
|
testEvalToBe(
|
||||||
testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment
|
"f(x,y) = x + y; f(1,2,3)",
|
||||||
testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found
|
"Error(2 arguments expected. Instead 3 argument(s) were passed.)",
|
||||||
testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found
|
)
|
||||||
testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666
|
testEvalToBe(
|
||||||
testEvalToBe("f(x,y)=x+y; f(1,2,3,4)", "????") //TODO : arity))
|
"f(x,y)=x+y; f(1,2,3,4)",
|
||||||
testEvalToBe("f(x,y)=x+y; f(1)", "????") //TODO : arity))
|
"Error(2 arguments expected. Instead 4 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x+y; f(1)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x(y); f(f)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))")
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x(y); f(z)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("function trics", () => {
|
||||||
|
testEvalToBe("f(x)=x(y); f(f)", "Error(y is not defined)")
|
||||||
|
testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))")
|
||||||
|
testEvalToBe("f(x)=x(y); f(z)", "Error(y is not defined)")
|
||||||
|
MySkip.testEvalToBe("f(x)=x(y); f(2)", "????") //prevent js error
|
||||||
|
MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment
|
||||||
|
MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found
|
||||||
|
MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found
|
||||||
|
MySkip.testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666
|
||||||
})
|
})
|
|
@ -1,7 +1,9 @@
|
||||||
@genType
|
@genType
|
||||||
type errorValue =
|
type errorValue =
|
||||||
|
| REArityError(option<string>, int, int) //TODO: Binding a lambda to a variable should record the variable name in lambda for error reporting
|
||||||
| REArrayIndexNotFound(string, int)
|
| REArrayIndexNotFound(string, int)
|
||||||
| REAssignmentExpected
|
| REAssignmentExpected
|
||||||
|
| REDistributionError(DistributionTypes.error)
|
||||||
| REExpressionExpected
|
| REExpressionExpected
|
||||||
| REFunctionExpected(string)
|
| REFunctionExpected(string)
|
||||||
| REJavaScriptExn(option<string>, option<string>) // Javascript Exception
|
| REJavaScriptExn(option<string>, option<string>) // Javascript Exception
|
||||||
|
@ -9,7 +11,6 @@ type errorValue =
|
||||||
| RERecordPropertyNotFound(string, string)
|
| RERecordPropertyNotFound(string, string)
|
||||||
| RESymbolNotFound(string)
|
| RESymbolNotFound(string)
|
||||||
| RESyntaxError(string)
|
| RESyntaxError(string)
|
||||||
| REDistributionError(DistributionTypes.error)
|
|
||||||
| RETodo(string) // To do
|
| RETodo(string) // To do
|
||||||
|
|
||||||
type t = errorValue
|
type t = errorValue
|
||||||
|
@ -17,6 +18,10 @@ type t = errorValue
|
||||||
@genType
|
@genType
|
||||||
let errorToString = err =>
|
let errorToString = err =>
|
||||||
switch err {
|
switch err {
|
||||||
|
| REArityError(_oFnName, arity, usedArity) =>
|
||||||
|
`${Js.String.make(arity)} arguments expected. Instead ${Js.String.make(
|
||||||
|
usedArity,
|
||||||
|
)} argument(s) were passed.`
|
||||||
| REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
|
| REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
|
||||||
| REAssignmentExpected => "Assignment expected"
|
| REAssignmentExpected => "Assignment expected"
|
||||||
| REExpressionExpected => "Expression expected"
|
| REExpressionExpected => "Expression expected"
|
||||||
|
|
|
@ -29,8 +29,8 @@ let eLambda = (parameters: array<string>, context, expr) =>
|
||||||
BExpressionValue.EvLambda({
|
BExpressionValue.EvLambda({
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
context: context,
|
context: context,
|
||||||
body: expr->castExpressionToInternalCode}
|
body: expr->castExpressionToInternalCode,
|
||||||
)->BExpressionT.EValue
|
})->BExpressionT.EValue
|
||||||
|
|
||||||
let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue
|
let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
module Bindings = Reducer_Expression_Bindings
|
module Bindings = Reducer_Expression_Bindings
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
type environment = ReducerInterface_ExpressionValue.environment
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
|
@ -11,25 +13,48 @@ type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
|
|
||||||
external castInternalCodeToExpression: internalCode => expression = "%identity"
|
external castInternalCodeToExpression: internalCode => expression = "%identity"
|
||||||
|
|
||||||
|
let checkArity = (lambdaValue: ExpressionValue.lambdaValue, args: list<expressionValue>) => {
|
||||||
|
let argsLength = Belt.List.length(args)
|
||||||
|
let parametersLength = Js.Array2.length(lambdaValue.parameters)
|
||||||
|
if argsLength !== parametersLength {
|
||||||
|
ErrorValue.REArityError(None, parametersLength, argsLength)->Error
|
||||||
|
} else {
|
||||||
|
args->Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkIfReduced = (args: list<expressionValue>) =>
|
||||||
|
args->Belt.List.reduceReverse(Ok(list{}), (rAcc, arg) =>
|
||||||
|
rAcc->Result.flatMap(acc =>
|
||||||
|
switch arg {
|
||||||
|
| EvSymbol(symbol) => ErrorValue.RESymbolNotFound(symbol)->Error
|
||||||
|
| _ => list{arg, ...acc}->Ok
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
let applyParametersToLambda = (
|
let applyParametersToLambda = (
|
||||||
internal: internalCode,
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
parameters: array<string>,
|
args,
|
||||||
args: list<expressionValue>,
|
|
||||||
context: externalBindings,
|
|
||||||
environment,
|
environment,
|
||||||
reducer: ExpressionT.reducerFn,
|
reducer: ExpressionT.reducerFn,
|
||||||
): result<expressionValue, 'e> => {
|
): result<expressionValue, 'e> => {
|
||||||
let expr = castInternalCodeToExpression(internal)
|
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
||||||
let parameterList = parameters->Belt.List.fromArray
|
checkIfReduced(args)->Result.flatMap(args => {
|
||||||
|
let expr = castInternalCodeToExpression(lambdaValue.body)
|
||||||
|
let parameterList = lambdaValue.parameters->Belt.List.fromArray
|
||||||
let zippedParameterList = parameterList->Belt.List.zip(args)
|
let zippedParameterList = parameterList->Belt.List.zip(args)
|
||||||
let bindings = Belt.List.reduce(zippedParameterList, context->Bindings.fromExternalBindings, (
|
let bindings = Belt.List.reduce(
|
||||||
acc,
|
zippedParameterList,
|
||||||
(variable, variableValue),
|
lambdaValue.context->Bindings.fromExternalBindings,
|
||||||
) => acc->Belt.Map.String.set(variable, variableValue))
|
(acc, (variable, variableValue)) => acc->Belt.Map.String.set(variable, variableValue),
|
||||||
|
)
|
||||||
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||||
reducer(newExpression, bindings, environment)
|
reducer(newExpression, bindings, environment)
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => {
|
let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => {
|
||||||
applyParametersToLambda(lambdaValue.body, lambdaValue.parameters, args, lambdaValue.context, environment, reducer)
|
applyParametersToLambda(lambdaValue, args, environment, reducer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,7 @@ let rec toString = aValue =>
|
||||||
}
|
}
|
||||||
| EvBool(aBool) => Js.String.make(aBool)
|
| EvBool(aBool) => Js.String.make(aBool)
|
||||||
| EvCall(fName) => `:${fName}`
|
| EvCall(fName) => `:${fName}`
|
||||||
| EvLambda(lambdaValue) =>
|
| EvLambda(lambdaValue) => `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
||||||
`lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
|
||||||
| EvNumber(aNumber) => Js.String.make(aNumber)
|
| EvNumber(aNumber) => Js.String.make(aNumber)
|
||||||
| EvString(aString) => `'${aString}'`
|
| EvString(aString) => `'${aString}'`
|
||||||
| EvSymbol(aString) => `:${aString}`
|
| EvSymbol(aString) => `:${aString}`
|
||||||
|
|
Loading…
Reference in New Issue
Block a user