tc_universe.mx raw
1 package types
2
3 import "git.smesh.lol/moxie/pkg/mxutil"
4
5 // UniverseState holds all predeclared type system state.
6 // Owned by the caller. No globals - all access through this struct.
7 type UniverseState struct {
8 Scope *Scope
9 Typ [UntypedNil + 1]*Basic
10 Error *TypeName
11 Registry map[string]*TCPackage
12 DirectImports map[string][]string
13 ByName map[string]*TCPackage // name -> package cache
14 byNameSeq int32
15 }
16
17 // LookupByName returns the package with the given short name, or nil.
18 func (u *UniverseState) LookupByName(name string) (pkg *TCPackage) {
19 if u.ByName == nil || u.byNameSeq != int32(len(u.Registry)) {
20 u.ByName = map[string]*TCPackage{}
21 for _, p := range u.Registry {
22 if p != nil {
23 u.ByName[p.Name] = p
24 }
25 }
26 u.byNameSeq = int32(len(u.Registry))
27 }
28 return u.ByName[name]
29 }
30
31 // Global bridge - DEPRECATED. Will be removed once all call sites
32 // thread UniverseState as a parameter. Do not add new reads.
33 var Universe *Scope
34 var Typ [UntypedNil + 1]*Basic
35 var universeError *TypeName
36
37
38 // InitUniverse creates the universe scope with predeclared types.
39 // Returns all products. Caller owns the returned state.
40 // Also sets globals for backward compat during migration.
41 func InitUniverse() (u *UniverseState) {
42 if Universe != nil {
43 return &UniverseState{
44 Scope: Universe,
45 Typ: Typ,
46 Error: universeError,
47 Registry: ImportRegistry,
48 DirectImports: PkgDirectImports,
49 }
50 }
51 return buildUniverse()
52 }
53
54 // SetUniverseGlobals sets the package-level globals from a UniverseState.
55 // Called by the program's main after receiving the return value from
56 // InitUniverse. The caller's arena owns the data.
57 func SetUniverseGlobals(u *UniverseState) {
58 Universe = u.Scope
59 Typ = u.Typ
60 universeError = u.Error
61 ImportRegistry = u.Registry
62 PkgDirectImports = u.DirectImports
63 }
64
65 // buildUniverse constructs the universe scope. No globals touched.
66 // All products returned by value.
67 func buildUniverse() (u *UniverseState) {
68 u = &UniverseState{}
69 u.Registry = map[string]*TCPackage{}
70 u.DirectImports = map[string][]string{}
71 u.Scope = NewScope(nil)
72
73 // Initialize Basic types in Typ table.
74 infos := [...]struct {
75 kind BasicKind
76 info BasicInfo
77 name string
78 }{
79 {Invalid, 0, "invalid type"},
80
81 {Bool, IsBoolean, "bool"},
82
83 {Int8, IsInteger | IsOrdered | IsNumeric, "int8"},
84 {Int16, IsInteger | IsOrdered | IsNumeric, "int16"},
85 {Int32, IsInteger | IsOrdered | IsNumeric, "int32"},
86 {Int64, IsInteger | IsOrdered | IsNumeric, "int64"},
87 {Uint8, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint8"},
88 {Uint16, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint16"},
89 {Uint32, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint32"},
90 {Uint64, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint64"},
91
92 {Float32, IsFloat | IsOrdered | IsNumeric, "float32"},
93 {Float64, IsFloat | IsOrdered | IsNumeric, "float64"},
94
95 // string and []byte share kind TCString in Moxie.
96 {TCString, IsString | IsOrdered, "string"},
97
98 {UnsafePointer, 0, "Pointer"}, // lives in unsafe package
99
100 {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
101 {UntypedInt, IsInteger | IsNumeric | IsUntyped, "untyped int32"},
102 {UntypedRune, IsInteger | IsNumeric | IsUntyped, "untyped rune"},
103 {UntypedFloat, IsFloat | IsNumeric | IsUntyped, "untyped float"},
104 {UntypedString, IsString | IsUntyped, "untyped string"},
105 {UntypedNil, IsUntyped, "untyped nil"},
106 }
107 for i, info := range infos {
108 u.Typ[i] = &Basic{Kind: info.kind, Info: info.info, Name: info.name}
109 }
110
111 s := u.Scope
112 s.Insert(NewTypeName(nil, "bool", u.Typ[Bool]))
113 s.Insert(NewTypeName(nil, "int8", u.Typ[Int8]))
114 s.Insert(NewTypeName(nil, "int16", u.Typ[Int16]))
115 s.Insert(NewTypeName(nil, "int32", u.Typ[Int32]))
116 s.Insert(NewTypeName(nil, "int64", u.Typ[Int64]))
117 s.Insert(NewTypeName(nil, "uint8", u.Typ[Uint8]))
118 s.Insert(NewTypeName(nil, "uint16", u.Typ[Uint16]))
119 s.Insert(NewTypeName(nil, "uint32", u.Typ[Uint32]))
120 s.Insert(NewTypeName(nil, "uint64", u.Typ[Uint64]))
121 s.Insert(NewTypeName(nil, "float32", u.Typ[Float32]))
122 s.Insert(NewTypeName(nil, "float64", u.Typ[Float64]))
123 s.Insert(NewTypeName(nil, "string", u.Typ[TCString]))
124
125 for _, b := range []*Basic{
126 u.Typ[Bool],
127 u.Typ[Int8], u.Typ[Int16], u.Typ[Int32], u.Typ[Int64],
128 u.Typ[Uint8], u.Typ[Uint16], u.Typ[Uint32], u.Typ[Uint64],
129 u.Typ[Float32], u.Typ[Float64],
130 u.Typ[TCString],
131 } {
132 addBasicStringMethod(b, u.Typ[TCString])
133 }
134
135 byteType := NewNamed(NewTypeName(nil, "byte", nil), u.Typ[Uint8])
136 s.Insert(byteType.Obj)
137 byteType.Obj.Typ = byteType
138 addStringMethod(byteType, u.Typ[TCString])
139
140 runeType := NewNamed(NewTypeName(nil, "rune", nil), u.Typ[Int32])
141 s.Insert(runeType.Obj)
142 runeType.Obj.Typ = runeType
143 addStringMethod(runeType, u.Typ[TCString])
144
145 uintptrUnderlying := u.Typ[Uint64]
146 if mxutil.TargetArch == "wasm" {
147 uintptrUnderlying = u.Typ[Uint32]
148 }
149 uintptrType := NewNamed(NewTypeName(nil, "uintptr", nil), uintptrUnderlying)
150 s.Insert(uintptrType.Obj)
151 uintptrType.Obj.Typ = uintptrType
152 addStringMethod(uintptrType, u.Typ[TCString])
153
154 errSig := NewSignature(nil, nil, NewTuple(NewTCVar(nil, "", u.Typ[TCString])), false)
155 strMeth := &IfaceMethod{Name: "String", Sig: errSig}
156 errMeth := &IfaceMethod{Name: "Error", Sig: errSig}
157 errIface := NewTCInterface([]*IfaceMethod{errMeth, strMeth}, nil)
158 errIface.Complete()
159 u.Error = NewTypeName(nil, "error", errIface)
160 s.Insert(u.Error)
161
162 complex64Type := NewNamed(NewTypeName(nil, "complex64", nil), u.Typ[Invalid])
163 s.Insert(complex64Type.Obj)
164 complex128Type := NewNamed(NewTypeName(nil, "complex128", nil), u.Typ[Invalid])
165 s.Insert(complex128Type.Obj)
166
167 anyIface := NewTCInterface(nil, nil)
168 anyIface.Complete()
169 s.Insert(NewTypeName(nil, "any", anyIface))
170
171 comparableIface := NewTCInterface(nil, nil)
172 comparableIface.Complete()
173 s.Insert(NewTypeName(nil, "comparable", comparableIface))
174
175 s.Insert(NewTCConst(nil, "true", u.Typ[UntypedBool], untypedBool(true)))
176 s.Insert(NewTCConst(nil, "false", u.Typ[UntypedBool], untypedBool(false)))
177 s.Insert(NewTCConst(nil, "iota", u.Typ[UntypedInt], untypedInt(0)))
178 s.Insert(NewTCConst(nil, "nil", u.Typ[UntypedNil], untypedNil()))
179
180 builtinNames := [18]string{
181 BuiltinAppend: "append",
182 BuiltinCap: "cap",
183 BuiltinClear: "clear",
184 BuiltinClose: "close",
185 BuiltinComplex: "complex",
186 BuiltinCopy: "copy",
187 BuiltinDelete: "delete",
188 BuiltinImag: "imag",
189 BuiltinLen: "len",
190 BuiltinMake: "__slicealloc",
191 BuiltinNew: "__ptralloc",
192 BuiltinPanic: "panic",
193 BuiltinPrint: "print",
194 BuiltinPrintln: "println",
195 BuiltinReal: "real",
196 BuiltinRecover: "recover",
197 BuiltinSpawn: "spawn",
198 }
199 for id, name := range builtinNames {
200 s.Insert(newBuiltin(name, BuiltinID(id)))
201 }
202 s.Insert(newBuiltin("min", BuiltinMin))
203 s.Insert(newBuiltin("max", BuiltinMax))
204 return u
205 }
206
207
208 func defTypeName(name string, typ Type) {
209 tn := NewTypeName(nil, name, typ)
210 Universe.Insert(tn)
211 }
212
213 func addStringMethod(named *Named, strType *Basic) {
214 stringSig := NewSignature(
215 NewTCVar(nil, "", named),
216 nil,
217 NewTuple(NewTCVar(nil, "", strType)),
218 false,
219 )
220 stringFn := NewTCFunc(nil, "String", stringSig)
221 if named.Methods == nil {
222 named.Methods = []*TCFunc{:0:1}
223 }
224 named.AddMethod(stringFn)
225 }
226
227 func addBasicStringMethod(b *Basic, strType *Basic) {
228 stringSig := NewSignature(
229 NewTCVar(nil, "", b),
230 nil,
231 NewTuple(NewTCVar(nil, "", strType)),
232 false,
233 )
234 stringFn := NewTCFunc(nil, "String", stringSig)
235 if b.Methods == nil {
236 b.Methods = []*TCFunc{:0:1}
237 }
238 b.AddMethod(stringFn)
239 }
240
241 func defObj(obj Object) {
242 Universe.Insert(obj)
243 }
244
245 func defConst(name string, typ Type, val ConstVal) {
246 Universe.Insert(NewTCConst(nil, name, typ, val))
247 }
248
249 func defNil() {
250 Universe.Insert(NewTCConst(nil, "nil", Typ[UntypedNil], untypedNil()))
251 }
252
253 // Placeholder constant values. These wrap go/constant values. In B4 they
254 // become native Moxie values.
255 type ConstBool struct{ V bool }
256 type ConstInt struct{ V int64 }
257 type ConstFloat struct {
258 V float64
259 Lit string
260 }
261 type ConstStr struct{ S string }
262 type ConstNil struct{}
263
264 func untypedBool(v bool) (c ConstVal) { return &ConstBool{V: v} }
265 func untypedInt(v int64) (c ConstVal) { return &ConstInt{V: v} }
266 func untypedFloat(v float64) (c ConstVal) { return &ConstFloat{V: v} }
267 func untypedStr(s string) (c ConstVal) { return &ConstStr{S: s} }
268 func untypedNil() (c ConstVal) { return &ConstNil{} }
269
270 func (c *ConstBool) String() (s string) { if c.V { return "true" }; return "false" }
271 func (c *ConstInt) String() (s string) {
272 n := c.V
273 if n == 0 {
274 return "0"
275 }
276 neg := n < 0
277 if neg {
278 n = -n
279 if n < 0 {
280 return "-9223372036854775808"
281 }
282 }
283 buf := []byte{:0:20}
284 for n > 0 {
285 push(buf, byte('0'+n%10))
286 n /= 10
287 }
288 if neg {
289 push(buf, '-')
290 }
291 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
292 buf[i], buf[j] = buf[j], buf[i]
293 }
294 return string(buf)
295 }
296 func (c *ConstFloat) String() (s string) {
297 if c.Lit != "" {
298 return NormalizeLLVMFloat(c.Lit)
299 }
300 if c.V == 0.0 {
301 return "0.0"
302 }
303 return "0.0"
304 }
305 func (c *ConstStr) String() (s string) { return c.S }
306 func (c *ConstNil) String() (s string) { return "nil" }
307
308 func NormalizeLLVMFloat(s string) (sv string) {
309 if len(s) == 0 {
310 return "0.0"
311 }
312 start := 0
313 if s[0] == '-' || s[0] == '+' {
314 start = 1
315 }
316 hasDot := false
317 ePos := -1
318 for i := start; i < len(s); i++ {
319 if s[i] == '.' {
320 hasDot = true
321 }
322 if s[i] == 'e' || s[i] == 'E' {
323 ePos = i
324 break
325 }
326 }
327 if !hasDot {
328 if ePos >= 0 {
329 return s[:ePos] | ".0" | s[ePos:]
330 }
331 return s | ".0"
332 }
333 dotIdx := -1
334 for i := start; i < len(s); i++ {
335 if s[i] == '.' {
336 dotIdx = i
337 break
338 }
339 }
340 if dotIdx == start {
341 s = s[:start] | "0" | s[start:]
342 dotIdx++
343 }
344 afterDot := dotIdx + 1
345 if afterDot >= len(s) || s[afterDot] == 'e' || s[afterDot] == 'E' {
346 s = s[:afterDot] | "0" | s[afterDot:]
347 }
348 return s
349 }
350
351 // Predeclared returns the universe-scope object with the given name, or nil.
352 func Predeclared(name string) (o Object) {
353 return Universe.Lookup(name)
354 }
355