universe.go raw
1 package typecheck
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 // Predeclared named types (accessible as objects in Universe).
11 var (
12 universeBool *TypeName
13 universeError *TypeName
14 universeByteAlias *TypeName // byte = uint8
15 universeRuneAlias *TypeName // rune = int32
16 )
17
18 func init() {
19 Universe = NewScope(nil)
20
21 // Initialize Basic types in Typ table.
22 infos := [...]struct {
23 kind BasicKind
24 info BasicInfo
25 name string
26 }{
27 {Invalid, 0, "invalid type"},
28
29 {Bool, IsBoolean, "bool"},
30
31 {Int8, IsInteger | IsOrdered | IsNumeric, "int8"},
32 {Int16, IsInteger | IsOrdered | IsNumeric, "int16"},
33 {Int32, IsInteger | IsOrdered | IsNumeric, "int32"},
34 {Int64, IsInteger | IsOrdered | IsNumeric, "int64"},
35 {Uint8, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint8"},
36 {Uint16, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint16"},
37 {Uint32, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint32"},
38 {Uint64, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint64"},
39
40 {Float32, IsFloat | IsOrdered | IsNumeric, "float32"},
41 {Float64, IsFloat | IsOrdered | IsNumeric, "float64"},
42
43 // string and []byte share kind String in Moxie.
44 {String, IsString | IsOrdered, "string"},
45
46 {UnsafePointer, 0, "Pointer"}, // lives in unsafe package
47
48 {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
49 {UntypedInt, IsInteger | IsNumeric | IsUntyped, "untyped int"},
50 {UntypedRune, IsInteger | IsNumeric | IsUntyped, "untyped rune"},
51 {UntypedFloat, IsFloat | IsNumeric | IsUntyped, "untyped float"},
52 {UntypedString, IsString | IsUntyped, "untyped string"},
53 {UntypedNil, IsUntyped, "untyped nil"},
54 }
55 for i, info := range infos {
56 Typ[i] = &Basic{kind: info.kind, info: info.info, name: info.name}
57 }
58
59 // In Moxie, int ≡ int32 and uint ≡ uint32. We expose "int" and "uint"
60 // as named aliases to int32/uint32 in the universe scope.
61 defTypeName("bool", Typ[Bool])
62 defTypeName("int8", Typ[Int8])
63 defTypeName("int16", Typ[Int16])
64 defTypeName("int32", Typ[Int32])
65 defTypeName("int64", Typ[Int64])
66 defTypeName("uint8", Typ[Uint8])
67 defTypeName("uint16", Typ[Uint16])
68 defTypeName("uint32", Typ[Uint32])
69 defTypeName("uint64", Typ[Uint64])
70 defTypeName("float32", Typ[Float32])
71 defTypeName("float64", Typ[Float64])
72 defTypeName("string", Typ[String])
73
74 // int = int32, uint = uint32 (Moxie always 32-bit)
75 intType := NewNamed(NewTypeName(nil, "int", nil), Typ[Int32])
76 uintType := NewNamed(NewTypeName(nil, "uint", nil), Typ[Uint32])
77 defObj(intType.obj)
78 defObj(uintType.obj)
79 intType.obj.typ = intType
80 uintType.obj.typ = uintType
81
82 // byte = uint8
83 byteType := NewNamed(NewTypeName(nil, "byte", nil), Typ[Uint8])
84 defObj(byteType.obj)
85 byteType.obj.typ = byteType
86 universeByteAlias = byteType.obj
87
88 // rune = int32
89 runeType := NewNamed(NewTypeName(nil, "rune", nil), Typ[Int32])
90 defObj(runeType.obj)
91 runeType.obj.typ = runeType
92 universeRuneAlias = runeType.obj
93
94 // uintptr (allowed only with import "unsafe")
95 uintptrType := NewNamed(NewTypeName(nil, "uintptr", nil), Typ[Uint64])
96 defObj(uintptrType.obj)
97 uintptrType.obj.typ = uintptrType
98
99 // error interface - includes String() so error values satisfy stringer
100 errStrSig := NewSignature(nil, nil, NewTuple(NewVar(nil, "", Typ[String])), false)
101 errMeth := &IfaceMethod{name: "Error", sig: errStrSig}
102 errStringMeth := &IfaceMethod{name: "String", sig: errStrSig}
103 errIface := NewInterface([]*IfaceMethod{errMeth, errStringMeth}, nil)
104 errIface.Complete()
105 universeError = NewTypeName(nil, "error", errIface)
106 defObj(universeError)
107
108 // complex64/128 are not valid in Moxie programs but appear in stdlib source.
109 // Register them as invalid basic types so the checker doesn't report "undefined".
110 complex64Type := NewNamed(NewTypeName(nil, "complex64", nil), Typ[Invalid])
111 defObj(complex64Type.obj)
112 complex128Type := NewNamed(NewTypeName(nil, "complex128", nil), Typ[Invalid])
113 defObj(complex128Type.obj)
114
115 // any is an alias for interface{} (Go 1.18+)
116 anyIface := NewInterface(nil, nil)
117 anyIface.Complete()
118 anyObj := NewTypeName(nil, "any", anyIface)
119 defObj(anyObj)
120
121 // comparable is a builtin interface satisfied by comparable types.
122 comparableIface := NewInterface(nil, nil)
123 comparableIface.Complete()
124 comparableObj := NewTypeName(nil, "comparable", comparableIface)
125 defObj(comparableObj)
126
127 // predeclared constants
128 defConst("true", Typ[UntypedBool], untypedBool(true))
129 defConst("false", Typ[UntypedBool], untypedBool(false))
130 defConst("iota", Typ[UntypedInt], untypedInt(0))
131 defNil()
132
133 // predeclared builtins
134 for id, name := range builtinNames {
135 Universe.Insert(newBuiltin(name, BuiltinID(id)))
136 }
137
138 // Go 1.21 builtins.
139 Universe.Insert(newBuiltin("min", BuiltinMin))
140 Universe.Insert(newBuiltin("max", BuiltinMax))
141 // Moxie arena-stack builtins.
142 Universe.Insert(newBuiltin("push", BuiltinPush))
143 Universe.Insert(newBuiltin("pop", BuiltinPop))
144 Universe.Insert(newBuiltin("resize", BuiltinResize))
145 }
146
147 var builtinNames = [...]string{
148 BuiltinAppend: "append",
149 BuiltinCap: "cap",
150 BuiltinClear: "clear",
151 BuiltinClose: "close",
152 BuiltinComplex: "complex",
153 BuiltinCopy: "copy",
154 BuiltinDelete: "delete",
155 BuiltinImag: "imag",
156 BuiltinLen: "len",
157 BuiltinMake: "make",
158 BuiltinNew: "new",
159 BuiltinPanic: "panic",
160 BuiltinPrint: "print",
161 BuiltinPrintln: "println",
162 BuiltinReal: "real",
163 BuiltinRecover: "recover",
164 BuiltinSpawn: "spawn",
165 }
166
167 func defTypeName(name string, typ Type) {
168 tn := NewTypeName(nil, name, typ)
169 Universe.Insert(tn)
170 }
171
172 func defObj(obj Object) {
173 Universe.Insert(obj)
174 }
175
176 func defConst(name string, typ Type, val ConstVal) {
177 Universe.Insert(NewConst(nil, name, typ, val))
178 }
179
180 func defNil() {
181 Universe.Insert(NewConst(nil, "nil", Typ[UntypedNil], untypedNil()))
182 }
183
184 // Placeholder constant values. These wrap go/constant values. In B4 they
185 // become native Moxie values.
186 type constBool struct{ v bool }
187 type constInt struct{ v int64 }
188 type constNil struct{}
189
190 func untypedBool(v bool) ConstVal { return constBool{v} }
191 func untypedInt(v int64) ConstVal { return constInt{v} }
192 func untypedNil() ConstVal { return constNil{} }
193
194 func (c constBool) String() string { if c.v { return "true" }; return "false" }
195 func (c constInt) String() string { return "0" }
196 func (c constNil) String() string { return "nil" }
197
198 // Predeclared returns the universe-scope object with the given name, or nil.
199 func Predeclared(name string) Object {
200 return Universe.Lookup(name)
201 }
202