elvish/eval/rat.go

68 lines
1.2 KiB
Go
Raw Normal View History

package eval
import (
"errors"
"fmt"
"math/big"
2017-08-31 02:52:27 +08:00
"github.com/xiaq/persistent/hash"
)
var ErrOnlyStrOrRat = errors.New("only str or rat may be converted to rat")
// Rat is a rational number.
type Rat struct {
b *big.Rat
}
var _ Value = Rat{}
func (Rat) Kind() string {
return "string"
}
2017-08-31 01:47:50 +08:00
func (r Rat) Equal(a interface{}) bool {
if r == a {
return true
}
r2, ok := a.(Rat)
if !ok {
return false
}
return r.b.Cmp(r2.b) == 0
}
2017-08-31 02:52:27 +08:00
func (r Rat) Hash() uint32 {
// TODO(xiaq): Use a more efficient implementation.
return hash.String(r.String())
}
func (r Rat) Repr(int) string {
return "(rat " + r.String() + ")"
}
func (r Rat) String() string {
if r.b.IsInt() {
return r.b.Num().String()
}
return r.b.String()
}
// ToRat converts a Value to rat. A str can be converted to a rat if it can be
// parsed. A rat is returned as-is. Other types of values cannot be converted.
func ToRat(v Value) (Rat, error) {
switch v := v.(type) {
case Rat:
return v, nil
case String:
r := big.Rat{}
_, err := fmt.Sscanln(string(v), &r)
if err != nil {
return Rat{}, fmt.Errorf("%s cannot be parsed as rat", v.Repr(NoPretty))
}
return Rat{&r}, nil
default:
return Rat{}, ErrOnlyStrOrRat
}
}