// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-dot.go package expr import ( "git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/scan" "git.portale-stac.it/go-pkg/expr/util" ) // -------- dot term func newDotTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriDot, EvalFunc: evalDot, } } func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if err = opTerm.CheckOperands(); err != nil { return } if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil { return } indexTerm := opTerm.Children[1] switch unboxedValue := leftValue.(type) { case kern.ExtIterator: if indexTerm.Symbol() == scan.SymVariable /*|| indexTerm.Tk.Sym == scan.SymString */ { opName := indexTerm.Source() if unboxedValue.HasOperation(opName) { v, err = unboxedValue.CallOperation(opName, map[string]any{}) } else { err = indexTerm.Errorf("this iterator do not support the %q command", opName) v = false } } else { err = indexTerm.Tk.ErrorExpectedGot("identifier") } case *kern.DictType: // var ok bool // s := opTerm.Children[1].Symbol() // if s == scan.SymVariable || s == scan.SymString { // src := opTerm.Children[1].Source() // if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' { // src = src[1 : len(src)-1] // } // if v, ok = unboxedValue.GetItem(src); !ok { // err = opTerm.Errorf("key %q not found", src) // } // } else if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil { // if v, ok = unboxedValue.GetItem(rightValue); !ok { // err = opTerm.Errorf("key %q not found", rightValue) // } // } v, err = dotGetDictItemValue(ctx, unboxedValue, opTerm.Children[1]) default: if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil { err = opTerm.Errorf("incompatible types: %s and %s", kern.TypeName(leftValue), kern.TypeName(rightValue)) } } return } func dotGetDictItemValue(ctx kern.ExprContext, d *kern.DictType, rightTerm *scan.Term) (v any, err error) { var ok bool var rightValue any s := rightTerm.Symbol() if s == scan.SymVariable || s == scan.SymString { // src := rightTerm.Source() // if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' { // src = src[1 : len(src)-1] // } src := util.UnquoteString(rightTerm.Source()) if v, ok = d.GetItem(src); !ok { err = errDictKeyNotFound(rightTerm, src) } } else if rightValue, err = rightTerm.Compute(ctx); err == nil { if v, ok = d.GetItem(rightValue); !ok { err = errDictKeyNotFound(rightTerm, rightValue) } } return } func errDictKeyNotFound(term *scan.Term, key any) error { if s, ok := key.(string); ok { return term.Errorf("key %q not found", s) } return term.Errorf("key %v not found", key) } // init func init() { scan.RegisterTermConstructor(scan.SymDot, newDotTerm) }