several changes:
1. moved scan/symbol.go to new package sym and adapted all files that reference Symbol type and its values. 2. new type interval defined by begin, end and step values. 3. replaced operator-range.go with operator-interval.go. 4. replaced range operator begin:end with begin..end..step. 5. new implementation of sub-collection extraction based on new interval literal.
This commit is contained in:
+151
-67
@@ -5,11 +5,15 @@
|
||||
package expr
|
||||
|
||||
import (
|
||||
"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"
|
||||
"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/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
|
||||
@@ -29,7 +33,7 @@ func verifyKey(indexList *array.ArrayType) (index any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int64) (index int64, err error) {
|
||||
func verifyIndex(indexTerm kern.Term, indexList *array.ArrayType, maxValue int64) (index int64, err error) {
|
||||
var v int64
|
||||
|
||||
if v, err = types.ToGoInt64((*indexList)[0], "index expression"); err == nil {
|
||||
@@ -45,28 +49,28 @@ func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int6
|
||||
return
|
||||
}
|
||||
|
||||
func verifyRange(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int64) (startIndex, endIndex int64, err error) {
|
||||
v, _ := ((*indexList)[0]).(*intPair)
|
||||
startIndex = v.a
|
||||
endIndex = v.b
|
||||
if endIndex == kern.ConstLastIndex {
|
||||
endIndex = int64(maxValue)
|
||||
}
|
||||
if startIndex < 0 && startIndex >= -maxValue {
|
||||
startIndex = int64(maxValue) + startIndex
|
||||
}
|
||||
if endIndex < 0 && endIndex >= -maxValue {
|
||||
endIndex = int64(maxValue) + endIndex
|
||||
}
|
||||
if startIndex < 0 || startIndex > maxValue {
|
||||
err = indexTerm.Errorf("range start-index %d is out of bounds", startIndex)
|
||||
} else if endIndex < 0 || endIndex > maxValue {
|
||||
err = indexTerm.Errorf("range end-index %d is out of bounds", endIndex)
|
||||
} else if startIndex > endIndex {
|
||||
err = indexTerm.Errorf("range start-index %d must not be greater than end-index %d", startIndex, endIndex)
|
||||
}
|
||||
return
|
||||
}
|
||||
// func verifyInterval(indexTerm kern.Term, indexList *array.ArrayType, maxValue int64) (startIndex, endIndex int64, err error) {
|
||||
// v, _ := ((*indexList)[0]).(*interval.IntervalType)
|
||||
// startIndex = v.Begin()
|
||||
// endIndex = v.End()
|
||||
// if endIndex == kern.ConstLastIndex {
|
||||
// endIndex = int64(maxValue)
|
||||
// }
|
||||
// if startIndex < 0 && startIndex >= -maxValue {
|
||||
// startIndex = int64(maxValue) + startIndex
|
||||
// }
|
||||
// if endIndex < 0 && endIndex >= -maxValue {
|
||||
// endIndex = int64(maxValue) + endIndex
|
||||
// }
|
||||
// if startIndex < 0 || startIndex > maxValue {
|
||||
// err = indexTerm.Errorf("%s start-index %d is out of bounds", interval.TypeName, startIndex)
|
||||
// } else if endIndex < 0 || endIndex > maxValue {
|
||||
// err = indexTerm.Errorf("%s end-index %d is out of bounds", interval.TypeName, endIndex)
|
||||
// } else if startIndex > endIndex {
|
||||
// err = indexTerm.Errorf("%s start-index %d must not be greater than end-index %d", interval.TypeName, startIndex, endIndex)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
var leftValue, rightValue any
|
||||
@@ -87,48 +91,9 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
}
|
||||
|
||||
if types.IsInteger((*indexList)[0]) {
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||
v = (*unboxedValue)[index]
|
||||
}
|
||||
case *list.LinkedList:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||
v, err = unboxedValue.At(index)
|
||||
}
|
||||
case string:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||
v = string(unboxedValue[index])
|
||||
}
|
||||
case *dict.DictType:
|
||||
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
} else if isIntPair((*indexList)[0]) {
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
var start, end int64
|
||||
if start, end, err = verifyRange(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||
sublist := array.ArrayType((*unboxedValue)[start:end])
|
||||
v = &sublist
|
||||
}
|
||||
case *list.LinkedList:
|
||||
var start, end int64
|
||||
if start, end, err = verifyRange(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||
v = unboxedValue.Sub(start, end)
|
||||
}
|
||||
case string:
|
||||
var start, end int64
|
||||
if start, end, err = verifyRange(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||
v = unboxedValue[start:end]
|
||||
}
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
v, err = collectionItemByIndex(opTerm, leftValue, rightValue, indexList)
|
||||
} else if interval.IsInterval((*indexList)[0]) {
|
||||
v, err = subCollectionByIndex(opTerm, leftValue, rightValue, indexList)
|
||||
} else if dict.IsDict(leftValue) {
|
||||
d := leftValue.(*dict.DictType)
|
||||
v, err = getDictItem(d, indexTerm, indexList, rightValue)
|
||||
@@ -139,7 +104,126 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func getDictItem(d *dict.DictType, indexTerm *scan.Term, indexList *array.ArrayType, rightValue any) (v any, err error) {
|
||||
func collectionItemByIndex(opTerm kern.Term, leftValue, rightValue any, indexList *array.ArrayType) (v any, err error) {
|
||||
indexTerm := opTerm.GetChild(1)
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||
v = (*unboxedValue)[index]
|
||||
}
|
||||
case *list.LinkedList:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||
v, err = unboxedValue.At(index)
|
||||
}
|
||||
case string:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||
v = string(unboxedValue[index])
|
||||
}
|
||||
case *dict.DictType:
|
||||
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func subCollectionByIndex(opTerm kern.Term, leftValue, rightValue any, indexList *array.ArrayType) (v any, err error) {
|
||||
triple := (*indexList)[0].(*interval.IntervalType)
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
v = intervalSubArray(unboxedValue, triple)
|
||||
case *list.LinkedList:
|
||||
v = intervalSubLinkedList(unboxedValue, triple)
|
||||
case string:
|
||||
v = intervalSubString(unboxedValue, triple)
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fixInterval(p *interval.IntervalType, maxLength int) (b, e, s int) {
|
||||
b, e, s = p.ToIntTriple()
|
||||
if b < 0 {
|
||||
b = maxLength + b
|
||||
}
|
||||
if e < 0 {
|
||||
e = maxLength + e //+ 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intervalSubString(source string, p *interval.IntervalType) (result string) {
|
||||
b, e, s := fixInterval(p, len(source))
|
||||
if b <= e {
|
||||
e = min(e, len(source))
|
||||
if s == 1 {
|
||||
result = source[b:e]
|
||||
} else {
|
||||
var sb strings.Builder
|
||||
for i := b; i < e; i += s {
|
||||
sb.WriteByte(source[i])
|
||||
}
|
||||
result = sb.String()
|
||||
}
|
||||
} else {
|
||||
var sb strings.Builder
|
||||
for i := b; i >= e; i -= s {
|
||||
sb.WriteByte(source[i])
|
||||
}
|
||||
result = sb.String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intervalSubArray(source *array.ArrayType, p *interval.IntervalType) (result *array.ArrayType) {
|
||||
var a array.ArrayType
|
||||
b, e, s := fixInterval(p, len(*source))
|
||||
if b <= e {
|
||||
e = min(e, len(*source))
|
||||
if s == 1 {
|
||||
a = (*source)[b:e]
|
||||
} else {
|
||||
size := (e-b)/s + 1
|
||||
a = make(array.ArrayType, 0, size)
|
||||
for i := b; i < e; i += s {
|
||||
a = append(a, (*source)[i])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size := (b-e)/s + 1
|
||||
a = make(array.ArrayType, 0, size)
|
||||
for i := b; i > e; i -= s {
|
||||
a = append(a, (*source)[i])
|
||||
}
|
||||
}
|
||||
result = &a
|
||||
return
|
||||
}
|
||||
|
||||
func intervalSubLinkedList(source *list.LinkedList, p *interval.IntervalType) (result *list.LinkedList) {
|
||||
b, e, s := fixInterval(p, source.Len())
|
||||
revert := b > e
|
||||
if revert {
|
||||
b, e = e, b
|
||||
source = source.Revert()
|
||||
}
|
||||
e = min(e, source.Len())
|
||||
if s == 1 {
|
||||
result = source.Sub(int64(b), int64(e))
|
||||
} else {
|
||||
result = source.SubStep(int64(b), int64(e), int64(s))
|
||||
}
|
||||
if revert {
|
||||
source = source.Revert()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getDictItem(d *dict.DictType, indexTerm kern.Term, indexList *array.ArrayType, rightValue any) (v any, err error) {
|
||||
var ok bool
|
||||
var indexValue any
|
||||
|
||||
@@ -153,5 +237,5 @@ func getDictItem(d *dict.DictType, indexTerm *scan.Term, indexList *array.ArrayT
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymIndex, newIndexTerm)
|
||||
scan.RegisterTermConstructor(sym.SymIndex, newIndexTerm)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user