expr/operator-rel.go
Celestino Amoroso 3736214c5a A lot of changes. Main ones are:
- fraction type renamed as FractionType and moved from operator-fraction.go to fraction-type.go
- ListType moved from operator-list.go to list-type.go
- all test file were renamed adding the "t_" prefix
- defined a test template in file t_temple_test.go
- new test file t_relational_test.go where relational tests are collected
- lists can now compared as set using operators <, <=, >, and >= (IMPORTANT: here = menas same content, not same list)
2024-05-28 07:26:05 +02:00

251 lines
5.1 KiB
Go

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-rel.go
package expr
import "reflect"
//-------- equal term
func newEqualTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalEqual,
}
}
func equals(a, b any) (eq bool, err error) {
if isNumOrFract(a) && isNumOrFract(b) {
if IsNumber(a) && IsNumber(b) {
if IsInteger(a) && IsInteger(b) {
li, _ := a.(int64)
ri, _ := b.(int64)
eq = li == ri
} else {
eq = numAsFloat(a) == numAsFloat(b)
}
} else {
var cmp int
if cmp, err = cmpAnyFract(a, b); err == nil {
eq = cmp == 0
}
}
} else {
eq = reflect.DeepEqual(a, b)
}
return
}
func evalEqual(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
v, err = equals(leftValue, rightValue)
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 ExprContext, self *term) (v any, err error) {
if v, err = evalEqual(ctx, self); err == nil {
b, _ := 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 isNumOrFract(a) && isNumOrFract(b) {
if IsNumber(a) && IsNumber(b) {
if IsInteger(a) && IsInteger(b) {
li, _ := a.(int64)
ri, _ := b.(int64)
isLess = li < ri
} else {
isLess = numAsFloat(a) < numAsFloat(b)
}
} else {
var cmp int
if cmp, err = cmpAnyFract(a, b); err == nil {
isLess = cmp < 0
}
}
} else if IsString(a) && IsString(b) {
ls, _ := a.(string)
rs, _ := b.(string)
isLess = ls < rs
// Inclusion test
} else if IsList(a) && IsList(b) {
aList, _ := a.(*ListType)
bList, _ := b.(*ListType)
isLess = len(*aList) < len(*bList)
if isLess {
for _, item := range *aList {
if bList.indexDeepCmp(item) < 0 {
isLess = false
break
}
}
}
} else {
err = self.errIncompatibleTypes(a, b)
}
return
}
func evalLess(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
v, err = lessThan(self, 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 sameContent(a, b any) (same bool, err error) {
la, _ := a.(*ListType)
lb, _ := b.(*ListType)
if len(*la) == len(*lb) {
same = true
for i, item := range *la {
if same, err = equals(item, (*lb)[i]); err != nil || !same {
break
}
}
}
return
}
func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) {
if isLessEq, err = lessThan(self, a, b); err == nil {
if !isLessEq {
if IsList(a) && IsList(b) {
isLessEq, err = sameContent(a, b)
} else {
isLessEq, err = equals(a, b)
}
}
}
return
}
func evalLessEqual(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
v, err = lessThanOrEqual(self, 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 ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
v, err = lessThan(self, rightValue, leftValue)
// if v, err = evalLessEqual(ctx, self); err == nil {
// b, _ := toBool(v)
// v = !b
// }
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 ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
v, err = lessThanOrEqual(self, rightValue, leftValue)
// if v, err = evalLess(ctx, self); err == nil {
// b, _ := toBool(v)
// v = !b
// }
return
}
// init
func init() {
registerTermConstructor(SymDoubleEqual, newEqualTerm)
registerTermConstructor(SymNotEqual, newNotEqualTerm)
registerTermConstructor(SymLess, newLessTerm)
registerTermConstructor(SymLessOrEqual, newLessEqualTerm)
registerTermConstructor(SymGreater, newGreaterTerm)
registerTermConstructor(SymGreaterOrEqual, newGreaterEqualTerm)
}