list iterators now support start, stop e step

This commit is contained in:
Celestino Amoroso 2024-05-04 08:07:49 +02:00
parent d9fbe6f36d
commit 2c5f02cc69
9 changed files with 115 additions and 37 deletions

View File

@ -9,15 +9,6 @@ import (
"io"
)
const (
initName = "init"
cleanName = "clean"
resetName = "reset"
nextName = "next"
currentName = "current"
indexName = "index"
)
type dataCursor struct {
ds map[string]Functor
ctx ExprContext
@ -77,7 +68,7 @@ func (dc *dataCursor) HasOperation(name string) (exists bool) {
func (dc *dataCursor) CallOperation(name string, args []any) (value any, err error) {
if name == indexName {
value = dc.Index()
value = int64(dc.Index())
} else if functor, ok := dc.ds[name]; ok && isFunctor(functor) {
if functor == dc.cleanFunc {
value, err = dc.Clean()

View File

@ -38,7 +38,7 @@ func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
break
}
if list, ok := v.(*ListType); ok {
if v, err = doAdd(ctx, name, NewListIterator(list)); err != nil {
if v, err = doAdd(ctx, name, NewListIterator(list, nil)); err != nil {
break
}
}
@ -114,7 +114,7 @@ func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) {
}
if list, ok := v.(*ListType); ok {
if v, err = doMul(ctx, name, NewListIterator(list)); err != nil {
if v, err = doMul(ctx, name, NewListIterator(list, nil)); err != nil {
break
}
}

View File

@ -40,7 +40,7 @@ func joinStrFunc(ctx ExprContext, name string, args []any) (result any, err erro
result = ""
} else if len(args) == 2 {
if ls, ok := args[1].(*ListType); ok {
result, err = doJoinStr(name, sep, NewListIterator(ls))
result, err = doJoinStr(name, sep, NewListIterator(ls, nil))
} else if it, ok := args[1].(Iterator); ok {
result, err = doJoinStr(name, sep, it)
} else {

View File

@ -11,22 +11,62 @@ import (
type ListIterator struct {
a *ListType
count int
index int
start int
stop int
step int
}
func NewListIterator(list *ListType) *ListIterator {
return &ListIterator{a: list, index: 0}
func NewListIterator(list *ListType, args []any) (it *ListIterator) {
var argc int = 0
listLen := len(([]any)(*list))
if args != nil {
argc = len(args)
}
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
if argc >= 1 {
if i, err := toInt(args[0], "start index"); err == nil {
if i < 0 {
i = listLen + i
}
it.start = i
}
if argc >= 2 {
if i, err := toInt(args[1], "stop index"); err == nil {
if i < 0 {
i = listLen + i
}
it.stop = i
}
if argc >= 3 {
if i, err := toInt(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 NewArrayIterator(array []any) *ListIterator {
return &ListIterator{a: (*ListType)(&array), index: 0}
func NewArrayIterator(array []any) (it *ListIterator) {
it = &ListIterator{a: (*ListType)(&array), count: 0, index: -1, start: 0, stop: len(array) - 1, step: 1}
return
}
func NewAnyIterator(value any) (it *ListIterator) {
if value == nil {
it = NewArrayIterator([]any{})
} else if list, ok := value.(*ListType); ok {
it = NewListIterator(list)
it = NewListIterator(list, nil)
} else if array, ok := value.([]any); ok {
it = NewArrayIterator(array)
} else if it1, ok := value.(*ListIterator); ok {
@ -46,7 +86,7 @@ func (it *ListIterator) String() string {
}
func (it *ListIterator) HasOperation(name string) bool {
yes := name == resetName || name == indexName
yes := name == resetName || name == indexName || name == countName
return yes
}
@ -55,7 +95,9 @@ func (it *ListIterator) CallOperation(name string, args []any) (v any, err error
case resetName:
v, err = it.Reset()
case indexName:
v = it.Index()
v = int64(it.Index())
case countName:
v = it.count
default:
err = errNoOperation(name)
}
@ -64,7 +106,7 @@ func (it *ListIterator) CallOperation(name string, args []any) (v any, err error
func (it *ListIterator) Current() (item any, err error) {
a := *(it.a)
if it.index >= 0 && it.index < len(a) {
if it.index >= 0 && it.index <= it.stop {
item = a[it.index]
} else {
err = io.EOF
@ -73,17 +115,18 @@ func (it *ListIterator) Current() (item any, err error) {
}
func (it *ListIterator) Next() (item any, err error) {
it.index += it.step
if item, err = it.Current(); err != io.EOF {
it.index++
it.count++
}
return
}
func (it *ListIterator) Index() int {
return it.index - 1
return it.index
}
func (it *ListIterator) Reset() (bool, error) {
it.index = 0
it.index = it.start
return true, nil
}

View File

@ -9,6 +9,18 @@ import (
"fmt"
)
// Operator names
const (
initName = "init"
cleanName = "clean"
resetName = "reset"
nextName = "next"
currentName = "current"
indexName = "index"
countName = "count"
)
type Iterator interface {
Next() (item any, err error) // must return io.EOF after the last item
Current() (item any, err error)

View File

@ -133,29 +133,52 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) {
v = dc
} else if list, ok := firstChildValue.(*ListType); ok {
v = NewListIterator(list)
var args []any
if args, err = evalSibling(ctx, self.children, nil); err == nil {
v = NewListIterator(list, args)
}
} else {
var list *ListType
if list, err = evalChildren(ctx, self.children, firstChildValue); err == nil {
v = NewListIterator(list)
var list []any
if list, err = evalSibling(ctx, self.children, firstChildValue); err == nil {
v = NewArrayIterator(list)
}
}
return
}
func evalChildren(ctx ExprContext, terms []*term, firstChildValue any) (list *ListType, err error) {
items := make(ListType, len(terms))
// func evalChildren(ctx ExprContext, terms []*term, firstChildValue any) (list *ListType, err error) {
// items := make(ListType, len(terms))
// for i, tree := range terms {
// var param any
// if i == 0 && firstChildValue != nil {
// param = firstChildValue
// } else if param, err = tree.compute(ctx); err != nil {
// break
// }
// items[i] = param
// }
// if err == nil {
// list = &items
// }
// return
// }
func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []any, err error) {
items := make([]any, 0, len(terms))
for i, tree := range terms {
var param any
if i == 0 && firstChildValue != nil {
if i == 0 {
if firstChildValue == nil {
continue
}
param = firstChildValue
} else if param, err = tree.compute(ctx); err != nil {
break
}
items[i] = param
items = append(items, param)
}
if err == nil {
list = &items
list = items
}
return
}

View File

@ -50,7 +50,7 @@ func evalBuiltin(ctx ExprContext, self *term) (v any, err error) {
}
}
if err == nil {
v = count
v = int64(count)
}
return
}

View File

@ -30,7 +30,12 @@ func evalLength(ctx ExprContext, self *term) (v any, err error) {
s, _ := childValue.(string)
v = int64(len(s))
} else if it, ok := childValue.(Iterator); ok {
v = int64(it.Index() + 1)
if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(countName) {
count, _ := extIt.CallOperation(countName, nil)
v, _ = toInt(count, "")
} else {
v = int64(it.Index() + 1)
}
} else {
err = self.errIncompatibleType(childValue)
}

View File

@ -174,11 +174,15 @@ func TestParser(t *testing.T) {
/* 152 */ {`builtin "math.arith"; mul(1|2, 1.0, 2)`, float64(1.0), nil},
/* 153 */ {`include "iterator.expr"; it=$(ds,3); ()it`, int64(0), nil},
/* 154 */ {`include "iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil},
/* 155 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(1), nil},
/* 155 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(2), nil},
/* 156 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; it.reset; ()it`, int64(0), nil},
/* 157 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil},
/* 158 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
/* 159 */ {`include "file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil},
/* 160 */ {`include "file-reader.expr"; it=$(ds,"int.list"); it++; it.index`, int64(0), nil},
/* 161 */ {`include "file-reader.expr"; it=$(ds,"int.list"); it.clean`, true, nil},
/* 162 */ {`builtin "os.file"`, int64(1), nil},
/* 163 */ {`it=$(1,2,3); it++`, int64(1), nil},
}
check_env_expr_path := 113
@ -186,7 +190,7 @@ func TestParser(t *testing.T) {
failed := 0
// inputs1 := []inputType{
// /* 140 */ {`ds={}; $(ds)`, nil, nil},
// /* 159 */ {`include "file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil},
// }
for i, input := range inputs {