Compare commits
	
		
			4 Commits
		
	
	
		
			dceb31f542
			...
			d215d837f6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d215d837f6 | |||
| ad3c1e5a60 | |||
| d6bf5ee500 | |||
| 4b176eb868 | 
@ -6,6 +6,7 @@ package expr
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TypeAny           = "any"
 | 
			
		||||
	TypeNil           = "nil"
 | 
			
		||||
	TypeBoolean       = "boolean"
 | 
			
		||||
	TypeFloat         = "float"
 | 
			
		||||
	TypeFraction      = "fraction"
 | 
			
		||||
@ -15,6 +16,7 @@ const (
 | 
			
		||||
	TypeNumber        = "number"
 | 
			
		||||
	TypePair          = "pair"
 | 
			
		||||
	TypeString        = "string"
 | 
			
		||||
	TypeDict          = "dict"
 | 
			
		||||
	TypeListOf        = "list-of-"
 | 
			
		||||
	TypeListOfStrings = "list-of-strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										213
									
								
								data-cursor.go
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								data-cursor.go
									
									
									
									
									
								
							@ -6,12 +6,14 @@ package expr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"slices"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type dataCursor struct {
 | 
			
		||||
	ds        map[string]Functor
 | 
			
		||||
	ctx       ExprContext
 | 
			
		||||
	initState bool // true if no item has prodiced yet (this replace di initial Next() call in the contructor)
 | 
			
		||||
	initState bool // true if no item has produced yet (this replace di initial Next() call in the contructor)
 | 
			
		||||
	// cursorValid bool // true if resource is nil or if clean has not yet been called
 | 
			
		||||
	index     int
 | 
			
		||||
	count     int
 | 
			
		||||
	current   any
 | 
			
		||||
@ -26,6 +28,7 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
 | 
			
		||||
	dc = &dataCursor{
 | 
			
		||||
		ds:        ds,
 | 
			
		||||
		initState: true,
 | 
			
		||||
		// cursorValid: true,
 | 
			
		||||
		index:     -1,
 | 
			
		||||
		count:     0,
 | 
			
		||||
		current:   nil,
 | 
			
		||||
@ -36,7 +39,6 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
 | 
			
		||||
		cleanFunc: ds[CleanName],
 | 
			
		||||
		resetFunc: ds[ResetName],
 | 
			
		||||
	}
 | 
			
		||||
	//dc.Next()
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -77,7 +79,7 @@ func (dc *dataCursor) String() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *dataCursor) HasOperation(name string) (exists bool) {
 | 
			
		||||
	exists = name == IndexName
 | 
			
		||||
	exists = slices.Contains([]string{CleanName, ResetName, CurrentName, IndexName}, name)
 | 
			
		||||
	if !exists {
 | 
			
		||||
		f, ok := dc.ds[name]
 | 
			
		||||
		exists = ok && isFunctor(f)
 | 
			
		||||
@ -88,63 +90,83 @@ func (dc *dataCursor) HasOperation(name string) (exists bool) {
 | 
			
		||||
func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any, err error) {
 | 
			
		||||
	if name == IndexName {
 | 
			
		||||
		value = int64(dc.Index())
 | 
			
		||||
	} else if name == CleanName {
 | 
			
		||||
		err = dc.Clean()
 | 
			
		||||
	} else if name == ResetName {
 | 
			
		||||
		err = dc.Reset()
 | 
			
		||||
	} else if functor, ok := dc.ds[name]; ok && isFunctor(functor) {
 | 
			
		||||
		if functor == dc.cleanFunc {
 | 
			
		||||
			value, err = dc.Clean()
 | 
			
		||||
		} else if functor == dc.resetFunc {
 | 
			
		||||
			value, err = dc.Reset()
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx := cloneContext(dc.ctx)
 | 
			
		||||
			value, err = functor.InvokeNamed(ctx, name, args)
 | 
			
		||||
			exportObjects(dc.ctx, ctx)
 | 
			
		||||
		}
 | 
			
		||||
		ctx := cloneContext(dc.ctx)
 | 
			
		||||
		value, err = functor.InvokeNamed(ctx, name, args)
 | 
			
		||||
		exportObjects(dc.ctx, ctx)
 | 
			
		||||
	} else {
 | 
			
		||||
		err = errNoOperation(name)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *dataCursor) Reset() (success bool, err error) {
 | 
			
		||||
// func (dc *dataCursor) Reset() (err error) {
 | 
			
		||||
// 	if dc.resetFunc != nil {
 | 
			
		||||
// 		if dc.resource != nil {
 | 
			
		||||
// 			ctx := cloneContext(dc.ctx)
 | 
			
		||||
// 			actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
 | 
			
		||||
// 			_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
 | 
			
		||||
// 			exportObjects(dc.ctx, ctx)
 | 
			
		||||
// 			dc.index = -1
 | 
			
		||||
// 			dc.count = 0
 | 
			
		||||
// 			dc.initState = true
 | 
			
		||||
// 			dc.current = nil
 | 
			
		||||
// 			dc.lastErr = nil
 | 
			
		||||
// 		} else {
 | 
			
		||||
// 			err = errInvalidDataSource()
 | 
			
		||||
// 		}
 | 
			
		||||
// 	} else {
 | 
			
		||||
// 		err = errNoOperation(ResetName)
 | 
			
		||||
// 	}
 | 
			
		||||
// 	return
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func (dc *dataCursor) Reset() (err error) {
 | 
			
		||||
	if dc.resetFunc != nil {
 | 
			
		||||
		if dc.resource != nil {
 | 
			
		||||
			ctx := cloneContext(dc.ctx)
 | 
			
		||||
			actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
 | 
			
		||||
			_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
 | 
			
		||||
			exportObjects(dc.ctx, ctx)
 | 
			
		||||
			dc.index = -1
 | 
			
		||||
			dc.count = 0
 | 
			
		||||
			dc.initState = true
 | 
			
		||||
			dc.current = nil
 | 
			
		||||
			dc.lastErr = nil
 | 
			
		||||
			//dc.Next()
 | 
			
		||||
		} else {
 | 
			
		||||
			err = errInvalidDataSource()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = errNoOperation(ResetName)
 | 
			
		||||
		ctx := cloneContext(dc.ctx)
 | 
			
		||||
		actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
 | 
			
		||||
		_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
 | 
			
		||||
		exportObjects(dc.ctx, ctx)
 | 
			
		||||
	}
 | 
			
		||||
	success = err == nil
 | 
			
		||||
	dc.index = -1
 | 
			
		||||
	dc.count = 0
 | 
			
		||||
	dc.initState = true
 | 
			
		||||
	dc.current = nil
 | 
			
		||||
	dc.lastErr = nil
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *dataCursor) Clean() (success bool, err error) {
 | 
			
		||||
func (dc *dataCursor) Clean() (err error) {
 | 
			
		||||
	if dc.cleanFunc != nil {
 | 
			
		||||
		if dc.resource != nil {
 | 
			
		||||
			ctx := cloneContext(dc.ctx)
 | 
			
		||||
			actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
 | 
			
		||||
			_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
 | 
			
		||||
			//			dc.resource = nil
 | 
			
		||||
			exportObjects(dc.ctx, ctx)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = errInvalidDataSource()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = errNoOperation(CleanName)
 | 
			
		||||
		ctx := cloneContext(dc.ctx)
 | 
			
		||||
		actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
 | 
			
		||||
		_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
 | 
			
		||||
		exportObjects(dc.ctx, ctx)
 | 
			
		||||
	}
 | 
			
		||||
	success = err == nil
 | 
			
		||||
	dc.lastErr = io.EOF
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// func (dc *dataCursor) Clean() (err error) {
 | 
			
		||||
// 	if dc.cleanFunc != nil {
 | 
			
		||||
// 		if dc.resource != nil {
 | 
			
		||||
// 			ctx := cloneContext(dc.ctx)
 | 
			
		||||
// 			actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
 | 
			
		||||
// 			_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
 | 
			
		||||
// 			exportObjects(dc.ctx, ctx)
 | 
			
		||||
// 		} else {
 | 
			
		||||
// 			err = errInvalidDataSource()
 | 
			
		||||
// 		}
 | 
			
		||||
// 	} else {
 | 
			
		||||
// 		err = errNoOperation(CleanName)
 | 
			
		||||
// 	}
 | 
			
		||||
// 	return
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
 | 
			
		||||
	dc.init()
 | 
			
		||||
 | 
			
		||||
@ -191,46 +213,89 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	current = dc.current
 | 
			
		||||
	if dc.resource != nil {
 | 
			
		||||
		filter := dc.ds[FilterName]
 | 
			
		||||
		mapper := dc.ds[MapName]
 | 
			
		||||
		var item any
 | 
			
		||||
		for item == nil && dc.lastErr == nil {
 | 
			
		||||
			ctx := cloneContext(dc.ctx)
 | 
			
		||||
			dc.index++
 | 
			
		||||
	filter := dc.ds[FilterName]
 | 
			
		||||
	mapper := dc.ds[MapName]
 | 
			
		||||
	var item any
 | 
			
		||||
	for item == nil && dc.lastErr == nil {
 | 
			
		||||
		ctx := cloneContext(dc.ctx)
 | 
			
		||||
		dc.index++
 | 
			
		||||
 | 
			
		||||
			actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
 | 
			
		||||
			if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
 | 
			
		||||
				if item == nil {
 | 
			
		||||
					dc.lastErr = io.EOF
 | 
			
		||||
				} else {
 | 
			
		||||
					accepted := true
 | 
			
		||||
					if filter != nil {
 | 
			
		||||
						if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
 | 
			
		||||
							item = nil
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if accepted {
 | 
			
		||||
						dc.count++
 | 
			
		||||
					}
 | 
			
		||||
					if item != nil && mapper != nil {
 | 
			
		||||
						item, dc.lastErr = dc.mapItem(mapper, item)
 | 
			
		||||
		actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
 | 
			
		||||
		if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
 | 
			
		||||
			if item == nil {
 | 
			
		||||
				dc.lastErr = io.EOF
 | 
			
		||||
			} else {
 | 
			
		||||
				accepted := true
 | 
			
		||||
				if filter != nil {
 | 
			
		||||
					if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
 | 
			
		||||
						item = nil
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if accepted {
 | 
			
		||||
					dc.count++
 | 
			
		||||
				}
 | 
			
		||||
				if item != nil && mapper != nil {
 | 
			
		||||
					item, dc.lastErr = dc.mapItem(mapper, item)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			exportObjects(dc.ctx, ctx)
 | 
			
		||||
		}
 | 
			
		||||
		dc.current = item
 | 
			
		||||
		if dc.lastErr != nil {
 | 
			
		||||
			dc.index--
 | 
			
		||||
			dc.Clean()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		dc.lastErr = errInvalidDataSource()
 | 
			
		||||
		exportObjects(dc.ctx, ctx)
 | 
			
		||||
	}
 | 
			
		||||
	dc.current = item
 | 
			
		||||
	if dc.lastErr != nil {
 | 
			
		||||
		dc.index--
 | 
			
		||||
		dc.Clean()
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF after the last item
 | 
			
		||||
// 	if dc.initState {
 | 
			
		||||
// 		dc.init()
 | 
			
		||||
// 	} else if err = dc.lastErr; err != nil {
 | 
			
		||||
// 		return
 | 
			
		||||
// 	}
 | 
			
		||||
// 	current = dc.current
 | 
			
		||||
// 	if dc.resource != nil {
 | 
			
		||||
// 		filter := dc.ds[FilterName]
 | 
			
		||||
// 		mapper := dc.ds[MapName]
 | 
			
		||||
// 		var item any
 | 
			
		||||
// 		for item == nil && dc.lastErr == nil {
 | 
			
		||||
// 			ctx := cloneContext(dc.ctx)
 | 
			
		||||
// 			dc.index++
 | 
			
		||||
 | 
			
		||||
// 			actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
 | 
			
		||||
// 			if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
 | 
			
		||||
// 				if item == nil {
 | 
			
		||||
// 					dc.lastErr = io.EOF
 | 
			
		||||
// 				} else {
 | 
			
		||||
// 					accepted := true
 | 
			
		||||
// 					if filter != nil {
 | 
			
		||||
// 						if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
 | 
			
		||||
// 							item = nil
 | 
			
		||||
// 						}
 | 
			
		||||
// 					}
 | 
			
		||||
// 					if accepted {
 | 
			
		||||
// 						dc.count++
 | 
			
		||||
// 					}
 | 
			
		||||
// 					if item != nil && mapper != nil {
 | 
			
		||||
// 						item, dc.lastErr = dc.mapItem(mapper, item)
 | 
			
		||||
// 					}
 | 
			
		||||
// 				}
 | 
			
		||||
// 			}
 | 
			
		||||
// 			exportObjects(dc.ctx, ctx)
 | 
			
		||||
// 		}
 | 
			
		||||
// 		dc.current = item
 | 
			
		||||
// 		if dc.lastErr != nil {
 | 
			
		||||
// 			dc.index--
 | 
			
		||||
// 			dc.Clean()
 | 
			
		||||
// 		}
 | 
			
		||||
// 	} else {
 | 
			
		||||
// 		dc.lastErr = errInvalidDataSource()
 | 
			
		||||
// 	}
 | 
			
		||||
// 	return
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func (dc *dataCursor) Index() int {
 | 
			
		||||
	return dc.index - 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -348,8 +348,8 @@ func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CallFunctionByParams(parentCtx ExprContext, name string, params map[string]any) (result any, err error) {
 | 
			
		||||
	var actualParams map[string]any
 | 
			
		||||
func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) {
 | 
			
		||||
	//var actualParams map[string]any
 | 
			
		||||
	if info, exists := GetFuncInfo(parentCtx, name); exists {
 | 
			
		||||
		functor := info.Functor()
 | 
			
		||||
		ctx := info.AllocContext(parentCtx)
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,8 @@ type Iterator interface {
 | 
			
		||||
 | 
			
		||||
type ExtIterator interface {
 | 
			
		||||
	Iterator
 | 
			
		||||
	Reset() error
 | 
			
		||||
	Clean() error
 | 
			
		||||
	HasOperation(name string) bool
 | 
			
		||||
	CallOperation(name string, args map[string]any) (value any, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -99,7 +99,9 @@ func (it *ListIterator) CallOperation(name string, args map[string]any) (v any,
 | 
			
		||||
	case NextName:
 | 
			
		||||
		v, err = it.Next()
 | 
			
		||||
	case ResetName:
 | 
			
		||||
		v, err = it.Reset()
 | 
			
		||||
		err = it.Reset()
 | 
			
		||||
	case CleanName:
 | 
			
		||||
		err = it.Clean()
 | 
			
		||||
	case IndexName:
 | 
			
		||||
		v = int64(it.Index())
 | 
			
		||||
	case CurrentName:
 | 
			
		||||
@ -147,8 +149,12 @@ func (it *ListIterator) Count() int {
 | 
			
		||||
	return it.count
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it *ListIterator) Reset() (bool, error) {
 | 
			
		||||
func (it *ListIterator) Reset() (error) {
 | 
			
		||||
	it.index = it.start - it.step
 | 
			
		||||
	it.count = 0
 | 
			
		||||
	return true, nil
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it *ListIterator) Clean() (error) {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -92,6 +92,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
 | 
			
		||||
 | 
			
		||||
	if ds != nil {
 | 
			
		||||
		var dc *dataCursor
 | 
			
		||||
		dcCtx := ctx.Clone()
 | 
			
		||||
		if initFunc, exists := ds[InitName]; exists && initFunc != nil {
 | 
			
		||||
			var args []any
 | 
			
		||||
			var resource any
 | 
			
		||||
@ -109,9 +110,10 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
 | 
			
		||||
			if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			dcCtx := ctx.Clone()
 | 
			
		||||
			exportObjects(dcCtx, initCtx)
 | 
			
		||||
			dc = NewDataCursor(dcCtx, ds, resource)
 | 
			
		||||
		} else {
 | 
			
		||||
			dc = NewDataCursor(dcCtx, ds, nil)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		v = dc
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ func TestIteratorParser(t *testing.T) {
 | 
			
		||||
		/*   6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
 | 
			
		||||
		/*   7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil},
 | 
			
		||||
		/*   8 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it++; it.index`, int64(0), nil},
 | 
			
		||||
		/*   9 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, true, nil},
 | 
			
		||||
		/*   9 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, nil, nil},
 | 
			
		||||
		/*  10 */ {`it=$(1,2,3); it++`, int64(1), nil},
 | 
			
		||||
		/*  11 */ {`it=$(1,2,3); it++; it.reset; it++`, int64(1), nil},
 | 
			
		||||
		/*  12 */ {`it=$([1,2,3,4],1); it++`, int64(2), nil},
 | 
			
		||||
@ -25,8 +25,10 @@ func TestIteratorParser(t *testing.T) {
 | 
			
		||||
		/*  14 */ {`it=$([1,2,3,4],1,3,2); it++; it++;`, int64(4), nil},
 | 
			
		||||
		/*  15 */ {`it=$([1,2,3,4],1,2,2); it++; it++;`, nil, `EOF`},
 | 
			
		||||
		/*  16 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(2), nil},
 | 
			
		||||
		/*  17 */ {`it=$({"next":func(){5}}); it++`, int64(5), nil},
 | 
			
		||||
		/*  18 */ {`it=$({"next":func(){5}}); it.clean`, nil, nil},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// runTestSuiteSpec(t, section, inputs, 11)
 | 
			
		||||
	//runTestSuiteSpec(t, section, inputs, 18)
 | 
			
		||||
	runTestSuite(t, section, inputs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user