expr/operator-dot.go

100 lines
2.4 KiB
Go
Raw Normal View History

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-dot.go
package expr
2024-04-21 14:24:56 +02:00
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) {
2024-04-27 14:44:52 +02:00
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)
}
2024-04-27 14:44:52 +02:00
}
}
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]
2024-04-27 14:44:52 +02:00
switch unboxedValue := leftValue.(type) {
case []any:
2024-04-21 14:24:56 +02:00
var index int
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
2024-04-27 14:44:52 +02:00
v = unboxedValue[index]
2024-04-21 14:24:56 +02:00
}
2024-04-27 14:44:52 +02:00
case string:
2024-04-21 14:24:56 +02:00
var index int
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
2024-04-27 14:44:52 +02:00
v = unboxedValue[index]
}
2024-04-27 14:44:52 +02:00
case map[any]any:
2024-04-21 14:24:56 +02:00
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)
}
2024-04-21 14:24:56 +02:00
}
// 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
}
}
2024-04-27 14:44:52 +02:00
default:
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymDot, newDotTerm)
}