Iterator defined by data-source now only requires one method: next()

This commit is contained in:
Celestino Amoroso 2024-07-21 05:45:22 +02:00
parent 6ecbe2feb1
commit c461fd138e
3 changed files with 62 additions and 69 deletions

View File

@ -13,19 +13,29 @@ type dataCursor struct {
ds map[string]Functor ds map[string]Functor
ctx ExprContext ctx ExprContext
index int index int
current any
lastErr error
resource any resource any
nextFunc Functor nextFunc Functor
cleanFunc Functor cleanFunc Functor
resetFunc Functor resetFunc Functor
currentFunc Functor // currentFunc Functor
} }
func NewDataCursor(ctx ExprContext, ds map[string]Functor) (dc *dataCursor) { func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *dataCursor) {
dc = &dataCursor{ dc = &dataCursor{
ds: ds, ds: ds,
index: -1, index: -1,
current: nil,
lastErr: nil,
resource: resource,
ctx: ctx.Clone(), ctx: ctx.Clone(),
nextFunc: ds[NextName],
// currentFunc: ds[CurrentName],
cleanFunc: ds[CleanName],
resetFunc: ds[ResetName],
} }
dc.Next()
return return
} }
@ -101,6 +111,7 @@ func (dc *dataCursor) Reset() (success bool, err error) {
dc.index = -1 dc.index = -1
} }
exportObjects(dc.ctx, ctx) exportObjects(dc.ctx, ctx)
dc.Next()
} else { } else {
err = errInvalidDataSource() err = errInvalidDataSource()
} }
@ -129,44 +140,14 @@ func (dc *dataCursor) Clean() (success bool, err error) {
} }
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
ctx := cloneContext(dc.ctx) if dc.current != nil {
if item, err = dc.currentFunc.Invoke(ctx, CurrentName, []any{}); err == nil && item == nil { item = dc.current
} else {
err = io.EOF err = io.EOF
} }
exportObjects(dc.ctx, ctx)
return return
} }
// func (dc *dataCursor) _Next() (item any, err error) { // must return io.EOF after the last item
// if dc.resource != nil {
// ctx := cloneContext(dc.ctx)
// // fmt.Printf("Entering Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
// if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{dc.resource}); err == nil {
// if item == nil {
// err = io.EOF
// } else {
// dc.index++
// }
// }
// // fmt.Printf("Exiting Inner-Ctx [%p]: %s\n", ctx, CtxToString(ctx, 0))
// exportObjects(dc.ctx, ctx)
// // fmt.Printf("Outer-Ctx [%p]: %s\n", dc.ctx, CtxToString(dc.ctx, 0))
// } else {
// err = errInvalidDataSource()
// }
// return
// }
// func (dc *dataCursor) _filter(item any) (filterdItem any, err error) {
// if filter, ok := dc.ds[filterName]; ok {
// ctx := cloneContext(dc.ctx)
// filterdItem, err = filter.Invoke(ctx, filterName, []any{item, dc.index})
// } else {
// filterdItem = item
// }
// return
// }
func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err error) { func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err error) {
var v any var v any
var ok bool var ok bool
@ -176,46 +157,54 @@ func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err
accepted = true // NOTE: A non-boolean value that is not nil means the item has been accepted accepted = true // NOTE: A non-boolean value that is not nil means the item has been accepted
} }
} }
return return
} }
func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) { func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) {
ctx := cloneContext(dc.ctx) ctx := cloneContext(dc.ctx)
mappedItem, err = mapper.Invoke(ctx, MapName, []any{item, dc.index}); mappedItem, err = mapper.Invoke(ctx, MapName, []any{item, dc.index})
return return
} }
func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF after the last item
var accepted bool var accepted bool
if err = dc.lastErr; err != nil {
return
}
current = dc.current
if dc.resource != nil { if dc.resource != nil {
filter := dc.ds[FilterName] filter := dc.ds[FilterName]
mapper := dc.ds[MapName] mapper := dc.ds[MapName]
var item any
for item == nil && err == nil { for item == nil && dc.lastErr == nil {
ctx := cloneContext(dc.ctx) ctx := cloneContext(dc.ctx)
if item, err = dc.nextFunc.Invoke(ctx, NextName, []any{dc.resource}); err == nil {
if item == nil {
err = io.EOF
} else {
dc.index++ dc.index++
if item, dc.lastErr = dc.nextFunc.Invoke(ctx, NextName, []any{dc.resource, dc.index}); dc.lastErr == nil {
if item == nil {
dc.lastErr = io.EOF
} else {
if filter != nil { if filter != nil {
if accepted, err = dc.checkFilter(filter, item); err != nil || !accepted { if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
item = nil item = nil
} }
} }
if item != nil && mapper != nil { if item != nil && mapper != nil {
item, err = dc.mapItem(mapper, item) item, dc.lastErr = dc.mapItem(mapper, item)
} }
} }
} }
exportObjects(dc.ctx, ctx) exportObjects(dc.ctx, ctx)
} }
dc.current = item
if dc.lastErr != nil {
dc.Clean()
}
} else { } else {
err = errInvalidDataSource() dc.lastErr = errInvalidDataSource()
} }
return return
} }
func (dc *dataCursor) Index() int { func (dc *dataCursor) Index() int {
return dc.index return dc.index-1
} }

