Compare commits

...

13 Commits

20 changed files with 225 additions and 70 deletions
+17 -17
View File
@@ -14,7 +14,7 @@ import (
"git.portale-stac.it/go-pkg/expr/types/array" "git.portale-stac.it/go-pkg/expr/types/array"
) )
type ListIterator struct { type ArrayIterator struct {
a *array.ArrayType a *array.ArrayType
count int64 count int64
index int64 index int64
@@ -23,13 +23,13 @@ type ListIterator struct {
step int64 step int64
} }
func NewListIterator(list *array.ArrayType, args []any) (it *ListIterator) { func NewArrayIteratorFromArray(a *array.ArrayType, args []any) (it *ArrayIterator) {
var argc int = 0 var argc int = 0
listLen := int64(len(([]any)(*list))) listLen := int64(len(([]any)(*a)))
if args != nil { if args != nil {
argc = len(args) argc = len(args)
} }
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1} it = &ArrayIterator{a: a, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
if argc >= 1 { if argc >= 1 {
if i, err := types.ToGoInt64(args[0], "start index"); err == nil { if i, err := types.ToGoInt64(args[0], "start index"); err == nil {
if i < 0 { if i < 0 {
@@ -62,12 +62,12 @@ func NewListIterator(list *array.ArrayType, args []any) (it *ListIterator) {
return return
} }
func NewArrayIterator(a []any) (it *ListIterator) { func NewArrayIterator(a []any) (it *ArrayIterator) {
it = &ListIterator{a: (*array.ArrayType)(&a), count: 0, index: -1, start: 0, stop: int64(len(a)) - 1, step: 1} it = &ArrayIterator{a: (*array.ArrayType)(&a), count: 0, index: -1, start: 0, stop: int64(len(a)) - 1, step: 1}
return return
} }
func (it *ListIterator) String() string { func (it *ArrayIterator) String() string {
var l = int64(0) var l = int64(0)
if it.a != nil { if it.a != nil {
l = int64(len(*it.a)) l = int64(len(*it.a))
@@ -75,17 +75,17 @@ func (it *ListIterator) String() string {
return fmt.Sprintf("$([#%d])", l) return fmt.Sprintf("$([#%d])", l)
} }
func (it *ListIterator) TypeName() string { func (it *ArrayIterator) TypeName() string {
return "ListIterator" return "ArrayIterator"
} }
func (it *ListIterator) HasOperation(name string) bool { func (it *ArrayIterator) HasOperation(name string) bool {
//yes := name == expr.NextName || name == expr.ResetName || name == expr.IndexName || name == expr.CountName || name == expr.CurrentName //yes := name == expr.NextName || name == expr.ResetName || name == expr.IndexName || name == expr.CountName || name == expr.CurrentName
yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name) yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name)
return yes return yes
} }
func (it *ListIterator) CallOperation(name string, args map[string]any) (v any, err error) { func (it *ArrayIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name { switch name {
case kern.NextName: case kern.NextName:
v, err = it.Next() v, err = it.Next()
@@ -105,7 +105,7 @@ func (it *ListIterator) CallOperation(name string, args map[string]any) (v any,
return return
} }
func (it *ListIterator) Current() (item any, err error) { func (it *ArrayIterator) Current() (item any, err error) {
a := *(it.a) a := *(it.a)
if it.start <= it.stop { if it.start <= it.stop {
if it.stop < int64(len(a)) && it.index >= it.start && it.index <= it.stop { if it.stop < int64(len(a)) && it.index >= it.start && it.index <= it.stop {
@@ -124,7 +124,7 @@ func (it *ListIterator) Current() (item any, err error) {
return return
} }
func (it *ListIterator) Next() (item any, err error) { func (it *ArrayIterator) Next() (item any, err error) {
it.index += it.step it.index += it.step
if item, err = it.Current(); err != io.EOF { if item, err = it.Current(); err != io.EOF {
it.count++ it.count++
@@ -132,20 +132,20 @@ func (it *ListIterator) Next() (item any, err error) {
return return
} }
func (it *ListIterator) Index() int64 { func (it *ArrayIterator) Index() int64 {
return it.index return it.index
} }
func (it *ListIterator) Count() int64 { func (it *ArrayIterator) Count() int64 {
return it.count return it.count
} }
func (it *ListIterator) Reset() error { func (it *ArrayIterator) Reset() error {
it.index = it.start - it.step it.index = it.start - it.step
it.count = 0 it.count = 0
return nil return nil
} }
func (it *ListIterator) Clean() error { func (it *ArrayIterator) Clean() error {
return nil return nil
} }
+12 -2
View File
@@ -92,13 +92,23 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
// params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item} // params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item}
params[kern.ParamIndex] = it.Index() params[kern.ParamIndex] = it.Index()
params[kern.ParamItem] = item params[kern.ParamItem] = item
localCtx.UnsafeSetVar("_", item)
localCtx.UnsafeSetVar("__", it.Index())
abort := false
if _, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil { if _, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil {
break abort = true
} else if abortAny, exists := localCtx.GetVar(iterVarAbort); exists { } else if abortAny, exists := localCtx.GetVar(iterVarAbort); exists {
if abort, ok := boolean.ToBool(abortAny); ok && abort { if abort, ok := boolean.ToBool(abortAny); ok && abort {
break abort = true
} }
} }
localCtx.DeleteVar("__")
localCtx.DeleteVar("_")
if abort {
break
}
} }
} }
+2 -2
View File
@@ -34,7 +34,7 @@ func doAdd(ctx kern.ExprContext, name string, it kern.Iterator, count, level int
for v, err = it.Next(); err == nil; v, err = it.Next() { for v, err = it.Next(); err == nil; v, err = it.Next() {
if list, ok := v.(*array.ArrayType); ok { if list, ok := v.(*array.ArrayType); ok {
v = NewListIterator(list, nil) v = NewArrayIteratorFromArray(list, nil)
} }
if subIter, ok := v.(kern.Iterator); ok { if subIter, ok := v.(kern.Iterator); ok {
if v, err = doAdd(ctx, name, subIter, count, level); err != nil { if v, err = doAdd(ctx, name, subIter, count, level); err != nil {
@@ -108,7 +108,7 @@ func doMul(ctx kern.ExprContext, name string, it kern.Iterator, count, level int
level++ level++
for v, err = it.Next(); err == nil; v, err = it.Next() { for v, err = it.Next(); err == nil; v, err = it.Next() {
if list, ok := v.(*array.ArrayType); ok { if list, ok := v.(*array.ArrayType); ok {
v = NewListIterator(list, nil) v = NewArrayIteratorFromArray(list, nil)
} }
if subIter, ok := v.(kern.Iterator); ok { if subIter, ok := v.(kern.Iterator); ok {
if v, err = doMul(ctx, name, subIter, count, level); err != nil { if v, err = doMul(ctx, name, subIter, count, level); err != nil {
+39 -3
View File
@@ -12,6 +12,8 @@ import (
"git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/types" "git.portale-stac.it/go-pkg/expr/types"
"git.portale-stac.it/go-pkg/expr/types/array" "git.portale-stac.it/go-pkg/expr/types/array"
"git.portale-stac.it/go-pkg/expr/types/dict"
"git.portale-stac.it/go-pkg/expr/types/list"
) )
const ( const (
@@ -45,14 +47,24 @@ func joinStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result
if v, exists := args[kern.ParamItem]; exists { if v, exists := args[kern.ParamItem]; exists {
argv := v.([]any) argv := v.([]any)
if len(argv) == 1 { if len(argv) == 1 {
var it kern.Iterator
if it, ok = argv[0].(kern.Iterator); !ok {
if a, ok := argv[0].(*array.ArrayType); ok { if a, ok := argv[0].(*array.ArrayType); ok {
result, err = doJoinStr(name, sep, NewListIterator(a, nil)) it = NewArrayIteratorFromArray(a, nil)
} else if it, ok := argv[0].(kern.Iterator); ok { } else if l, ok := argv[0].(*list.LinkedList); ok {
it = NewLinkedListIterator(l, nil)
} else if d, ok := argv[0].(*dict.DictType); ok {
if it, err = NewDictIteratorA(d, "none", "values"); err != nil {
return
}
}
}
if it != nil {
result, err = doJoinStr(name, sep, it) result, err = doJoinStr(name, sep, it)
} else if s, ok := argv[0].(string); ok { } else if s, ok := argv[0].(string); ok {
result = s result = s
} else { } else {
err = kern.ErrInvalidParameterValue(name, kern.ParamItem, v) err = kern.ErrInvalidParameterValue(name, kern.ParamItem, argv[0])
} }
} else { } else {
result, err = doJoinStr(name, sep, NewArrayIterator(argv)) result, err = doJoinStr(name, sep, NewArrayIterator(argv))
@@ -64,6 +76,30 @@ func joinStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result
return return
} }
// func joinStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
// if sep, ok := args[kern.ParamSeparator].(string); ok {
// if v, exists := args[kern.ParamItem]; exists {
// argv := v.([]any)
// if len(argv) == 1 {
// if a, ok := argv[0].(*array.ArrayType); ok {
// result, err = doJoinStr(name, sep, NewListIterator(a, nil))
// } else if it, ok := argv[0].(kern.Iterator); ok {
// result, err = doJoinStr(name, sep, it)
// } else if s, ok := argv[0].(string); ok {
// result = s
// } else {
// err = kern.ErrInvalidParameterValue(name, kern.ParamItem, argv[0])
// }
// } else {
// result, err = doJoinStr(name, sep, NewArrayIterator(argv))
// }
// }
// } else {
// err = kern.ErrWrongParamType(name, kern.ParamSeparator, kern.TypeString, args[kern.ParamSeparator])
// }
// return
// }
func subStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { func subStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var start = 0 var start = 0
var count = -1 var count = -1
+7
View File
@@ -70,6 +70,13 @@ func (it *DictIterator) makeKeys(m map[any]any, sort sortType) {
} }
} }
// NewDictIterator creates a new DictIterator for the given dict.DictType and optional arguments.
// The first argument can be a string specifying the sort type ("asc", "desc", "none", or "default").
// The second argument can be a string specifying the iteration mode ("keys", "values", "items", or "default").
func NewDictIteratorA(dict *dict.DictType, args ...any) (it *DictIterator, err error) {
return NewDictIterator(dict, args)
}
func NewDictIterator(dict *dict.DictType, args []any) (it *DictIterator, err error) { func NewDictIterator(dict *dict.DictType, args []any) (it *DictIterator, err error) {
var sortType = sortTypeNone var sortType = sortTypeNone
var s string var s string
+74 -4
View File
@@ -506,6 +506,50 @@ Currently, boolean operations are evaluated using _short cut evaluation_. This m
TIP: `ecli` provides the _ctrl()_ function that allows to change this behaviour. TIP: `ecli` provides the _ctrl()_ function that allows to change this behaviour.
==== ====
=== Intervals
_Expr_ supports intervals, which are a special kind of data type. An interval is a range *_open on the right_* of integer values between a lower and an upper bound. The lower and upper bounds can be specified in any order, i.e. the lower bound can be greater than the upper bound. In this case, the interval is considered _descending_.
Unlike arrays, intervals are not collections of values, but rather a compact representation of a range of values. And unlike other programming languages that separate lower and upper bounds by a colonn, _Expr_ separates them by a double dot symbol `..`.
NOTE: Intervals are _open on the right_, which means that the upper bound is not included in the interval. For example, the interval `1..5` contains the values 1, 2, 3, and 4, but not 5.
_Expr_'s intervals also support step values, which are optionally specified by a third integer value after the upper bound, separated by another doble dot symbol `..`. In this case, the interval represents a range of values starting from the lower bound, up to the upper bound, with a step increment equal to the specified step value. If the step value is not specified, it defaults to 1.
IMPORTANT: The step value must be a positive integer, despite the fact that the lower bound is greater than the upper bound. If it is negative or zero, an error is returned.
.Interval literal syntax
====
*_interval_* = [_lower-bound_] "**..**" _upper-bound_ ["**..**" _step_]
_lower-bound_ = _integer-expr_ +
_upper-bound_ = _integer-expr_ +
_step_ = _positive-integer-expr_
====
.Examples
`>>>` [blue]`3..5` +
[green]`3..5..1`
`>>>` [blue]`5..3` +
[green]`5..3..1`
`>>>` [blue]`..4` +
[green]`0..4..1`
`>>>` [blue]`4..` +
[green]`4..4..1`
`>>>` [blue]`-1..-4` +
[green]`-1..-4..1`
`>>>` [blue]`-1..-4..-1` +
[red]`Eval Error: [1:8] invalid interval specification: step must be positive`
`>>>` [blue]`r = -1..-4` [gray]_// assign interval to variable r_ +
[green]`-1..-4..1`
Main usages of intervals are to generate slices of arrays and to check if a value is in an interval.
=== Arrays === Arrays
_Expr_ supports arrays of mixed-type values, also specified by normal expressions. Internally, _Expr_'s arrays are Go slices. _Expr_ supports arrays of mixed-type values, also specified by normal expressions. Internally, _Expr_'s arrays are Go slices.
@@ -513,7 +557,7 @@ _Expr_ supports arrays of mixed-type values, also specified by normal expression
==== ====
*_array_* = _empty-array_ | _non-empty-array_ + *_array_* = _empty-array_ | _non-empty-array_ +
_empty-array_ = "**[]**" + _empty-array_ = "**[]**" +
_non-empty-array_ = "**[**" _any-value_ {"**,**" _any-value_} "**]**" + _non-empty-array_ = "**[**" _any-value_ {"**,**" _any-value_} "**]**"
==== ====
.Examples .Examples
@@ -559,7 +603,7 @@ Array's items can be accessed using the index `[]` operator.
.Sub-array (or slice of array) syntax .Sub-array (or slice of array) syntax
==== ====
*_slice_* = _array-expr_ "**[**" _integer-expr_ "**:**" _integer-expr_ "**]**" *_slice_* = _array-expr_ "**[**" _interval-expr_ "**]**"
==== ====
.Examples: Getting items from arrays .Examples: Getting items from arrays
@@ -569,7 +613,7 @@ Array's items can be accessed using the index `[]` operator.
`>>>` [blue]`index=2; ["a", "b", "c", "d"][index]` + `>>>` [blue]`index=2; ["a", "b", "c", "d"][index]` +
[green]`c` [green]`c`
`>>>` [blue]`["a", "b", "c", "d"][2:]` + `>>>` [blue]`["a", "b", "c", "d"][2..4]` +
[green]`["c", "d"]` [green]`["c", "d"]`
`>>>` [blue]`array=[1,2,3]; array[1]` + `>>>` [blue]`array=[1,2,3]; array[1]` +
@@ -1583,7 +1627,33 @@ Module activation: +
Syntax: + Syntax: +
`{4sp}run(<iterator>, <operator>, <vars>) -> any` `{4sp}run(<iterator>, <operator>, <vars>) -> any`
Iterates over the specified iterator and applies the specified operator to the current value of the iterator. where:
[horizontal]
iterator:: is any iterator.
operator:: is a function that accepts two optional parameters: _index_ and _item_.
vars:: is a dictionary defining a set of variables that are used to initialize the local context of run() and that will be inherited by each call to the operator.
TIP: Instead of using _index_ and _item_ parameter, the operator function can refere the two automatic variables `$_` and `$__` respectively.
_run()_ iterates over the specified iterator and applies the specified operator to the current value of the iterator.
It returns the value of the variable _status_ it defined, otherwise _nil_.
In addition to the variables defined in vars, the local context includes the function _abort()_. The operator can call _abort()_ to terminate iterations.
_abort()_ accepts the optional parameter _status_ used to change the value of of the variable of the same name and, therefore, of the value returned by _run()_.
.Examples
`>>>` [blue]`builtin "iterator"` [gray]__// enable the iterator builtin module__ +
[green]`1` +
`>>>` [blue]`run($(10..15), func(){status = $\_})` [gray]__// returns the last iteration's index__ +
[green]`4` +
`>>>` [blue]`run($(10..15), func(){status = $__})` [gray]_// returns the last iteration's item_ +
[green]`14` +
`>>>` [blue]`run($(1..5), func(index,item){ (index > 3) ? {abort()} :: {status = item} })` +
[green]`4` +
`>>>` [blue]`run($(1..5), func(index,item){ (index > 2) ? {abort("aborted")} :: {status = item} })` +
[green]`aborted`
==== Module "math.arith" ==== Module "math.arith"
Module activation: + Module activation: +
+18 -17
View File
@@ -17,6 +17,8 @@ import (
type IntIterator struct { type IntIterator struct {
count int64 count int64
index int64 index int64
next int64
current any
start int64 start int64
stop int64 stop int64
step int64 step int64
@@ -110,26 +112,23 @@ func (it *IntIterator) CallOperation(name string, args map[string]any) (v any, e
} }
func (it *IntIterator) Current() (item any, err error) { func (it *IntIterator) Current() (item any, err error) {
if it.start <= it.stop { return it.current, nil
if it.index >= it.start && it.index < it.stop {
item = it.index
} else {
err = io.EOF
}
} else {
if it.index > it.stop && it.index <= it.start {
item = it.index
} else {
err = io.EOF
}
}
return
} }
func (it *IntIterator) Next() (item any, err error) { func (it *IntIterator) Next() (item any, err error) {
it.index += it.step item = it.next
if item, err = it.Current(); err != io.EOF { if it.step > 0 {
if it.next+it.step > it.stop {
err = io.EOF
}
} else if it.next+it.step < it.stop {
err = io.EOF
}
if err == nil {
it.index++
it.count++ it.count++
it.next += it.step
it.current = item
} }
return return
} }
@@ -143,7 +142,9 @@ func (it *IntIterator) Count() int64 {
} }
func (it *IntIterator) Reset() error { func (it *IntIterator) Reset() error {
it.index = it.start - it.step it.index = -1
it.next = it.start
it.current = nil
it.count = 0 it.count = 0
return nil return nil
} }
+1 -1
View File
@@ -30,7 +30,7 @@ func NewIterator(ctx kern.ExprContext, value any, ops []*scan.Term) (it kern.Ite
switch v := value.(type) { switch v := value.(type) {
case *array.ArrayType: case *array.ArrayType:
it = NewListIterator(v, nil) it = NewArrayIteratorFromArray(v, nil)
case *list.LinkedList: case *list.LinkedList:
it = NewLinkedListIterator(v, nil) it = NewLinkedListIterator(v, nil)
case *dict.DictType: case *dict.DictType:
+1 -1
View File
@@ -52,7 +52,7 @@ func ErrFuncDivisionByZero(funcName string) error {
// } // }
func ErrInvalidParameterValue(funcName, paramName string, paramValue any) error { func ErrInvalidParameterValue(funcName, paramName string, paramValue any) error {
return fmt.Errorf("%s(): invalid value %s (%#v) for parameter %q", funcName, TypeName(paramValue), paramValue, paramName) return fmt.Errorf("%s(): invalid value %s (%s) for parameter %q", funcName, paramValue, TypeName(paramValue), paramName)
} }
func undefArticle(s string) (article string) { func undefArticle(s string) (article string) {
+1 -1
View File
@@ -26,7 +26,7 @@ const (
ParamIterator = "iterator" ParamIterator = "iterator"
) )
// to be moved in its own source file // to be moved into its own source file
const ( const (
ConstLastIndex = 0xFFFF_FFFF ConstLastIndex = 0xFFFF_FFFF
) )
+1 -1
View File
@@ -140,7 +140,7 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
} else if a, ok := firstChildValue.(*array.ArrayType); ok { } else if a, ok := firstChildValue.(*array.ArrayType); ok {
var args []any var args []any
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil { if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
v = NewListIterator(a, args) v = NewArrayIteratorFromArray(a, args)
} }
} else if ll, ok := firstChildValue.(*list.LinkedList); ok { } else if ll, ok := firstChildValue.(*list.LinkedList); ok {
var args []any var args []any
+11
View File
@@ -10,6 +10,7 @@ import (
"git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan" "git.portale-stac.it/go-pkg/expr/scan"
"git.portale-stac.it/go-pkg/expr/sym" "git.portale-stac.it/go-pkg/expr/sym"
"git.portale-stac.it/go-pkg/expr/types/list"
"git.portale-stac.it/go-pkg/expr/types/str" "git.portale-stac.it/go-pkg/expr/types/str"
) )
@@ -35,7 +36,17 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
count := 0 count := 0
if str.IsString(childValue) { if str.IsString(childValue) {
module, _ := childValue.(string) module, _ := childValue.(string)
if module == "" {
ll := list.NewLinkedList()
IterateBuiltinModules(func(name, description string, imported bool) bool {
ll.PushBack(name)
return true
})
v = ll
return
} else {
count, err = ImportInContextByGlobPattern(ctx, module) count, err = ImportInContextByGlobPattern(ctx, module)
}
} else { } else {
var moduleSpec any var moduleSpec any
var it kern.Iterator var it kern.Iterator
+4
View File
@@ -10,6 +10,7 @@ import (
"git.portale-stac.it/go-pkg/expr/sym" "git.portale-stac.it/go-pkg/expr/sym"
"git.portale-stac.it/go-pkg/expr/types/array" "git.portale-stac.it/go-pkg/expr/types/array"
"git.portale-stac.it/go-pkg/expr/types/dict" "git.portale-stac.it/go-pkg/expr/types/dict"
"git.portale-stac.it/go-pkg/expr/types/interval"
"git.portale-stac.it/go-pkg/expr/types/list" "git.portale-stac.it/go-pkg/expr/types/list"
) )
@@ -46,6 +47,9 @@ func evalIn(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
} else if list.IsLinkedList(rightValue) { } else if list.IsLinkedList(rightValue) {
ls, _ := rightValue.(*list.LinkedList) ls, _ := rightValue.(*list.LinkedList)
v = ls.HasValue(leftValue) v = ls.HasValue(leftValue)
} else if interval.IsInterval(rightValue) {
r, _ := rightValue.(*interval.IntervalType)
v = r.Contains(leftValue)
} else { } else {
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue) err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
} }
+1 -1
View File
@@ -15,7 +15,6 @@ type TermPriority uint32
const ( const (
PriNone TermPriority = iota PriNone TermPriority = iota
PriInterval
PriBut PriBut
PriAssign PriAssign
PriIterOp // map, filter, digest, etc PriIterOp // map, filter, digest, etc
@@ -24,6 +23,7 @@ const (
PriAnd PriAnd
PriNot PriNot
PriRelational PriRelational
PriInterval
PriBitwiseOr PriBitwiseOr
PriBitwiseAnd PriBitwiseAnd
PriBitwiseNot PriBitwiseNot
+4 -2
View File
@@ -35,7 +35,9 @@ func TestExpr(t *testing.T) {
/* 19 */ {`a=2; ${a}`, int64(2), nil}, /* 19 */ {`a=2; ${a}`, int64(2), nil},
/* 20 */ {`$_=2; $_`, int64(2), nil}, /* 20 */ {`$_=2; $_`, int64(2), nil},
/* 21 */ {`$$`, dict.NewDict(map[any]any{"vars": dict.NewDict(nil), "funcs": dict.NewDict(nil)}), nil}, /* 21 */ {`$$`, dict.NewDict(map[any]any{"vars": dict.NewDict(nil), "funcs": dict.NewDict(nil)}), nil},
/* 22 */ {` /* 22 */ {`builtin "string"; strJoin("-", [<"a", "b", "c">])`, nil, `strJoin(): invalid value [<"a", "b", "c">] (linked-list) for parameter "item"`},
/* 22 */ {`builtin ""`, nil, `strJoin(): invalid value [<"a", "b", "c">] (linked-list) for parameter "item"`},
/* 23 */ {`
ds={ ds={
"init":func(@end){@current=0 but true}, "init":func(@end){@current=0 but true},
//"current":func(){current}, //"current":func(){current},
@@ -50,6 +52,6 @@ func TestExpr(t *testing.T) {
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
// RunTestSuiteSpec(t, section, inputs, 19) // RunTestSuiteSpec(t, section, inputs, 22)
RunTestSuite(t, section, inputs) RunTestSuite(t, section, inputs)
} }
+2 -1
View File
@@ -45,10 +45,11 @@ func TestCollections(t *testing.T) {
/* 29 */ {`"abcdef"['x'..]`, nil, `[1:14] interval expression expected integer, got string (x)`}, /* 29 */ {`"abcdef"['x'..]`, nil, `[1:14] interval expression expected integer, got string (x)`},
/* 30 */ {`"abcdef"[1+..]`, nil, `[1:12] infix operator "+" requires two non-nil operands, got 1`}, /* 30 */ {`"abcdef"[1+..]`, nil, `[1:12] infix operator "+" requires two non-nil operands, got 1`},
/* 31 */ {`"abcdef"[1..4+]`, nil, `[1:15] infix operator "+" requires two non-nil operands, got 1`}, /* 31 */ {`"abcdef"[1..4+]`, nil, `[1:15] infix operator "+" requires two non-nil operands, got 1`},
/* 32 */ {`r=-1..0..2; "abcdef"[r]`, "fdb", nil},
} }
t.Setenv("EXPR_PATH", ".") t.Setenv("EXPR_PATH", ".")
// RunTestSuiteSpec(t, section, inputs, 30) // RunTestSuiteSpec(t, section, inputs, 32)
RunTestSuite(t, section, inputs) RunTestSuite(t, section, inputs)
} }
+8 -8
View File
@@ -13,7 +13,7 @@ import (
func TestNewListIterator(t *testing.T) { func TestNewListIterator(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, 3, 1}) it := NewArrayIteratorFromArray(a, []any{1, 3, 1})
if item, err := it.Next(); err != nil { if item, err := it.Next(); err != nil {
t.Errorf("error: %v", err) t.Errorf("error: %v", err)
} else if item != "b" { } else if item != "b" {
@@ -25,7 +25,7 @@ func TestNewListIterator(t *testing.T) {
func TestNewListIterator2(t *testing.T) { func TestNewListIterator2(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{3, 1, -1}) it := NewArrayIteratorFromArray(a, []any{3, 1, -1})
if item, err := it.Next(); err != nil { if item, err := it.Next(); err != nil {
t.Errorf("error: %v", err) t.Errorf("error: %v", err)
} else if item != "d" { } else if item != "d" {
@@ -37,7 +37,7 @@ func TestNewListIterator2(t *testing.T) {
func TestNewListIterator3(t *testing.T) { func TestNewListIterator3(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, -1, 1}) it := NewArrayIteratorFromArray(a, []any{1, -1, 1})
if item, err := it.Next(); err != nil { if item, err := it.Next(); err != nil {
t.Errorf("error: %v", err) t.Errorf("error: %v", err)
} else if item != "b" { } else if item != "b" {
@@ -116,7 +116,7 @@ func TestNewString(t *testing.T) {
func TestHasOperation(t *testing.T) { func TestHasOperation(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, 3, 1}) it := NewArrayIteratorFromArray(a, []any{1, 3, 1})
hasOp := it.HasOperation("reset") hasOp := it.HasOperation("reset")
if !hasOp { if !hasOp {
t.Errorf("HasOperation(reset) must be true, got false") t.Errorf("HasOperation(reset) must be true, got false")
@@ -126,7 +126,7 @@ func TestHasOperation(t *testing.T) {
func TestCallOperationReset(t *testing.T) { func TestCallOperationReset(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, 3, 1}) it := NewArrayIteratorFromArray(a, []any{1, 3, 1})
if v, err := it.CallOperation("reset", nil); err != nil { if v, err := it.CallOperation("reset", nil); err != nil {
t.Errorf("Error on CallOperation(reset): %v", err) t.Errorf("Error on CallOperation(reset): %v", err)
} else { } else {
@@ -137,7 +137,7 @@ func TestCallOperationReset(t *testing.T) {
func TestCallOperationIndex(t *testing.T) { func TestCallOperationIndex(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, 3, 1}) it := NewArrayIteratorFromArray(a, []any{1, 3, 1})
if v, err := it.CallOperation("index", nil); err != nil { if v, err := it.CallOperation("index", nil); err != nil {
t.Errorf("Error on CallOperation(index): %v", err) t.Errorf("Error on CallOperation(index): %v", err)
} else { } else {
@@ -148,7 +148,7 @@ func TestCallOperationIndex(t *testing.T) {
func TestCallOperationCount(t *testing.T) { func TestCallOperationCount(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, 3, 1}) it := NewArrayIteratorFromArray(a, []any{1, 3, 1})
if v, err := it.CallOperation("count", nil); err != nil { if v, err := it.CallOperation("count", nil); err != nil {
t.Errorf("Error on CallOperation(count): %v", err) t.Errorf("Error on CallOperation(count): %v", err)
} else { } else {
@@ -159,7 +159,7 @@ func TestCallOperationCount(t *testing.T) {
func TestCallOperationUnknown(t *testing.T) { func TestCallOperationUnknown(t *testing.T) {
a := array.NewArrayA("a", "b", "c", "d") a := array.NewArrayA("a", "b", "c", "d")
it := NewListIterator(a, []any{1, 3, 1}) it := NewArrayIteratorFromArray(a, []any{1, 3, 1})
if v, err := it.CallOperation("unknown", nil); err == nil { if v, err := it.CallOperation("unknown", nil); err == nil {
t.Errorf("Expected error on CallOperation(unknown), got %v", v) t.Errorf("Expected error on CallOperation(unknown), got %v", v)
} }
+2 -1
View File
@@ -45,9 +45,10 @@ func TestIteratorParser(t *testing.T) {
/* 26 */ {`it=$(1..5..2); it++`, int64(1), nil}, /* 26 */ {`it=$(1..5..2); it++`, int64(1), nil},
/* 27 */ {`it=$(1.5..5..2); it++`, nil, `[1:13] interval expression expected integer, got float (1.5)`}, /* 27 */ {`it=$(1.5..5..2); it++`, nil, `[1:13] interval expression expected integer, got float (1.5)`},
/* 28 */ {`it=$(.."z"); it++`, nil, `[1:7] interval expression expected integer, got string (z)`}, /* 28 */ {`it=$(.."z"); it++`, nil, `[1:7] interval expression expected integer, got string (z)`},
/* 29 */ {`it=$(3..1); it++; it.index`, int64(0), nil},
} }
// RunTestSuiteSpec(t, section, inputs, 27) // RunTestSuiteSpec(t, section, inputs, 25)
RunTestSuite(t, section, inputs) RunTestSuite(t, section, inputs)
} }
+12
View File
@@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/types"
) )
const TypeName = "interval" const TypeName = "interval"
@@ -60,6 +61,17 @@ func (p *IntervalType) ToIntTriple() (b, e, s int) {
return return
} }
func (p *IntervalType) Contains(value any) (ok bool) {
if v, err := types.ToGoInt64(value, TypeName); err == nil {
if p.begin <= p.end {
ok = (v >= p.begin && v < p.end && (v-p.begin)%p.step == 0)
} else {
ok = (v <= p.begin && v > p.end && (v-p.begin)%p.step == 0)
}
}
return
}
// func (b *bool) EqualTo(other kern.Equaler) (equal bool) { // func (b *bool) EqualTo(other kern.Equaler) (equal bool) {
// if otherBool, ok := other.(*bool); ok { // if otherBool, ok := other.(*bool); ok {
// equal = b == otherBool // equal = b == otherBool
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/kern"
) )
const LinkedListTypeName = "lisked-list" const LinkedListTypeName = "linked-list"
func IsLinkedList(v any) (ok bool) { func IsLinkedList(v any) (ok bool) {
_, ok = v.(*LinkedList) _, ok = v.(*LinkedList)