From c461fd138e4331a0f4f373112e9f0e9c9edae1aa Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Sun, 21 Jul 2024 05:45:22 +0200 Subject: [PATCH] Iterator defined by data-source now only requires one method: next() --- data-cursor.go | 101 ++++++++++++++++++++------------------------ operand-iterator.go | 24 ++++++----- t_expr_test.go | 6 +-- 3 files changed, 62 insertions(+), 69 deletions(-) diff --git a/data-cursor.go b/data-cursor.go index 3f94eb0..ad41a8a 100644 --- a/data-cursor.go +++ b/data-cursor.go @@ -13,19 +13,29 @@ type dataCursor struct { ds map[string]Functor ctx ExprContext index int + current any + lastErr error resource any nextFunc Functor cleanFunc 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{ - ds: ds, - index: -1, - ctx: ctx.Clone(), + ds: ds, + index: -1, + current: nil, + lastErr: nil, + resource: resource, + ctx: ctx.Clone(), + nextFunc: ds[NextName], +// currentFunc: ds[CurrentName], + cleanFunc: ds[CleanName], + resetFunc: ds[ResetName], } + dc.Next() return } @@ -101,6 +111,7 @@ func (dc *dataCursor) Reset() (success bool, err error) { dc.index = -1 } exportObjects(dc.ctx, ctx) + dc.Next() } else { err = errInvalidDataSource() } @@ -129,93 +140,71 @@ func (dc *dataCursor) Clean() (success bool, err error) { } func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item - ctx := cloneContext(dc.ctx) - if item, err = dc.currentFunc.Invoke(ctx, CurrentName, []any{}); err == nil && item == nil { + if dc.current != nil { + item = dc.current + } else { err = io.EOF } - exportObjects(dc.ctx, ctx) 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) { var v any var ok bool ctx := cloneContext(dc.ctx) if v, err = filter.Invoke(ctx, FilterName, []any{item, dc.index}); err == nil && v != nil { if accepted, ok = v.(bool); !ok { - 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 -} -func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) { - ctx := cloneContext(dc.ctx) - mappedItem, err = mapper.Invoke(ctx, MapName, []any{item, dc.index}); return } -func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item +func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) { + ctx := cloneContext(dc.ctx) + mappedItem, err = mapper.Invoke(ctx, MapName, []any{item, dc.index}) + return +} + +func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF after the last item var accepted bool + if err = dc.lastErr; err != nil { + return + } + current = dc.current if dc.resource != nil { filter := dc.ds[FilterName] mapper := dc.ds[MapName] - - for item == nil && err == nil { + var item any + for item == nil && dc.lastErr == nil { ctx := cloneContext(dc.ctx) - if item, err = dc.nextFunc.Invoke(ctx, NextName, []any{dc.resource}); err == nil { + dc.index++ + if item, dc.lastErr = dc.nextFunc.Invoke(ctx, NextName, []any{dc.resource, dc.index}); dc.lastErr == nil { if item == nil { - err = io.EOF + dc.lastErr = io.EOF } else { - dc.index++ 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 } } if item != nil && mapper != nil { - item, err = dc.mapItem(mapper, item) + item, dc.lastErr = dc.mapItem(mapper, item) } } } exportObjects(dc.ctx, ctx) } + dc.current = item + if dc.lastErr != nil { + dc.Clean() + } } else { - err = errInvalidDataSource() + dc.lastErr = errInvalidDataSource() } return } func (dc *dataCursor) Index() int { - return dc.index + return dc.index-1 } diff --git a/operand-iterator.go b/operand-iterator.go index d452cc5..150e9d6 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -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) { if dictAny, ok := firstChildValue.(*DictType); ok { - requiredFields := []string{CurrentName, NextName} - fieldsMask := 0b11 + requiredFields := []string{/*CurrentName,*/ NextName} + fieldsMask := 0b1 foundFields := 0 ds = make(map[string]Functor) for keyAny, item := range *dictAny { @@ -108,9 +108,10 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { } if ds != nil { - dc := NewDataCursor(ctx, ds) + var dc *dataCursor if initFunc, exists := ds[InitName]; exists && initFunc != nil { var args []any + var resource any if len(opTerm.children) > 1 { if args, err = evalTermArray(ctx, opTerm.children[1:]); err != nil { return @@ -119,17 +120,20 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { args = []any{} } - initCtx := dc.ctx.Clone() - if dc.resource, err = initFunc.Invoke(initCtx, InitName, args); err != nil { + initCtx := ctx.Clone() + if resource, err = initFunc.Invoke(initCtx, InitName, args); err != nil { 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.currentFunc = ds[CurrentName] - dc.cleanFunc = ds[CleanName] - dc.resetFunc = ds[ResetName] + // dc.nextFunc = ds[NextName] + // dc.currentFunc = ds[CurrentName] + // dc.cleanFunc = ds[CleanName] + // dc.resetFunc = ds[ResetName] v = dc } else if list, ok := firstChildValue.(*ListType); ok { diff --git a/t_expr_test.go b/t_expr_test.go index 029518a..d58389b 100644 --- a/t_expr_test.go +++ b/t_expr_test.go @@ -19,8 +19,8 @@ func TestExpr(t *testing.T) { /* 5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil}, /* 6 */ {` ds={ - "init":func(end){@end=end; @current=0 but true}, - "current":func(){current}, + "init":func(@end){@current=0 but true}, + //"current":func(){current}, "next":func(){ ((next=current+1) <= end) ? [true] {@current=next but current} :: {nil} } @@ -32,6 +32,6 @@ func TestExpr(t *testing.T) { } // t.Setenv("EXPR_PATH", ".") - // parserTestSpec(t, section, inputs, 3) + //runTestSuiteSpec(t, section, inputs, 6) runTestSuite(t, section, inputs) }