// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-interval.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" "git.portale-stac.it/go-pkg/expr/types/interval" ) // -------- interval term func newIntervalTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriInterval, EvalFunc: evalInterval, } } func changeColonToInterval(t *scan.Term) { if t.IsSymbol(sym.SymDoubleDot) { t.SetSymbol(sym.SymInterval) t.EvalFunc = evalInterval if child := t.GetLeftChild(); child != nil && child.IsSymbol(sym.SymDoubleDot) { child.SetSymbol(sym.SymInterval) } } } func evalInterval(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var begin, end int64 step := int64(1) switch opTerm.GetChildCount() { case 0: begin = 0 end = int64(kern.ConstLastIndex) case 1: var leftValue any if leftValue, err = opTerm.GetChild(0).Compute(ctx); err != nil { return } if begin, err = checkIntervalComponent(opTerm, leftValue); err != nil { return } end = int64(kern.ConstLastIndex) default: var beginValue, endValue, stepValue any subTerm := opTerm.GetLeftChild() if subTerm.IsOneOf(sym.SymInterval, sym.SymDoubleDot) { if beginValue, endValue, err = subTerm.EvalInfix(ctx); err != nil { return } if stepValue, err = opTerm.GetRightChild().Compute(ctx); err != nil { return } step, err = checkIntervalComponent(opTerm.GetRightChild(), stepValue) } else if beginValue, endValue, err = opTerm.EvalInfix(ctx); err != nil { return } if begin, err = checkIntervalComponent(opTerm, beginValue); err != nil { return } if end, err = checkIntervalComponent(opTerm, endValue); err != nil { return } } if step <= 0 { err = opTerm.Errorf("invalid %s specification: step must be positive", interval.TypeName) } else { v = interval.NewInterval(begin, end, step) } return } func checkIntervalComponent(t kern.Term, value any) (component int64, err error) { if component, err = types.ToGoInt64(value, "%s expression"); err != nil { err = t.Errorf(err.Error(), interval.TypeName) } return } func errIntervalInvalidSpecification(t kern.Term) error { return t.Errorf("invalid %s specification", interval.TypeName) } func errIntervalUnexpectedExpression(t *scan.Term) error { return t.Errorf("unexpected %s expression", interval.TypeName) } // init func init() { scan.RegisterTermConstructor(sym.SymInterval, newIntervalTerm) scan.RegisterTermConstructor(sym.SymDoubleDot, newIntervalTerm) }