// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operand-func.go package expr import ( "errors" "fmt" ) // -------- function call term func newFuncCallTerm(tk *Token, args []*term) *term { return &term{ tk: *tk, parent: nil, children: args, position: posLeaf, priority: priValue, evalFunc: evalFuncCall, } } // -------- eval func call func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) { if info, exists, owner := GetFuncInfo(ctx, name); exists { passedCount := len(*varParams) if info.MinArgs() > passedCount { err = errTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) } for i, p := range info.Params() { if i >= passedCount { if !p.IsOptional() { break } *varParams = append(*varParams, p.DefaultValue()) } } if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) { err = errTooMuchParams(name, info.MaxArgs(), len(*varParams)) } if err == nil && owner != ctx { ctx.RegisterFuncInfo(info) } } else { err = fmt.Errorf("unknown function %s()", name) } return } func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) { ctx := cloneContext(parentCtx) name, _ := self.tk.Value.(string) params := make([]any, len(self.children), len(self.children)+5) for i, tree := range self.children { var param any if param, err = tree.compute(ctx); err != nil { break } params[i] = param } if err == nil { if err = checkFunctionCall(ctx, name, ¶ms); err == nil { if v, err = ctx.Call(name, params); err == nil { exportObjects(parentCtx, ctx) } } } return } // -------- function definition term func newFuncDefTerm(tk *Token, args []*term) *term { return &term{ tk: *tk, // value is the expression body parent: nil, children: args, // function params position: posLeaf, priority: priValue, evalFunc: evalFuncDef, } } // -------- eval func def func evalFuncDef(ctx ExprContext, self *term) (v any, err error) { bodySpec := self.value() if expr, ok := bodySpec.(*ast); ok { paramList := make([]ExprFuncParam, 0, len(self.children)) for _, param := range self.children { var defValue any flags := paramFlags(0) if len(param.children) > 0 { flags |= pfOptional if defValue, err = param.children[0].compute(ctx); err != nil { return } } info := newFuncParamFlagDef(param.source(), flags, defValue) paramList = append(paramList, info) } v = newExprFunctor(expr, paramList, ctx) } else { err = errors.New("invalid function definition: the body specification must be an expression") } return }