CallFunction() has been replaced by three new functions:

CallFunctionByTerm(), CallFunctionByArgs() and CallFunctionByParams()
This commit is contained in:
Celestino Amoroso 2024-08-02 06:39:33 +02:00
parent 075b0b5691
commit dceb31f542
6 changed files with 63 additions and 38 deletions

View File

@ -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
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}