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, "int64"},
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, "uint64"},
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 defTypeName("bool", Typ[Bool])
57 defTypeName("int8", Typ[Int8])
58 defTypeName("int16", Typ[Int16])
59 defTypeName("int32", Typ[Int32])
60 defTypeName("int64", Typ[Int64])
61 defTypeName("uint8", Typ[Uint8])
62 defTypeName("uint16", Typ[Uint16])
63 defTypeName("uint32", Typ[Uint32])
64 defTypeName("uint64", Typ[Uint64])
65 defTypeName("float32", Typ[Float32])
66 defTypeName("float64", Typ[Float64])
67 defTypeName("string", Typ[TCString])
68
69 // byte = uint8
70 byteType := NewNamed(NewTypeName(nil, "byte", nil), Typ[Uint8])
71 defObj(byteType.obj)
72 byteType.obj.typ = byteType
73
74 // rune = int32
75 runeType := NewNamed(NewTypeName(nil, "rune", nil), Typ[Int32])
76 defObj(runeType.obj)
77 runeType.obj.typ = runeType
78
79 // uintptr (allowed only with import "unsafe")
80 uintptrType := NewNamed(NewTypeName(nil, "uintptr", nil), Typ[Uint64])
81 defObj(uintptrType.obj)
82 uintptrType.obj.typ = uintptrType
83
84 // error interface
85 errMeth := &IfaceMethod{name: "Error", sig: NewSignature(nil, nil, NewTuple(NewTCVar(nil, "", Typ[TCString])), false)}
86 errIface := NewTCInterface([]*IfaceMethod{errMeth}, nil)
87 errIface.Complete()
88 universeError = NewTypeName(nil, "error", errIface)
89 defObj(universeError)
90
91 // complex64/128 are not valid in Moxie programs but appear in stdlib source.
92 // Register them as invalid basic types so the checker doesn't report "undefined".
93 complex64Type := NewNamed(NewTypeName(nil, "complex64", nil), Typ[Invalid])
94 defObj(complex64Type.obj)
95 complex128Type := NewNamed(NewTypeName(nil, "complex128", nil), Typ[Invalid])
96 defObj(complex128Type.obj)
97
98 // any is an alias for interface{} (Go 1.18+)
99 anyIface := NewTCInterface(nil, nil)
100 anyIface.Complete()
101 anyObj := NewTypeName(nil, "any", anyIface)
102 defObj(anyObj)
103
104 // comparable is a builtin interface satisfied by comparable types.
105 comparableIface := NewTCInterface(nil, nil)
106 comparableIface.Complete()
107 comparableObj := NewTypeName(nil, "comparable", comparableIface)
108 defObj(comparableObj)
109
110 // predeclared constants
111 defConst("true", Typ[UntypedBool], untypedBool(true))
112 defConst("false", Typ[UntypedBool], untypedBool(false))
113 defConst("iota", Typ[UntypedInt], untypedInt(0))
114 defNil()
115
116 // predeclared builtins
117 builtinNames := [17]string{
118 BuiltinAppend: "append",
119 BuiltinCap: "cap",
120 BuiltinClear: "clear",
121 BuiltinClose: "close",
122 BuiltinComplex: "complex",
123 BuiltinCopy: "copy",
124 BuiltinDelete: "delete",
125 BuiltinImag: "imag",
126 BuiltinLen: "len",
127 BuiltinMake: "make",
128 BuiltinNew: "new",
129 BuiltinPanic: "panic",
130 BuiltinPrint: "print",
131 BuiltinPrintln: "println",
132 BuiltinReal: "real",
133 BuiltinRecover: "recover",
134 BuiltinSpawn: "spawn",
135 }
136 for id, name := range builtinNames {
137 Universe.Insert(newBuiltin(name, BuiltinID(id)))
138 }
139
140 // Go 1.21 builtins.
141 Universe.Insert(newBuiltin("min", BuiltinMin))
142 Universe.Insert(newBuiltin("max", BuiltinMax))
143 }
144
145 func defTypeName(name string, typ Type) {
146 tn := NewTypeName(nil, name, typ)
147 Universe.Insert(tn)
148 }
149
150 func defObj(obj Object) {
151 Universe.Insert(obj)
152 }
153
154 func defConst(name string, typ Type, val ConstVal) {
155 Universe.Insert(NewTCConst(nil, name, typ, val))
156 }
157
158 func defNil() {
159 Universe.Insert(NewTCConst(nil, "nil", Typ[UntypedNil], untypedNil()))
160 }
161
162 // Placeholder constant values. These wrap go/constant values. In B4 they
163 // become native Moxie values.
164 type constBool struct{ v bool }
165 type constInt struct{ v int64 }
166 type constFloat struct {
167 v float64
168 lit string
169 }
170 type constStr struct{ s string }
171 type constNil struct{}
172
173 func untypedBool(v bool) ConstVal { return constBool{v} }
174 func untypedInt(v int64) ConstVal { return constInt{v} }
175 func untypedFloat(v float64) ConstVal { return constFloat{v: v} }
176 func untypedStr(s string) ConstVal { return constStr{s} }
177 func untypedNil() ConstVal { return constNil{} }
178
179 func (c constBool) String() string { if c.v { return "true" }; return "false" }
180 func (c constInt) String() string {
181 n := c.v
182 if n == 0 {
183 return "0"
184 }
185 neg := n < 0
186 if neg {
187 n = -n
188 if n < 0 {
189 return "-9223372036854775808"
190 }
191 }
192 buf := []byte{:0:20}
193 for n > 0 {
194 buf = append(buf, byte('0'+n%10))
195 n /= 10
196 }
197 if neg {
198 buf = append(buf, '-')
199 }
200 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
201 buf[i], buf[j] = buf[j], buf[i]
202 }
203 return string(buf)
204 }
205 func (c constFloat) String() string {
206 if c.lit != "" {
207 return normalizeLLVMFloat(c.lit)
208 }
209 if c.v == 0.0 {
210 return "0.0"
211 }
212 return "0.0"
213 }
214 func (c constStr) String() string { return c.s }
215 func (c constNil) String() string { return "nil" }
216
217 func normalizeLLVMFloat(s string) string {
218 if len(s) == 0 {
219 return "0.0"
220 }
221 start := 0
222 if s[0] == '-' || s[0] == '+' {
223 start = 1
224 }
225 hasDot := false
226 ePos := -1
227 for i := start; i < len(s); i++ {
228 if s[i] == '.' {
229 hasDot = true
230 }
231 if s[i] == 'e' || s[i] == 'E' {
232 ePos = i
233 break
234 }
235 }
236 if !hasDot {
237 if ePos >= 0 {
238 return s[:ePos] + ".0" + s[ePos:]
239 }
240 return s + ".0"
241 }
242 dotIdx := -1
243 for i := start; i < len(s); i++ {
244 if s[i] == '.' {
245 dotIdx = i
246 break
247 }
248 }
249 if dotIdx == start {
250 s = s[:start] + "0" + s[start:]
251 dotIdx++
252 }
253 afterDot := dotIdx + 1
254 if afterDot >= len(s) || s[afterDot] == 'e' || s[afterDot] == 'E' {
255 s = s[:afterDot] + "0" + s[afterDot:]
256 }
257 return s
258 }
259
260 // Predeclared returns the universe-scope object with the given name, or nil.
261 func Predeclared(name string) Object {
262 return Universe.Lookup(name)
263 }
264