blob: 8e5b3e05158ed8ee34e9a5648b8a1c897c7fa7e6 [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// Copyright 2018 The CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cue
16
17import (
18 "math/big"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010019
20 "cuelang.org/go/cue/ast"
21 "cuelang.org/go/cue/errors"
Marcel van Lohuizen6ceb6012019-02-18 18:30:38 +010022 "cuelang.org/go/cue/literal"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010023 "github.com/cockroachdb/apd"
24)
25
26// errRange indicates that a value is out of range for the target type.
27var errRange = errors.New("value out of range")
28
29// errSyntax indicates that a value does not have the right syntax for the
30// target type.
31var errSyntax = errors.New("invalid syntax")
32
33var errInvalidString = errors.New("invalid string")
34
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010035type numInfo struct {
36 rep multiplier
37 k kind
38}
39
40func newNumInfo(k kind, m multiplier, base int, sep bool) numInfo {
41 switch base {
42 case 10:
43 m |= base10
44 case 2:
45 m |= base2
46 k = intKind
47 case 8:
48 m |= base8
49 k = intKind
50 case 16:
51 m |= base16
52 k = intKind
53 }
54 if sep {
55 m |= hasSeparators
56 }
57 return numInfo{m, k}
58}
59
60func unifyNuminfo(a, b numInfo) numInfo {
61 k := unifyType(a.k, b.k)
62 return numInfo{a.rep | b.rep, k}
63}
64
65func (n numInfo) isValid() bool { return n.k != bottomKind }
66func (n numInfo) multiplier() multiplier { return n.rep & (hasSeparators - 1) }
67
68type multiplier uint16
69
70const (
71 mul1 multiplier = 1 << iota
72 mul2
73 mul3
74 mul4
75 mul5
76 mul6
77 mul7
78 mul8
79
80 mulBin
81 mulDec
82
83 // _ 3 for dec, 4 for hex. Maybe support first and rest, like CLDR.
84 hasSeparators
85
86 base2
87 base8
88 base10
89 base16
90
91 mulK = mulDec | mul1
92 mulM = mulDec | mul2
93 mulG = mulDec | mul3
94 mulT = mulDec | mul4
95 mulP = mulDec | mul5
96 mulE = mulDec | mul6
97 mulZ = mulDec | mul7
98 mulY = mulDec | mul8
99
100 mulKi = mulBin | mul1
101 mulMi = mulBin | mul2
102 mulGi = mulBin | mul3
103 mulTi = mulBin | mul4
104 mulPi = mulBin | mul5
105 mulEi = mulBin | mul6
106 mulZi = mulBin | mul7
107 mulYi = mulBin | mul8
108)
109
110type litParser struct {
111 ctx *context
112 node *ast.BasicLit
113 src string
114 p int
115 // pDot int // first position after the dot, if any
116 ch byte
117 useSep bool
118 buf []byte
119 err value
120}
121
122func (p *litParser) error(l ast.Node, args ...interface{}) value {
123 return p.ctx.mkErr(newNode(l), args...)
124}
125
126func (p *litParser) next() bool {
127 if p.p >= len(p.src) {
128 p.ch = 0
129 return false
130 }
131 p.ch = p.src[p.p]
132 p.p++
133 if p.ch == '.' {
134 p.buf = append(p.buf, '.')
135
136 }
137 return true
138}
139
140func (p *litParser) init(l *ast.BasicLit) (err value) {
141 s := l.Value
142 b := p.buf
143 *p = litParser{ctx: p.ctx, node: l, src: s}
144 p.buf = b[:0]
145 if !p.next() {
146 return p.error(l, "invalid literal %q", s)
147 }
148 return nil
149}
150
151func (p *litParser) parse(l *ast.BasicLit) (n value) {
152 s := l.Value
153 switch s {
154 case "null":
155 return &nullLit{newExpr(l)}
156 case "true":
157 return &boolLit{newExpr(l), true}
158 case "false":
159 return &boolLit{newExpr(l), false}
160 }
161 if err := p.init(l); err != nil {
162 return err
163 }
164 switch p.ch {
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400165 case '"', '\'', '`', '#':
Marcel van Lohuizen6ceb6012019-02-18 18:30:38 +0100166 info, nStart, _, err := literal.ParseQuotes(s, s)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100167 if err != nil {
168 return p.error(l, err.Error())
169 }
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400170 s := p.src[nStart:]
171 return parseString(p.ctx, p.node, info, s)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100172 case '.':
173 p.next()
174 n = p.scanNumber(true)
175 default:
176 n = p.scanNumber(false)
177 }
178 if p.err != nil {
179 return p.err
180 }
181 if p.p < len(p.src) {
182 return p.error(l, "invalid number")
183 }
184 return n
185}
186
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400187// parseString decodes a string without the starting and ending quotes.
Marcel van Lohuizen6ceb6012019-02-18 18:30:38 +0100188func parseString(ctx *context, node ast.Expr, q literal.QuoteInfo, s string) (n value) {
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400189 src := newExpr(node)
190 str, err := q.Unquote(s)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100191 if err != nil {
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400192 return ctx.mkErr(src, err, "invalid string: %v", err)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100193 }
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400194 if q.IsDouble() {
195 return &stringLit{src, str}
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100196 }
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400197 return &bytesLit{src, []byte(str)}
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100198}
199
200func (p *litParser) digitVal(ch byte) (d int) {
201 switch {
202 case '0' <= ch && ch <= '9':
203 d = int(ch - '0')
204 case ch == '_':
205 p.useSep = true
206 return 0
207 case 'a' <= ch && ch <= 'f':
208 d = int(ch - 'a' + 10)
209 case 'A' <= ch && ch <= 'F':
210 d = int(ch - 'A' + 10)
211 default:
212 return 16 // larger than any legal digit val
213 }
214 return d
215}
216
217func (p *litParser) scanMantissa(base int) {
218 var last byte
219 for p.digitVal(p.ch) < base {
220 if p.ch != '_' {
221 p.buf = append(p.buf, p.ch)
222 }
223 last = p.ch
224 p.next()
225 }
226 if last == '_' {
227 p.err = p.error(p.node, "illegal '_' in number")
228 }
229}
230
231func (p *litParser) scanNumber(seenDecimalPoint bool) value {
232 // digitVal(s.ch) < 10
233 isFloat := false
234 base := 10
235
236 if seenDecimalPoint {
237 isFloat = true
238 p.scanMantissa(10)
239 goto exponent
240 }
241
242 if p.ch == '0' {
243 // int or float
244 p.next()
245 if p.ch == 'x' || p.ch == 'X' {
246 base = 16
247 // hexadecimal int
248 p.next()
249 p.scanMantissa(16)
250 if p.p <= 2 {
251 // only scanned "0x" or "0X"
252 return p.error(p.node, "illegal hexadecimal number %q", p.src)
253 }
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100254 } else if p.ch == 'b' {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100255 base = 2
256 // binary int
257 p.next()
258 p.scanMantissa(2)
259 if p.p <= 2 {
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100260 // only scanned "0b"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100261 return p.error(p.node, "illegal binary number %q", p.src)
262 }
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100263 } else if p.ch == 'o' {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100264 base = 8
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100265 // octal int
266 p.next()
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100267 p.scanMantissa(8)
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100268 if p.p <= 2 {
269 // only scanned "0o"
270 return p.error(p.node, "illegal octal number %q", p.src)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100271 }
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100272 } else {
273 // int or float
274 p.scanMantissa(10)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100275 if p.ch == '.' || p.ch == 'e' {
276 goto fraction
277 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100278 }
279 goto exit
280 }
281
282 // decimal int or float
283 p.scanMantissa(10)
284
285 // TODO: allow 3h4s, etc.
286 // switch p.ch {
287 // case 'h', 'm', 's', "ยต"[0], 'u', 'n':
288 // }
289
290fraction:
291 if p.ch == '.' {
292 isFloat = true
293 p.next()
294 p.scanMantissa(10)
295 }
296
297exponent:
298 switch p.ch {
299 case 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y':
300 mul := charToMul[p.ch]
301 p.next()
302 if p.ch == 'i' {
303 mul |= mulBin
304 p.next()
305 } else {
306 mul |= mulDec
307 }
308 n := &numLit{
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200309 numBase: newNumBase(p.node, newNumInfo(intKind, mul, 10, p.useSep)),
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100310 }
311 n.v.UnmarshalText(p.buf)
312 p.ctx.Mul(&n.v, &n.v, mulToRat[mul])
313 cond, _ := p.ctx.RoundToIntegralExact(&n.v, &n.v)
314 if cond.Inexact() {
315 return p.error(p.node, "number cannot be represented as int")
316 }
317 return n
318
319 case 'e':
320 isFloat = true
321 p.next()
322 p.buf = append(p.buf, 'e')
323 if p.ch == '-' || p.ch == '+' {
324 p.buf = append(p.buf, p.ch)
325 p.next()
326 }
327 p.scanMantissa(10)
328 }
329
330exit:
331 if isFloat {
332 f := &numLit{
333 numBase: newNumBase(p.node, newNumInfo(floatKind, 0, 10, p.useSep)),
334 }
335 f.v.UnmarshalText(p.buf)
336 return f
337 }
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200338 i := &numLit{numBase: newNumBase(p.node, newNumInfo(intKind, 0, base, p.useSep))}
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100339 i.v.Coeff.SetString(string(p.buf), base)
340 return i
341}
342
343type mulInfo struct {
344 fact *big.Rat
345 mul multiplier
346}
347
348var charToMul = map[byte]multiplier{
349 'K': mul1,
350 'M': mul2,
351 'G': mul3,
352 'T': mul4,
353 'P': mul5,
354 'E': mul6,
355 'Z': mul7,
356 'Y': mul8,
357}
358
359var mulToRat = map[multiplier]*apd.Decimal{}
360
361func init() {
362 d := apd.New(1, 0)
363 b := apd.New(1, 0)
364 dm := apd.New(1000, 0)
365 bm := apd.New(1024, 0)
366
367 c := apd.BaseContext
368 for i := uint(0); int(i) < len(charToMul); i++ {
369 // TODO: may we write to one of the sources?
370 var bn, dn apd.Decimal
371 c.Mul(&dn, d, dm)
372 d = &dn
373 c.Mul(&bn, b, bm)
374 b = &bn
375 mulToRat[mulDec|1<<i] = d
376 mulToRat[mulBin|1<<i] = b
377 }
378}