diff --git a/int-iterator.go b/int-iterator.go index 6c7910b..434b60f 100644 --- a/int-iterator.go +++ b/int-iterator.go @@ -11,6 +11,7 @@ import ( "git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/types" + "git.portale-stac.it/go-pkg/expr/types/interval" ) type IntIterator struct { @@ -21,6 +22,16 @@ type IntIterator struct { step int64 } +func NewIntIteratorFromInterval(p *interval.IntervalType) (it *IntIterator, err error) { + b := p.Begin() + e := p.End() + s := p.Step() + if b > e { + s = -s + } + return NewIntIteratorA(b, e, s) +} + func NewIntIteratorA(args ...any) (it *IntIterator, err error) { return NewIntIterator(args) } diff --git a/operand-iterator.go b/operand-iterator.go index 23068a5..a724d06 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -13,6 +13,7 @@ import ( "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/dict" + "git.portale-stac.it/go-pkg/expr/types/interval" "git.portale-stac.it/go-pkg/expr/types/list" ) @@ -146,11 +147,13 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil { v = NewLinkedListIterator(ll, args) } - } else if intVal, ok := firstChildValue.(int64); ok { - var args []any - if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil { - v, err = NewIntIterator(args) - } + } else if intervalVal, ok := firstChildValue.(*interval.IntervalType); ok { + v, err = NewIntIteratorFromInterval(intervalVal) + // } else if intVal, ok := firstChildValue.(int64); ok { + // var args []any + // if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil { + // v, err = NewIntIterator(args) + // } } else if it, ok := firstChildValue.(kern.Iterator); ok { v, err = NewIterIter(it, ctx, opTerm.Children[1:]) } else { diff --git a/operand-selector-case.go b/operand-selector-case.go index 314f23b..0bcba97 100644 --- a/operand-selector-case.go +++ b/operand-selector-case.go @@ -5,9 +5,6 @@ package expr import ( - "fmt" - "strings" - "git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/scan" "git.portale-stac.it/go-pkg/expr/sym" @@ -20,17 +17,17 @@ type selectorCase struct { caseExpr kern.Expr } -func (sc *selectorCase) String() string { - var sb strings.Builder - if sc.filterList != nil { - sc.filterList.ToString(&sb) - sb.WriteByte(' ') - } - sb.WriteByte('{') - sb.WriteString(sc.caseExpr.String()) - sb.WriteByte('}') - return sb.String() -} +// func (sc *selectorCase) String() string { +// var sb strings.Builder +// if sc.filterList != nil { +// sc.filterList.ToString(&sb) +// sb.WriteByte(' ') +// } +// sb.WriteByte('{') +// sb.WriteString(sc.caseExpr.String()) +// sb.WriteByte('}') +// return sb.String() +// } func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr) *scan.Term { tk := scan.NewValueToken(row, col, sym.SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr}) @@ -46,9 +43,14 @@ func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr // -------- eval selector case func evalSelectorCase(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { - var ok bool - if v, ok = opTerm.Value().(*selectorCase); !ok { - err = fmt.Errorf("selector-case expected, got %T", opTerm.Value()) - } + v, _ = opTerm.Value().(*selectorCase) return } + +// func evalSelectorCase(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { +// var ok bool +// if v, ok = opTerm.Value().(*selectorCase); !ok { +// err = fmt.Errorf("selector-case expected, got %T", opTerm.Value()) +// } +// return +// } diff --git a/operator-interval.go b/operator-interval.go index 670d4de..41520fe 100644 --- a/operator-interval.go +++ b/operator-interval.go @@ -88,9 +88,9 @@ func checkIntervalComponent(t kern.Term, value any) (component int64, err error) return } -func errIntervalInvalidSpecification(t kern.Term) error { - return t.Errorf("invalid %s specification", interval.TypeName) -} +// func errIntervalInvalidSpecification(t kern.Term) error { +// return t.Errorf("invalid %s specification", interval.TypeName) +// } func errIntervalUnexpectedExpression(t *scan.Term) error { return t.Errorf("unexpected %s expression", interval.TypeName) diff --git a/parser.go b/parser.go index 1625026..0fc721a 100644 --- a/parser.go +++ b/parser.go @@ -173,33 +173,28 @@ func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSy itemExpected := false itemCtx := remFlags(ctx, allowIndex) for lastSym != termSym && lastSym != sym.SymEos { - // zeroRequired := scanner.Current().Sym == sym.SymDoubleDot var itemTree *scan.Ast if itemTree, err = parser.parseItem(scanner, itemCtx, sym.SymComma, termSym); err == nil { root := itemTree.Root() if root != nil { - if hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymDoubleDot { - changeColonToInterval(root) + if root.Symbol() == sym.SymDoubleDot { + if hasFlag(ctx, allowIndex) { + changeColonToInterval(root) + } else { + // err = root.Errorf("unexpected range expression") + err = errIntervalUnexpectedExpression(root) + break + } } - if !hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymInterval { - // err = root.Errorf("unexpected range expression") - err = errIntervalUnexpectedExpression(root) - break - } - args = append(args, root) - // if hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymInterval && zeroRequired { //len(root.children) == 0 { - // if len(root.Children) == 1 { - // root.Children = append(root.Children, root.Children[0]) - // } else if len(root.Children) > 1 { - // // err = root.Errorf("invalid range specification") - // err = errIntervalInvalidSpecification(root) - // break - // } - // zeroTk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), sym.SymInteger, "0", int64(0)) - // zeroTerm := scan.NewTerm(zeroTk) - // zeroTerm.SetParent(root) - // root.Children[0] = zeroTerm + // if hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymDoubleDot { + // changeColonToInterval(root) // } + // if !hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymInterval { + // // err = root.Errorf("unexpected range expression") + // err = errIntervalUnexpectedExpression(root) + // break + // } + args = append(args, root) } else if itemExpected { prev := scanner.Previous() err = prev.ErrorExpectedGot("list-item") diff --git a/t_builtin-iterator_test.go b/t_builtin-iterator_test.go index 37d738a..27d9c93 100644 --- a/t_builtin-iterator_test.go +++ b/t_builtin-iterator_test.go @@ -14,7 +14,7 @@ func TestFuncRun(t *testing.T) { inputs := []inputType{ /* 1 */ {`builtin "iterator"; it=$(1,2,3); run(it)`, nil, nil}, /* 2 */ {`builtin "iterator"; run($(1,2,3), func(index,item){item+10})`, nil, nil}, - /* 3 */ {`builtin "iterator"; run($(4), func(index,item){status=status+item; true}, {"status":0})`, int64(6), nil}, + /* 3 */ {`builtin "iterator"; run($(..4), func(index,item){status=status+item; true}, {"status":0})`, int64(6), nil}, /* 4 */ {`builtin ["iterator", "fmt"]; run($(1,2,3), func(index,item){println(item+10)})`, nil, nil}, /* 5 */ {`builtin "iterator"; run(nil)`, nil, `paramter "iterator" must be an iterator, passed [nil]`}, /* 6 */ {`builtin "iterator"; run($(1,2,3), nil)`, nil, nil}, @@ -26,6 +26,6 @@ func TestFuncRun(t *testing.T) { //t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 3) + // RunTestSuiteSpec(t, section, inputs, 3) RunTestSuite(t, section, inputs) } diff --git a/t_common_test.go b/t_common_test.go index d763b1d..499750f 100644 --- a/t_common_test.go +++ b/t_common_test.go @@ -131,7 +131,7 @@ func doTest(t *testing.T, ctx kern.ExprContext, section string, input *inputType good = false } } else { - t.Errorf(">>>%s/%d: `%s` -> got-err = , expected-err = %v [%s]", section, count, input.source, input.wantResult, kern.TypeName(input.wantResult)) + t.Errorf(">>>%s/%d: `%s` -> result = %v [%s], got-err = , expected-err = %v", section, count, input.source, gotResult, kern.TypeName(gotResult), wantErr) good = false } } diff --git a/t_context_test.go b/t_context_test.go index 08a0422..727ea77 100644 --- a/t_context_test.go +++ b/t_context_test.go @@ -83,7 +83,7 @@ func TestList(t *testing.T) { inputs := []inputType{ /* 1 */ {`$$(5)`, list.NewLinkedListA(5), nil}, - /* 2 */ {`$$($(2))`, list.NewLinkedListA(0, 1), nil}, + /* 2 */ {`$$($(..2))`, list.NewLinkedListA(0, 1), nil}, /* 3 */ {`string(($$global).funcs.bool)`, `bool(value):boolean{}`, nil}, } diff --git a/t_expr_test.go b/t_expr_test.go index efe5f0e..2250914 100644 --- a/t_expr_test.go +++ b/t_expr_test.go @@ -31,8 +31,12 @@ func TestExpr(t *testing.T) { /* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`}, /* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil}, /* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil}, - /* 18 */ {`$$`, dict.NewDict(map[any]any{"vars": dict.NewDict(nil), "funcs": dict.NewDict(nil)}), nil}, - /* 19 */ {` + /* 18 */ {`2 ? {"a"}`, nil, `[1:2] no case catches the value (2) of the selection expression`}, + /* 19 */ {`2 ? 5`, nil, "[1:6] expected `{`, got `5`"}, + /* 20 */ {`a=2; ${a}`, int64(2), nil}, + /* 21 */ {`$_=2; $_`, int64(2), nil}, + /* 22 */ {`$$`, dict.NewDict(map[any]any{"vars": dict.NewDict(nil), "funcs": dict.NewDict(nil)}), nil}, + /* 23 */ {` ds={ "init":func(@end){@current=0 but true}, //"current":func(){current}, @@ -44,11 +48,9 @@ func TestExpr(t *testing.T) { it++; it++ `, int64(1), nil}, - /* 20 */ {`a=2; ${a}`, int64(2), nil}, - /* 21 */ {`$_=2; $_`, int64(2), nil}, } // t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 21) + // RunTestSuiteSpec(t, section, inputs, 19) RunTestSuite(t, section, inputs) } diff --git a/t_index_test.go b/t_index_test.go index e45b3fe..c8b2ffb 100644 --- a/t_index_test.go +++ b/t_index_test.go @@ -41,10 +41,14 @@ func TestCollections(t *testing.T) { /* 25 */ {`[<0,1,2,3,4>][0..]`, list.NewLinkedListA(0, 1, 2, 3, 4), nil}, /* 26 */ {`[<0,1,2,3,4>][0..-1..2]`, list.NewLinkedListA(0, 2), nil}, /* 27 */ {`[<0,1,2,3,4>][-1..0..2]`, list.NewLinkedListA(4, 2), nil}, + /* 28 */ {`[-1..0..2]`, nil, `[1:8] unexpected interval expression`}, + /* 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`}, + /* 31 */ {`"abcdef"[1..4+]`, nil, `[1:15] infix operator "+" requires two non-nil operands, got 1`}, } t.Setenv("EXPR_PATH", ".") - // RunTestSuiteSpec(t, section, inputs, 27) + // RunTestSuiteSpec(t, section, inputs, 30) RunTestSuite(t, section, inputs) } diff --git a/t_iter-iter_test.go b/t_iter-iter_test.go index 2d90709..dc0c9fa 100644 --- a/t_iter-iter_test.go +++ b/t_iter-iter_test.go @@ -13,10 +13,10 @@ import ( func TestIterIterator(t *testing.T) { section := "Iter-Iter" inputs := []inputType{ - /* 1 */ {`it=$(4); $$($(it) filter ${_}==100)`, list.NewLinkedListA(), nil}, - /* 2 */ {`it=$(4); $$($(it, $_) filter ${_}==100)`, list.NewLinkedListA(), nil}, - /* 3 */ {`it=$(4); $(it, 10+$_, last-1) digest ${_}`, int64(12), nil}, - /* 4 */ {`f=func(n){last-n}; it=$(4); $(it, 10+$_, f(-1)) digest ${_}`, int64(14), nil}, + /* 1 */ {`it=$(..4); $$($(it) filter ${_}==100)`, list.NewLinkedListA(), nil}, + /* 2 */ {`it=$(..4); $$($(it, $_) filter ${_}==100)`, list.NewLinkedListA(), nil}, + /* 3 */ {`it=$(..4); $(it, 10+$_, last-1) digest ${_}`, int64(12), nil}, + /* 4 */ {`f=func(n){last-n}; it=$(..4); $(it, 10+$_, f(-1)) digest ${_}`, int64(14), nil}, } // runTestSuiteSpec(t, section, inputs, 4) diff --git a/t_iterator_test.go b/t_iterator_test.go index eb90a1a..da4ac92 100644 --- a/t_iterator_test.go +++ b/t_iterator_test.go @@ -39,12 +39,15 @@ func TestIteratorParser(t *testing.T) { /* 20 */ {`it=$({1:"one",2:"two",3:"three"}, "default", "value"); it++`, "one", nil}, /* 21 */ {`it=$({1:"one",2:"two",3:"three"}, "desc", "key"); it++`, int64(3), nil}, /* 22 */ {`it=$({1:"one",2:"two",3:"three"}, "asc", "item"); it++`, array.NewArray([]any{int64(1), "one"}), nil}, - /* 23 */ {`$$($(1,4,0))`, nil, `step cannot be zero`}, - /* 24 */ {`$$($(1,4,-1))`, nil, `step cannot be negative when start < stop`}, - /* 25 */ {`$$($(4,1,1))`, nil, `step cannot be positive when start > stop`}, + /* 23 */ {`$$($(1..4..0))`, nil, `[1:11] invalid interval specification: step must be positive`}, + /* 24 */ {`$$($(1..4..-1))`, nil, `[1:11] invalid interval specification: step must be positive`}, + /* 25 */ {`$$($(4..1..1))`, list.NewLinkedListA(4, 3, 2), 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)`}, + /* 28 */ {`it=$(.."z"); it++`, nil, `[1:7] interval expression expected integer, got string (z)`}, } - // runTestSuiteSpec(t, section, inputs, 25) + // RunTestSuiteSpec(t, section, inputs, 27) RunTestSuite(t, section, inputs) } @@ -138,9 +141,9 @@ func TestFilterIterator(t *testing.T) { func TestDigestIterator(t *testing.T) { section := "Iterator-Digest" inputs := []inputType{ - /* 1 */ {`$(10) digest ${_}`, int64(9), nil}, - /* 2 */ {`$(10,0) digest ${_}`, int64(1), nil}, - /* 3 */ {`$(10,0,-2) digest ${_}`, int64(2), nil}, + /* 1 */ {`$(..10) digest ${_}`, int64(9), nil}, + /* 2 */ {`$(10..0) digest ${_}`, int64(1), nil}, + /* 3 */ {`$(10..0..2) digest ${_}`, int64(2), nil}, } // runTestSuiteSpec(t, section, inputs, 2) @@ -166,8 +169,8 @@ func TestMapIterator(t *testing.T) { section := "Iterator-Map" inputs := []inputType{ /* 1 */ {`$$([3,4,5] map ${_#})`, list.NewLinkedListA(1, 2, 3), nil}, - /* 2 */ {`#$$($(10) map ${_})`, int64(10), nil}, - /* 3 */ {`#$$($(10,0) map ${_})`, int64(10), nil}, + /* 2 */ {`#$$($(..10) map ${_})`, int64(10), nil}, + /* 3 */ {`#$$($(10..0) map ${_})`, int64(10), nil}, /* 4 */ {`builtin "os.file"; $$(fileLineIterator("test-file.txt") map ${__})`, list.NewLinkedListA(0, 1), nil}, /* 5 */ {`$$(["1", "2", "3"] map int())`, nil, `int(): too few params -- expected 1, got 0`}, }