From dceb31f5426cabe66c4d419e25aad18c1dff975b Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Fri, 2 Aug 2024 06:39:33 +0200 Subject: [PATCH] CallFunction() has been replaced by three new functions: CallFunctionByTerm(), CallFunctionByArgs() and CallFunctionByParams() --- data-cursor.go | 11 +++--- expr-function.go | 3 +- function.go | 81 ++++++++++++++++++++++++++-------------- operand-func.go | 2 +- operand-iterator.go | 2 +- t_builtin-string_test.go | 2 +- 6 files changed, 63 insertions(+), 38 deletions(-) diff --git a/data-cursor.go b/data-cursor.go index cff0c0d..1c473d7 100644 --- a/data-cursor.go +++ b/data-cursor.go @@ -108,7 +108,7 @@ func (dc *dataCursor) Reset() (success bool, err error) { if dc.resetFunc != nil { if dc.resource != nil { ctx := cloneContext(dc.ctx) - actualParams := buildActualParams(dc.resetFunc, []any{dc.resource}) + actualParams := bindActualParams(dc.resetFunc, []any{dc.resource}) _, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams) exportObjects(dc.ctx, ctx) dc.index = -1 @@ -131,7 +131,7 @@ func (dc *dataCursor) Clean() (success bool, err error) { if dc.cleanFunc != nil { if dc.resource != nil { ctx := cloneContext(dc.ctx) - actualParams := buildActualParams(dc.cleanFunc, []any{dc.resource}) + actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource}) _, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams) // dc.resource = nil exportObjects(dc.ctx, ctx) @@ -161,7 +161,7 @@ func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err var ok bool ctx := cloneContext(dc.ctx) - actualParams := buildActualParams(filter, []any{item, dc.index}) + actualParams := bindActualParams(filter, []any{item, dc.index}) if v, err = filter.InvokeNamed(ctx, FilterName, actualParams); err == nil && v != nil { if accepted, ok = v.(bool); !ok { accepted = true // NOTE: A non-boolean value that is not nil means the item has been accepted @@ -172,7 +172,7 @@ func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) { ctx := cloneContext(dc.ctx) - actualParams := buildActualParams(mapper, []any{item, dc.index}) + actualParams := bindActualParams(mapper, []any{item, dc.index}) mappedItem, err = mapper.InvokeNamed(ctx, MapName, actualParams) return } @@ -199,7 +199,7 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af ctx := cloneContext(dc.ctx) dc.index++ - actualParams := buildActualParams(dc.nextFunc, []any{dc.resource, dc.index}) + actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index}) if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil { if item == nil { dc.lastErr = io.EOF @@ -238,4 +238,3 @@ func (dc *dataCursor) Index() int { func (dc *dataCursor) Count() int { return dc.count } - diff --git a/expr-function.go b/expr-function.go index 9a59731..e8545a6 100644 --- a/expr-function.go +++ b/expr-function.go @@ -32,7 +32,8 @@ type ExprFunc interface { MaxArgs() int Functor() Functor Params() []ExprFuncParam + ParamSpec(paramName string) ExprFuncParam ReturnType() string - PrepareCall(parentCtx ExprContext, name string, callTerm *term) (ctx ExprContext, actualParams map[string]any, err error) + PrepareCall(name string, actualParams map[string]any) (err error) AllocContext(parentCtx ExprContext) (ctx ExprContext) } diff --git a/function.go b/function.go index c0a29bf..a04ba8d 100644 --- a/function.go +++ b/function.go @@ -213,24 +213,23 @@ func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) { return } -func (info *funcInfo) checkExistingParam(paramName string) (exists bool) { - exists = false +func (info *funcInfo) ParamSpec(paramName string) ExprFuncParam { for _, spec := range info.formalParams { if spec.Name() == paramName { - exists = true - break + return spec } } - return + return nil } -func (info *funcInfo) initActualParams(ctx ExprContext, name string, callTerm *term) (actualParams map[string]any, err error) { +func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualParams map[string]any, err error) { var varArgs []any var varName string namedParamsStarted := false - actualParams = make(map[string]any, len(info.formalParams)) + formalParams := info.Params() + actualParams = make(map[string]any, len(formalParams)) if callTerm == nil { return } @@ -242,8 +241,8 @@ func (info *funcInfo) initActualParams(ctx ExprContext, name string, callTerm *t break } if paramName, namedParam := getAssignVarName(tree); namedParam { - if !info.checkExistingParam(paramName) { - err = fmt.Errorf("%s(): unknown param %q", name, paramName) + if info.ParamSpec(paramName) == nil { + err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName) break } actualParams[paramName] = paramValue @@ -251,8 +250,8 @@ func (info *funcInfo) initActualParams(ctx ExprContext, name string, callTerm *t } else if !namedParamsStarted { if varArgs != nil { varArgs = append(varArgs, paramValue) - } else if i < len(info.formalParams) { - spec := info.formalParams[i] + } else if i < len(formalParams) { + spec := formalParams[i] if spec.IsRepeat() { varArgs = make([]any, 0, len(callTerm.children)-i) varArgs = append(varArgs, paramValue) @@ -261,11 +260,11 @@ func (info *funcInfo) initActualParams(ctx ExprContext, name string, callTerm *t actualParams[spec.Name()] = paramValue } } else { - err = ErrTooManyParams(name, len(info.formalParams), len(callTerm.children)) + err = ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.children)) break } } else { - err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", name, i+1) + err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", info.Name(), i+1) break } } @@ -277,14 +276,11 @@ func (info *funcInfo) initActualParams(ctx ExprContext, name string, callTerm *t return } -func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, callTerm *term) (ctx ExprContext, actualParams map[string]any, err error) { - if actualParams, err = info.initActualParams(parentCtx, name, callTerm); err != nil { - return - } - +func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) { passedCount := len(actualParams) if info.MinArgs() > passedCount { err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) + return } if passedCount < len(info.formalParams) { @@ -304,13 +300,9 @@ func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, callTerm * } } - if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) { + if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) { err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams)) } - - if err == nil { - ctx = info.AllocContext(parentCtx) - } return } @@ -323,12 +315,45 @@ func getAssignVarName(t *term) (name string, ok bool) { return } -func CallFunction(parentCtx ExprContext, name string, callTerm *term) (result any, err error) { +func CallFunctionByTerm(parentCtx ExprContext, name string, callTerm *term) (result any, err error) { var actualParams map[string]any if info, exists := GetFuncInfo(parentCtx, name); exists { - var ctx ExprContext - if ctx, actualParams, err = info.PrepareCall(parentCtx, name, callTerm); err == nil { - functor := info.Functor() + if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil { + ctx := info.AllocContext(parentCtx) + if err = info.PrepareCall(name, actualParams); err == nil { + functor := info.Functor() + result, err = functor.InvokeNamed(ctx, name, actualParams) + exportObjectsToParent(ctx) + } + } + } else { + err = fmt.Errorf("unknown function %s()", name) + } + return +} + +func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result any, err error) { + var actualParams map[string]any + if info, exists := GetFuncInfo(parentCtx, name); exists { + functor := info.Functor() + actualParams = bindActualParams(functor, args) + ctx := info.AllocContext(parentCtx) + if err = info.PrepareCall(name, actualParams); err == nil { + result, err = functor.InvokeNamed(ctx, name, actualParams) + exportObjectsToParent(ctx) + } + } else { + err = fmt.Errorf("unknown function %s()", name) + } + return +} + +func CallFunctionByParams(parentCtx ExprContext, name string, params map[string]any) (result any, err error) { + var actualParams map[string]any + if info, exists := GetFuncInfo(parentCtx, name); exists { + functor := info.Functor() + ctx := info.AllocContext(parentCtx) + if err = info.PrepareCall(name, actualParams); err == nil { result, err = functor.InvokeNamed(ctx, name, actualParams) exportObjectsToParent(ctx) } @@ -347,7 +372,7 @@ func GetParam(args map[string]any, paramName string, paramNum int) (value any, e return } -func buildActualParams(functor Functor, args []any) (actualParams map[string]any) { +func bindActualParams(functor Functor, args []any) (actualParams map[string]any) { formalParams := functor.GetParams() actualParams = make(map[string]any, len(args)) for i, arg := range args { diff --git a/operand-func.go b/operand-func.go index 6aa564d..0b6238a 100644 --- a/operand-func.go +++ b/operand-func.go @@ -40,7 +40,7 @@ func newFuncCallTerm(tk *Token, args []*term) *term { func evalFuncCall(ctx ExprContext, opTerm *term) (v any, err error) { name, _ := opTerm.tk.Value.(string) - v, err = CallFunction(ctx, name, opTerm) + v, err = CallFunctionByTerm(ctx, name, opTerm) return } diff --git a/operand-iterator.go b/operand-iterator.go index beea309..47d6991 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -103,7 +103,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { args = []any{} } - actualParams := buildActualParams(initFunc, args) + actualParams := bindActualParams(initFunc, args) initCtx := ctx.Clone() if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil { diff --git a/t_builtin-string_test.go b/t_builtin-string_test.go index a24acb1..be58d8a 100644 --- a/t_builtin-string_test.go +++ b/t_builtin-string_test.go @@ -63,6 +63,6 @@ func TestFuncString(t *testing.T) { //t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 16) + // runTestSuiteSpec(t, section, inputs, 19) runTestSuite(t, section, inputs) }