2024-04-19 09:05:26 +02:00
|
|
|
// 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"
|
|
|
|
|
2024-04-19 09:05:26 +02:00
|
|
|
// -------- dot term
|
|
|
|
func newDotTerm(tk *Token) (inst *term) {
|
|
|
|
return &term{
|
|
|
|
tk: *tk,
|
|
|
|
children: make([]*term, 0, 2),
|
|
|
|
position: posInfix,
|
|
|
|
priority: priDot,
|
|
|
|
evalFunc: evalDot,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-28 04:44:19 +02:00
|
|
|
func verifyIndex(ctx ExprContext, indexTerm *term, maxValue int) (index int, err error) {
|
2024-04-27 14:44:52 +02:00
|
|
|
var v int
|
2024-04-28 04:44:19 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-04-19 09:05:26 +02:00
|
|
|
func evalDot(ctx ExprContext, self *term) (v any, err error) {
|
|
|
|
var leftValue, rightValue any
|
|
|
|
|
2024-04-28 04:44:19 +02:00
|
|
|
if err = self.checkOperands(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if leftValue, err = self.children[0].compute(ctx); err != nil {
|
2024-04-19 09:05:26 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
indexTerm := self.children[1]
|
|
|
|
|
2024-04-27 14:44:52 +02:00
|
|
|
switch unboxedValue := leftValue.(type) {
|
2024-05-06 04:15:46 +02:00
|
|
|
case *ListType:
|
2024-04-21 14:24:56 +02:00
|
|
|
var index int
|
2024-05-06 04:15:46 +02:00
|
|
|
array := ([]any)(*unboxedValue)
|
|
|
|
if index, err = verifyIndex(ctx, indexTerm, len(array)); err == nil {
|
|
|
|
v = array[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
|
2024-04-28 04:44:19 +02:00
|
|
|
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
|
2024-04-27 14:44:52 +02:00
|
|
|
v = unboxedValue[index]
|
2024-04-19 09:05:26 +02:00
|
|
|
}
|
2024-04-27 14:44:52 +02:00
|
|
|
case map[any]any:
|
2024-04-21 14:24:56 +02:00
|
|
|
var ok bool
|
2024-04-28 04:44:19 +02:00
|
|
|
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
|
|
|
}
|
2024-05-04 00:30:35 +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:
|
2024-04-28 04:44:19 +02:00
|
|
|
if indexTerm.symbol() == SymIdentifier {
|
|
|
|
opName := indexTerm.source()
|
2024-05-04 00:30:35 +02:00
|
|
|
if unboxedValue.HasOperation(opName) {
|
|
|
|
v, err = unboxedValue.CallOperation(opName, []any{})
|
2024-04-27 22:34:23 +02:00
|
|
|
} else {
|
2024-05-04 00:30:35 +02:00
|
|
|
err = indexTerm.Errorf("this iterator do not support the %q command", opName)
|
|
|
|
v = false
|
2024-04-27 22:34:23 +02:00
|
|
|
}
|
|
|
|
}
|
2024-04-27 14:44:52 +02:00
|
|
|
default:
|
2024-04-19 09:05:26 +02:00
|
|
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// init
|
|
|
|
func init() {
|
|
|
|
registerTermConstructor(SymDot, newDotTerm)
|
|
|
|
}
|