1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package adt
16
17 import (
18 "fmt"
19 "strconv"
20 "strings"
21
22 "cuelang.org/go/cue/ast"
23 "cuelang.org/go/cue/errors"
24 "cuelang.org/go/cue/literal"
25 "cuelang.org/go/cue/token"
26 "cuelang.org/go/internal"
27 )
28
29
30
31 type Feature uint32
32
33
34
35
36 const (
37 InvalidLabel Feature = 0
38
39
40
41 MaxIndex = 1<<(32-indexShift) - 1
42 )
43
44
45 var (
46 AnyDefinition Feature = makeLabel(MaxIndex, DefinitionLabel)
47 AnyHidden Feature = makeLabel(MaxIndex, HiddenLabel)
48 AnyString Feature = makeLabel(MaxIndex, StringLabel)
49 AnyIndex Feature = makeLabel(MaxIndex, IntLabel)
50 )
51
52
53
54 type StringIndexer interface {
55
56
57
58
59 StringToIndex(s string) (index int64)
60
61
62 IndexToString(index int64) string
63
64
65 NextUniqueID() uint64
66 }
67
68
69
70 func (f Feature) SelectorString(index StringIndexer) string {
71 x := f.safeIndex()
72 switch f.Typ() {
73 case IntLabel:
74 if f == AnyIndex {
75 return "_"
76 }
77 return strconv.Itoa(int(x))
78 case StringLabel:
79 s := index.IndexToString(x)
80 if ast.IsValidIdent(s) && !internal.IsDefOrHidden(s) {
81 return s
82 }
83 if f == AnyString {
84 return "_"
85 }
86 return literal.String.Quote(s)
87 default:
88 return f.IdentString(index)
89 }
90 }
91
92
93
94 func (f Feature) IdentString(index StringIndexer) string {
95 s := index.IndexToString(f.safeIndex())
96 if f.IsHidden() || f.IsLet() {
97 if p := strings.IndexByte(s, '\x00'); p >= 0 {
98 s = s[:p]
99 }
100 }
101 return s
102 }
103
104
105
106
107 func (f Feature) PkgID(index StringIndexer) string {
108 if !f.IsHidden() {
109 return ""
110 }
111 s := index.IndexToString(f.safeIndex())
112 if p := strings.IndexByte(s, '\x00'); p >= 0 {
113 s = s[p+1:]
114 }
115 return s
116 }
117
118
119 func (f Feature) StringValue(index StringIndexer) string {
120 if !f.IsString() {
121 panic("not a string label")
122 }
123 x := f.safeIndex()
124 return index.IndexToString(x)
125 }
126
127
128 func (f Feature) RawString(index StringIndexer) string {
129 x := f.safeIndex()
130 return index.IndexToString(x)
131 }
132
133
134
135 func (f Feature) ToValue(ctx *OpContext) Value {
136 if !f.IsRegular() {
137 panic("not a regular label")
138 }
139
140 if f.IsInt() {
141 return ctx.NewInt64(int64(f.Index()))
142 }
143 x := f.safeIndex()
144 str := ctx.IndexToString(x)
145 return ctx.NewString(str)
146 }
147
148
149 func (c *OpContext) StringLabel(s string) Feature {
150 return LabelFromValue(c, nil, &String{Str: s})
151 }
152
153
154 func MakeStringLabel(r StringIndexer, s string) Feature {
155 i := r.StringToIndex(s)
156
157
158 f, err := MakeLabel(nil, i, StringLabel)
159 if err != nil {
160 panic("out of free string slots")
161 }
162 return f
163 }
164
165
166 func MakeIdentLabel(r StringIndexer, s, pkgpath string) Feature {
167 t := StringLabel
168 switch {
169 case strings.HasPrefix(s, "_#"):
170 t = HiddenDefinitionLabel
171 s = HiddenKey(s, pkgpath)
172 case strings.HasPrefix(s, "#"):
173 t = DefinitionLabel
174 case strings.HasPrefix(s, "_"):
175 s = HiddenKey(s, pkgpath)
176 t = HiddenLabel
177 }
178 i := r.StringToIndex(s)
179 f, err := MakeLabel(nil, i, t)
180 if err != nil {
181 panic("out of free string slots")
182 }
183 return f
184 }
185
186
187
188 func HiddenKey(s, pkgPath string) string {
189
190 return fmt.Sprintf("%s\x00%s", s, pkgPath)
191 }
192
193
194 func MakeNamedLabel(r StringIndexer, t FeatureType, s string) Feature {
195 i := r.StringToIndex(s)
196 f, err := MakeLabel(nil, i, t)
197 if err != nil {
198 panic("out of free string slots")
199 }
200 return f
201 }
202
203
204
205
206
207
208
209 func MakeLetLabel(r StringIndexer, s string) Feature {
210 id := r.NextUniqueID()
211 s = fmt.Sprintf("%s\x00%X", s, id)
212 i := r.StringToIndex(s)
213 f, err := MakeLabel(nil, i, LetLabel)
214 if err != nil {
215 panic("out of free string slots")
216 }
217 return f
218 }
219
220
221 func MakeIntLabel(t FeatureType, i int64) Feature {
222 f, err := MakeLabel(nil, i, t)
223 if err != nil {
224 panic("index out of range")
225 }
226 return f
227 }
228
229 const msgGround = "invalid non-ground value %s (must be concrete %s)"
230
231 func LabelFromValue(c *OpContext, src Expr, v Value) Feature {
232 v, _ = c.getDefault(v)
233
234 var i int64
235 var t FeatureType
236 if isError(v) {
237 return InvalidLabel
238 }
239 switch v.Kind() {
240 case IntKind, NumKind:
241 x, _ := Unwrap(v).(*Num)
242 if x == nil {
243 c.addErrf(IncompleteError, pos(v), msgGround, v, "int")
244 return InvalidLabel
245 }
246 t = IntLabel
247 var err error
248 i, err = x.X.Int64()
249 if err != nil || x.K != IntKind {
250 if src == nil {
251 src = v
252 }
253 c.AddErrf("invalid index %v: %v", src, err)
254 return InvalidLabel
255 }
256 if i < 0 {
257 switch src.(type) {
258 case nil, *Num, *UnaryExpr:
259
260
261 c.AddErrf("invalid index %v (index must be non-negative)", x)
262 default:
263
264 c.AddErrf("index %v out of range [%v]", src, x)
265 }
266 return InvalidLabel
267 }
268
269 case StringKind:
270 x, _ := Unwrap(v).(*String)
271 if x == nil {
272 c.addErrf(IncompleteError, pos(v), msgGround, v, "string")
273 return InvalidLabel
274 }
275 t = StringLabel
276 i = c.StringToIndex(x.Str)
277
278 default:
279 if src != nil {
280 c.AddErrf("invalid index %s (invalid type %v)", src, v.Kind())
281 } else {
282 c.AddErrf("invalid index type %v", v.Kind())
283 }
284 return InvalidLabel
285 }
286
287
288 f, err := MakeLabel(nil, i, t)
289 if err != nil {
290 c.AddErr(err)
291 }
292 return f
293 }
294
295
296 func MakeLabel(src ast.Node, index int64, f FeatureType) (Feature, errors.Error) {
297 if 0 > index || index > MaxIndex-1 {
298 p := token.NoPos
299 if src != nil {
300 p = src.Pos()
301 }
302 return InvalidLabel,
303 errors.Newf(p, "int label out of range (%d not >=0 and <= %d)",
304 index, MaxIndex-1)
305 }
306 return Feature(index)<<indexShift | Feature(f), nil
307 }
308
309 func makeLabel(index int64, f FeatureType) Feature {
310 return Feature(index)<<indexShift | Feature(f)
311 }
312
313
314 type FeatureType int8
315
316 const (
317 InvalidLabelType FeatureType = iota
318 StringLabel
319 IntLabel
320 DefinitionLabel
321 HiddenLabel
322 HiddenDefinitionLabel
323 LetLabel
324 )
325
326 const (
327 fTypeMask Feature = 0b1111
328
329 indexShift = 4
330 )
331
332 func (f FeatureType) IsDef() bool {
333 return f == DefinitionLabel || f == HiddenDefinitionLabel
334 }
335
336 func (f FeatureType) IsHidden() bool {
337 return f == HiddenLabel || f == HiddenDefinitionLabel
338 }
339
340 func (f FeatureType) IsLet() bool {
341 return f == LetLabel
342 }
343
344
345 func (f Feature) IsValid() bool { return f != InvalidLabel }
346
347
348 func (f Feature) Typ() FeatureType { return FeatureType(f & fTypeMask) }
349
350
351 func (f Feature) IsRegular() bool {
352 t := f.Typ()
353 return t == IntLabel || t == StringLabel
354 }
355
356
357 func (f Feature) IsString() bool { return f.Typ() == StringLabel }
358
359
360
361 func (f Feature) IsDef() bool {
362 return f.Typ().IsDef()
363 }
364
365
366 func (f Feature) IsInt() bool { return f.Typ() == IntLabel }
367
368
369
370 func (f Feature) IsHidden() bool {
371 return f.Typ().IsHidden()
372 }
373
374
375 func (f Feature) IsLet() bool {
376 return f.Typ().IsLet()
377 }
378
379
380 func (f Feature) Index() int {
381 return int(f >> indexShift)
382 }
383
384
385 func (f Feature) safeIndex() int64 {
386 x := int(f >> indexShift)
387 if x == MaxIndex {
388 x = 0
389 }
390 return int64(x)
391 }
392
393
394
395
View as plain text