diff --git a/builtin-iterator.go b/builtin-iterator.go index d156525..5495453 100644 --- a/builtin-iterator.go +++ b/builtin-iterator.go @@ -17,26 +17,31 @@ 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("paramter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator])) + // 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("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator])) + // 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("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars])) + // 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 } @@ -52,12 +57,21 @@ func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Itera 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 ok bool var op kern.Functor - var v any - // var usingDefaultOp = false var params map[string]any var item any @@ -68,14 +82,20 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any 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} - if v, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil { + // params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item} + params[kern.ParamIndex] = it.Index() + params[kern.ParamItem] = item + if _, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil { break - } else { - var success bool - if success, ok = boolean.ToBool(v); !success || !ok { + } else if abortAny, exists := localCtx.GetVar(iterVarAbort); exists { + if abort, ok := boolean.ToBool(abortAny); ok && abort { break } } @@ -87,7 +107,7 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any } if err == nil { if op == nil { - ctx.UnsafeSetVar(iterVarStatus, it.Count()) + localCtx.UnsafeSetVar(iterVarStatus, it.Count()) } result, _ = localCtx.GetVar(iterVarStatus) }