Evaluate function literals and function calls.
Signed-off-by: jmug <u.g.a.mariano@gmail.com>
This commit is contained in:
parent
500a058ff8
commit
a76f47a7a3
4 changed files with 137 additions and 1 deletions
|
|
@ -59,6 +59,20 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
|
|||
env.Set(node.Name.Value, val)
|
||||
case *ast.Identifier:
|
||||
return evalIdentifier(node, env)
|
||||
case *ast.FunctionLiteral:
|
||||
params := node.Parameters
|
||||
body := node.Body
|
||||
return &object.Function{Parameters: params, Body: body, Env: env}
|
||||
case *ast.CallExpression:
|
||||
fn := Eval(node.Function, env)
|
||||
if isError(fn) {
|
||||
return fn
|
||||
}
|
||||
args := evalExpressions(node.Arguments, env)
|
||||
if len(args) == 1 && isError(args[0]) {
|
||||
return args[0]
|
||||
}
|
||||
return applyFunction(fn, args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -184,6 +198,46 @@ func evalIdentifier(exp *ast.Identifier, env *object.Environment) object.Object
|
|||
return val
|
||||
}
|
||||
|
||||
func evalExpressions(
|
||||
exps []ast.Expression,
|
||||
env *object.Environment,
|
||||
) []object.Object {
|
||||
var res []object.Object
|
||||
for _, exp := range exps {
|
||||
ev := Eval(exp, env)
|
||||
if isError(ev) {
|
||||
return []object.Object{ev}
|
||||
}
|
||||
res = append(res, ev)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func applyFunction(fnObj object.Object, args []object.Object) object.Object {
|
||||
fn, ok := fnObj.(*object.Function)
|
||||
if !ok {
|
||||
return newError("not a function: %s", fn.Type())
|
||||
}
|
||||
env := extendFunctionEnv(fn, args)
|
||||
ret := Eval(fn.Body, env)
|
||||
return unwrapReturnValue(ret)
|
||||
}
|
||||
|
||||
func extendFunctionEnv(fn *object.Function, args []object.Object) *object.Environment {
|
||||
env := object.NewEnclosedEnvironment(fn.Env)
|
||||
for pi, param := range fn.Parameters {
|
||||
env.Set(param.Value, args[pi])
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
func unwrapReturnValue(obj object.Object) object.Object {
|
||||
if ret, ok := obj.(*object.ReturnValue); ok {
|
||||
return ret.Value
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
func isTruthy(obj object.Object) bool {
|
||||
switch obj {
|
||||
case _TRUE:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue