goscript_types/
universe.rs

1#![allow(dead_code)]
2
3use super::constant;
4use super::obj::*;
5use super::objects::{ObjKey, PackageKey, ScopeKey, TCObjects, TypeKey, Types};
6use super::package::*;
7use super::scope::*;
8use super::typ::*;
9use std::collections::HashMap;
10
11/// ExprKind describes the kind of an expression; the kind
12/// determines if an expression is valid in 'statement context'.
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
14pub enum ExprKind {
15    Conversion,
16    Expression,
17    Statement,
18}
19
20/// A Builtin is the id of a builtin function.
21#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
22pub enum Builtin {
23    Append,
24    Cap,
25    Close,
26    Complex,
27    Copy,
28    Delete,
29    Imag,
30    Len,
31    Make,
32    New,
33    Panic,
34    Print,
35    Println,
36    Real,
37    Recover,
38    // package unsafe
39    Alignof,
40    Offsetof,
41    Sizeof,
42    // testing support
43    Assert,
44    Trace,
45    // goscript native extension
46    Ffi,
47}
48
49#[derive(Copy, Clone)]
50pub struct BuiltinInfo {
51    pub name: &'static str,
52    pub arg_count: usize,
53    pub variadic: bool,
54    pub kind: ExprKind,
55}
56
57/// Universe sets up the universe scope, the unsafe package
58/// and all the builtin types and functions
59pub struct Universe {
60    scope: ScopeKey,
61    unsafe_: PackageKey,
62    iota: ObjKey,
63    byte: TypeKey,
64    rune: TypeKey,
65    slice_of_bytes: TypeKey, // for builtin append
66    no_value_tuple: TypeKey, // for OperandMode::NoValue
67    // indir is a sentinel type name that is pushed onto the object path
68    // to indicate an "indirection" in the dependency from one type name
69    // to the next. For instance, for "type p *p" the object path contains
70    // p followed by indir, indicating that there's an indirection *p.
71    // Indirections are used to break type cycles.
72    indir: ObjKey,
73    // guard_sig is a empty signature type used to guard against func cycles
74    guard_sig: TypeKey,
75    types: HashMap<BasicType, TypeKey>,
76    builtins: HashMap<Builtin, BuiltinInfo>,
77}
78
79impl Universe {
80    pub fn new(objs: &mut TCObjects) -> Universe {
81        // universe scope and unsafe package
82        let (uskey, unsafe_) = Universe::def_universe_unsafe(objs);
83        // types
84        let types = Universe::basic_types(&mut objs.types);
85        Universe::def_basic_types(&types, &uskey, &unsafe_, objs);
86        Universe::def_basic_types(
87            &Universe::alias_types(&mut objs.types),
88            &uskey,
89            &unsafe_,
90            objs,
91        );
92        Universe::def_error_type(&types, &uskey, &unsafe_, objs);
93        // consts
94        Universe::def_consts(&types, &uskey, &unsafe_, objs);
95        Universe::def_nil(&types, &uskey, &unsafe_, objs);
96        // builtins
97        let builtins = Universe::builtin_funcs();
98        let ftype = types[&BasicType::Invalid];
99        Universe::def_builtins(&builtins, ftype, &uskey, &unsafe_, objs);
100        // iota byte rune
101        let (iota, byte, rune) = Universe::iota_byte_rune(&uskey, objs);
102        let slice_of_bytes = objs.new_t_slice(byte);
103        let no_value_tuple = objs.new_t_tuple(vec![]);
104        let indir = objs.new_type_name(0, None, "*".to_string(), None);
105        let guard_sig = objs.new_t_signature(None, None, no_value_tuple, no_value_tuple, false);
106        Universe {
107            scope: uskey,
108            unsafe_: unsafe_,
109            iota: iota,
110            byte: byte,
111            rune: rune,
112            slice_of_bytes: slice_of_bytes,
113            no_value_tuple: no_value_tuple,
114            indir: indir,
115            guard_sig: guard_sig,
116            types: types,
117            builtins: builtins,
118        }
119    }
120
121    pub fn scope(&self) -> &ScopeKey {
122        &self.scope
123    }
124
125    pub fn unsafe_pkg(&self) -> &PackageKey {
126        &self.unsafe_
127    }
128
129    pub fn types(&self) -> &HashMap<BasicType, TypeKey> {
130        &self.types
131    }
132
133    pub fn builtins(&self) -> &HashMap<Builtin, BuiltinInfo> {
134        &self.builtins
135    }
136
137    pub fn iota(&self) -> &ObjKey {
138        &self.iota
139    }
140
141    pub fn byte(&self) -> &TypeKey {
142        &self.byte
143    }
144
145    pub fn rune(&self) -> &TypeKey {
146        &self.rune
147    }
148
149    pub fn slice_of_bytes(&self) -> &TypeKey {
150        &self.slice_of_bytes
151    }
152
153    pub fn no_value_tuple(&self) -> &TypeKey {
154        &self.no_value_tuple
155    }
156
157    pub fn indir(&self) -> &ObjKey {
158        &self.indir
159    }
160
161    pub fn guard_sig(&self) -> &TypeKey {
162        &self.guard_sig
163    }
164
165    fn def_universe_unsafe(objs: &mut TCObjects) -> (ScopeKey, PackageKey) {
166        let uskey = objs
167            .scopes
168            .insert(Scope::new(None, 0, 0, "universe".to_owned(), false));
169        let pkg_skey = objs.scopes.insert(Scope::new(
170            Some(uskey),
171            0,
172            0,
173            "package unsafe".to_owned(),
174            false,
175        ));
176        let mut pkg = Package::new("unsafe".to_owned(), Some("unsafe".to_owned()), pkg_skey);
177        pkg.mark_complete();
178        (uskey, objs.pkgs.insert(pkg))
179    }
180
181    ///define this:
182    ///type error interface {
183    ///    Error() string
184    ///}
185    fn def_error_type(
186        types: &HashMap<BasicType, TypeKey>,
187        universe: &ScopeKey,
188        unsafe_: &PackageKey,
189        objs: &mut TCObjects,
190    ) {
191        let res = objs.lobjs.insert(LangObj::new_var(
192            0,
193            None,
194            "".to_owned(),
195            Some(types[&BasicType::Str]),
196        ));
197        let params = objs.new_t_tuple(vec![]);
198        let results = objs.new_t_tuple(vec![res]);
199        let sig = objs.new_t_signature(None, None, params, results, false);
200        let err = objs
201            .lobjs
202            .insert(LangObj::new_func(0, None, "Error".to_owned(), Some(sig)));
203        let inter_detail = InterfaceDetail::new(vec![err], vec![], objs);
204        inter_detail.complete(objs);
205        let underlying = objs.types.insert(Type::Interface(inter_detail));
206        let typ = objs.new_t_named(None, Some(underlying), vec![]);
207        let recv = objs
208            .lobjs
209            .insert(LangObj::new_var(0, None, "".to_owned(), Some(typ)));
210        objs.types[sig]
211            .try_as_signature_mut()
212            .unwrap()
213            .set_recv(Some(recv));
214        let type_name = objs.lobjs.insert(LangObj::new_type_name(
215            0,
216            None,
217            "error".to_owned(),
218            Some(typ),
219        ));
220        Universe::def(type_name, universe, unsafe_, objs);
221    }
222
223    fn def_basic_types(
224        types: &HashMap<BasicType, TypeKey>,
225        universe: &ScopeKey,
226        unsafe_: &PackageKey,
227        objs: &mut TCObjects,
228    ) {
229        for (_, v) in types {
230            let name = objs.types[*v].try_as_basic().unwrap().name();
231            let t = objs
232                .lobjs
233                .insert(LangObj::new_type_name(0, None, name.to_owned(), Some(*v)));
234            Universe::def(t, universe, unsafe_, objs);
235        }
236    }
237
238    fn basic_types(tobjs: &mut Types) -> HashMap<BasicType, TypeKey> {
239        vec![
240            // use vec becasue array doesn't have into_iter()!
241            // may be more expensive, but looks better this way.
242            (BasicType::Invalid, BasicInfo::IsInvalid, "invalid type"),
243            (BasicType::Bool, BasicInfo::IsBoolean, "bool"),
244            (BasicType::Int, BasicInfo::IsInteger, "int"),
245            (BasicType::Int8, BasicInfo::IsInteger, "int8"),
246            (BasicType::Int16, BasicInfo::IsInteger, "int16"),
247            (BasicType::Int32, BasicInfo::IsInteger, "int32"),
248            (BasicType::Int64, BasicInfo::IsInteger, "int64"),
249            (BasicType::Uint, BasicInfo::IsInteger, "uint"),
250            (BasicType::Uint8, BasicInfo::IsInteger, "uint8"),
251            (BasicType::Uint16, BasicInfo::IsInteger, "uint16"),
252            (BasicType::Uint32, BasicInfo::IsInteger, "uint32"),
253            (BasicType::Uint64, BasicInfo::IsInteger, "uint64"),
254            (BasicType::Uintptr, BasicInfo::IsInteger, "uintptr"),
255            (BasicType::Float32, BasicInfo::IsFloat, "float32"),
256            (BasicType::Float64, BasicInfo::IsFloat, "float64"),
257            (BasicType::Complex64, BasicInfo::IsComplex, "complex64"),
258            (BasicType::Complex128, BasicInfo::IsComplex, "complex128"),
259            (BasicType::Str, BasicInfo::IsString, "string"),
260            (BasicType::UnsafePointer, BasicInfo::IsInvalid, "Pointer"),
261            (BasicType::UntypedBool, BasicInfo::IsBoolean, "untyped bool"),
262            (BasicType::UntypedInt, BasicInfo::IsInteger, "untyped int"),
263            (BasicType::UntypedRune, BasicInfo::IsInteger, "untyped rune"),
264            (BasicType::UntypedFloat, BasicInfo::IsFloat, "untyped float"),
265            (
266                BasicType::UntypedComplex,
267                BasicInfo::IsComplex,
268                "untyped complex",
269            ),
270            (
271                BasicType::UntypedString,
272                BasicInfo::IsString,
273                "untyped string",
274            ),
275            (BasicType::UntypedNil, BasicInfo::IsInvalid, "untyped nil"),
276        ]
277        .into_iter()
278        .map(|(t, i, n)| (t, tobjs.insert(Type::Basic(BasicDetail::new(t, i, n)))))
279        .collect::<HashMap<_, _>>()
280    }
281
282    fn alias_types(tobjs: &mut Types) -> HashMap<BasicType, TypeKey> {
283        [
284            (BasicType::Byte, BasicInfo::IsInteger, "byte"),
285            (BasicType::Rune, BasicInfo::IsInteger, "rune"),
286        ]
287        .iter()
288        .map(|(t, i, n)| (*t, tobjs.insert(Type::Basic(BasicDetail::new(*t, *i, n)))))
289        .collect::<HashMap<_, _>>()
290    }
291
292    fn def_consts(
293        types: &HashMap<BasicType, TypeKey>,
294        universe: &ScopeKey,
295        unsafe_: &PackageKey,
296        objs: &mut TCObjects,
297    ) {
298        for (n, t, v) in vec![
299            // use vec becasue array doesn't have into_iter()!
300            (
301                "true",
302                BasicType::UntypedBool,
303                constant::Value::with_bool(true),
304            ),
305            (
306                "false",
307                BasicType::UntypedBool,
308                constant::Value::with_bool(false),
309            ),
310            ("iota", BasicType::UntypedInt, constant::Value::with_i64(0)),
311        ]
312        .into_iter()
313        {
314            let cst = LangObj::new_const(0, None, n.to_owned(), Some(types[&t]), v);
315            Universe::def(objs.lobjs.insert(cst), universe, unsafe_, objs);
316        }
317    }
318
319    fn def_nil(
320        types: &HashMap<BasicType, TypeKey>,
321        universe: &ScopeKey,
322        unsafe_: &PackageKey,
323        objs: &mut TCObjects,
324    ) {
325        let nil = LangObj::new_nil(types[&BasicType::UntypedNil]);
326        Universe::def(objs.lobjs.insert(nil), universe, unsafe_, objs);
327    }
328
329    fn builtin_funcs() -> HashMap<Builtin, BuiltinInfo> {
330        vec![
331            // use vec becasue array doesn't have into_iter()!
332            (Builtin::Append, "append", 1, true, ExprKind::Expression),
333            (Builtin::Cap, "cap", 1, false, ExprKind::Expression),
334            (Builtin::Close, "close", 1, false, ExprKind::Statement),
335            (Builtin::Complex, "complex", 2, false, ExprKind::Expression),
336            (Builtin::Copy, "copy", 2, false, ExprKind::Statement),
337            (Builtin::Delete, "delete", 2, false, ExprKind::Statement),
338            (Builtin::Imag, "imag", 1, false, ExprKind::Expression),
339            (Builtin::Len, "len", 1, false, ExprKind::Expression),
340            (Builtin::Make, "make", 1, true, ExprKind::Expression),
341            (Builtin::New, "new", 1, false, ExprKind::Expression),
342            (Builtin::Panic, "panic", 1, false, ExprKind::Statement),
343            (Builtin::Print, "print", 0, true, ExprKind::Statement),
344            (Builtin::Println, "println", 0, true, ExprKind::Statement),
345            (Builtin::Real, "real", 1, false, ExprKind::Expression),
346            (Builtin::Recover, "recover", 0, false, ExprKind::Statement),
347            (Builtin::Alignof, "Alignof", 1, false, ExprKind::Expression),
348            (
349                Builtin::Offsetof,
350                "Offsetof",
351                1,
352                false,
353                ExprKind::Expression,
354            ),
355            (Builtin::Sizeof, "Sizeof", 1, false, ExprKind::Expression),
356            (Builtin::Assert, "assert", 1, false, ExprKind::Statement),
357            (Builtin::Trace, "trace", 0, true, ExprKind::Statement),
358            (Builtin::Ffi, "ffi", 2, false, ExprKind::Expression),
359        ]
360        .into_iter()
361        .map(|(f, name, no, v, k)| {
362            (
363                f,
364                BuiltinInfo {
365                    name: name,
366                    arg_count: no,
367                    variadic: v,
368                    kind: k,
369                },
370            )
371        })
372        .collect::<HashMap<_, _>>()
373    }
374
375    fn def_builtins(
376        builtins: &HashMap<Builtin, BuiltinInfo>,
377        typ: TypeKey,
378        universe: &ScopeKey,
379        unsafe_: &PackageKey,
380        objs: &mut TCObjects,
381    ) {
382        for (f, info) in builtins.iter() {
383            let fobj = objs
384                .lobjs
385                .insert(LangObj::new_builtin(*f, info.name.to_owned(), typ));
386            Universe::def(fobj, universe, unsafe_, objs);
387        }
388    }
389
390    fn iota_byte_rune(universe: &ScopeKey, objs: &mut TCObjects) -> (ObjKey, TypeKey, TypeKey) {
391        let scope = &objs.scopes[*universe];
392        let iota = *scope.lookup("iota").unwrap();
393        let byte = objs.lobjs[*scope.lookup("byte").unwrap()].typ().unwrap();
394        let rune = objs.lobjs[*scope.lookup("rune").unwrap()].typ().unwrap();
395        (iota, byte, rune)
396    }
397
398    // Objects with names containing blanks are internal and not entered into
399    // a scope. Objects with exported names are inserted in the unsafe package
400    // scope; other objects are inserted in the universe scope.
401    fn def(okey: ObjKey, universe: &ScopeKey, unsafe_: &PackageKey, objs: &mut TCObjects) {
402        let obj = &objs.lobjs[okey];
403        assert!(obj.color() == ObjColor::Black);
404        if obj.name().contains(' ') {
405            return;
406        }
407        // fix Obj link for named types
408        let typ_val = &mut objs.types[obj.typ().unwrap()];
409        if let Some(n) = typ_val.try_as_named_mut() {
410            n.set_obj(okey);
411        }
412
413        let skey = if obj.exported() {
414            match obj.entity_type() {
415                EntityType::TypeName | EntityType::Builtin(_) => {
416                    objs.lobjs[okey].set_pkg(Some(*unsafe_))
417                }
418                _ => unreachable!(),
419            }
420            objs.pkgs[*unsafe_].scope()
421        } else {
422            universe
423        };
424        let re = Scope::insert(*skey, okey, objs);
425        assert!(re.is_none());
426    }
427}