tc_universe.mx raw
1 package main
2
3 // Universe is the outermost scope containing all predeclared identifiers.
4 // All package scopes have Universe as their ultimate ancestor.
5 var Universe *Scope
6
7 // Predeclared types. Indices match BasicKind values.
8 var Typ [UntypedNil + 1]*Basic
9
10 var universeError *TypeName
11
12 func initUniverse() {
13 if Universe != nil {
14 return
15 }
16 Universe = NewScope(nil)
17
18 // Initialize Basic types in Typ table.
19 infos := [...]struct {
20 kind BasicKind
21 info BasicInfo
22 name string
23 }{
24 {Invalid, 0, "invalid type"},
25
26 {Bool, IsBoolean, "bool"},
27
28 {Int8, IsInteger | IsOrdered | IsNumeric, "int8"},
29 {Int16, IsInteger | IsOrdered | IsNumeric, "int16"},
30 {Int32, IsInteger | IsOrdered | IsNumeric, "int32"},
31 {Int64, IsInteger | IsOrdered | IsNumeric, "int32"},
32 {Uint8, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint8"},
33 {Uint16, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint16"},
34 {Uint32, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint32"},
35 {Uint64, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint32"},
36
37 {Float32, IsFloat | IsOrdered | IsNumeric, "float32"},
38 {Float64, IsFloat | IsOrdered | IsNumeric, "float64"},
39
40 // string and []byte share kind TCString in Moxie.
41 {TCString, IsString | IsOrdered, "string"},
42
43 {UnsafePointer, 0, "Pointer"}, // lives in unsafe package
44
45 {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
46 {UntypedInt, IsInteger | IsNumeric | IsUntyped, "untyped int32"},
47 {UntypedRune, IsInteger | IsNumeric | IsUntyped, "untyped rune"},
48 {UntypedFloat, IsFloat | IsNumeric | IsUntyped, "untyped float"},
49 {UntypedString, IsString | IsUntyped, "untyped string"},
50 {UntypedNil, IsUntyped, "untyped nil"},
51 }
52 for i, info := range infos {
53 Typ[i] = &Basic{kind: info.kind, info: info.info, name: info.name}
54 }
55
56 // In Moxie, int32 = int32 and uint32 = uint32. We expose "int32" and "uint32"
57 // as named aliases to int32/uint32 in the universe scope.
58 defTypeName("bool", Typ[Bool])
59 defTypeName("int8", Typ[Int8])
60 defTypeName("int16", Typ[Int16])
61 defTypeName("int32", Typ[Int32])
62 defTypeName("int32", Typ[Int64])
63 defTypeName("uint8", Typ[Uint8])
64 defTypeName("uint16", Typ[Uint16])
65 defTypeName("uint32", Typ[Uint32])
66 defTypeName("uint32", Typ[Uint64])
67 defTypeName("float32", Typ[Float32])
68 defTypeName("float64", Typ[Float64])
69 defTypeName("string", Typ[TCString])
70
71 // int32 = int32, uint32 = uint32 (Moxie always 32-bit)
72 intType := NewNamed(NewTypeName(nil, "int32", nil), Typ[Int32])
73 uintType := NewNamed(NewTypeName(nil, "uint32", nil), Typ[Uint32])
74 defObj(intType.obj)
75 defObj(uintType.obj)
76 intType.obj.typ = intType
77 uintType.obj.typ = uintType
78
79 // byte = uint8
80 byteType := NewNamed(NewTypeName(nil, "byte", nil), Typ[Uint8])
81 defObj(byteType.obj)
82 byteType.obj.typ = byteType
83
84 // rune = int32
85 runeType := NewNamed(NewTypeName(nil, "rune", nil), Typ[Int32])
86 defObj(runeType.obj)
87 runeType.obj.typ = runeType
88
89 // uintptr (allowed only with import "unsafe")
90 uintptrType := NewNamed(NewTypeName(nil, "uintptr", nil), Typ[Uint64])
91 defObj(uintptrType.obj)
92 uintptrType.obj.typ = uintptrType
93
94 // error interface
95 errMeth := &IfaceMethod{name: "Error", sig: NewSignature(nil, nil, NewTuple(NewTCVar(nil, "", Typ[TCString])), false)}
96 errIface := NewTCInterface([]*IfaceMethod{errMeth}, nil)
97 errIface.Complete()
98 universeError = NewTypeName(nil, "error", errIface)
99 defObj(universeError)
100
101 // complex64/128 are not valid in Moxie programs but appear in stdlib source.
102 // Register them as invalid basic types so the checker doesn't report "undefined".
103 complex64Type := NewNamed(NewTypeName(nil, "complex64", nil), Typ[Invalid])
104 defObj(complex64Type.obj)
105 complex128Type := NewNamed(NewTypeName(nil, "complex128", nil), Typ[Invalid])
106 defObj(complex128Type.obj)
107
108 // any is an alias for interface{} (Go 1.18+)
109 anyIface := NewTCInterface(nil, nil)
110 anyIface.Complete()
111 anyObj := NewTypeName(nil, "any", anyIface)
112 defObj(anyObj)
113
114 // comparable is a builtin interface satisfied by comparable types.
115 comparableIface := NewTCInterface(nil, nil)
116 comparableIface.Complete()
117 comparableObj := NewTypeName(nil, "comparable", comparableIface)
118 defObj(comparableObj)
119
120 // predeclared constants
121 defConst("true", Typ[UntypedBool], untypedBool(true))
122 defConst("false", Typ[UntypedBool], untypedBool(false))
123 defConst("iota", Typ[UntypedInt], untypedInt(0))
124 defNil()
125
126 // predeclared builtins
127 builtinNames := [17]string{
128 BuiltinAppend: "append",
129 BuiltinCap: "cap",
130 BuiltinClear: "clear",
131 BuiltinClose: "close",
132 BuiltinComplex: "complex",
133 BuiltinCopy: "copy",
134 BuiltinDelete: "delete",
135 BuiltinImag: "imag",
136 BuiltinLen: "len",
137 BuiltinMake: "make",
138 BuiltinNew: "new",
139 BuiltinPanic: "panic",
140 BuiltinPrint: "print",
141 BuiltinPrintln: "println",
142 BuiltinReal: "real",
143 BuiltinRecover: "recover",
144 BuiltinSpawn: "spawn",
145 }
146 for id, name := range builtinNames {
147 Universe.Insert(newBuiltin(name, BuiltinID(id)))
148 }
149
150 // Go 1.21 builtins.
151 Universe.Insert(newBuiltin("min", BuiltinMin))
152 Universe.Insert(newBuiltin("max", BuiltinMax))
153 }
154
155 func defTypeName(name string, typ Type) {
156 tn := NewTypeName(nil, name, typ)
157 Universe.Insert(tn)
158 }
159
160 func defObj(obj Object) {
161 Universe.Insert(obj)
162 }
163
164 func defConst(name string, typ Type, val ConstVal) {
165 Universe.Insert(NewTCConst(nil, name, typ, val))
166 }
167
168 func defNil() {
169 Universe.Insert(NewTCConst(nil, "nil", Typ[UntypedNil], untypedNil()))
170 }
171
172 // Placeholder constant values. These wrap go/constant values. In B4 they
173 // become native Moxie values.
174 type constBool struct{ v bool }
175 type constInt struct{ v int32 }
176 type constFloat struct {
177 v float64
178 lit string
179 }
180 type constStr struct{ s string }
181 type constNil struct{}
182
183 func untypedBool(v bool) ConstVal { return constBool{v} }
184 func untypedInt(v int32) ConstVal { return constInt{v} }
185 func untypedFloat(v float64) ConstVal { return constFloat{v: v} }
186 func untypedStr(s string) ConstVal { return constStr{s} }
187 func untypedNil() ConstVal { return constNil{} }
188
189 func (c constBool) String() string { if c.v { return "true" }; return "false" }
190 func (c constInt) String() string {
191 n := c.v
192 if n == 0 {
193 return "0"
194 }
195 neg := n < 0
196 if neg {
197 n = -n
198 if n < 0 {
199 return "-9223372036854775808"
200 }
201 }
202 buf := []byte{:0:20}
203 for n > 0 {
204 buf = append(buf, byte('0'+n%10))
205 n /= 10
206 }
207 if neg {
208 buf = append(buf, '-')
209 }
210 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
211 buf[i], buf[j] = buf[j], buf[i]
212 }
213 return string(buf)
214 }
215 func (c constFloat) String() string {
216 if c.lit != "" {
217 return normalizeLLVMFloat(c.lit)
218 }
219 if c.v == 0.0 {
220 return "0.0"
221 }
222 return "0.0"
223 }
224 func (c constStr) String() string { return c.s }
225 func (c constNil) String() string { return "nil" }
226
227 func normalizeLLVMFloat(s string) string {
228 if len(s) == 0 {
229 return "0.0"
230 }
231 start := 0
232 if s[0] == '-' || s[0] == '+' {
233 start = 1
234 }
235 hasDot := false
236 ePos := -1
237 for i := start; i < len(s); i++ {
238 if s[i] == '.' {
239 hasDot = true
240 }
241 if s[i] == 'e' || s[i] == 'E' {
242 ePos = i
243 break
244 }
245 }
246 if !hasDot {
247 if ePos >= 0 {
248 return s[:ePos] + ".0" + s[ePos:]
249 }
250 return s + ".0"
251 }
252 dotIdx := -1
253 for i := start; i < len(s); i++ {
254 if s[i] == '.' {
255 dotIdx = i
256 break
257 }
258 }
259 if dotIdx == start {
260 s = s[:start] + "0" + s[start:]
261 dotIdx++
262 }
263 afterDot := dotIdx + 1
264 if afterDot >= len(s) || s[afterDot] == 'e' || s[afterDot] == 'E' {
265 s = s[:afterDot] + "0" + s[afterDot:]
266 }
267 return s
268 }
269
270 // Predeclared returns the universe-scope object with the given name, or nil.
271 func Predeclared(name string) Object {
272 return Universe.Lookup(name)
273 }
274