expr/operator-rel.go

228 lines
5.0 KiB
Go

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