138 lines
4.0 KiB
Go
138 lines
4.0 KiB
Go
// Copyright (c) 2024-2026 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"
|
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
|
)
|
|
|
|
const (
|
|
iterParamOperator = "operator"
|
|
iterParamVars = "vars"
|
|
iterVarStatus = "status"
|
|
iterParamStatus = "status"
|
|
iterVarAbort = "__abort"
|
|
)
|
|
|
|
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("parameter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator]))
|
|
err = errBadParamType(kern.ParamIterator, kern.TypeIterator, args[kern.ParamIterator])
|
|
return
|
|
}
|
|
|
|
if args[iterParamOperator] != nil {
|
|
if op, ok = args[iterParamOperator].(kern.Functor); !ok || op == nil {
|
|
// err = fmt.Errorf("parameter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator]))
|
|
err = errBadParamType(iterParamOperator, "function", args[iterParamOperator])
|
|
return
|
|
}
|
|
}
|
|
|
|
var vars *dict.DictType
|
|
if vars, ok = args[iterParamVars].(*dict.DictType); !ok && args[iterParamVars] != nil {
|
|
// err = fmt.Errorf("parameter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars]))
|
|
err = errBadParamType(iterParamVars, kern.TypeDict, 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 errBadParamType(paramName, wantedType string, wantedValue any) error {
|
|
return fmt.Errorf("type of %q must be %s, passed %v [%s]", paramName, wantedType, wantedValue, kern.TypeName(wantedValue))
|
|
}
|
|
|
|
func abortFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
|
if status, provided := args[iterParamStatus]; provided {
|
|
ctx.UnsafeSetVar("@"+iterVarStatus, status)
|
|
}
|
|
ctx.UnsafeSetVar("@"+iterVarAbort, true)
|
|
return
|
|
}
|
|
|
|
func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
|
var it kern.Iterator
|
|
var op kern.Functor
|
|
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
|
|
}
|
|
|
|
localCtx.RegisterFunc("abort", kern.NewGolangFunctor(abortFunc), kern.TypeAny, []kern.ExprFuncParam{
|
|
kern.NewFuncParamFlagDef(iterParamStatus, kern.PfOptional, "aborted"),
|
|
})
|
|
|
|
params = map[string]any{kern.ParamIndex: 0, kern.ParamItem: nil}
|
|
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}
|
|
params[kern.ParamIndex] = it.Index()
|
|
params[kern.ParamItem] = item
|
|
|
|
localCtx.UnsafeSetVar("_", it.Index())
|
|
localCtx.UnsafeSetVar("__", item)
|
|
|
|
abort := false
|
|
if _, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil {
|
|
abort = true
|
|
} else if abortAny, exists := localCtx.GetVar(iterVarAbort); exists {
|
|
if abort, ok := boolean.ToBool(abortAny); ok && abort {
|
|
abort = true
|
|
}
|
|
}
|
|
localCtx.DeleteVar("__")
|
|
localCtx.DeleteVar("_")
|
|
if abort {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if err == io.EOF {
|
|
err = nil
|
|
}
|
|
if err == nil {
|
|
if op == nil {
|
|
localCtx.UnsafeSetVar(iterVarStatus, it.Count())
|
|
}
|
|
result, _ = localCtx.GetVar(iterVarStatus)
|
|
}
|
|
return
|
|
}
|
|
|
|
func ImportIterFuncs(ctx kern.ExprContext) {
|
|
ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{
|
|
kern.NewFuncParam(kern.ParamIterator),
|
|
kern.NewFuncParamFlag(iterParamOperator, kern.PfOptional),
|
|
kern.NewFuncParamFlag(iterParamVars, kern.PfOptional),
|
|
})
|
|
}
|
|
|
|
func init() {
|
|
RegisterBuiltinModule("iterator", ImportIterFuncs, "Iterator helper functions")
|
|
}
|