Change the `if` special form to use TCO
the bodies of `if` might be utilized for tail call recursion so we need to run the body inside the TCO loop
This commit is contained in:
parent
0ef38cd9bd
commit
d86b47c283
|
@ -167,8 +167,28 @@ tco:
|
|||
// is not `nil` or `false` evaluates THEN otherwise
|
||||
// evaluate the ELSE expression and return the result.
|
||||
case "if":
|
||||
ret, err = If(rt, scope, list.Rest().(*List))
|
||||
break tco // return
|
||||
args := list.Rest().(*List)
|
||||
if args.Count() != 3 {
|
||||
return nil, MakeError(rt, "'if' needs exactly 3 aruments")
|
||||
}
|
||||
|
||||
pred, err := EvalForms(rt, scope, args.First())
|
||||
result := pred.GetType()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result != ast.False && result != ast.Nil {
|
||||
// Truthy clause
|
||||
expressions = args.Rest().First()
|
||||
} else {
|
||||
|
||||
// Falsy clause
|
||||
expressions = args.Rest().Rest().First()
|
||||
}
|
||||
|
||||
continue tco // Loop over to execute the new expressions
|
||||
|
||||
// `do` evaluation rules:
|
||||
// * Evaluate the body as a new block in the TCO loop
|
||||
|
@ -177,6 +197,8 @@ tco:
|
|||
expressions = MakeBlock(list.Rest().(*List).ToSlice())
|
||||
continue tco // Loop over to execute the new expressions
|
||||
|
||||
// case "let":
|
||||
|
||||
// list evaluation rules:
|
||||
// * The first element of the list has to be an expression which is callable
|
||||
// * An empty list evaluates to itself.
|
||||
|
|
|
@ -79,29 +79,3 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
|||
|
||||
return MakeFunction(scope, params, body), nil
|
||||
}
|
||||
|
||||
// If defines a conditional expression which evaluates the first
|
||||
// element of the given `args` as the conditional and if the result
|
||||
// is truthy evaluates and returns the second arg otherwise does the
|
||||
// same for the third arg.
|
||||
func If(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||
|
||||
if args.Count() != 3 {
|
||||
return nil, MakeError(rt, "'if' needs exactly 3 aruments")
|
||||
}
|
||||
|
||||
pred, err := EvalForms(rt, scope, args.First())
|
||||
result := pred.GetType()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result != ast.False && result != ast.Nil {
|
||||
// Truthy clause
|
||||
return EvalForms(rt, scope, args.Rest().First())
|
||||
}
|
||||
|
||||
// Falsy clause
|
||||
return EvalForms(rt, scope, args.Rest().Rest().First())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue