linked-list supports index assign and concatenation

This commit is contained in:
2026-07-13 11:34:25 +02:00
parent 072fd9af39
commit 4df222496d
7 changed files with 52 additions and 29 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ const (
TypeItem = "item" TypeItem = "item"
TypeIterator = "iterator" TypeIterator = "iterator"
TypeNumber = "number" TypeNumber = "number"
TypePair = "pair" TypeIntPair = "int-pair"
TypeString = "string" TypeString = "string"
TypeDict = "dict" TypeDict = "dict"
TypeListOf = "list-of-" TypeListOf = "list-of-"
+7
View File
@@ -9,6 +9,7 @@ import (
"git.portale-stac.it/go-pkg/expr/scan" "git.portale-stac.it/go-pkg/expr/scan"
"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/list"
"git.portale-stac.it/go-pkg/expr/util" "git.portale-stac.it/go-pkg/expr/util"
) )
@@ -73,6 +74,12 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *sca
} }
case *dict.DictType: case *dict.DictType:
collection.SetItem(keyValue, value) collection.SetItem(keyValue, value)
case *list.LinkedList:
if index, ok := keyValue.(int64); ok {
err = collection.SetItem(index, value)
} else {
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
}
default: default:
err = collectionTerm.Errorf("collection expected") err = collectionTerm.Errorf("collection expected")
} }
+19 -19
View File
@@ -29,10 +29,10 @@ func verifyKey(indexList *array.ArrayType) (index any, err error) {
return return
} }
func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int) (index int, err error) { func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int64) (index int64, err error) {
var v int var v int64
if v, err = types.ToGoInt((*indexList)[0], "index expression"); err == nil { if v, err = types.ToGoInt64((*indexList)[0], "index expression"); err == nil {
if v < 0 && v >= -maxValue { if v < 0 && v >= -maxValue {
v = maxValue + v v = maxValue + v
} }
@@ -45,18 +45,18 @@ func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int)
return return
} }
func verifyRange(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int) (startIndex, endIndex int, err error) { func verifyRange(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int64) (startIndex, endIndex int64, err error) {
v, _ := ((*indexList)[0]).(*intPair) v, _ := ((*indexList)[0]).(*intPair)
startIndex = v.a startIndex = v.a
endIndex = v.b endIndex = v.b
if endIndex == kern.ConstLastIndex { if endIndex == kern.ConstLastIndex {
endIndex = maxValue endIndex = int64(maxValue)
} }
if startIndex < 0 && startIndex >= -maxValue { if startIndex < 0 && startIndex >= -maxValue {
startIndex = maxValue + startIndex startIndex = int64(maxValue) + startIndex
} }
if endIndex < 0 && endIndex >= -maxValue { if endIndex < 0 && endIndex >= -maxValue {
endIndex = maxValue + endIndex endIndex = int64(maxValue) + endIndex
} }
if startIndex < 0 || startIndex > maxValue { if startIndex < 0 || startIndex > maxValue {
err = indexTerm.Errorf("range start-index %d is out of bounds", startIndex) err = indexTerm.Errorf("range start-index %d is out of bounds", startIndex)
@@ -89,18 +89,18 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
if types.IsInteger((*indexList)[0]) { if types.IsInteger((*indexList)[0]) {
switch unboxedValue := leftValue.(type) { switch unboxedValue := leftValue.(type) {
case *array.ArrayType: case *array.ArrayType:
var index int var index int64
if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil { if index, err = verifyIndex(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
v = (*unboxedValue)[index] v = (*unboxedValue)[index]
} }
case *list.LinkedList: case *list.LinkedList:
var index int var index int64
if index, err = verifyIndex(indexTerm, indexList, unboxedValue.Len()); err == nil { if index, err = verifyIndex(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
v, err = unboxedValue.At(index) v, err = unboxedValue.At(index)
} }
case string: case string:
var index int var index int64
if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil { if index, err = verifyIndex(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
v = string(unboxedValue[index]) v = string(unboxedValue[index])
} }
case *dict.DictType: case *dict.DictType:
@@ -111,19 +111,19 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
} else if isIntPair((*indexList)[0]) { } else if isIntPair((*indexList)[0]) {
switch unboxedValue := leftValue.(type) { switch unboxedValue := leftValue.(type) {
case *array.ArrayType: case *array.ArrayType:
var start, end int var start, end int64
if start, end, err = verifyRange(indexTerm, indexList, len(*unboxedValue)); err == nil { if start, end, err = verifyRange(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
sublist := array.ArrayType((*unboxedValue)[start:end]) sublist := array.ArrayType((*unboxedValue)[start:end])
v = &sublist v = &sublist
} }
case *list.LinkedList: case *list.LinkedList:
var start, end int var start, end int64
if start, end, err = verifyRange(indexTerm, indexList, unboxedValue.Len()); err == nil { if start, end, err = verifyRange(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
v = unboxedValue.Sub(start, end) v = unboxedValue.Sub(start, end)
} }
case string: case string:
var start, end int var start, end int64
if start, end, err = verifyRange(indexTerm, indexList, len(unboxedValue)); err == nil { if start, end, err = verifyRange(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
v = unboxedValue[start:end] v = unboxedValue[start:end]
} }
default: default:
+3 -3
View File
@@ -14,11 +14,11 @@ import (
// -------- range term // -------- range term
type intPair struct { type intPair struct {
a, b int a, b int64
} }
func (p *intPair) TypeName() string { func (p *intPair) TypeName() string {
return kern.TypePair return kern.TypeIntPair
} }
func (p *intPair) ToString(opt kern.FmtOpt) string { func (p *intPair) ToString(opt kern.FmtOpt) string {
@@ -70,7 +70,7 @@ func evalRange(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
startIndex, _ := leftValue.(int64) startIndex, _ := leftValue.(int64)
endIndex, _ := rightValue.(int64) endIndex, _ := rightValue.(int64)
v = &intPair{int(startIndex), int(endIndex)} v = &intPair{startIndex, endIndex}
return return
} }
+7
View File
@@ -15,6 +15,7 @@ import (
"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/float" "git.portale-stac.it/go-pkg/expr/types/float"
"git.portale-stac.it/go-pkg/expr/types/fract" "git.portale-stac.it/go-pkg/expr/types/fract"
"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"
) )
@@ -50,6 +51,12 @@ func sumValues(plusTerm *scan.Term, leftValue, rightValue any) (v any, err error
sumList = append(sumList, *leftList...) sumList = append(sumList, *leftList...)
sumList = append(sumList, *rightList...) sumList = append(sumList, *rightList...)
v = &sumList v = &sumList
} else if list.IsLinkedList(leftValue) && list.IsLinkedList(rightValue) {
lsLeft := leftValue.(*list.LinkedList)
lsRight := rightValue.(*list.LinkedList)
ls := lsLeft.Clone()
ls.SeqPushBack(NewLinkedListIterator(lsRight, nil))
v = ls
} else if (fract.IsFraction(leftValue) && types.IsNumber(rightValue)) || (fract.IsFraction(rightValue) && types.IsNumber(leftValue)) { } else if (fract.IsFraction(leftValue) && types.IsNumber(rightValue)) || (fract.IsFraction(rightValue) && types.IsNumber(leftValue)) {
if float.IsFloat(leftValue) || float.IsFloat(rightValue) { if float.IsFloat(leftValue) || float.IsFloat(rightValue) {
v = types.NumAsFloat(leftValue) + types.NumAsFloat(rightValue) v = types.NumAsFloat(leftValue) + types.NumAsFloat(rightValue)
+2 -2
View File
@@ -81,8 +81,8 @@ func TestAccessSubFields(t *testing.T) {
/* 1 */ {`D.a.uno`, int64(10), nil}, /* 1 */ {`D.a.uno`, int64(10), nil},
/* 2 */ {`D.a.uno = 111; D.a."uno"`, int64(111), nil}, /* 2 */ {`D.a.uno = 111; D.a."uno"`, int64(111), nil},
/* 3 */ {`D.a.uno = 111; D["a"]["uno"]`, int64(111), nil}, /* 3 */ {`D.a.uno = 111; D["a"]["uno"]`, int64(111), nil},
// /* 4 */ {`D.b[1] = 22; D["b"][1]`, int64(22), nil}, /* 4 */ {`D.b[1] = 22; D["b"][1]`, int64(22), nil},
/* 4 */ {`D.b[1] = 22; D["b"][1]`, nil, `[1:3] collection expected`}, // /* 4 */ {`D.b[1] = 22; D["b"][1]`, nil, `[1:3] collection expected`},
} }
RunCtxTestSuiteSpec(t, ctx, section, inputs, 4) RunCtxTestSuiteSpec(t, ctx, section, inputs, 4)
// runCtxTestSuite(t, ctx, section, inputs) // runCtxTestSuite(t, ctx, section, inputs)
+13 -4
View File
@@ -117,7 +117,7 @@ func (ls *LinkedList) LastNode() *ListNode {
return ls.last return ls.last
} }
func (ls *LinkedList) Last() (data interface{}, err error) { func (ls *LinkedList) Last() (data any, err error) {
if ls.last != nil { if ls.last != nil {
data = ls.last.data data = ls.last.data
} else { } else {
@@ -126,7 +126,8 @@ func (ls *LinkedList) Last() (data interface{}, err error) {
return return
} }
func (ls *LinkedList) NodeAt(index int) (node *ListNode, err error) { func (ls *LinkedList) NodeAt(index64 int64) (node *ListNode, err error) {
index := int(index64)
if ls.count == 0 { if ls.count == 0 {
err = errorListEmpty() err = errorListEmpty()
} else if index > ls.count { } else if index > ls.count {
@@ -143,7 +144,7 @@ func (ls *LinkedList) NodeAt(index int) (node *ListNode, err error) {
return return
} }
func (ls *LinkedList) At(index int) (data interface{}, err error) { func (ls *LinkedList) At(index int64) (data any, err error) {
node, err := ls.NodeAt(index) node, err := ls.NodeAt(index)
if err == nil { if err == nil {
data = node.data data = node.data
@@ -151,6 +152,14 @@ func (ls *LinkedList) At(index int) (data interface{}, err error) {
return return
} }
func (ls *LinkedList) SetItem(index int64, data any) (err error) {
node, err := ls.NodeAt(index)
if err == nil {
node.data = data
}
return
}
func (ls *LinkedList) Insert(index int, data any) *ListNode { func (ls *LinkedList) Insert(index int, data any) *ListNode {
var prev *ListNode var prev *ListNode
@@ -183,7 +192,7 @@ func (ls *LinkedList) PushBackStringArray(items []string) {
} }
} }
func (ls *LinkedList) Sub(start, end int) (subList *LinkedList) { func (ls *LinkedList) Sub(start, end int64) (subList *LinkedList) {
subList = NewLinkedList() subList = NewLinkedList()
if node, err := ls.NodeAt(start); err == nil { if node, err := ls.NodeAt(start); err == nil {
for i := start; i < end && node != nil; i++ { for i := start; i < end && node != nil; i++ {