// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-rel.go package expr import ( "reflect" "git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/scan" ) //-------- equal term func newEqualTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRelational, EvalFunc: evalEqual, } } // type deepFuncTemplate func(a, b any) (eq bool, err error) func equals(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) { if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) { if kern.IsNumber(a) && kern.IsNumber(b) { if kern.IsInteger(a) && kern.IsInteger(b) { li, _ := a.(int64) ri, _ := b.(int64) eq = li == ri } else { eq = kern.NumAsFloat(a) == kern.NumAsFloat(b) } } else { var cmp int if cmp, err = kern.CmpAnyFract(a, b); err == nil { eq = cmp == 0 } } } else if deepCmp != nil && kern.IsList(a) && kern.IsList(b) { eq, err = deepCmp(a, b) } else { eq = reflect.DeepEqual(a, b) } return } func evalEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = equals(leftValue, rightValue, nil) return } //-------- not equal term func newNotEqualTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRelational, EvalFunc: evalNotEqual, } } func evalNotEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { if v, err = evalEqual(ctx, opTerm); err == nil { b, _ := kern.ToBool(v) v = !b } return } //-------- less term func newLessTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRelational, EvalFunc: evalLess, } } func lessThan(self *scan.Term, a, b any) (isLess bool, err error) { if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) { if kern.IsNumber(a) && kern.IsNumber(b) { if kern.IsInteger(a) && kern.IsInteger(b) { li, _ := a.(int64) ri, _ := b.(int64) isLess = li < ri } else { isLess = kern.NumAsFloat(a) < kern.NumAsFloat(b) } } else { var cmp int if cmp, err = kern.CmpAnyFract(a, b); err == nil { isLess = cmp < 0 } } } else if kern.IsString(a) && kern.IsString(b) { ls, _ := a.(string) rs, _ := b.(string) isLess = ls < rs // Inclusion test } else if kern.IsList(a) && kern.IsList(b) { aList, _ := a.(*kern.ListType) bList, _ := b.(*kern.ListType) isLess = len(*aList) < len(*bList) && bList.Contains(aList) } else { err = self.ErrIncompatibleTypes(a, b) } return } func evalLess(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = lessThan(opTerm, leftValue, rightValue) return } //-------- less or equal term func newLessEqualTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRelational, EvalFunc: evalLessEqual, } } func lessThanOrEqual(self *scan.Term, a, b any) (isLessEq bool, err error) { if isLessEq, err = lessThan(self, a, b); err == nil { if !isLessEq { if kern.IsList(a) && kern.IsList(b) { isLessEq, err = kern.SameContent(a, b) } else { isLessEq, err = equals(a, b, nil) } } } return } func evalLessEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = lessThanOrEqual(opTerm, leftValue, rightValue) return } //-------- greater term func newGreaterTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRelational, EvalFunc: evalGreater, } } func evalGreater(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = lessThan(opTerm, rightValue, leftValue) return } //-------- greater or equal term func newGreaterEqualTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriRelational, EvalFunc: evalGreaterEqual, } } func evalGreaterEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = lessThanOrEqual(opTerm, rightValue, leftValue) return } // init func init() { scan.RegisterTermConstructor(scan.SymDoubleEqual, newEqualTerm) scan.RegisterTermConstructor(scan.SymNotEqual, newNotEqualTerm) scan.RegisterTermConstructor(scan.SymLess, newLessTerm) scan.RegisterTermConstructor(scan.SymLessOrEqual, newLessEqualTerm) scan.RegisterTermConstructor(scan.SymGreater, newGreaterTerm) scan.RegisterTermConstructor(scan.SymGreaterOrEqual, newGreaterEqualTerm) }