-
Notifications
You must be signed in to change notification settings - Fork 15
/
value_number.go
120 lines (100 loc) · 2.39 KB
/
value_number.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package rel
import (
"reflect"
"strconv"
"unsafe"
"github.com/arr-ai/hash"
"github.com/arr-ai/wbnf/parser"
"github.com/go-errors/errors"
)
// Number is a number.
type Number float64
// NewNumber returns a Number for the given number.
func NewNumber(n float64) Number {
return Number(n)
}
// Float64 returns the value of the number.
func (n Number) Float64() float64 {
return float64(n)
}
func (n Number) Int() (int, bool) {
f := n.Float64()
i := int(f)
if float64(i) == f {
return i, true
}
return 0, false
}
// Hash computes a hash for a Number.
func (n Number) Hash(seed uintptr) uintptr {
return hash.Float64(float64(n), seed)
}
// Equal tests two Values for equality. Any other type returns false.
func (n Number) Equal(v interface{}) bool {
if b, ok := v.(Number); ok {
return n == b
}
return false
}
func (n Number) format() string {
return strconv.FormatFloat(float64(n), 'G', -1, 64)
}
// String returns a string representation of a Number.
func (n Number) String() string {
// TODO: Validate ulp heuristic parameters.
s := n.format()
if len(s) < 15 {
return s
}
u := *(*uint64)(unsafe.Pointer(&n))
u++
if s := (*Number)(unsafe.Pointer(&u)).format(); len(s) < 10 {
return s
}
u -= 2
if s := (*Number)(unsafe.Pointer(&u)).format(); len(s) < 10 {
return s
}
return s
}
// Eval returns the number.
func (n Number) Eval(_ Scope) (Value, error) {
return n, nil
}
// Source returns a scanner locating the Number's source code.
func (n Number) Source() parser.Scanner {
return *parser.NewScanner("")
}
var numberKind = registerKind(100, reflect.TypeOf(Number(0)))
// Kind returns a number that is unique for each major kind of Value.
func (n Number) Kind() int {
return numberKind
}
// Bool returns true iff the tuple has attributes.
func (n Number) IsTrue() bool {
return n != 0
}
// Less returns true iff v is not a number or n < v.
func (n Number) Less(v Value) bool {
if n.Kind() != v.Kind() {
return n.Kind() < v.Kind()
}
return n < v.(Number)
}
// Negate returns -n.
func (n Number) Negate() Value {
if !n.IsTrue() {
return n
}
return NewNumber(-float64(n))
}
// Export exports a Number.
func (n Number) Export() interface{} {
return n.Float64()
}
func (n Number) Bind(scope Scope, value Value) (Scope, error) {
if !n.Equal(value) {
return EmptyScope, errors.Errorf("%s doesn't equal to %s, cannot bind these two numbers", n, value)
}
return EmptyScope, nil
}