From bf2c7df0f039aed1133711bb3ba3ff234df4d0e7 Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Tue, 14 Jul 2026 06:49:50 +0200 Subject: [PATCH] forgot to add the array module. Separated tests on array and list from operators --- t_list_test.go | 73 +++---------- t_operator_test.go | 43 -------- types/array/array-type.go | 225 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 99 deletions(-) create mode 100644 types/array/array-type.go diff --git a/t_list_test.go b/t_list_test.go index b9750e5..8a74e55 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -11,62 +11,6 @@ import ( "git.portale-stac.it/go-pkg/expr/types/list" ) -func TestArray(t *testing.T) { - section := "Array" - - inputs := []inputType{ - /* 1 */ {`[]`, array.NewArrayA(), nil}, - /* 2 */ {`[1,2,3]`, array.NewArrayA(int64(1), int64(2), int64(3)), nil}, - /* 3 */ {`[1,2,"hello"]`, array.NewArrayA(int64(1), int64(2), "hello"), nil}, - /* 4 */ {`[1+2, not true, "hello"]`, array.NewArrayA(int64(3), false, "hello"), nil}, - /* 5 */ {`[1,2]+[3]`, array.NewArrayA(int64(1), int64(2), int64(3)), nil}, - /* 6 */ {`[1,4,3,2]-[3]`, array.NewArrayA(int64(1), int64(4), int64(2)), nil}, - /* 7 */ {`builtin "math.arith"; add([1,4,3,2])`, int64(10), nil}, - /* 8 */ {`builtin "math.arith"; add([1,[2,2],3,2])`, int64(10), nil}, - /* 9 */ {`builtin "math.arith"; mul([1,4,3.0,2])`, float64(24.0), nil}, - /* 10 */ {`builtin "math.arith"; add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`}, - /* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil}, - /* 12 */ {`[1,2,3] <+ 2+2`, array.NewArrayA(int64(1), int64(2), int64(3), int64(4)), nil}, - /* 13 */ {`2-1 +> [2,3]`, array.NewArrayA(int64(1), int64(2), int64(3)), nil}, - /* 14 */ {`[1,2,3][1]`, int64(2), nil}, - /* 15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil}, - /* 16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil}, - /* 17 */ {`list=["one","two","three"]; list[10]`, nil, `[1:34] index 10 out of bounds`}, - /* 18 */ {`["a", "b", "c"]`, array.NewArrayA("a", "b", "c"), nil}, - /* 19 */ {`["a", "b", "c"]`, array.NewArray([]any{"a", "b", "c"}), nil}, - /* 20 */ {`#["a", "b", "c"]`, int64(3), nil}, - /* 21 */ {`"b" in ["a", "b", "c"]`, true, nil}, - /* 22 */ {`a=[1,2]; (a)<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil}, - /* 23 */ {`a=[1,2]; (a)<+3; a`, array.NewArrayA(int64(1), int64(2)), nil}, - /* 24 */ {`["a","b","c","d"][1]`, "b", nil}, - /* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`}, - /* 26 */ {`[0,1,2,3,4][:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, - /* 27 */ {`["a", "b", "c"] <+ ;`, nil, `[1:18] infix operator "<+" requires two non-nil operands, got 1`}, - /* 28 */ {`2 << 3;`, int64(16), nil}, - /* 29 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`}, - /* 30 */ {`2 >> 3;`, int64(0), nil}, - /* 31 */ {`a=[1,2]; a<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil}, - /* 32 */ {`a=[1,2]; 5+>a`, array.NewArrayA(int64(5), int64(1), int64(2)), nil}, - /* 33 */ {`L=[1,2]; L[0]=9; L`, array.NewArrayA(int64(9), int64(2)), nil}, - /* 34 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`}, - /* 35 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [array]`}, - /* 36 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`}, - /* 37 */ {`[0,1,2,3,4][2:3]`, array.NewArrayA(int64(2)), nil}, - /* 38 */ {`[0,1,2,3,4][3:-1]`, array.NewArrayA(int64(3)), nil}, - /* 30 */ {`[0,1,2,3,4][-3:-1]`, array.NewArrayA(int64(2), int64(3)), nil}, - /* 40 */ {`[0,1,2,3,4][0:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, - /* 41 */ {`[0] << $([1,2,3,4])`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, - /* 42 */ {`L=[]; [1] >> L; L`, array.NewArrayA(), nil}, - /* 43 */ {`L=[]; L << [1]; L`, array.NewArrayA(), nil}, - // /* 44 */ {`[0,1,2,3,4][2:3]`, kern.NewListA(int64(20)), nil}, - } - - // t.Setenv("EXPR_PATH", ".") - - // runTestSuiteSpec(t, section, inputs, 44) - RunTestSuite(t, section, inputs) -} - func TestLinkedListParser(t *testing.T) { section := "Linked-List" @@ -89,3 +33,20 @@ func TestLinkedListParser(t *testing.T) { // runTestSuiteSpec(t, section, inputs, 4) RunTestSuite(t, section, inputs) } + +func TestLinkedInsert(t *testing.T) { + section := "LinkedList-Insert" + inputs := []inputType{ + /* 1 */ {`[<>] << 1`, list.NewLinkedListA(1), nil}, + /* 2 */ {`[<>] << [1,2]`, list.NewLinkedListA(array.NewArrayA(int64(1), int64(2))), nil}, + /* 3 */ {`[<>] << [<1,2>]`, list.NewLinkedListA(list.NewLinkedListA(1, 2)), nil}, + /* 4 */ {`1 >> [<>]`, list.NewLinkedListA(1), nil}, + /* 5 */ {`[1,2] >> [<>]`, list.NewLinkedListA(array.NewArrayA(int64(1), int64(2))), nil}, + /* 6 */ {`[<1,2>] >> [<>]`, list.NewLinkedListA(list.NewLinkedListA(1, 2)), nil}, + /* 7 */ {`$([1,2]) >> [<>]`, list.NewLinkedListA(1, 2), nil}, + /* 8 */ {`$([<1,2>]) >> [<>]`, list.NewLinkedListA(1, 2), nil}, + } + + // runTestSuiteSpec(t, section, inputs, 9) + RunTestSuite(t, section, inputs) +} diff --git a/t_operator_test.go b/t_operator_test.go index b745892..45aaf9d 100644 --- a/t_operator_test.go +++ b/t_operator_test.go @@ -9,7 +9,6 @@ import ( "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" ) func TestOperator(t *testing.T) { @@ -51,48 +50,6 @@ func TestOperator(t *testing.T) { RunTestSuite(t, section, inputs) } -func TestOperatorInsert(t *testing.T) { - section := "Operator-Insert" - inputs := []inputType{ - /* 1 */ {`["a", "b"] << nil`, array.NewArrayA("a", "b"), nil}, - /* 2 */ {`["a", "b"] << []`, array.NewArrayA("a", "b", array.NewArrayA()), nil}, - /* 3 */ {`["a", "b"] << $([])`, array.NewArrayA("a", "b"), nil}, - /* 4 */ {`["a", "b"] << 3`, array.NewArrayA("a", "b", int64(3)), nil}, - /* 5 */ {`3 << ["a", "b"]`, nil, `[1:5] left operand '3' [integer] and right operand '["a", "b"]' [array] are not compatible with operator "<<"`}, - /* 6 */ {`nil >> ["a", "b"]`, array.NewArrayA("a", "b"), nil}, - /* 7 */ {`[] >> ["a", "b"]`, array.NewArrayA(array.NewArrayA(), "a", "b"), nil}, - /* 8 */ {`$([]) >> ["a", "b"]`, array.NewArrayA("a", "b"), nil}, - /* 9 */ {`["a", "b"] << $([1,2,3])`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil}, - /* 10 */ {`L=["a", "b"]; L << $([1,2,3])`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil}, - /* 11 */ {`L=["a", "b"]; L << $([1,2,3]); L`, array.NewArrayA("a", "b"), nil}, - /* 12 */ {`L << $([1,2,3])`, nil, `undefined variable or function "L"`}, - /* 13 */ {`[<>] << 1`, list.NewLinkedListA(1), nil}, - /* 14 */ {`[<>] << [1,2]`, list.NewLinkedListA(array.NewArrayA(int64(1), int64(2))), nil}, - /* 15 */ {`[<>] << [<1,2>]`, list.NewLinkedListA(list.NewLinkedListA(1, 2)), nil}, - /* 16 */ {`1 >> [<>]`, list.NewLinkedListA(1), nil}, - /* 17 */ {`[1,2] >> [<>]`, list.NewLinkedListA(array.NewArrayA(int64(1), int64(2))), nil}, - /* 18 */ {`[<1,2>] >> [<>]`, list.NewLinkedListA(list.NewLinkedListA(1, 2)), nil}, - /* 19 */ {`$([1,2]) >> [<>]`, list.NewLinkedListA(1, 2), nil}, - /* 20 */ {`$([<1,2>]) >> [<>]`, list.NewLinkedListA(1, 2), nil}, - } - - // runTestSuiteSpec(t, section, inputs, 9) - RunTestSuite(t, section, inputs) -} - -func TestOperatorDeepAssign(t *testing.T) { - section := "Operator-DeepAssign" - inputs := []inputType{ - /* 1 */ {`DD={"uno": 1, "due": 2}; D=DD; D["uno"]=11; DD`, dict.NewDict(map[any]any{"uno": int64(11), "due": int64(2)}), nil}, - /* 2 */ {`DD={"uno": 1, "due": 2}; D:=DD; D["uno"]=11; DD`, dict.NewDict(map[any]any{"uno": int64(1), "due": int64(2)}), nil}, - /* 3 */ {`LL=["a", "b"]; L=LL; L[0]="x"; LL`, array.NewArrayA("x", "b"), nil}, - /* 4 */ {`LL=["a", "b"]; L:=LL; L[0]="x"; LL`, array.NewArrayA("a", "b"), nil}, - } - - // runTestSuiteSpec(t, section, inputs, 4) - RunTestSuite(t, section, inputs) -} - func TestOperatorDigest(t *testing.T) { section := "Operator-Digest" inputs := []inputType{ diff --git a/types/array/array-type.go b/types/array/array-type.go new file mode 100644 index 0000000..198537b --- /dev/null +++ b/types/array/array-type.go @@ -0,0 +1,225 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// array-type.go +package array + +import ( + "fmt" + "strings" + + "git.portale-stac.it/go-pkg/expr/kern" +) + +type ArrayType []any + +func IsArray(v any) (ok bool) { + _, ok = v.(*ArrayType) + return ok +} + +func NewArrayA(listAny ...any) (list *ArrayType) { + if listAny == nil { + listAny = []any{} + } + return NewArray(listAny) +} + +func NewArray(arrayAny []any) (aRef *ArrayType) { + if arrayAny != nil { + a := make(ArrayType, len(arrayAny)) + copy(a, arrayAny) + aRef = &a + } + return +} + +func MakeArray(length, capacity int) (list *ArrayType) { + if capacity < length { + capacity = length + } + ls := make(ArrayType, length, capacity) + list = &ls + return +} + +func ArrayFromStrings(stringSlice []string) (aRef *ArrayType) { + aRef = MakeArray(len(stringSlice), 0) + for i, s := range stringSlice { + (*aRef)[i] = s + } + return +} + +func (aRef *ArrayType) ToString(opt kern.FmtOpt) (s string) { + indent := kern.GetFormatIndent(opt) + flags := kern.GetFormatFlags(opt) + + var sb strings.Builder + sb.WriteByte('[') + if len(*aRef) > 0 { + innerOpt := kern.MakeFormatOptions(flags, indent+1) + nest := strings.Repeat(" ", indent+1) + + if flags&kern.MultiLine != 0 { + sb.WriteByte('\n') + sb.WriteString(nest) + } + for i, item := range []any(*aRef) { + if i > 0 { + if flags&kern.MultiLine != 0 { + sb.WriteString(",\n") + sb.WriteString(nest) + } else { + sb.WriteString(", ") + } + } + kern.Format(&sb, item, innerOpt) + } + if flags&kern.MultiLine != 0 { + sb.WriteByte('\n') + sb.WriteString(strings.Repeat(" ", indent)) + } + } + sb.WriteByte(']') + s = sb.String() + if flags&kern.Truncate != 0 && len(s) > kern.TruncateSize { + s = kern.TruncateString(s) + } + return +} + +func (aRef *ArrayType) String() string { + return aRef.ToString(0) +} + +func (aRef *ArrayType) TypeName() string { + return kern.TypeArray +} + +func (aRef *ArrayType) Contains(t *ArrayType) (answer bool) { + if len(*aRef) >= len(*t) { + answer = true + for _, item := range *t { + if answer = aRef.IndexDeepSameCmp(item) >= 0; !answer { + break + } + } + } + return +} + +func (aRef *ArrayType) EqualTo(other kern.Equaler) (equal bool) { + if otherList, ok := other.(*ArrayType); ok { + equal = aRef.Equals(*otherList) + } + return +} + +func (aRef *ArrayType) Equals(ls2 ArrayType) (answer bool) { + if ls2 != nil && len(*aRef) == len(ls2) { + answer = true + for index, i1 := range *aRef { + // if !reflect.DeepEqual(i1, ls2[index]) { + // answer = false + // break + // } + if !kern.Equal(i1, ls2[index]) { + answer = false + break + } + } + } + return +} + +func (aRef *ArrayType) Clone() kern.Cloner { + ls := make(ArrayType, len(*aRef)) + for i, item := range *aRef { + ls[i] = kern.Clone(item) + } + return &ls +} + +func (aRef *ArrayType) IndexDeepSameCmp(target any) (index int64) { + index = -1 + for i, item := range *aRef { + if kern.Equal(item, target) { + index = int64(i) + break + } + } + return +} + +// func (ls *ListType) IndexDeepSameCmp(target any) (index int) { +// var eq bool +// var err error +// index = -1 +// for i, item := range *ls { +// if eq, err = deepSame(item, target, SameContent); err != nil { +// break +// } else if eq { +// index = i +// break +// } +// } +// return +// } + +func SameContent(a, b any) (same bool, err error) { + aRef, aValid := a.(*ArrayType) + bRef, bValid := b.(*ArrayType) + if !aValid || !bValid { + err = fmt.Errorf("invalid type for comparison") + return + } + if len(*aRef) == len(*bRef) { + same = true + for _, item := range *aRef { + if pos := bRef.IndexDeepSameCmp(item); pos < 0 { + same = false + break + } + } + } + return +} + +// func deepSame(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) { +// if IsNumOrFract(a) && IsNumOrFract(b) { +// if IsNumber(a) && IsNumber(b) { +// if IsInteger(a) && IsInteger(b) { +// li, _ := a.(int64) +// ri, _ := b.(int64) +// eq = li == ri +// } else { +// eq = NumAsFloat(a) == NumAsFloat(b) +// } +// } else { +// var cmp int +// if cmp, err = fract.CmpAnyFract(a, b); err == nil { +// eq = cmp == 0 +// } +// } +// } else if deepCmp != nil && IsList(a) && IsList(b) { +// eq, err = deepCmp(a, b) +// } else { +// eq = reflect.DeepEqual(a, b) +// } + +// return +// } + +func (aRef *ArrayType) SetItem(index int64, value any) (err error) { + if index >= 0 && index < int64(len(*aRef)) { + (*aRef)[index] = value + } else { + err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*aRef)-1) + } + return +} + +func (aRef *ArrayType) AppendItem(value any) { + *aRef = append(*aRef, value) +}