// 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) }