This repository has been archived by the owner on Jan 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kind.go
328 lines (307 loc) · 7.16 KB
/
kind.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
package typ
import (
"fmt"
"github.com/mb0/xelf/bfr"
)
// Kind is a bit-set describing a type. It represents all type information except reference names
// and type parameters. It is a handy implementation detail, but not part of the xelf specification.
type Kind uint64
func (Kind) Bits() map[string]int64 { return kindConsts }
// A Kind describes a type in a slot that uses the 12 least significant bits. The rest of the bits
// are reserved to be used by specific types. Type variables use it to store a unique type id and
// other types might use it in the future to optimization access the most important type parameter
// details without chasing pointers.
const (
SlotSize = 12
SlotMask = 0xfff
)
// Each bit in a slot has a certain meaning. The first six bits specify a base type, next two bits
// flag the type a context or optional variant.
const (
KindNum Kind = 1 << iota // 0x001
KindChar // 0x002
KindIdxr // 0x004
KindKeyr // 0x008
KindExpr // 0x010
KindMeta // 0x020
KindCtx // 0x040
KindOpt // 0x080
KindBit1 // 0x100
KindBit2 // 0x200
KindBit3 // 0x400
KindBit4 // 0x800
)
const (
MaskUber = KindExpr | KindMeta // 0000 0011 0000
MaskBits = 0xf00 // 1111 0000 0000
MaskBase = KindAny | MaskUber // 0000 0011 1111
MaskElem = MaskBase | MaskBits // 1111 0011 1111
MaskRef = MaskElem | KindCtx // 1111 0111 1111
)
const (
KindVoid = 0x00
KindPrim = KindNum | KindChar // 0000 0000 0011
KindCont = KindIdxr | KindKeyr // 0000 0000 1100
KindAny = KindPrim | KindCont // 0000 0000 1111
KindBool = KindNum | KindBit1 // 0x101
KindInt = KindNum | KindBit2 // 0x201
KindReal = KindNum | KindBit3 // 0x401
KindSpan = KindNum | KindBit4 // 0x801
KindStr = KindChar | KindBit1 // 0x102
KindRaw = KindChar | KindBit2 // 0x202
KindUUID = KindChar | KindBit3 // 0x402
KindTime = KindChar | KindBit4 // 0x802
KindList = KindIdxr | KindBit1 // 0x104
KindDict = KindKeyr | KindBit2 // 0x208
KindRec = KindCont | KindBit3 // 0x30c
KindBits = KindCtx | KindInt // 0x241
KindEnum = KindCtx | KindStr // 0x142
KindObj = KindCtx | KindRec // 0x34c
KindTyp = KindExpr | KindBit1 // 0x110
KindFunc = KindExpr | KindBit2 // 0x210
KindDyn = KindExpr | KindBit3 // 0x410
KindTag = KindExpr | KindBit4 // 0x810
KindForm = KindCtx | KindFunc // 0x250
KindCall = KindCtx | KindDyn // 0x450
KindSym = KindCtx | KindTag // 0x850
KindVar = KindMeta | KindBit1 // 0x120
KindRef = KindMeta | KindBit2 // 0x220
KindSch = KindMeta | KindBit3 // 0x420
KindAlt = KindMeta | KindBit4 // 0x820
)
func ParseKind(str string) (Kind, error) {
if len(str) == 0 {
return KindVoid, ErrInvalid
}
// we allow the schema prefix for all types
// outside an explicit type context non-prominent types must use the prefix
pref := str[0] == '~'
if pref {
str = str[1:]
}
switch str {
case "void":
return KindVoid, nil
case "any":
return KindAny, nil
case "typ":
return KindTyp, nil
case "idxr":
return KindIdxr, nil
case "keyr":
return KindKeyr, nil
case "cont":
return KindCont, nil
case "expr":
return KindExpr, nil
case "list":
return KindList, nil
case "dict":
return KindDict, nil
case "sym":
return KindSym, nil
case "dyn":
return KindDyn, nil
case "call":
return KindCall, nil
case "form":
return KindForm, nil
case "func":
return KindFunc, nil
case "named":
return KindTag, nil
case "alt":
return KindAlt, nil
}
var kk Kind
if str[len(str)-1] == '?' {
str = str[:len(str)-1]
kk = KindOpt
}
if len(str) > 5 {
return KindVoid, ErrInvalid
}
switch str {
case "num":
return kk | KindNum, nil
case "char":
return kk | KindChar, nil
case "prim":
return kk | KindPrim, nil
case "bool":
return kk | KindBool, nil
case "int":
return kk | KindInt, nil
case "real":
return kk | KindReal, nil
case "str":
return kk | KindStr, nil
case "raw":
return kk | KindRaw, nil
case "uuid":
return kk | KindUUID, nil
case "time":
return kk | KindTime, nil
case "span":
return kk | KindSpan, nil
case "rec":
return kk | KindRec, nil
case "bits":
return kk | KindBits, nil
case "enum":
return kk | KindEnum, nil
case "obj":
return kk | KindObj, nil
}
return KindVoid, ErrInvalid
}
func (k Kind) WriteBfr(b *bfr.Ctx) (err error) {
str := simpleStr(k)
if str != "" {
err = b.Fmt(str)
if k != KindAny && k&KindOpt != 0 {
err = b.WriteByte('?')
}
return err
}
return nil
}
func (k Kind) String() string {
str := simpleStr(k)
if str != "" {
if k != KindAny && k&KindOpt != 0 {
return str + "?"
}
return str
}
return "invalid"
}
func (k Kind) MarshalText() ([]byte, error) {
return []byte(k.String()), nil
}
func (k *Kind) UnmarshalText(txt []byte) error {
kk, err := ParseKind(string(txt))
*k = kk
return err
}
func simpleStr(k Kind) string {
switch k & SlotMask {
case KindVoid:
return "void"
case KindAny:
return "any"
case KindTyp:
return "typ"
case KindForm:
return "form"
case KindFunc:
return "func"
case KindDyn:
return "dyn"
case KindCall:
return "call"
case KindTag:
return "named"
case KindSym:
return "sym"
case KindVar:
id := k >> SlotSize
if id == 0 {
return "@"
}
return fmt.Sprintf("@%d", k>>SlotSize)
case KindAlt:
return "alt"
case KindIdxr:
return "idxr"
case KindKeyr:
return "keyr"
case KindCont:
return "cont"
case KindExpr:
return "expr"
case KindMeta:
return "meta"
case KindList:
return "list"
case KindDict:
return "dict"
}
switch k & MaskRef {
case KindRef:
return "@"
case KindSch:
return "~"
case KindNum:
return "num"
case KindChar:
return "char"
case KindBool:
return "bool"
case KindInt:
return "int"
case KindReal:
return "real"
case KindStr:
return "str"
case KindRaw:
return "raw"
case KindUUID:
return "uuid"
case KindTime:
return "time"
case KindSpan:
return "span"
case KindRec:
return "rec"
case KindBits:
return "bits"
case KindEnum:
return "enum"
case KindObj:
return "obj"
}
return ""
}
var kindConsts = map[string]int64{
"Num": int64(KindNum),
"Char": int64(KindChar),
"Idxr": int64(KindIdxr),
"Keyr": int64(KindKeyr),
"Expr": int64(KindExpr),
"Meta": int64(KindMeta),
"Ctx": int64(KindCtx),
"Opt": int64(KindOpt),
"Bit1": int64(KindBit1),
"Bit2": int64(KindBit2),
"Bit3": int64(KindBit3),
"Bit4": int64(KindBit4),
"Void": int64(KindVoid),
"Prim": int64(KindPrim),
"Cont": int64(KindCont),
"Any": int64(KindAny),
"Bool": int64(KindBool),
"Int": int64(KindInt),
"Real": int64(KindReal),
"Span": int64(KindSpan),
"Str": int64(KindStr),
"Raw": int64(KindRaw),
"UUID": int64(KindUUID),
"Time": int64(KindTime),
"List": int64(KindList),
"Dict": int64(KindDict),
"Rec": int64(KindRec),
"Bits": int64(KindBits),
"Enum": int64(KindEnum),
"Obj": int64(KindObj),
"Typ": int64(KindTyp),
"Func": int64(KindFunc),
"Form": int64(KindForm),
"Dyn": int64(KindDyn),
"Call": int64(KindDyn),
"Named": int64(KindTag),
"Sym": int64(KindSym),
"Var": int64(KindVar),
"Ref": int64(KindRef),
"Alt": int64(KindAlt),
}