1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package literal
16
17 import (
18 "cuelang.org/go/cue/errors"
19 "cuelang.org/go/cue/token"
20 "github.com/cockroachdb/apd/v3"
21 )
22
23
24 var baseContext apd.Context
25
26 func init() {
27 baseContext = apd.BaseContext
28 baseContext.Precision = 34
29 }
30
31
32
33
34 type NumInfo struct {
35 pos token.Pos
36 src string
37 p int
38 ch byte
39 buf []byte
40
41 mul Multiplier
42 base byte
43 neg bool
44 UseSep bool
45 isFloat bool
46 err error
47 }
48
49
50
51 func (p *NumInfo) String() string {
52 if len(p.buf) > 0 && p.base == 10 && p.mul == 0 {
53 return string(p.buf)
54 }
55 var d apd.Decimal
56 _ = p.decimal(&d)
57 return d.String()
58 }
59
60 type decimal = apd.Decimal
61
62
63 func (p *NumInfo) Decimal(v *decimal) error {
64 return p.decimal(v)
65 }
66
67 func (p *NumInfo) decimal(v *apd.Decimal) error {
68 if p.base != 10 {
69 _, _, _ = v.SetString("0")
70 b := p.buf
71 if p.buf[0] == '-' {
72 v.Negative = p.neg
73 b = p.buf[1:]
74 }
75 v.Coeff.SetString(string(b), int(p.base))
76 return nil
77 }
78 _ = v.UnmarshalText(p.buf)
79 if p.mul != 0 {
80 _, _ = baseContext.Mul(v, v, mulToRat[p.mul])
81 cond, _ := baseContext.RoundToIntegralExact(v, v)
82 if cond.Inexact() {
83 return p.errorf("number cannot be represented as int")
84 }
85 }
86 return nil
87 }
88
89
90 func (p *NumInfo) Multiplier() Multiplier {
91 return p.mul
92 }
93
94
95 func (p *NumInfo) IsInt() bool {
96 return !p.isFloat
97 }
98
99
100 func ParseNum(s string, n *NumInfo) error {
101 *n = NumInfo{pos: n.pos, src: s, buf: n.buf[:0]}
102 if !n.next() {
103 return n.errorf("invalid number %q", s)
104 }
105 if n.ch == '-' {
106 n.neg = true
107 n.buf = append(n.buf, '-')
108 n.next()
109 }
110 seenDecimalPoint := false
111 if n.ch == '.' {
112 n.next()
113 seenDecimalPoint = true
114 }
115 err := n.scanNumber(seenDecimalPoint)
116 if err != nil {
117 return err
118 }
119 if n.err != nil {
120 return n.err
121 }
122 if n.p < len(n.src) {
123 return n.errorf("invalid number %q", s)
124 }
125 if len(n.buf) == 0 {
126 n.buf = append(n.buf, '0')
127 }
128 return nil
129 }
130
131 func (p *NumInfo) errorf(format string, args ...interface{}) error {
132 return errors.Newf(p.pos, format, args...)
133 }
134
135
136 type Multiplier byte
137
138 const (
139 mul1 Multiplier = 1 + iota
140 mul2
141 mul3
142 mul4
143 mul5
144 mul6
145 mul7
146 mul8
147
148 mulBin = 0x10
149 mulDec = 0x20
150
151 K = mulDec | mul1
152 M = mulDec | mul2
153 G = mulDec | mul3
154 T = mulDec | mul4
155 P = mulDec | mul5
156 E = mulDec | mul6
157 Z = mulDec | mul7
158 Y = mulDec | mul8
159
160 Ki = mulBin | mul1
161 Mi = mulBin | mul2
162 Gi = mulBin | mul3
163 Ti = mulBin | mul4
164 Pi = mulBin | mul5
165 Ei = mulBin | mul6
166 Zi = mulBin | mul7
167 Yi = mulBin | mul8
168 )
169
170 func (p *NumInfo) next() bool {
171 if p.p >= len(p.src) {
172 p.ch = 0
173 return false
174 }
175 p.ch = p.src[p.p]
176 p.p++
177 if p.ch == '.' {
178 if len(p.buf) == 0 {
179 p.buf = append(p.buf, '0')
180 }
181 p.buf = append(p.buf, '.')
182 }
183 return true
184 }
185
186 func (p *NumInfo) digitVal(ch byte) (d int) {
187 switch {
188 case '0' <= ch && ch <= '9':
189 d = int(ch - '0')
190 case ch == '_':
191 p.UseSep = true
192 return 0
193 case 'a' <= ch && ch <= 'f':
194 d = int(ch - 'a' + 10)
195 case 'A' <= ch && ch <= 'F':
196 d = int(ch - 'A' + 10)
197 default:
198 return 16
199 }
200 return d
201 }
202
203 func (p *NumInfo) scanMantissa(base int) bool {
204 hasDigit := false
205 var last byte
206 for p.digitVal(p.ch) < base {
207 if p.ch != '_' {
208 p.buf = append(p.buf, p.ch)
209 hasDigit = true
210 }
211 last = p.ch
212 p.next()
213 }
214 if last == '_' {
215 p.err = p.errorf("illegal '_' in number")
216 }
217 return hasDigit
218 }
219
220 func (p *NumInfo) scanNumber(seenDecimalPoint bool) error {
221 p.base = 10
222
223 if seenDecimalPoint {
224 p.isFloat = true
225 if !p.scanMantissa(10) {
226 return p.errorf("illegal fraction %q", p.src)
227 }
228 goto exponent
229 }
230
231 if p.ch == '0' {
232
233 p.next()
234 switch p.ch {
235 case 'x', 'X':
236 p.base = 16
237
238 p.next()
239 if !p.scanMantissa(16) {
240
241 return p.errorf("illegal hexadecimal number %q", p.src)
242 }
243 case 'b':
244 p.base = 2
245
246 p.next()
247 if !p.scanMantissa(2) {
248
249 return p.errorf("illegal binary number %q", p.src)
250 }
251 case 'o':
252 p.base = 8
253
254 p.next()
255 if !p.scanMantissa(8) {
256
257 return p.errorf("illegal octal number %q", p.src)
258 }
259 default:
260
261 p.scanMantissa(8)
262 if p.ch == '8' || p.ch == '9' {
263 p.scanMantissa(10)
264 if p.ch != '.' && p.ch != 'e' && p.ch != 'E' {
265 return p.errorf("illegal integer number %q", p.src)
266 }
267 }
268 switch p.ch {
269 case 'e', 'E':
270 if len(p.buf) == 0 {
271 p.buf = append(p.buf, '0')
272 }
273 fallthrough
274 case '.':
275 goto fraction
276 }
277 if len(p.buf) > 0 {
278 p.base = 8
279 }
280 }
281 goto exit
282 }
283
284
285 if !p.scanMantissa(10) {
286 return p.errorf("illegal number start %q", p.src)
287 }
288
289 fraction:
290 if p.ch == '.' {
291 p.isFloat = true
292 p.next()
293 p.scanMantissa(10)
294 }
295
296 exponent:
297 switch p.ch {
298 case 'K', 'M', 'G', 'T', 'P':
299 p.mul = charToMul[p.ch]
300 p.next()
301 if p.ch == 'i' {
302 p.mul |= mulBin
303 p.next()
304 } else {
305 p.mul |= mulDec
306 }
307 var v apd.Decimal
308 p.isFloat = false
309 return p.decimal(&v)
310
311 case 'e', 'E':
312 p.isFloat = true
313 p.next()
314 p.buf = append(p.buf, 'e')
315 if p.ch == '-' || p.ch == '+' {
316 p.buf = append(p.buf, p.ch)
317 p.next()
318 }
319 if !p.scanMantissa(10) {
320 return p.errorf("illegal exponent %q", p.src)
321 }
322 }
323
324 exit:
325 return nil
326 }
327
328 var charToMul = map[byte]Multiplier{
329 'K': mul1,
330 'M': mul2,
331 'G': mul3,
332 'T': mul4,
333 'P': mul5,
334 'E': mul6,
335 'Z': mul7,
336 'Y': mul8,
337 }
338
339 var mulToRat = map[Multiplier]*apd.Decimal{}
340
341 func init() {
342 d := apd.New(1, 0)
343 b := apd.New(1, 0)
344 dm := apd.New(1000, 0)
345 bm := apd.New(1024, 0)
346
347 c := apd.BaseContext
348 for i := Multiplier(1); int(i) < len(charToMul); i++ {
349
350 var bn, dn apd.Decimal
351 _, _ = c.Mul(&dn, d, dm)
352 d = &dn
353 _, _ = c.Mul(&bn, b, bm)
354 b = &bn
355 mulToRat[mulDec|i] = d
356 mulToRat[mulBin|i] = b
357 }
358 }
359
View as plain text