Compare commits

...

4 Commits

7 changed files with 161 additions and 82 deletions

View File

@ -6,6 +6,7 @@ package expr
const ( const (
TypeAny = "any" TypeAny = "any"
TypeNil = "nil"
TypeBoolean = "boolean" TypeBoolean = "boolean"
TypeFloat = "float" TypeFloat = "float"
TypeFraction = "fraction" TypeFraction = "fraction"
@ -15,6 +16,7 @@ const (
TypeNumber = "number" TypeNumber = "number"
TypePair = "pair" TypePair = "pair"
TypeString = "string" TypeString = "string"
TypeDict = "dict"
TypeListOf = "list-of-" TypeListOf = "list-of-"
TypeListOfStrings = "list-of-strings" TypeListOfStrings = "list-of-strings"
) )

View File

@ -6,12 +6,14 @@ package expr
import ( import (
"io" "io"
"slices"
) )
type dataCursor struct { type dataCursor struct {
ds map[string]Functor ds map[string]Functor
ctx ExprContext 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 index int
count int count int
current any current any
@ -26,6 +28,7 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
dc = &dataCursor{ dc = &dataCursor{
ds: ds, ds: ds,
initState: true, initState: true,
// cursorValid: true,
index: -1, index: -1,
count: 0, count: 0,
current: nil, current: nil,
@ -36,7 +39,6 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
cleanFunc: ds[CleanName], cleanFunc: ds[CleanName],
resetFunc: ds[ResetName], resetFunc: ds[ResetName],
} }
//dc.Next()
return return
} }
@ -77,7 +79,7 @@ func (dc *dataCursor) String() string {
} }
func (dc *dataCursor) HasOperation(name string) (exists bool) { func (dc *dataCursor) HasOperation(name string) (exists bool) {
exists = name == IndexName exists = slices.Contains([]string{CleanName, ResetName, CurrentName, IndexName}, name)
if !exists { if !exists {
f, ok := dc.ds[name] f, ok := dc.ds[name]
exists = ok && isFunctor(f) 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) { func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any, err error) {
if name == IndexName { if name == IndexName {
value = int64(dc.Index()) 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) { } else if functor, ok := dc.ds[name]; ok && isFunctor(functor) {
if functor == dc.cleanFunc { ctx := cloneContext(dc.ctx)
value, err = dc.Clean() value, err = functor.InvokeNamed(ctx, name, args)
} else if functor == dc.resetFunc { exportObjects(dc.ctx, ctx)
value, err = dc.Reset()
} else {
ctx := cloneContext(dc.ctx)
value, err = functor.InvokeNamed(ctx, name, args)
exportObjects(dc.ctx, ctx)
}
} else { } else {
err = errNoOperation(name) err = errNoOperation(name)
} }
return 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.resetFunc != nil {
if dc.resource != nil { ctx := cloneContext(dc.ctx)
ctx := cloneContext(dc.ctx) actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
actualParams := bindActualParams(dc.resetFunc, []any{dc.resource}) _, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams) exportObjects(dc.ctx, ctx)
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)
} }
success = err == nil dc.index = -1
dc.count = 0
dc.initState = true
dc.current = nil
dc.lastErr = nil
return return
} }
func (dc *dataCursor) Clean() (success bool, err error) { func (dc *dataCursor) Clean() (err error) {
if dc.cleanFunc != nil { if dc.cleanFunc != nil {
if dc.resource != nil { ctx := cloneContext(dc.ctx)
ctx := cloneContext(dc.ctx) actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource}) _, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams) exportObjects(dc.ctx, ctx)
// dc.resource = nil
exportObjects(dc.ctx, ctx)
} else {
err = errInvalidDataSource()
}
} else {
err = errNoOperation(CleanName)
} }
success = err == nil dc.lastErr = io.EOF
return 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 func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
dc.init() dc.init()
@ -191,46 +213,89 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af
return return
} }
current = dc.current current = dc.current
if dc.resource != nil { filter := dc.ds[FilterName]
filter := dc.ds[FilterName] mapper := dc.ds[MapName]
mapper := dc.ds[MapName] var item any
var item any for item == nil && dc.lastErr == nil {
for item == nil && dc.lastErr == nil { ctx := cloneContext(dc.ctx)
ctx := cloneContext(dc.ctx) dc.index++
dc.index++
actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, 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, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
if item == nil { if item == nil {
dc.lastErr = io.EOF dc.lastErr = io.EOF
} else { } else {
accepted := true accepted := true
if filter != nil { if filter != nil {
if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted { if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
item = nil item = nil
}
}
if accepted {
dc.count++
}
if item != nil && mapper != nil {
item, dc.lastErr = dc.mapItem(mapper, item)
} }
} }
if accepted {
dc.count++
}
if item != nil && mapper != nil {
item, dc.lastErr = dc.mapItem(mapper, item)
}
} }
exportObjects(dc.ctx, ctx)
} }
dc.current = item exportObjects(dc.ctx, ctx)
if dc.lastErr != nil { }
dc.index-- dc.current = item
dc.Clean() if dc.lastErr != nil {
} dc.index--
} else { dc.Clean()
dc.lastErr = errInvalidDataSource()
} }
return 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 { func (dc *dataCursor) Index() int {
return dc.index - 1 return dc.index - 1
} }