View File

@ -66,8 +66,8 @@ func evalFirstChild(ctx ExprContext, iteratorTerm *term) (value any, err error)
func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]Functor, err error) { func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]Functor, err error) {
if dictAny, ok := firstChildValue.(*DictType); ok { if dictAny, ok := firstChildValue.(*DictType); ok {
requiredFields := []string{CurrentName, NextName} requiredFields := []string{/*CurrentName,*/ NextName}
fieldsMask := 0b11 fieldsMask := 0b1
foundFields := 0 foundFields := 0
ds = make(map[string]Functor) ds = make(map[string]Functor)
for keyAny, item := range *dictAny { for keyAny, item := range *dictAny {
@ -108,9 +108,10 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
} }
if ds != nil { if ds != nil {
dc := NewDataCursor(ctx, ds) var dc *dataCursor
if initFunc, exists := ds[InitName]; exists && initFunc != nil { if initFunc, exists := ds[InitName]; exists && initFunc != nil {
var args []any var args []any
var resource any
if len(opTerm.children) > 1 { if len(opTerm.children) > 1 {
if args, err = evalTermArray(ctx, opTerm.children[1:]); err != nil { if args, err = evalTermArray(ctx, opTerm.children[1:]); err != nil {
return return
@ -119,17 +120,20 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
args = []any{} args = []any{}
} }
initCtx := dc.ctx.Clone() initCtx := ctx.Clone()
if dc.resource, err = initFunc.Invoke(initCtx, InitName, args); err != nil { if resource, err = initFunc.Invoke(initCtx, InitName, args); err != nil {
return return
} }
exportObjects(dc.ctx, initCtx) dcCtx := ctx.Clone()
exportObjects(dcCtx, initCtx)
dc = NewDataCursor(dcCtx, ds, resource)
//exportObjects(dc.ctx, initCtx)
} }
dc.nextFunc = ds[NextName] // dc.nextFunc = ds[NextName]
dc.currentFunc = ds[CurrentName] // dc.currentFunc = ds[CurrentName]
dc.cleanFunc = ds[CleanName] // dc.cleanFunc = ds[CleanName]
dc.resetFunc = ds[ResetName] // dc.resetFunc = ds[ResetName]
v = dc v = dc
} else if list, ok := firstChildValue.(*ListType); ok { } else if list, ok := firstChildValue.(*ListType); ok {

View File

@ -19,8 +19,8 @@ func TestExpr(t *testing.T) {
/* 5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil}, /* 5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil},
/* 6 */ {` /* 6 */ {`
ds={ ds={
"init":func(end){@end=end; @current=0 but true}, "init":func(@end){@current=0 but true},
"current":func(){current}, //"current":func(){current},
"next":func(){ "next":func(){
((next=current+1) <= end) ? [true] {@current=next but current} :: {nil} ((next=current+1) <= end) ? [true] {@current=next but current} :: {nil}
} }
@ -32,6 +32,6 @@ func TestExpr(t *testing.T) {
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
// parserTestSpec(t, section, inputs, 3) //runTestSuiteSpec(t, section, inputs, 6)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }