arity error
This commit is contained in:
parent
806ff93983
commit
c68138e5f6
|
@ -1,17 +1,42 @@
|
|||
open Jest
|
||||
open Reducer_TestHelpers
|
||||
|
||||
Skip.describe("function trics", () => {
|
||||
testEvalToBe("f(x,y)=x(y); f(f)", "????")
|
||||
testEvalToBe("f(x)=x(y); f(f)", "????")
|
||||
testEvalToBe("f(x)=x; f(f)", "????")
|
||||
describe("Arity check", () => {
|
||||
testEvalToBe("f(x,y) = x + y; f(1,2)", "Ok(3)")
|
||||
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(1,2,3)",
|
||||
"Error(2 arguments expected. Instead 3 argument(s) were passed.)",
|
||||
)
|
||||
testEvalToBe(
|
||||
"f(x,y)=x+y; f(1,2,3,4)",
|
||||
"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.)",
|
||||
)
|
||||
})
|
||||
|
||||
testEvalToBe("f(x,y)=x(y); f(z)", "????")
|
||||
testEvalToBe("f(x,y)=x(y); f(2)", "????") //prevent js error
|
||||
testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment
|
||||
testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found
|
||||
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("f(x,y)=x+y; f(1,2,3,4)", "????") //TODO : arity))
|
||||
testEvalToBe("f(x,y)=x+y; f(1)", "????") //TODO : arity))
|
||||
})
|
||||
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
|
||||
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)
|
||||
| REAssignmentExpected
|
||||
| REDistributionError(DistributionTypes.error)
|
||||
| REExpressionExpected
|
||||
| REFunctionExpected(string)
|
||||
| REJavaScriptExn(option<string>, option<string>) // Javascript Exception
|
||||
|
@ -9,7 +11,6 @@ type errorValue =
|
|||
| RERecordPropertyNotFound(string, string)
|
||||
| RESymbolNotFound(string)
|
||||
| RESyntaxError(string)
|
||||
| REDistributionError(DistributionTypes.error)
|
||||
| RETodo(string) // To do
|
||||
|
||||
type t = errorValue
|
||||
|
@ -17,6 +18,10 @@ type t = errorValue
|
|||
@genType
|
||||
let errorToString = 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)}`
|
||||
| REAssignmentExpected => "Assignment expected"
|
||||
| REExpressionExpected => "Expression expected"
|
||||
|
|
|
@ -29,8 +29,8 @@ let eLambda = (parameters: array<string>, context, expr) =>
|
|||
BExpressionValue.EvLambda({
|
||||
parameters: parameters,
|
||||
context: context,
|
||||
body: expr->castExpressionToInternalCode}
|
||||
)->BExpressionT.EValue
|
||||
body: expr->castExpressionToInternalCode,
|
||||
})->BExpressionT.EValue
|
||||
|
||||
let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
module Bindings = Reducer_Expression_Bindings
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||
module Result = Belt.Result
|
||||
|
||||
type environment = ReducerInterface_ExpressionValue.environment
|
||||
type expression = ExpressionT.expression
|
||||
|
@ -11,25 +13,48 @@ type internalCode = ReducerInterface_ExpressionValue.internalCode
|
|||
|
||||
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 = (
|
||||
internal: internalCode,
|
||||
parameters: array<string>,
|
||||
args: list<expressionValue>,
|
||||
context: externalBindings,
|
||||
lambdaValue: ExpressionValue.lambdaValue,
|
||||
args,
|
||||
environment,
|
||||
reducer: ExpressionT.reducerFn,
|
||||
): result<expressionValue, 'e> => {
|
||||
let expr = castInternalCodeToExpression(internal)
|
||||
let parameterList = parameters->Belt.List.fromArray
|
||||
let zippedParameterList = parameterList->Belt.List.zip(args)
|
||||
let bindings = Belt.List.reduce(zippedParameterList, context->Bindings.fromExternalBindings, (
|
||||
acc,
|
||||
(variable, variableValue),
|
||||
) => acc->Belt.Map.String.set(variable, variableValue))
|
||||
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||
reducer(newExpression, bindings, environment)
|
||||
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
||||
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 bindings = Belt.List.reduce(
|
||||
zippedParameterList,
|
||||
lambdaValue.context->Bindings.fromExternalBindings,
|
||||
(acc, (variable, variableValue)) => acc->Belt.Map.String.set(variable, variableValue),
|
||||
)
|
||||
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||
reducer(newExpression, bindings, environment)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
| EvCall(fName) => `:${fName}`
|
||||
| EvLambda(lambdaValue) =>
|
||||
`lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
||||
| EvLambda(lambdaValue) => `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
||||
| EvNumber(aNumber) => Js.String.make(aNumber)
|
||||
| EvString(aString) => `'${aString}'`
|
||||
| EvSymbol(aString) => `:${aString}`
|
||||
|
|
Loading…
Reference in New Issue
Block a user