// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-range.go package expr import ( "fmt" "git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/scan" ) // -------- range term type intPair struct { a, b int } func (p *intPair) TypeName() string { return kern.TypePair } func (p *intPair) ToString(opt kern.FmtOpt) string { return fmt.Sprintf("(%d, %d)", p.a, p.b) } func isIntPair(v any) bool { _, ok := v.(*intPair) return ok } func newRangeTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRange, EvalFunc: evalRange, } } func changeColonToRange(t *scan.Term) { if t.Tk.IsSymbol(scan.SymColon) { t.Tk.Sym = scan.SymRange t.EvalFunc = evalRange } } func evalRange(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if len(opTerm.Children) == 0 { leftValue = int64(0) rightValue = int64(-1) } else if len(opTerm.Children) == 1 { if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil { return } rightValue = int64(kern.ConstLastIndex) } else if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } if !(kern.IsInteger(leftValue) && kern.IsInteger(rightValue)) { // err = opTerm.errIncompatibleTypes(leftValue, rightValue) err = errRangeInvalidSpecification(opTerm) return } startIndex, _ := leftValue.(int64) endIndex, _ := rightValue.(int64) v = &intPair{int(startIndex), int(endIndex)} return } func errRangeInvalidSpecification(t *scan.Term) error { return t.Errorf("invalid range specification") } func errRangeUnexpectedExpression(t *scan.Term) error { return t.Errorf("unexpected range expression") } // init func init() { scan.RegisterTermConstructor(scan.SymRange, newRangeTerm) }