diff --git a/kern/linked-list-type.go b/kern/linked-list-type.go new file mode 100644 index 0000000..adc69c6 --- /dev/null +++ b/kern/linked-list-type.go @@ -0,0 +1,130 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// linked-list-type.go +package kern + +import ( + "strings" +) + +const LinkedListTypeName = "lisked-list" +const MaxUint64Allowed = uint64(9_223_372_036_854_775_807) + +func IsLinkedList(v any) (ok bool) { + _, ok = v.(*LinkedList) + return ok +} + +func NewLinkedListA(listAny ...any) (list *LinkedList) { + if listAny == nil { + listAny = []any{} + } + list = NewLinkedList() + for _, item := range listAny { + list.PushBack(FixAnyNumber(item)) + } + return +} + +func LinkedListFromStrings(stringList []string) (list *LinkedList) { + list = NewLinkedList() + for _, s := range stringList { + list.PushBack(s) + } + return +} + +func (ls *LinkedList) ToString(opt FmtOpt) (s string) { + indent := GetFormatIndent(opt) + flags := GetFormatFlags(opt) + + var sb strings.Builder + sb.WriteString("[<") + if ls.Len() > 0 { + innerOpt := MakeFormatOptions(flags, indent+1) + nest := strings.Repeat(" ", indent+1) + + if flags&MultiLine != 0 { + sb.WriteByte('\n') + sb.WriteString(nest) + } + + i := 0 + for item := ls.FirstNode(); item != nil; item = item.Next() { + if i > 0 { + if flags&MultiLine != 0 { + sb.WriteString(",\n") + sb.WriteString(nest) + } else { + sb.WriteString(", ") + } + } + // data := item.Data() + // if s, ok := data.(string); ok { + // sb.WriteByte('"') + // sb.WriteString(s) + // sb.WriteByte('"') + // } else if formatter, ok := data.(Formatter); ok { + // sb.WriteString(formatter.ToString(innerOpt)) + // } else { + // fmt.Fprintf(&sb, "%v", data) + // } + Format(&sb, item.Data(), innerOpt) + i++ + } + if flags&MultiLine != 0 { + sb.WriteByte('\n') + sb.WriteString(strings.Repeat(" ", indent)) + } + } + sb.WriteString(">]") + s = sb.String() + if flags&Truncate != 0 && len(s) > TruncateSize { + s = TruncateString(s) + } + return +} + +func (ls *LinkedList) String() string { + return ls.ToString(0) +} + +func (ls *LinkedList) TypeName() string { + return LinkedListTypeName +} + +// func (ls *LinkedList) Contains(t *ListType) (answer bool) { +// if len(*ls) >= len(*t) { +// answer = true +// for _, item := range *t { +// if answer = ls.IndexDeepSameCmp(item) >= 0; !answer { +// break +// } +// } +// } +// return +// } + +func (ls1 *LinkedList) Equals(ls2 *LinkedList) (answer bool) { + if ls2 != nil && ls1.Len() == ls2.Len() { + answer = true + i2 := ls2.FirstNode() + for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() { + if !Equal(i1.Data(), i2.Data()) { + answer = false + break + } + i2 = i2.Next() + } + } + return +} + +func (ls1 *LinkedList) Clone() (ls2 *LinkedList) { + ls2 = NewLinkedListA() + for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() { + ls2.PushBack(Clone(i1.Data())) + } + return +} diff --git a/linked-list-iterator.go b/linked-list-iterator.go new file mode 100644 index 0000000..da01d3a --- /dev/null +++ b/linked-list-iterator.go @@ -0,0 +1,144 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// list-iterator.go +package expr + +import ( + "fmt" + "io" + "slices" + + "git.portale-stac.it/go-pkg/expr/kern" +) + +type LinkedListIterator struct { + a *kern.ListType + count int64 + index int64 + start int64 + stop int64 + step int64 +} + +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 + return +} + +func (it *LinkedListIterator) String() string { + var l = int64(0) + if it.a != nil { + l = int64(len(*it.a)) + } + return fmt.Sprintf("$([#%d])", l) +} + +func (it *LinkedListIterator) TypeName() string { + return "LinkedListIterator" +} + +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 +} + +func (it *LinkedListIterator) 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 *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 + } + } else { + if it.start < int64(len(a)) && it.index >= it.stop && it.index <= it.start { + item = a[it.index] + } else { + err = io.EOF + } + + } + return +} + +func (it *LinkedListIterator) Next() (item any, err error) { + it.index += it.step + if item, err = it.Current(); err != io.EOF { + it.count++ + } + return +} + +func (it *LinkedListIterator) Index() int64 { + return it.index +} + +func (it *LinkedListIterator) Count() int64 { + return it.count +} + +func (it *LinkedListIterator) Reset() error { + it.index = it.start - it.step + it.count = 0 + return nil +} + +func (it *LinkedListIterator) Clean() error { + return nil +} diff --git a/operand-linked-list.go b/operand-linked-list.go new file mode 100644 index 0000000..cd5ef3f --- /dev/null +++ b/operand-linked-list.go @@ -0,0 +1,43 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// operand-list.go +package expr + +import ( + "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/scan" +) + +// -------- list term +// func newLinkedListTermA(args ...*scan.Term) *scan.Term { +// return newLinkedListTerm(0, 0, args) +// } + +func newLinkedListTerm(row, col int, args []*scan.Term) *scan.Term { + return &scan.Term{ + Tk: *scan.NewValueToken(row, col, scan.SymLinkedList, "[<>]", args), + Parent: nil, + Children: nil, + Position: scan.PosLeaf, + Priority: scan.PriValue, + EvalFunc: evalLinkedList, + } +} + +// -------- list func +func evalLinkedList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { + list, _ := opTerm.Value().([]*scan.Term) + items := kern.NewLinkedList() + for _, tree := range list { + var param any + if param, err = tree.Compute(ctx); err != nil { + break + } + items.PushBack(param) + } + if err == nil { + v = items + } + return +}