123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- package glisp
- import (
- "bytes"
- "errors"
- "fmt"
- )
- func signumFloat(f SexpFloat) int {
- if f > 0 {
- return 1
- }
- if f < 0 {
- return -1
- }
- return 0
- }
- func signumInt(i SexpInt) 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:
- return signumFloat(f - SexpFloat(e)), nil
- case SexpFloat:
- return signumFloat(f - e), nil
- case SexpChar:
- return signumFloat(f - SexpFloat(e)), nil
- }
- errmsg := fmt.Sprintf("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 - e), nil
- case SexpFloat:
- return signumFloat(SexpFloat(i) - e), nil
- case SexpChar:
- return signumInt(i - SexpInt(e)), nil
- }
- errmsg := fmt.Sprintf("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(SexpInt(c) - e), nil
- case SexpFloat:
- return signumFloat(SexpFloat(c) - e), nil
- case SexpChar:
- return signumInt(SexpInt(c - e)), nil
- }
- errmsg := fmt.Sprintf("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), []byte(e)), nil
- }
- errmsg := fmt.Sprintf("cannot compare %T to %T", s, expr)
- return 0, errors.New(errmsg)
- }
- func compareSymbol(sym SexpSymbol, expr Sexp) (int, error) {
- switch e := expr.(type) {
- case SexpSymbol:
- return signumInt(SexpInt(sym.number - e.number)), nil
- }
- errmsg := fmt.Sprintf("cannot compare %T to %T", sym, expr)
- return 0, errors.New(errmsg)
- }
- func comparePair(a SexpPair, b Sexp) (int, error) {
- var bp SexpPair
- switch t := b.(type) {
- case SexpPair:
- bp = t
- default:
- errmsg := fmt.Sprintf("cannot compare %T to %T", a, b)
- return 0, errors.New(errmsg)
- }
- res, err := Compare(a.head, bp.head)
- if err != nil {
- return 0, err
- }
- if res != 0 {
- return res, nil
- }
- return Compare(a.tail, bp.tail)
- }
- func compareArray(a SexpArray, b Sexp) (int, error) {
- var ba SexpArray
- switch t := b.(type) {
- case SexpArray:
- ba = t
- default:
- errmsg := fmt.Sprintf("cannot compare %T to %T", a, b)
- return 0, errors.New(errmsg)
- }
- var length int
- if len(a) < len(ba) {
- length = len(a)
- } else {
- length = len(ba)
- }
- for i := 0; i < length; i++ {
- res, err := Compare(a[i], ba[i])
- if err != nil {
- return 0, err
- }
- if res != 0 {
- return res, nil
- }
- }
- return signumInt(SexpInt(len(a) - len(ba))), nil
- }
- func compareBool(a SexpBool, b Sexp) (int, error) {
- var bb SexpBool
- switch bt := b.(type) {
- case SexpBool:
- bb = bt
- default:
- errmsg := fmt.Sprintf("cannot compare %T to %T", a, b)
- return 0, errors.New(errmsg)
- }
- // true > false
- if a && bb {
- return 0, nil
- }
- if a {
- return 1, nil
- }
- if bb {
- return -1, nil
- }
- return 0, nil
- }
- func Compare(a Sexp, b Sexp) (int, error) {
- switch at := a.(type) {
- case SexpInt:
- return compareInt(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 compareSymbol(at, b)
- case SexpPair:
- return comparePair(at, b)
- case SexpArray:
- return compareArray(at, b)
- case SexpSentinel:
- if at == SexpNull && b == SexpNull {
- return 0, nil
- } else {
- return -1, nil
- }
- }
- errmsg := fmt.Sprintf("cannot compare %T to %T", a, b)
- return 0, errors.New(errmsg)
- }
|