88 lines
1.9 KiB
Go
88 lines
1.9 KiB
Go
// 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)
|
|
}
|