Files
tablizer/vendor/github.com/glycerine/zygomys/zygo/comparisons.go
2024-05-14 12:10:58 +02:00

324 lines
6.7 KiB
Go

package zygo
import (
"bytes"
"errors"
"fmt"
"math"
"reflect"
)
func IsNaNFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
var err error
a := args[0]
if sel, isSel := a.(Selector); isSel {
a, err = sel.RHS(env)
if err != nil {
return SexpNull, err
}
}
switch at := a.(type) {
case *SexpFloat:
if math.IsNaN(at.Val) {
return &SexpBool{Val: true}, nil
}
}
return &SexpBool{Val: false}, nil
}
func signumFloat(f float64) int {
if f > 0 {
return 1
}
if f < 0 {
return -1
}
return 0
}
func signumInt(i int64) int {
if i > 0 {
return 1
}
if i < 0 {
return -1
}
return 0
}
func compareFloat(f *SexpFloat, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpInt:
if math.IsNaN(f.Val) {
return 2, nil
}
return signumFloat(f.Val - float64(e.Val)), nil
case *SexpFloat:
nanCount := 0
if math.IsNaN(f.Val) {
nanCount++
}
if math.IsNaN(e.Val) {
nanCount++
}
if nanCount > 0 {
return 1 + nanCount, nil
}
return signumFloat(f.Val - e.Val), nil
case *SexpChar:
if math.IsNaN(f.Val) {
return 2, nil
}
return signumFloat(f.Val - float64(e.Val)), nil
}
errmsg := fmt.Sprintf("err 91: cannot compare %T to %T", f, expr)
return 0, errors.New(errmsg)
}
func compareInt(i *SexpInt, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpInt:
return signumInt(i.Val - e.Val), nil
case *SexpFloat:
return signumFloat(float64(i.Val) - e.Val), nil
case *SexpChar:
return signumInt(i.Val - int64(e.Val)), nil
case *SexpReflect:
r := reflect.Value(e.Val)
ifa := r.Interface()
switch z := ifa.(type) {
case *int64:
return signumInt(i.Val - *z), nil
}
P("compareInt(): ifa = %v/%T", ifa, ifa)
P("compareInt(): r.Elem() = %v/%T", r.Elem(), r.Elem())
P("compareInt(): r.Elem().Interface() = %v/%T", r.Elem().Interface(), r.Elem().Interface())
P("compareInt(): r.Elem().Type() = %v/%T", r.Elem().Type(), r.Elem().Type())
P("compareInt(): r.Elem().Type().Name() = %v/%T", r.Elem().Type().Name(), r.Elem().Type().Name())
}
errmsg := fmt.Sprintf("err 92: cannot compare %T to %T", i, expr)
return 0, errors.New(errmsg)
}
func compareChar(c *SexpChar, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpInt:
return signumInt(int64(c.Val) - e.Val), nil
case *SexpFloat:
return signumFloat(float64(c.Val) - e.Val), nil
case *SexpChar:
return signumInt(int64(c.Val) - int64(e.Val)), nil
}
errmsg := fmt.Sprintf("err 93: cannot compare %T to %T", c, expr)
return 0, errors.New(errmsg)
}
func compareString(s *SexpStr, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpStr:
return bytes.Compare([]byte(s.S), []byte(e.S)), nil
case *SexpReflect:
r := reflect.Value(e.Val)
ifa := r.Interface()
switch z := ifa.(type) {
case *string:
return bytes.Compare([]byte(s.S), []byte(*z)), nil
}
}
errmsg := fmt.Sprintf("err 94: cannot compare %T to %T", s, expr)
return 0, errors.New(errmsg)
}
func (env *Zlisp) compareSymbol(sym *SexpSymbol, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpSymbol:
return signumInt(int64(sym.number - e.number)), nil
}
errmsg := fmt.Sprintf("err 95: cannot compare %T to %T", sym, expr)
return 0, errors.New(errmsg)
}
func (env *Zlisp) comparePair(a *SexpPair, b Sexp) (int, error) {
var bp *SexpPair
switch t := b.(type) {
case *SexpPair:
bp = t
default:
errmsg := fmt.Sprintf("err 96: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
res, err := env.Compare(a.Head, bp.Head)
if err != nil {
return 0, err
}
if res != 0 {
return res, nil
}
return env.Compare(a.Tail, bp.Tail)
}
func (env *Zlisp) compareArray(a *SexpArray, b Sexp) (int, error) {
var ba *SexpArray
switch t := b.(type) {
case *SexpArray:
ba = t
default:
errmsg := fmt.Sprintf("err 97: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
var length int
if len(a.Val) < len(ba.Val) {
length = len(a.Val)
} else {
length = len(ba.Val)
}
for i := 0; i < length; i++ {
res, err := env.Compare(a.Val[i], ba.Val[i])
if err != nil {
return 0, err
}
if res != 0 {
return res, nil
}
}
return signumInt(int64(len(a.Val) - len(ba.Val))), nil
}
func compareBool(a *SexpBool, b Sexp) (int, error) {
var bb *SexpBool
switch bt := b.(type) {
case *SexpBool:
bb = bt
default:
errmsg := fmt.Sprintf("err 98: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
// true > false
if a.Val && bb.Val {
return 0, nil
}
if a.Val {
return 1, nil
}
if bb.Val {
return -1, nil
}
return 0, nil
}
func comparePointers(a *SexpPointer, bs Sexp) (int, error) {
var b *SexpPointer
switch bt := bs.(type) {
case *SexpPointer:
b = bt
default:
return 0, fmt.Errorf("err 99: cannot compare %T to %T", a, bs)
}
if a.Target == b.Target {
return 0, nil
}
return 1, nil
}
func (env *Zlisp) Compare(a Sexp, b Sexp) (int, error) {
var err error
if sel, isSel := a.(Selector); isSel {
a, err = sel.RHS(env)
if err != nil {
return 0, err
}
}
if sel, isSel := b.(Selector); isSel {
b, err = sel.RHS(env)
if err != nil {
return 0, err
}
}
switch at := a.(type) {
case *SexpInt:
return compareInt(at, b)
case *SexpUint64:
return compareUint64(at, b)
case *SexpChar:
return compareChar(at, b)
case *SexpFloat:
return compareFloat(at, b)
case *SexpBool:
return compareBool(at, b)
case *SexpStr:
return compareString(at, b)
case *SexpSymbol:
return env.compareSymbol(at, b)
case *SexpPair:
return env.comparePair(at, b)
case *SexpArray:
return env.compareArray(at, b)
case *SexpHash:
return compareHash(at, b)
case *RegisteredType:
return compareRegisteredTypes(at, b)
case *SexpPointer:
return comparePointers(at, b)
case *SexpSentinel:
if at == SexpNull && b == SexpNull {
return 0, nil
} else {
return -1, nil
}
case *SexpTime:
switch bt := b.(type) {
case *SexpTime:
if bt.Tm.Unix() == at.Tm.Unix() {
return 0, nil
}
return -1, nil
}
case *SexpReflect:
r := reflect.Value(at.Val)
ifa := r.Interface()
//P("Compare(): ifa = %v/%t", ifa, ifa)
//P("Compare(): r.Elem() = %v/%T", r.Elem(), r.Elem())
switch z := ifa.(type) {
case *int64:
return compareInt(&SexpInt{Val: *z}, b)
case *string:
return compareString(&SexpStr{S: *z}, b)
}
}
errmsg := fmt.Sprintf("err 100: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
// only compare uint64 to uint64
func compareUint64(i *SexpUint64, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpUint64:
return signumUint64(i.Val - e.Val), nil
}
errmsg := fmt.Sprintf("err 101: cannot compare %T to %T", i, expr)
return 0, errors.New(errmsg)
}
func signumUint64(i uint64) int {
if i > 0 {
return 1
}
if i < 0 {
return -1
}
return 0
}