// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-dot.go package expr import "fmt" // -------- dot term func newDotTerm(tk *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priDot, evalFunc: evalDot, } } func verifyIndex(indexTerm *term, indexValue any, maxValue int) (index int, err error) { var v int if v, err = indexTerm.toInt(indexValue, "index expression value must be integer"); err == nil { if v >= 0 && v < maxValue { index = v } else if index >= -maxValue { index = maxValue + v } else { err = indexTerm.Errorf("index %d out of bounds", v) } } return } func evalDot(ctx ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = self.evalInfix(ctx); err != nil { return } indexTerm := self.children[1] switch unboxedValue := leftValue.(type) { case []any: var index int if index, err = verifyIndex(indexTerm, rightValue, len(unboxedValue)); err == nil { v = unboxedValue[index] } case string: var index int if index, err = verifyIndex(indexTerm, rightValue, len(unboxedValue)); err == nil { v = unboxedValue[index] } case map[any]any: var ok bool if v, ok = unboxedValue[rightValue]; !ok { err = fmt.Errorf("key %v does not belong to the dictionary", rightValue) } case *dataCursor: if indexTerm.symbol() == SymString { opName := indexTerm.value() if opName == resetName { err = unboxedValue.Reset() } else if opName == cleanName { err = unboxedValue.Clean() } else { err = indexTerm.Errorf("iterators do not support command %q", opName) } v = err == nil } default: err = self.errIncompatibleTypes(leftValue, rightValue) } return } // init func init() { registerTermConstructor(SymDot, newDotTerm) }