-
Notifications
You must be signed in to change notification settings - Fork 0
/
number.go
141 lines (128 loc) · 2.57 KB
/
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package prim
import (
"fmt"
)
type Number struct {
Value uint64
Size int
Signed bool
}
func NewNumber(val uint64, size int, signed bool) *Number {
n := &Number{Value: 0, Size: size, Signed: signed}
n.Set(val)
return n
}
func (n Number) Clone() *Number {
ret := &Number{}
*ret = n
return ret
}
func (n *Number) Set(val uint64) *Number {
if n.Signed {
// sign extend
mask := uint64(0xFFFFFFFFFFFFFF80) << uint64(8*(n.Size-1))
if (mask & val) != 0 {
val |= mask
}
} else {
// remove unused bits
mask := uint64(0xFFFFFFFFFFFFFFFF) << uint64(8*n.Size)
val = val & ^mask
}
n.Value = val
return n
}
func (n *Number) Binary(o Primitive, op Operation) (Primitive, error) {
m := o.(*Number)
// comparison
switch op {
case EQ:
return NewBoolean(n.Value == m.Value), nil
case NE:
return NewBoolean(n.Value != m.Value), nil
case GT:
return NewBoolean(n.Value > m.Value), nil
case GE:
return NewBoolean(n.Value >= m.Value), nil
case LE:
return NewBoolean(n.Value <= m.Value), nil
case LT:
return NewBoolean(n.Value < m.Value), nil
case BAND:
return NewBoolean(n.Value != 0 && m.Value != 0), nil
case BOR:
return NewBoolean(n.Value != 0 || m.Value != 0), nil
}
// arith and logic
ret := n.Clone()
switch op {
case ADD:
ret.Set(n.Value + m.Value)
case SUB:
ret.Set(n.Value - m.Value)
case DIV:
if m.Value == 0 {
return nil, fmt.Errorf("division by zero")
}
ret.Set(n.Value / m.Value)
case MOD:
if m.Value == 0 {
return nil, fmt.Errorf("division by zero")
}
ret.Set(n.Value % m.Value)
case MUL:
ret.Set(n.Value * m.Value)
case AND:
ret.Set(n.Value & m.Value)
case OR:
ret.Set(n.Value | m.Value)
case XOR:
ret.Set(n.Value ^ m.Value)
case LSL:
ret.Set(n.Value << m.Value)
case LSR:
ret.Set(n.Value >> m.Value)
default:
return nil, fmt.Errorf("Unknown number binary operation: %v", op)
}
return ret, nil
}
func (n *Number) Unary(op Operation) (Primitive, error) {
ret := n.Clone()
switch op {
case NEG, SUB:
ret.Set(-n.Value)
case INV:
ret.Set(^n.Value)
default:
return nil, fmt.Errorf("Unknown number unary operation: %v", op)
}
return ret, nil
}
func (n *Number) Get() interface{} {
if !n.Signed {
switch n.Size {
case 1:
return uint8(n.Value)
case 2:
return uint16(n.Value)
case 4:
return uint32(n.Value)
default:
return uint64(n.Value)
}
} else {
switch n.Size {
case 1:
return int8(n.Value)
case 2:
return int16(n.Value)
case 4:
return int32(n.Value)
default:
return int64(n.Value)
}
}
}
// type assertion Number -> Primitive
var _ Primitive = (*Number)(nil)