View File

@ -348,8 +348,8 @@ func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result
return return
} }
func CallFunctionByParams(parentCtx ExprContext, name string, params map[string]any) (result any, err error) { func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) {
var actualParams map[string]any //var actualParams map[string]any
if info, exists := GetFuncInfo(parentCtx, name); exists { if info, exists := GetFuncInfo(parentCtx, name); exists {
functor := info.Functor() functor := info.Functor()
ctx := info.AllocContext(parentCtx) ctx := info.AllocContext(parentCtx)

View File

@ -33,6 +33,8 @@ type Iterator interface {
type ExtIterator interface { type ExtIterator interface {
Iterator Iterator
Reset() error
Clean() error
HasOperation(name string) bool HasOperation(name string) bool
CallOperation(name string, args map[string]any) (value any, err error) CallOperation(name string, args map[string]any) (value any, err error)
} }

View File

@ -99,7 +99,9 @@ func (it *ListIterator) CallOperation(name string, args map[string]any) (v any,
case NextName: case NextName:
v, err = it.Next() v, err = it.Next()
case ResetName: case ResetName:
v, err = it.Reset() err = it.Reset()
case CleanName:
err = it.Clean()
case IndexName: case IndexName:
v = int64(it.Index()) v = int64(it.Index())
case CurrentName: case CurrentName:
@ -147,8 +149,12 @@ func (it *ListIterator) Count() int {
return it.count return it.count
} }
func (it *ListIterator) Reset() (bool, error) { func (it *ListIterator) Reset() (error) {
it.index = it.start - it.step it.index = it.start - it.step
it.count = 0 it.count = 0
return true, nil return nil
}
func (it *ListIterator) Clean() (error) {
return nil
} }

View File

@ -92,6 +92,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
if ds != nil { if ds != nil {
var dc *dataCursor var dc *dataCursor
dcCtx := ctx.Clone()
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 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 { if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil {
return return
} }
dcCtx := ctx.Clone()
exportObjects(dcCtx, initCtx) exportObjects(dcCtx, initCtx)
dc = NewDataCursor(dcCtx, ds, resource) dc = NewDataCursor(dcCtx, ds, resource)
} else {
dc = NewDataCursor(dcCtx, ds, nil)
} }
v = dc v = dc

View File

@ -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}, /* 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}, /* 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}, /* 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}, /* 10 */ {`it=$(1,2,3); it++`, int64(1), nil},
/* 11 */ {`it=$(1,2,3); it++; it.reset; 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}, /* 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}, /* 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`}, /* 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}, /* 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) runTestSuite(t, section, inputs)
} }