From 081395be5fae06ab60b91c92f0d946d9589f73ef Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Mon, 18 May 2026 09:49:44 +0200 Subject: [PATCH] linked-list-iterator and context operator $$ enhancement --- iter-factory.go | 2 ++ linked-list-iterator.go | 80 ++++++++++------------------------------- operand-iterator.go | 5 +++ operator-context.go | 10 ++++-- t_iter-iter_test.go | 4 +-- t_iterator_test.go | 18 +++++----- t_list_test.go | 4 ++- 7 files changed, 47 insertions(+), 76 deletions(-) diff --git a/iter-factory.go b/iter-factory.go index ec27ba9..45e5beb 100644 --- a/iter-factory.go +++ b/iter-factory.go @@ -19,6 +19,8 @@ func NewIterator(ctx kern.ExprContext, value any, ops []*scan.Term) (it kern.Ite switch v := value.(type) { case *kern.ListType: it = NewListIterator(v, nil) + case *kern.LinkedList: + it = NewLinkedListIterator(v, nil) case *kern.DictType: it, err = NewDictIterator(v, nil) case []any: diff --git a/linked-list-iterator.go b/linked-list-iterator.go index da01d3a..b8df669 100644 --- a/linked-list-iterator.go +++ b/linked-list-iterator.go @@ -13,59 +13,23 @@ import ( ) type LinkedListIterator struct { - a *kern.ListType - count int64 - index int64 - start int64 - stop int64 - step int64 + a *kern.LinkedList + count int64 + index int64 + current *kern.ListNode } -func NewLinkedListIterator(list *kern.ListType, args []any) (it *LinkedListIterator) { - var argc int = 0 - listLen := int64(len(([]any)(*list))) - if args != nil { - argc = len(args) - } - it = &LinkedListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1} - if argc >= 1 { - if i, err := kern.ToGoInt64(args[0], "start index"); err == nil { - if i < 0 { - i = listLen + i - } - it.start = i - } - if argc >= 2 { - if i, err := kern.ToGoInt64(args[1], "stop index"); err == nil { - if i < 0 { - i = listLen + i - } - it.stop = i - } - if argc >= 3 { - if i, err := kern.ToGoInt64(args[2], "step"); err == nil { - if i < 0 { - i = -i - } - if it.start > it.stop { - it.step = -i - } else { - it.step = i - } - } - } - } - } - it.index = it.start - it.step +func NewLinkedListIterator(list *kern.LinkedList, args []any) (it *LinkedListIterator) { + it = &LinkedListIterator{a: list, count: 0, index: -1, current: list.FirstNode()} return } func (it *LinkedListIterator) String() string { var l = int64(0) if it.a != nil { - l = int64(len(*it.a)) + l = int64(it.a.Len()) } - return fmt.Sprintf("$([#%d])", l) + return fmt.Sprintf("$([<#%d>])", l) } func (it *LinkedListIterator) TypeName() string { @@ -73,7 +37,6 @@ func (it *LinkedListIterator) TypeName() string { } func (it *LinkedListIterator) HasOperation(name string) bool { - //yes := name == expr.NextName || name == expr.ResetName || name == expr.IndexName || name == expr.CountName || name == expr.CurrentName yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name) return yes } @@ -99,28 +62,22 @@ func (it *LinkedListIterator) CallOperation(name string, args map[string]any) (v } func (it *LinkedListIterator) Current() (item any, err error) { - a := *(it.a) - if it.start <= it.stop { - if it.stop < int64(len(a)) && it.index >= it.start && it.index <= it.stop { - item = a[it.index] - } else { - err = io.EOF - } + if it.current != nil { + item = it.current.Data() } else { - if it.start < int64(len(a)) && it.index >= it.stop && it.index <= it.start { - item = a[it.index] - } else { - err = io.EOF - } - + err = io.EOF } return } func (it *LinkedListIterator) Next() (item any, err error) { - it.index += it.step - if item, err = it.Current(); err != io.EOF { + if it.current != nil { + item = it.current.Data() + it.current = it.current.Next() + it.index++ it.count++ + } else { + err = io.EOF } return } @@ -134,7 +91,8 @@ func (it *LinkedListIterator) Count() int64 { } func (it *LinkedListIterator) Reset() error { - it.index = it.start - it.step + it.current = it.a.FirstNode() + it.index = -1 it.count = 0 return nil } diff --git a/operand-iterator.go b/operand-iterator.go index af08fb5..4da7abc 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -137,6 +137,11 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil { v = NewListIterator(list, args) } + } else if list, ok := firstChildValue.(*kern.LinkedList); ok { + var args []any + if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil { + v = NewLinkedListIterator(list, args) + } } else if intVal, ok := firstChildValue.(int64); ok { var args []any if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil { diff --git a/operator-context.go b/operator-context.go index 64d7f93..d23a002 100644 --- a/operator-context.go +++ b/operator-context.go @@ -58,7 +58,11 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error v = d } } else if childValue != nil { - if it, ok := childValue.(kern.Iterator); ok { + it, ok := childValue.(kern.Iterator) + if !ok { + it, err = NewIterator(ctx, childValue, nil) + } + if err == nil { var item any // values := kern.NewListA() values := kern.NewLinkedListA() @@ -70,8 +74,8 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error err = nil v = values } - } else { - err = opTerm.ErrIncompatiblePrefixPostfixType(childValue) + // } else { + // err = opTerm.ErrIncompatiblePrefixPostfixType(childValue) } } else { err = opTerm.ErrIncompatiblePrefixPostfixType(childValue) diff --git a/t_iter-iter_test.go b/t_iter-iter_test.go index b8945e5..5265e48 100644 --- a/t_iter-iter_test.go +++ b/t_iter-iter_test.go @@ -13,8 +13,8 @@ import ( func TestIterIterator(t *testing.T) { section := "Iter-Iter" inputs := []inputType{ - /* 1 */ {`it=$(4); $$($(it) filter ${_}==100)`, kern.NewListA(), nil}, - /* 2 */ {`it=$(4); $$($(it, $_) filter ${_}==100)`, kern.NewListA(), nil}, + /* 1 */ {`it=$(4); $$($(it) filter ${_}==100)`, kern.NewLinkedListA(), nil}, + /* 2 */ {`it=$(4); $$($(it, $_) filter ${_}==100)`, kern.NewLinkedListA(), nil}, /* 3 */ {`it=$(4); $(it, 10+$_, last-1) digest ${_}`, int64(12), nil}, /* 4 */ {`f=func(n){last-n}; it=$(4); $(it, 10+$_, f(-1)) digest ${_}`, int64(14), nil}, } diff --git a/t_iterator_test.go b/t_iterator_test.go index 6a0a9ca..1237ca5 100644 --- a/t_iterator_test.go +++ b/t_iterator_test.go @@ -44,8 +44,8 @@ func TestIteratorParser(t *testing.T) { func TestFilterIterator(t *testing.T) { section := "Iterator-Filter" inputs := []inputType{ - /* 1 */ {`$$([1,2,3] filter $_%2==0)`, kern.NewList([]any{int64(2)}), nil}, - /* 2 */ {`it = [1,2,3] filter $_%2!=1; $$(it)`, kern.NewList([]any{int64(2)}), nil}, + /* 1 */ {`$$([1,2,3] filter $_%2==0)`, kern.NewLinkedListA(2), nil}, + /* 2 */ {`it = [1,2,3] filter $_%2!=1; $$(it)`, kern.NewLinkedListA(2), nil}, /* 3 */ {`builtin "os.file"; #$$(fileLineIterator("test-file.txt") filter (#${_} == 2))`, int64(0), nil}, /* 4 */ {`builtin "os.file"; #$$(fileLineIterator("test-file.txt") filter (#${_} == 3))`, int64(2), nil}, } @@ -69,11 +69,11 @@ func TestDigestIterator(t *testing.T) { func TestCatIterator(t *testing.T) { section := "Iterator-Cat" inputs := []inputType{ - /* 1 */ {`$$([1] cat [])`, kern.NewList([]any{int64(1)}), nil}, - /* 2 */ {`$$([1] cat [2])`, kern.NewList([]any{int64(1), int64(2)}), nil}, - /* 3 */ {`$$([1] cat nil)`, kern.NewList([]any{int64(1)}), nil}, - /* 4 */ {`$$(nil cat [2])`, kern.NewList([]any{int64(2)}), nil}, - /* 5 */ {`$$(nil cat nil)`, kern.NewList([]any{}), nil}, + /* 1 */ {`$$([1] cat [])`, kern.NewLinkedListA(1), nil}, + /* 2 */ {`$$([1] cat [2])`, kern.NewLinkedListA(1, 2), nil}, + /* 3 */ {`$$([1] cat nil)`, kern.NewLinkedListA(1), nil}, + /* 4 */ {`$$(nil cat [2])`, kern.NewLinkedListA(2), nil}, + /* 5 */ {`$$(nil cat nil)`, kern.NewLinkedListA(), nil}, /* 6 */ {`$$(["a","b"] cat ["x"-true])`, nil, `[1:23] left operand 'x' [string] and right operand 'true' [bool] are not compatible with operator "-"`}, } @@ -84,10 +84,10 @@ func TestCatIterator(t *testing.T) { func TestMapIterator(t *testing.T) { section := "Iterator-Map" inputs := []inputType{ - /* 1 */ {`$$([3,4,5] map ${_#})`, kern.NewList([]any{int64(1), int64(2), int64(3)}), nil}, + /* 1 */ {`$$([3,4,5] map ${_#})`, kern.NewLinkedListA(1, 2, 3), nil}, /* 2 */ {`#$$($(10) map ${_})`, int64(10), nil}, /* 3 */ {`#$$($(10,0) map ${_})`, int64(10), nil}, - /* 4 */ {`builtin "os.file"; $$(fileLineIterator("test-file.txt") map ${__})`, kern.NewList([]any{int64(0), int64(1)}), nil}, + /* 4 */ {`builtin "os.file"; $$(fileLineIterator("test-file.txt") map ${__})`, kern.NewLinkedListA(0, 1), nil}, /* 5 */ {`$$(["1", "2", "3"] map int())`, nil, `int(): too few params -- expected 1, got 0`}, } diff --git a/t_list_test.go b/t_list_test.go index 6abbe2f..c958a9c 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -71,10 +71,12 @@ func TestLinkedListParser(t *testing.T) { inputs := []inputType{ /* 1 */ {`[<1,2>]`, kern.NewLinkedListA(1, 2), nil}, + /* 2 */ {`it=$([<1,2,3>]); it++`, int64(1), nil}, + /* 3 */ {`it=$([<1,2,3>]); #($$(it))`, int64(3), nil}, } // t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 44) + // runTestSuiteSpec(t, section, inputs, 3) runTestSuite(t, section, inputs) }