diff --git a/builtin-base.go b/builtin-base.go index 840669a..9bdb06c 100644 --- a/builtin-base.go +++ b/builtin-base.go @@ -272,7 +272,7 @@ func setFunc(ctx kern.ExprContext, name string, args map[string]any) (result any func ImportBuiltinsFuncs(ctx kern.ExprContext) { anyParams := []kern.ExprFuncParam{ - NewFuncParam(kern.ParamValue), + kern.NewFuncParam(kern.ParamValue), } ctx.RegisterFunc("isNil", kern.NewGolangFunctor(isNilFunc), kern.TypeBoolean, anyParams) @@ -290,27 +290,27 @@ func ImportBuiltinsFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams) ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams) ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamValue), - NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)), + kern.NewFuncParam(kern.ParamValue), + kern.NewFuncParamFlagDef(ParamDenominator, kern.PfDefault, int64(1)), }) ctx.RegisterFunc("eval", kern.NewGolangFunctor(evalFunc), kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), + kern.NewFuncParam(kern.ParamSource), }) ctx.RegisterFunc("var", kern.NewGolangFunctor(varFunc), kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamName), - NewFuncParamFlagDef(kern.ParamValue, PfDefault, nil), + kern.NewFuncParam(kern.ParamName), + kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault, nil), }) ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamName), - NewFuncParam(kern.ParamValue), + kern.NewFuncParam(kern.ParamName), + kern.NewFuncParam(kern.ParamValue), }) // ctx.RegisterFunc("unset", kern.NewGolangFunctor(unsetFunc), kern.TypeAny, []kern.ExprFuncParam{ - // NewFuncParam(kern.ParamName), - // NewFuncParam(kern.ParamValue), + // kern.NewFuncParam(kern.ParamName), + // kern.NewFuncParam(kern.ParamValue), // }) } diff --git a/builtin-fmt.go b/builtin-fmt.go index 9673674..c15becf 100644 --- a/builtin-fmt.go +++ b/builtin-fmt.go @@ -47,10 +47,10 @@ func printLnFunc(ctx kern.ExprContext, name string, args map[string]any) (result func ImportFmtFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("print", kern.NewGolangFunctor(printFunc), kern.TypeInt, []kern.ExprFuncParam{ - NewFuncParamFlag(kern.ParamItem, PfRepeat), + kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat), }) ctx.RegisterFunc("println", kern.NewGolangFunctor(printLnFunc), kern.TypeInt, []kern.ExprFuncParam{ - NewFuncParamFlag(kern.ParamItem, PfRepeat), + kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat), }) } diff --git a/builtin-import.go b/builtin-import.go index ae27d17..75f6fec 100644 --- a/builtin-import.go +++ b/builtin-import.go @@ -69,10 +69,10 @@ func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Itera func ImportImportFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("import", kern.NewGolangFunctor(importFunc), kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParamFlag(kern.ParamFilepath, PfRepeat), + kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat), }) ctx.RegisterFunc("importAll", kern.NewGolangFunctor(importAllFunc), kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParamFlag(kern.ParamFilepath, PfRepeat), + kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat), }) } diff --git a/builtin-iterator.go b/builtin-iterator.go index 5bc4595..a06313f 100644 --- a/builtin-iterator.go +++ b/builtin-iterator.go @@ -94,9 +94,9 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any func ImportIterFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamIterator), - NewFuncParamFlag(iterParamOperator, PfOptional), - NewFuncParamFlag(iterParamVars, PfOptional), + kern.NewFuncParam(kern.ParamIterator), + kern.NewFuncParamFlag(iterParamOperator, kern.PfOptional), + kern.NewFuncParamFlag(iterParamVars, kern.PfOptional), }) } diff --git a/builtin-math-arith.go b/builtin-math-arith.go index 8f605ca..3ca6db8 100644 --- a/builtin-math-arith.go +++ b/builtin-math-arith.go @@ -172,11 +172,11 @@ func mulFunc(ctx kern.ExprContext, name string, args map[string]any) (result any func ImportMathFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("add", kern.NewGolangFunctor(addFunc), kern.TypeNumber, []kern.ExprFuncParam{ - NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(0)), + kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault|kern.PfRepeat, int64(0)), }) ctx.RegisterFunc("mul", kern.NewGolangFunctor(mulFunc), kern.TypeNumber, []kern.ExprFuncParam{ - NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(1)), + kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault|kern.PfRepeat, int64(1)), }) } diff --git a/builtin-os-file.go b/builtin-os-file.go index 70b7ac3..48dbe24 100644 --- a/builtin-os-file.go +++ b/builtin-os-file.go @@ -224,37 +224,37 @@ func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any) func ImportOsFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("fileOpen", kern.NewGolangFunctor(openFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamFilepath), + kern.NewFuncParam(kern.ParamFilepath), }) ctx.RegisterFunc("fileAppend", kern.NewGolangFunctor(appendFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamFilepath), + kern.NewFuncParam(kern.ParamFilepath), }) ctx.RegisterFunc("fileCreate", kern.NewGolangFunctor(createFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamFilepath), + kern.NewFuncParam(kern.ParamFilepath), }) ctx.RegisterFunc("fileClose", kern.NewGolangFunctor(closeFileFunc), kern.TypeBoolean, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamHandle), + kern.NewFuncParam(kern.ParamHandle), }) ctx.RegisterFunc("fileWriteText", kern.NewGolangFunctor(fileWriteTextFunc), kern.TypeInt, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamHandle), - NewFuncParamFlagDef(kern.ParamItem, PfDefault|PfRepeat, ""), + kern.NewFuncParam(kern.ParamHandle), + kern.NewFuncParamFlagDef(kern.ParamItem, kern.PfDefault|kern.PfRepeat, ""), }) ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamHandle), - NewFuncParamFlagDef(osLimitCh, PfDefault, "\n"), + kern.NewFuncParam(kern.ParamHandle), + kern.NewFuncParamFlagDef(osLimitCh, kern.PfDefault, "\n"), }) ctx.RegisterFunc("fileReadTextAll", kern.NewGolangFunctor(fileReadTextAllFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamHandle), + kern.NewFuncParam(kern.ParamHandle), }) ctx.RegisterFunc("fileReadIterator", kern.NewGolangFunctor(fileReadIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{ - NewFuncParam(paramHandleOrPath), + kern.NewFuncParam(paramHandleOrPath), }) } diff --git a/builtin-string.go b/builtin-string.go index 35d56ce..b3b1e83 100644 --- a/builtin-string.go +++ b/builtin-string.go @@ -225,44 +225,44 @@ func lowerStrFunc(ctx kern.ExprContext, name string, args map[string]any) (resul // Import above functions in the context func ImportStringFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("strJoin", kern.NewGolangFunctor(joinStrFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSeparator), - NewFuncParamFlag(kern.ParamItem, PfRepeat), + kern.NewFuncParam(kern.ParamSeparator), + kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat), }) ctx.RegisterFunc("strSub", kern.NewGolangFunctor(subStrFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), - NewFuncParamFlagDef(kern.ParamStart, PfDefault, int64(0)), - NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)), + kern.NewFuncParam(kern.ParamSource), + kern.NewFuncParamFlagDef(kern.ParamStart, kern.PfDefault, int64(0)), + kern.NewFuncParamFlagDef(kern.ParamCount, kern.PfDefault, int64(-1)), }) ctx.RegisterFunc("strSplit", kern.NewGolangFunctor(splitStrFunc), "list of "+kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), - NewFuncParamFlagDef(kern.ParamSeparator, PfDefault, ""), - NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)), + kern.NewFuncParam(kern.ParamSource), + kern.NewFuncParamFlagDef(kern.ParamSeparator, kern.PfDefault, ""), + kern.NewFuncParamFlagDef(kern.ParamCount, kern.PfDefault, int64(-1)), }) ctx.RegisterFunc("strTrim", kern.NewGolangFunctor(trimStrFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), + kern.NewFuncParam(kern.ParamSource), }) ctx.RegisterFunc("strStartsWith", kern.NewGolangFunctor(startsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), - NewFuncParam(kern.ParamPrefix), - NewFuncParamFlag(strParamOther, PfRepeat), + kern.NewFuncParam(kern.ParamSource), + kern.NewFuncParam(kern.ParamPrefix), + kern.NewFuncParamFlag(strParamOther, kern.PfRepeat), }) ctx.RegisterFunc("strEndsWith", kern.NewGolangFunctor(endsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), - NewFuncParam(kern.ParamSuffix), - NewFuncParamFlag(strParamOther, PfRepeat), + kern.NewFuncParam(kern.ParamSource), + kern.NewFuncParam(kern.ParamSuffix), + kern.NewFuncParamFlag(strParamOther, kern.PfRepeat), }) ctx.RegisterFunc("strUpper", kern.NewGolangFunctor(upperStrFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), + kern.NewFuncParam(kern.ParamSource), }) ctx.RegisterFunc("strLower", kern.NewGolangFunctor(lowerStrFunc), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParam(kern.ParamSource), + kern.NewFuncParam(kern.ParamSource), }) } diff --git a/dict-iterator.go b/dict-iterator.go index d9d96a4..f446a7d 100644 --- a/dict-iterator.go +++ b/dict-iterator.go @@ -116,8 +116,11 @@ func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err err } } - dictIt.makeKeys(*dict, sortType) - return dictIt, err + if err == nil { + dictIt.makeKeys(*dict, sortType) + it = dictIt + } + return } func NewMapIterator(m map[any]any) (it *DictIterator) { @@ -139,7 +142,6 @@ func (it *DictIterator) TypeName() string { } func (it *DictIterator) HasOperation(name string) bool { - // yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName, kern.KeyName, kern.ValueName}, name) return yes } diff --git a/function.go b/function.go deleted file mode 100644 index a419101..0000000 --- a/function.go +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). -// All rights reserved. - -// function.go -package expr - -import ( - "fmt" - "strings" - - "git.portale-stac.it/go-pkg/expr/kern" - "git.portale-stac.it/go-pkg/expr/scan" -) - -// ---- Function template -// type FuncTemplate func(ctx expr.ExprContext, name string, args map[string]any) (result any, err error) - -// ---- Common functor definition -type BaseFunctor struct { - info kern.ExprFunc -} - -func (functor *BaseFunctor) ToString(opt kern.FmtOpt) (s string) { - if functor.info != nil { - s = functor.info.ToString(opt) - } else { - s = "func(){}" - } - return s -} - -func (functor *BaseFunctor) GetParams() (params []kern.ExprFuncParam) { - if functor.info != nil { - return functor.info.Params() - } else { - return []kern.ExprFuncParam{} - } -} - -func (functor *BaseFunctor) SetFunc(info kern.ExprFunc) { - functor.info = info -} - -func (functor *BaseFunctor) GetFunc() kern.ExprFunc { - return functor.info -} - -func (functor *BaseFunctor) GetDefinitionContext() kern.ExprContext { - return nil -} - -// ---- Function Parameters -type paramFlags uint16 - -const ( - PfDefault paramFlags = 1 << iota - PfOptional - PfRepeat -) - -type funcParamInfo struct { - name string - flags paramFlags - defaultValue any -} - -func NewFuncParam(name string) kern.ExprFuncParam { - return &funcParamInfo{name: name} -} - -func NewFuncParamFlag(name string, flags paramFlags) kern.ExprFuncParam { - return &funcParamInfo{name: name, flags: flags} -} - -func NewFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo { - return &funcParamInfo{name: name, flags: flags, defaultValue: defValue} -} - -func (param *funcParamInfo) Name() string { - return param.name -} - -func (param *funcParamInfo) Type() string { - return kern.TypeAny -} - -func (param *funcParamInfo) IsDefault() bool { - return (param.flags & PfDefault) != 0 -} - -func (param *funcParamInfo) IsOptional() bool { - return (param.flags & PfOptional) != 0 -} - -func (param *funcParamInfo) IsRepeat() bool { - return (param.flags & PfRepeat) != 0 -} - -func (param *funcParamInfo) DefaultValue() any { - return param.defaultValue -} - -// --- Functions - -// funcInfo implements expr.ExprFunc -type funcInfo struct { - name string - minArgs int - maxArgs int - functor kern.Functor - formalParams []kern.ExprFuncParam - returnType string -} - -func newFuncInfo(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (info *funcInfo, err error) { - var minArgs = 0 - var maxArgs = 0 - for _, p := range params { - if maxArgs == -1 { - return nil, fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name()) - } - if p.IsDefault() || p.IsOptional() { - maxArgs++ - } else if maxArgs == minArgs { - minArgs++ - maxArgs++ - } else { - return nil, fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name()) - } - if p.IsRepeat() { - minArgs-- - maxArgs = -1 - } - } - - info = &funcInfo{ - name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params, - } - functor.SetFunc(info) - return info, nil -} - -func (info *funcInfo) Params() []kern.ExprFuncParam { - return info.formalParams -} - -func (info *funcInfo) ReturnType() string { - return info.returnType -} - -func (info *funcInfo) ToString(opt kern.FmtOpt) string { - var sb strings.Builder - if len(info.Name()) == 0 { - sb.WriteString("func") - } else { - sb.WriteString(info.Name()) - } - sb.WriteByte('(') - if info.formalParams != nil { - for i, p := range info.formalParams { - if i > 0 { - sb.WriteString(", ") - } - sb.WriteString(p.Name()) - - if p.IsDefault() { - sb.WriteByte('=') - if s, ok := p.DefaultValue().(string); ok { - sb.WriteByte('"') - sb.WriteString(s) - sb.WriteByte('"') - } else { - sb.WriteString(fmt.Sprintf("%v", p.DefaultValue())) - } - } - } - } - if info.maxArgs < 0 { - sb.WriteString(" ...") - } - sb.WriteString("):") - if len(info.returnType) > 0 { - sb.WriteString(info.returnType) - } else { - sb.WriteString(kern.TypeAny) - } - sb.WriteString("{}") - return sb.String() -} - -func (info *funcInfo) Name() string { - return info.name -} - -func (info *funcInfo) MinArgs() int { - return info.minArgs -} - -func (info *funcInfo) MaxArgs() int { - return info.maxArgs -} - -func (info *funcInfo) Functor() kern.Functor { - return info.functor -} - -func (info *funcInfo) AllocContext(parentCtx kern.ExprContext) (ctx kern.ExprContext) { - if defCtx := info.functor.GetDefinitionContext(); defCtx != nil { - ctx = defCtx.Clone() - ctx.SetParent(defCtx) - } else { - ctx = parentCtx.Clone() - ctx.SetParent(parentCtx) - } - return -} - -func (info *funcInfo) ParamSpec(paramName string) kern.ExprFuncParam { - for _, spec := range info.formalParams { - if spec.Name() == paramName { - return spec - } - } - return nil -} - -func initActualParams(ctx kern.ExprContext, info kern.ExprFunc, callTerm *scan.Term) (actualParams map[string]any, err error) { - var varArgs []any - var varName string - - namedParamsStarted := false - - formalParams := info.Params() - actualParams = make(map[string]any, len(formalParams)) - if callTerm == nil { - return - } - - for i, tree := range callTerm.Children { - var paramValue any - paramCtx := ctx.Clone() - if paramValue, err = tree.Compute(paramCtx); err != nil { - break - } - if paramName, namedParam := kern.GetAssignVarName(tree); namedParam { - if info.ParamSpec(paramName) == nil { - err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName) - break - } - actualParams[paramName] = paramValue - namedParamsStarted = true - } else if !namedParamsStarted { - if varArgs != nil { - varArgs = append(varArgs, paramValue) - } else if i < len(formalParams) { - spec := formalParams[i] - if spec.IsRepeat() { - varArgs = make([]any, 0, len(callTerm.Children)-i) - varArgs = append(varArgs, paramValue) - varName = spec.Name() - } else { - actualParams[spec.Name()] = paramValue - } - } else { - err = kern.ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.Children)) - break - } - } else { - err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", info.Name(), i+1) - break - } - } - if err == nil { - if varArgs != nil { - actualParams[varName] = varArgs - } - } - return -} - -func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) { - passedCount := len(actualParams) - if info.MinArgs() > passedCount { - err = kern.ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) - return - } - - if passedCount < len(info.formalParams) { - for _, p := range info.formalParams { - if _, exists := actualParams[p.Name()]; !exists { - if !p.IsDefault() { - break - } - if p.IsRepeat() { - varArgs := make([]any, 1) - varArgs[0] = p.DefaultValue() - actualParams[p.Name()] = varArgs - } else { - actualParams[p.Name()] = p.DefaultValue() - } - } - } - } - - if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) { - err = kern.ErrTooManyParams(name, info.MaxArgs(), len(actualParams)) - } - return -} - -// ----- Call a function --- - -// func getAssignVarName(t *term) (name string, ok bool) { -// if ok = t.symbol() == SymEqual; ok { -// name = t.children[0].source() -// } -// return -// } - -// func CallFunctionByTerm(parentCtx expr.ExprContext, name string, callTerm *term) (result any, err error) { -// var actualParams map[string]any -// if info, exists := GetFuncInfo(parentCtx, name); exists { -// 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 expr.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 expr.ExprContext, name string, actualParams 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) -// } -// } else { -// err = fmt.Errorf("unknown function %s()", name) -// } -// return -// } - -// func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) { -// if value, exists = args[paramName]; !exists { -// if paramNum > 0 && paramNum <= len(args) { -// value, exists = args["arg"+strconv.Itoa(paramNum)] -// } -// } -// return -// } - -// 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 { -// if i < len(formalParams) { -// actualParams[formalParams[i].Name()] = arg -// } else { -// actualParams["arg"+strconv.Itoa(i+1)] = arg -// } -// } -// return -// } diff --git a/helpers.go b/helpers.go index bccde1d..0e748c5 100644 --- a/helpers.go +++ b/helpers.go @@ -45,7 +45,7 @@ func EvalStringV(source string, args []Arg) (result any, err error) { functor := kern.NewGolangFunctor(f) // ctx.RegisterFunc(arg.Name, functor, 0, -1) ctx.RegisterFunc(arg.Name, functor, kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, 0), + kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault|kern.PfRepeat, 0), }) } else { err = fmt.Errorf("invalid function specification: %q", arg.Name) diff --git a/iter-factory.go b/iter-factory.go index 268a8fb..3d097b9 100644 --- a/iter-factory.go +++ b/iter-factory.go @@ -5,10 +5,13 @@ package expr import ( + "fmt" + "slices" + "git.portale-stac.it/go-pkg/expr/kern" ) -func NewIterator(value any) (it kern.Iterator, err error) { +func NewIterator(ctx kern.ExprContext, value any, args map[string]any) (it kern.Iterator, err error) { if value == nil { return NewArrayIterator([]any{}), nil } @@ -21,9 +24,24 @@ func NewIterator(value any) (it kern.Iterator, err error) { case []any: it = NewArrayIterator(v) case kern.Iterator: - it = v + // it = v + var op kern.Functor + if len(args) >= 1 { + if opArg, ok := args["op"]; ok { + if op, ok = opArg.(kern.Functor); !ok { + err = fmt.Errorf("the 'op' argument must be a kern.Functor, got %T", opArg) + } + } + } + if err == nil { + it, err = NewIterIter(v, ctx, op, args) + } default: it = NewArrayIterator([]any{value}) } return } + +func HasStandardOperation(name string) bool { + return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name) +} diff --git a/iter-iter.go b/iter-iter.go new file mode 100644 index 0000000..a4fa7ee --- /dev/null +++ b/iter-iter.go @@ -0,0 +1,132 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// iter-iter.go +package expr + +import ( + "fmt" + "io" + + "git.portale-stac.it/go-pkg/expr/kern" +) + +type IterIter struct { + it kern.Iterator + count int64 + index int64 + ctx kern.ExprContext + op kern.Functor + opName string + args map[string]any + current any +} + +func NewIterIter(it kern.Iterator, ctx kern.ExprContext, op kern.Functor, args map[string]any) (iter kern.Iterator, err error) { + var opName string + if op != nil { + if f := op.GetFunc(); f != nil { + opName = f.Name() + // } else { + // return nil, fmt.Errorf("invalid functor argument for iter-iter: expected kern.Functor, got %T", args["op"]) + } + } + if len(opName) == 0 { + opName = "anonymous" + } + iter = &IterIter{it: it, count: 0, index: -1, ctx: ctx, op: op, opName: opName, args: args} + + return +} + +func (it *IterIter) String() string { + return fmt.Sprintf("$(%s)", it.it) +} + +func (it *IterIter) TypeName() string { + return "IterIter" +} + +func (it *IterIter) HasOperation(name string) bool { + return HasStandardOperation(name) +} + +func (it *IterIter) CallOperation(name string, args map[string]any) (v any, err error) { + switch name { + case kern.NextName: + v, err = it.Next() + case kern.ResetName: + err = it.Reset() + case kern.CleanName: + err = it.Clean() + case kern.IndexName: + v = int64(it.Index()) + case kern.CurrentName: + v, err = it.Current() + case kern.CountName: + v = it.count + default: + err = kern.ErrNoOperation(name) + } + return +} + +func (it *IterIter) Current() (item any, err error) { + if it.current != nil { + item = it.current + } else if it.op != nil { + if item, err = it.op.InvokeNamed(it.ctx, it.opName, it.args); err == nil { + it.current = item + } + } else { + var exists bool + if it.current, exists = it.ctx.GetVar("_"); !exists { + err = fmt.Errorf("current item not available") + } else { + item = it.current + } + } + return +} + +func (it *IterIter) Next() (item any, err error) { + var src any + + it.current = nil + ctx := it.ctx + for src, err = it.it.Next(); src == nil && err == nil; src, err = it.it.Next() { + } + + if err == nil { + if src == nil { + err = io.EOF + } else { + ctx.UnsafeSetVar("_", src) + ctx.UnsafeSetVar("__", it.it.Index()) + ctx.UnsafeSetVar("_#", it.it.Count()) + item, err = it.Current() + ctx.DeleteVar("_#") + ctx.DeleteVar("__") + ctx.DeleteVar("_") + } + } + return +} + +func (it *IterIter) Index() int64 { + return it.index +} + +func (it *IterIter) Count() int64 { + return it.count +} + +func (it *IterIter) Reset() error { + it.index = -1 + it.count = 0 + return nil +} + +func (it *IterIter) Clean() error { + return nil +} diff --git a/kern/bind-go-functions.go b/kern/bind-go-functions.go index 7c2866e..b54ed90 100644 --- a/kern/bind-go-functions.go +++ b/kern/bind-go-functions.go @@ -5,19 +5,19 @@ package kern // ---- Linking with Go functions -type golangFunctor struct { +type GolangFunctor struct { BaseFunctor f FuncTemplate } -func NewGolangFunctor(f FuncTemplate) *golangFunctor { - return &golangFunctor{f: f} +func NewGolangFunctor(f FuncTemplate) *GolangFunctor { + return &GolangFunctor{f: f} } -func (functor *golangFunctor) TypeName() string { +func (functor *GolangFunctor) TypeName() string { return "GoFunctor" } -func (functor *golangFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func (functor *GolangFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) { return functor.f(ctx, name, args) } diff --git a/kern/expr-function.go b/kern/expr-function.go index 8c639a5..2d50b9d 100644 --- a/kern/expr-function.go +++ b/kern/expr-function.go @@ -37,3 +37,8 @@ type ExprFunc interface { PrepareCall(name string, actualParams map[string]any) (err error) AllocContext(parentCtx ExprContext) (ctx ExprContext) } + +func IsFunctor(v any) (ok bool) { + _, ok = v.(Functor) + return +} diff --git a/kern/func-info.go b/kern/func-info.go new file mode 100644 index 0000000..f8ba6d6 --- /dev/null +++ b/kern/func-info.go @@ -0,0 +1,164 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// func-info.go +package kern + +import ( + "fmt" + "strings" +) + +// --- Functions + +// FuncInfo implements expr.ExprFunc +type FuncInfo struct { + name string + minArgs int + maxArgs int + functor Functor + formalParams []ExprFuncParam + returnType string +} + +func NewFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *FuncInfo, err error) { + var minArgs = 0 + var maxArgs = 0 + for _, p := range params { + if maxArgs == -1 { + return nil, fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name()) + } + if p.IsDefault() || p.IsOptional() { + maxArgs++ + } else if maxArgs == minArgs { + minArgs++ + maxArgs++ + } else { + return nil, fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name()) + } + if p.IsRepeat() { + minArgs-- + maxArgs = -1 + } + } + + info = &FuncInfo{ + name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params, + } + functor.SetFunc(info) + return info, nil +} + +func (info *FuncInfo) Params() []ExprFuncParam { + return info.formalParams +} + +func (info *FuncInfo) ReturnType() string { + return info.returnType +} + +func (info *FuncInfo) ToString(opt FmtOpt) string { + var sb strings.Builder + if len(info.Name()) == 0 { + sb.WriteString("func") + } else { + sb.WriteString(info.Name()) + } + sb.WriteByte('(') + if info.formalParams != nil { + for i, p := range info.formalParams { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString(p.Name()) + + if p.IsDefault() { + sb.WriteByte('=') + if s, ok := p.DefaultValue().(string); ok { + sb.WriteByte('"') + sb.WriteString(s) + sb.WriteByte('"') + } else { + sb.WriteString(fmt.Sprintf("%v", p.DefaultValue())) + } + } + } + } + if info.maxArgs < 0 { + sb.WriteString(" ...") + } + sb.WriteString("):") + if len(info.returnType) > 0 { + sb.WriteString(info.returnType) + } else { + sb.WriteString(TypeAny) + } + sb.WriteString("{}") + return sb.String() +} + +func (info *FuncInfo) Name() string { + return info.name +} + +func (info *FuncInfo) MinArgs() int { + return info.minArgs +} + +func (info *FuncInfo) MaxArgs() int { + return info.maxArgs +} + +func (info *FuncInfo) Functor() Functor { + return info.functor +} + +func (info *FuncInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) { + if defCtx := info.functor.GetDefinitionContext(); defCtx != nil { + ctx = defCtx.Clone() + ctx.SetParent(defCtx) + } else { + ctx = parentCtx.Clone() + ctx.SetParent(parentCtx) + } + return +} + +func (info *FuncInfo) ParamSpec(paramName string) ExprFuncParam { + for _, spec := range info.formalParams { + if spec.Name() == paramName { + return spec + } + } + return nil +} + +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) { + for _, p := range info.formalParams { + if _, exists := actualParams[p.Name()]; !exists { + if !p.IsDefault() { + break + } + if p.IsRepeat() { + varArgs := make([]any, 1) + varArgs[0] = p.DefaultValue() + actualParams[p.Name()] = varArgs + } else { + actualParams[p.Name()] = p.DefaultValue() + } + } + } + } + + if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) { + err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams)) + } + return +} diff --git a/kern/function.go b/kern/function.go index 32a0d51..79323b1 100644 --- a/kern/function.go +++ b/kern/function.go @@ -14,11 +14,6 @@ type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (resul type DeepFuncTemplate func(a, b any) (eq bool, err error) -func IsFunctor(v any) (ok bool) { - _, ok = v.(Functor) - return -} - // ---- Common functor definition type BaseFunctor struct { info ExprFunc @@ -54,17 +49,17 @@ func (functor *BaseFunctor) GetDefinitionContext() ExprContext { } // ---- Function Parameters -type paramFlags uint16 +type FuncParamFlags uint16 const ( - PfDefault paramFlags = 1 << iota + PfDefault FuncParamFlags = 1 << iota PfOptional PfRepeat ) type funcParamInfo struct { name string - flags paramFlags + flags FuncParamFlags defaultValue any } @@ -72,11 +67,11 @@ func NewFuncParam(name string) ExprFuncParam { return &funcParamInfo{name: name} } -func NewFuncParamFlag(name string, flags paramFlags) ExprFuncParam { +func NewFuncParamFlag(name string, flags FuncParamFlags) ExprFuncParam { return &funcParamInfo{name: name, flags: flags} } -func NewFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo { +func NewFuncParamFlagDef(name string, flags FuncParamFlags, defValue any) *funcParamInfo { return &funcParamInfo{name: name, flags: flags, defaultValue: defValue} } diff --git a/operand-func.go b/operand-func.go index 000a1ec..53667b0 100644 --- a/operand-func.go +++ b/operand-func.go @@ -70,14 +70,14 @@ func evalFuncDef(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { paramList := make([]kern.ExprFuncParam, 0, len(opTerm.Children)) for _, param := range opTerm.Children { var defValue any - flags := paramFlags(0) + flags := kern.FuncParamFlags(0) if len(param.Children) > 0 { - flags |= PfDefault + flags |= kern.PfDefault if defValue, err = param.Children[0].Compute(ctx); err != nil { return } } - info := NewFuncParamFlagDef(param.Source(), flags, defValue) + info := kern.NewFuncParamFlagDef(param.Source(), flags, defValue) paramList = append(paramList, info) } v = newExprFunctor(ast, paramList, ctx) diff --git a/operand-iterator.go b/operand-iterator.go index 17a5913..b6156a5 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -5,7 +5,9 @@ package expr import ( + "fmt" "slices" + "strconv" "strings" "git.portale-stac.it/go-pkg/expr/kern" @@ -125,7 +127,7 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { } else { if dictIt, ok := firstChildValue.(*kern.DictType); ok { var args []any - if args, err = evalSibling(ctx, opTerm.Children, nil); err == nil { + if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil { v, err = NewDictIterator(dictIt, args) } } else { @@ -134,24 +136,70 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { } } else if list, ok := firstChildValue.(*kern.ListType); ok { var args []any - if args, err = evalSibling(ctx, opTerm.Children, nil); err == nil { + if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil { v = NewListIterator(list, args) } } else if intVal, ok := firstChildValue.(int64); ok { var args []any - if args, err = evalSibling(ctx, opTerm.Children, intVal); err == nil { + if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil { v, err = NewIntIterator(args) } } else { - var list []any - if list, err = evalSibling(ctx, opTerm.Children, firstChildValue); err == nil { - v = NewArrayIterator(list) + var siblings []any + if siblings, err = evalSiblings(ctx, opTerm.Children, firstChildValue); err == nil { + // if v, err = evalIterIter(ctx, firstChildValue, siblings); err == nil && v == nil { + // if it, ok := firstChildValue.(kern.Iterator); ok { + // if len(siblings) > 1 { + // if op, ok := siblings[1].(kern.Functor); ok { + // args := make(map[string]any, len(siblings)-2) + // for i, arg := range siblings[2:] { + // args["arg"+strconv.Itoa(i+1)] = arg + // } + // v, err = NewIterIter(it, ctx, op, args) + // } else { + // err = opTerm.Children[1].Errorf("the first sibling parameter must be a functor to be used as operation for the iterator") + // } + // } else { + // v, err = NewIterIter(it, ctx, nil, nil) + // } + if v, err = evalIterIter(ctx, firstChildValue, siblings); err == nil && v == nil { + v = NewArrayIterator(siblings) + } } } return } -func evalSibling(ctx kern.ExprContext, terms []*scan.Term, firstChildValue any) (list []any, err error) { +func evalIterIter(ctx kern.ExprContext, firstChildValue any, siblings []any) (v any, err error) { + var op kern.Functor + var args map[string]any + + if it, ok := firstChildValue.(kern.Iterator); ok { + if len(siblings) > 1 { + if op, ok = siblings[1].(kern.Functor); ok { + args = make(map[string]any, len(siblings)-2) + for i, arg := range siblings[2:] { + switch a := arg.(type) { + case *kern.DictType: + for keyAny, item := range *a { + if key, ok := keyAny.(string); ok { + args[key] = item + } + } + default: + args["arg"+strconv.Itoa(i+1)] = arg + } + } + } else if op == nil { + return nil, fmt.Errorf("the first sibling parameter must be a functor to be used as operation for the iterator") + } + } + v, err = NewIterIter(it, ctx, op, args) + } + return +} + +func evalSiblings(ctx kern.ExprContext, terms []*scan.Term, firstChildValue any) (list []any, err error) { items := make([]any, 0, len(terms)) for i, tree := range terms { var param any diff --git a/operator-builtin.go b/operator-builtin.go index 2dc6057..3dc6da2 100644 --- a/operator-builtin.go +++ b/operator-builtin.go @@ -37,7 +37,7 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { } else { var moduleSpec any var it kern.Iterator - if it, err = NewIterator(childValue); err != nil { + if it, err = NewIterator(ctx, childValue, nil); err != nil { return } for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() { diff --git a/operator-default.go b/operator-default.go index e6a7cc3..9e7d7af 100644 --- a/operator-default.go +++ b/operator-default.go @@ -111,7 +111,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err erro if functor, ok := rightValue.(kern.Functor); ok { //ctx.RegisterFunc(leftTerm.source(), functor, 0, -1) ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, []kern.ExprFuncParam{ - NewFuncParamFlag(kern.ParamValue, PfDefault|PfRepeat), + kern.NewFuncParamFlag(kern.ParamValue, kern.PfDefault|kern.PfRepeat), }) } else { v = rightValue diff --git a/operator-digest.go b/operator-digest.go index 402853c..26772db 100644 --- a/operator-digest.go +++ b/operator-digest.go @@ -37,7 +37,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if it, err = NewIterator(leftValue); err != nil { + if it, err = NewIterator(ctx, leftValue, nil); err != nil { return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", kern.TypeName(leftValue)) } diff --git a/operator-filter.go b/operator-filter.go index cd6daec..87b9762 100644 --- a/operator-filter.go +++ b/operator-filter.go @@ -28,6 +28,7 @@ func evalFilter(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any var it kern.Iterator var item any + var ok bool if err = opTerm.CheckOperands(); err != nil { return @@ -37,8 +38,10 @@ func evalFilter(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if it, err = NewIterator(leftValue); err != nil { - return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue)) + if it, ok = leftValue.(kern.Iterator); !ok { + if it, err = NewIterator(ctx, leftValue, nil); err != nil { + return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue)) + } } values := kern.NewListA() diff --git a/operator-groupby.go b/operator-groupby.go index 9323b87..48c3180 100644 --- a/operator-groupby.go +++ b/operator-groupby.go @@ -40,7 +40,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if it, err = NewIterator(leftValue); err != nil { + if it, err = NewIterator(ctx, leftValue, nil); err != nil { return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue)) } diff --git a/operator-join.go b/operator-join.go index c7af63f..daeda13 100644 --- a/operator-join.go +++ b/operator-join.go @@ -41,11 +41,11 @@ func evalJoin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if itLeft, err = NewIterator(leftValue); err != nil { + if itLeft, err = NewIterator(ctx, leftValue, nil); err != nil { return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", kern.TypeName(leftValue)) } - if itRight, err = NewIterator(rightValue); err != nil { + if itRight, err = NewIterator(ctx, rightValue, nil); err != nil { return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", kern.TypeName(rightValue)) } diff --git a/operator-map.go b/operator-map.go index 65ef742..60ff9ec 100644 --- a/operator-map.go +++ b/operator-map.go @@ -37,7 +37,7 @@ func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if it, err = NewIterator(leftValue); err != nil { + if it, err = NewIterator(ctx, leftValue, nil); err != nil { return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue)) } diff --git a/plugins.go b/plugins.go index 4b25a7c..a93d47f 100644 --- a/plugins.go +++ b/plugins.go @@ -100,7 +100,7 @@ func importPluginFromSearchPath(ctx kern.ExprContext, name any) (count int, err var it kern.Iterator dirList := buildSearchDirList(ctx, "plugin", ENV_EXPR_PLUGIN_PATH) count = 0 - if it, err = NewIterator(name); err != nil { + if it, err = NewIterator(ctx, name, nil); err != nil { return } for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() { diff --git a/simple-store.go b/simple-store.go index f72cd9e..bc78ad5 100644 --- a/simple-store.go +++ b/simple-store.go @@ -200,12 +200,12 @@ func (ctx *SimpleStore) GetLocalFuncInfo(name string) (info kern.ExprFunc, exist } func (ctx *SimpleStore) RegisterFuncInfo(info kern.ExprFunc) { - ctx.funcStore[info.Name()], _ = info.(*funcInfo) + ctx.funcStore[info.Name()], _ = info.(*kern.FuncInfo) } func (ctx *SimpleStore) RegisterFunc(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (exprFunc kern.ExprFunc, err error) { - var info *funcInfo - if info, err = newFuncInfo(name, functor, returnType, params); err == nil { + var info *kern.FuncInfo + if info, err = kern.NewFuncInfo(name, functor, returnType, params); err == nil { ctx.funcStore[name] = info exprFunc = info } diff --git a/t_funcs_test.go b/t_funcs_test.go index 3f90ff7..982393d 100644 --- a/t_funcs_test.go +++ b/t_funcs_test.go @@ -100,7 +100,7 @@ func TestGoFunction(t *testing.T) { ctx := NewSimpleStoreWithoutGlobalContext() ctx.RegisterFunc("myName", kern.NewGolangFunctor(myName), kern.TypeString, []kern.ExprFuncParam{ - NewFuncParamFlagDef("name", PfOptional|PfDefault, "Celestino Amoroso"), + kern.NewFuncParamFlagDef("name", kern.PfOptional|kern.PfDefault, "Celestino Amoroso"), }) runCtxTestSuite(t, ctx, section, inputs) diff --git a/t_iter-iter_test.go b/t_iter-iter_test.go new file mode 100644 index 0000000..66565a2 --- /dev/null +++ b/t_iter-iter_test.go @@ -0,0 +1,63 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// t_iter-iter_test.go +package expr + +import ( + "testing" + + "git.portale-stac.it/go-pkg/expr/kern" +) + +func TestIterIterator(t *testing.T) { + section := "Iterator" + inputs := []inputType{ + /* 1 */ {`it=$(4); $(it) filter ${_}==100`, kern.NewListA(), nil}, + /* 2 */ {`it=$(4); $(it, func(){$_}) filter ${_}==100`, kern.NewListA(), nil}, + /* 3 */ {`it=$(4); $(it, func(arg1){arg1+$_}, 10) filter ${_}==100`, kern.NewListA(), nil}, + } + + runTestSuiteSpec(t, section, inputs, 3) + // runTestSuite(t, section, inputs) +} + +// func TestNewIterIterator(t *testing.T) { +// var it kern.Iterator +// var err error + +// list := kern.NewListA("a", "b", "c", "d") +// itList := NewListIterator(list, []any{1, 3, 1}) +// it, err = NewIterator(nil, itList, map[string]any{"op": kern.NewFunctor("test")}) +// if err != nil { +// t.Errorf("error: %v", err) +// } else { +// if item, err := it.Next(); err != nil { +// t.Errorf("error: %v", err) +// } else if item != "b" { +// t.Errorf("expected %q, got %q", "b", item) +// } else { +// t.Logf("Next: %v", item) +// } +// } +// } + +// func TestNewIterIteratorNoOp(t *testing.T) { +// var it kern.Iterator +// var err error + +// list := kern.NewListA("a", "b", "c", "d") +// itList := NewListIterator(list, []any{1, 3, 1}) +// it, err = NewIterator(nil, itList, nil) +// if err != nil { +// t.Errorf("error: %v", err) +// } else { +// if item, err := it.Next(); err != nil { +// t.Errorf("error: %v", err) +// } else if item != "b" { +// t.Errorf("expected %q, got %q", "b", item) +// } else { +// t.Logf("Next: %v", item) +// } +// } +// } diff --git a/t_iter-list_test.go b/t_iter-list_test.go index 1aa472b..2076ca1 100644 --- a/t_iter-list_test.go +++ b/t_iter-list_test.go @@ -61,7 +61,7 @@ func TestNewIterList2(t *testing.T) { func TestNewIterList3(t *testing.T) { list := []any{"a", "b", "c", "d"} - it, _ := NewIterator(list) + it, _ := NewIterator(nil, list, nil) if item, err := it.Next(); err != nil { t.Errorf("error: %v", err) } else if item != "a" { @@ -73,7 +73,7 @@ func TestNewIterList3(t *testing.T) { func TestNewIterList4(t *testing.T) { list := any(nil) - it, _ := NewIterator(list) + it, _ := NewIterator(nil, list, nil) if _, err := it.Next(); err != io.EOF { t.Errorf("error: %v", err) } @@ -81,7 +81,7 @@ func TestNewIterList4(t *testing.T) { func TestNewIterList5(t *testing.T) { list := "123" - it, _ := NewIterator(list) + it, _ := NewIterator(nil, list, nil) if item, err := it.Next(); err != nil { t.Errorf("error: %v", err) } else if item != "123" { @@ -93,8 +93,8 @@ func TestNewIterList5(t *testing.T) { func TestNewIterList6(t *testing.T) { list := kern.NewListA("a", "b", "c", "d") - it1, _ := NewIterator(list) - it, _ := NewIterator(it1) + it1, _ := NewIterator(nil, list, nil) + it, _ := NewIterator(nil, it1, nil) if item, err := it.Next(); err != nil { t.Errorf("error: %v", err) } else if item != "a" { @@ -106,7 +106,7 @@ func TestNewIterList6(t *testing.T) { func TestNewString(t *testing.T) { list := "123" - it, _ := NewIterator(list) + it, _ := NewIterator(nil, list, nil) if s := it.String(); s != "$([#1])" { t.Errorf("expected $([#1]), got %s", s) }