expr/operator-index.go

92 lines
2.1 KiB
Go

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-index.go
package expr
// -------- index term
func newIndexTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priDot,
evalFunc: evalIndex,
}
}
func verifyKey(indexTerm *term, indexList *ListType) (index any, err error) {
if len(*indexList) != 1 {
err = indexTerm.Errorf("one index only is allowed")
} else {
index = (*indexList)[0]
}
return
}
func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int, err error) {
var v int
if len(*indexList) != 1 {
err = indexTerm.Errorf("one index only is allowed")
} else if v, err = toInt((*indexList)[0], "index expression"); err == nil {
if v < 0 && v >= -maxValue {
v = maxValue + v
}
if v >= 0 && v < maxValue {
index = v
} else {
err = indexTerm.Errorf("index %d out of bounds", v)
}
}
return
}
func evalIndex(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var indexList *ListType
var ok bool
if err = self.checkOperands(); err != nil {
return
}
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
if indexList, ok = rightValue.(*ListType); !ok {
err = self.Errorf("invalid index expression")
return
}
indexTerm := self.children[1]
switch unboxedValue := leftValue.(type) {
case *ListType:
var index int
if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil {
v = (*unboxedValue)[index]
}
case string:
var index int
if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil {
v = string(unboxedValue[index])
}
case *DictType:
var ok bool
var indexValue any
if indexValue, err = verifyKey(indexTerm, indexList); err == nil {
if v, ok = (*unboxedValue)[indexValue]; !ok {
err = indexTerm.Errorf("key %v does not belong to the dictionary", rightValue)
}
}
default:
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymIndex, newIndexTerm)
}