// 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(ctx ExprContext, indexTerm *term, maxValue int) (index int, err error) { var v int var indexValue any if indexValue, err = indexTerm.compute(ctx); err == nil { 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 err = self.checkOperands(); err != nil { return } if leftValue, err = self.children[0].compute(ctx); err != nil { return } indexTerm := self.children[1] switch unboxedValue := leftValue.(type) { case []any: var index int if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil { v = unboxedValue[index] } case string: var index int if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil { v = unboxedValue[index] } case map[any]any: var ok bool var indexValue any if indexValue, err = indexTerm.compute(ctx); err == nil { if v, ok = unboxedValue[indexValue]; !ok { err = fmt.Errorf("key %v does not belong to the dictionary", rightValue) } } // case *dataCursor: // if indexTerm.symbol() == SymIdentifier { // opName := indexTerm.source() // 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 // } case ExtIterator: if indexTerm.symbol() == SymIdentifier { opName := indexTerm.source() if unboxedValue.HasOperation(opName) { v, err = unboxedValue.CallOperation(opName, []any{}) } else { err = indexTerm.Errorf("this iterator do not support the %q command", opName) v = false } } default: err = self.errIncompatibleTypes(leftValue, rightValue) } return } // init func init() { registerTermConstructor(SymDot, newDotTerm) }