expr/builtin-iterator.go

106 lines
2.6 KiB
Go

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-iterator.go
package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
)
const (
iterParamOperator = "operator"
iterParamVars = "vars"
iterVarStatus = "status"
)
func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Iterator, op kern.Functor, err error) {
var ok bool
if it, ok = args[kern.ParamIterator].(kern.Iterator); !ok {
err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator]))
return
}
if args[iterParamOperator] != nil {
if op, ok = args[iterParamOperator].(kern.Functor); !ok || op == nil {
err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator]))
return
}
}
var vars *kern.DictType
if vars, ok = args[iterParamVars].(*kern.DictType); !ok && args[iterParamVars] != nil {
err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars]))
return
}
if vars != nil {
for key, value := range *vars {
var varName string
if varName, ok = key.(string); ok {
localCtx.UnsafeSetVar(varName, value)
}
}
}
return
}
func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var it kern.Iterator
var ok bool
var op kern.Functor
var v any
// var usingDefaultOp = false
var params map[string]any
var item any
localCtx := ctx.Clone()
localCtx.UnsafeSetVar(iterVarStatus, nil)
if it, op, err = parseRunArgs(localCtx, args); err != nil {
return
}
for item, err = it.Next(); err == nil; item, err = it.Next() {
if op != nil {
params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item}
if v, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil {
break
} else {
var success bool
if success, ok = kern.ToBool(v); !success || !ok {
break
}
}
}
}
if err == io.EOF {
err = nil
}
if err == nil {
if op == nil {
ctx.UnsafeSetVar(iterVarStatus, it.Count())
}
result, _ = localCtx.GetVar(iterVarStatus)
}
return
}
func ImportIterFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamIterator),
NewFuncParamFlag(iterParamOperator, PfOptional),
NewFuncParamFlag(iterParamVars, PfOptional),
})
}
func init() {
RegisterBuiltinModule("iterator", ImportIterFuncs, "Iterator helper functions")
}