// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-rel.go package expr import ( "reflect" "git.portale-stac.it/go-pkg/expr/kern" ) //-------- equal term func newEqualTerm(tk *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: 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 *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 *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priRelational, evalFunc: evalNotEqual, } } func evalNotEqual(ctx kern.ExprContext, opTerm *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 *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priRelational, evalFunc: evalLess, } } func lessThan(self *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 *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 *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priRelational, evalFunc: evalLessEqual, } } func lessThanOrEqual(self *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 *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 *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priRelational, evalFunc: evalGreater, } } func evalGreater(ctx kern.ExprContext, opTerm *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 *Token) (inst *term) { return &term{ tk: *tk, children: make([]*term, 0, 2), position: posInfix, priority: priRelational, evalFunc: evalGreaterEqual, } } func evalGreaterEqual(ctx kern.ExprContext, opTerm *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() { registerTermConstructor(SymDoubleEqual, newEqualTerm) registerTermConstructor(SymNotEqual, newNotEqualTerm) registerTermConstructor(SymLess, newLessTerm) registerTermConstructor(SymLessOrEqual, newLessEqualTerm) registerTermConstructor(SymGreater, newGreaterTerm) registerTermConstructor(SymGreaterOrEqual, newGreaterEqualTerm) }