// 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" "git.portale-stac.it/go-pkg/expr/scan" ) const iterIterType = "IterIter" type IterIter struct { it kern.Iterator count int64 index int64 ctx kern.ExprContext exprList []*scan.Term current any } func NewIterIter(it kern.Iterator, ctx kern.ExprContext, exprs []*scan.Term) (iter kern.Iterator, err error) { if ctx == nil { err = fmt.Errorf("context is required for %s", iterIterType) } else if it == nil { err = fmt.Errorf("source iterator is required for %s", iterIterType) } else { iter = &IterIter{it: it, count: 0, index: -1, ctx: ctx, exprList: exprs, current: nil} } return } func (it *IterIter) String() string { return fmt.Sprintf("$(%s)", it.it) } func (it *IterIter) TypeName() string { return iterIterType } func (it *IterIter) HasOperation(name string) bool { return HasIterStandardOperations(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 len(it.exprList) > 0 { // Evaluate the expression list and use the result as the current item var exprValue any for _, expr := range it.exprList { if exprValue, err = expr.Compute(it.ctx); err != nil { break } it.ctx.UnsafeSetVar(kern.ControlLastResult, exprValue) } if err == nil { item = exprValue } } 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 }