Files
expr/operator-interval.go
T

104 lines
2.7 KiB
Go

// 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)
}