// 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/sym" "git.portale-stac.it/go-pkg/expr/types/dict" "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() == sym.SymVariable /*|| indexTerm.Tk.Sym == sym.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 *dict.DictType: 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 *dict.DictType, rightTerm *scan.Term) (v any, err error) { var ok bool var rightValue any s := rightTerm.Symbol() if s == sym.SymVariable || s == sym.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(sym.SymDot, newDotTerm) }