go_types/
objects.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4//
5//
6// This code is adapted from the offical Go code written in Go
7// with license as follows:
8// Copyright 2013 The Go Authors. All rights reserved.
9// Use of this source code is governed by a BSD-style
10// license that can be found in the LICENSE file.
11
12use super::check::DeclInfo;
13use super::constant;
14use super::obj::LangObj;
15use super::package::Package;
16use super::scope::Scope;
17use super::typ::*;
18use super::universe::Universe;
19use go_parser::{piggy_key_type, PiggyVec, Pos};
20use std::borrow::Cow;
21
22piggy_key_type! {
23    pub struct ObjKey;
24    pub struct TypeKey;
25    pub struct PackageKey;
26    pub struct DeclInfoKey;
27    pub struct ScopeKey;
28}
29
30pub type LangObjs = PiggyVec<ObjKey, LangObj>;
31pub type Types = PiggyVec<TypeKey, Type>;
32pub type Packages = PiggyVec<PackageKey, Package>;
33pub type Decls = PiggyVec<DeclInfoKey, DeclInfo>;
34pub type Scopes = PiggyVec<ScopeKey, Scope>;
35
36/// The container of all "managed" objects
37/// also works as a "global" variable holder
38pub struct TCObjects {
39    pub lobjs: LangObjs,
40    pub types: Types,
41    pub pkgs: Packages,
42    pub decls: Decls,
43    pub scopes: Scopes,
44    pub universe: Option<Universe>,
45    // "global" variable
46    pub fmt_qualifier: Box<dyn Fn(&Package) -> Cow<str>>,
47}
48
49fn default_fmt_qualifier(p: &Package) -> Cow<str> {
50    p.path().into()
51}
52
53impl TCObjects {
54    pub fn new() -> TCObjects {
55        let fmtq = Box::new(default_fmt_qualifier);
56        const CAP: usize = 16;
57        let mut objs = TCObjects {
58            lobjs: PiggyVec::with_capacity(CAP),
59            types: PiggyVec::with_capacity(CAP),
60            pkgs: PiggyVec::with_capacity(CAP),
61            decls: PiggyVec::with_capacity(CAP),
62            scopes: PiggyVec::with_capacity(CAP),
63            universe: None,
64            fmt_qualifier: fmtq,
65        };
66        objs.universe = Some(Universe::new(&mut objs));
67        objs
68    }
69
70    pub fn universe(&self) -> &Universe {
71        self.universe.as_ref().unwrap()
72    }
73
74    pub fn new_scope(
75        &mut self,
76        parent: Option<ScopeKey>,
77        pos: Pos,
78        end: Pos,
79        comment: String,
80        is_func: bool,
81    ) -> ScopeKey {
82        let scope = Scope::new(parent, pos, end, comment, is_func);
83        let skey = self.scopes.insert(scope);
84        if let Some(s) = parent {
85            // don't add children to Universe scope
86            if s != *self.universe().scope() {
87                self.scopes[s].add_child(skey);
88            }
89        }
90        skey
91    }
92
93    pub fn new_package(&mut self, path: String) -> PackageKey {
94        let skey = self.new_scope(
95            Some(*self.universe().scope()),
96            0,
97            0,
98            format!("package {}", path),
99            false,
100        );
101        let pkg = Package::new(path, None, skey);
102        self.pkgs.insert(pkg)
103    }
104
105    pub fn new_pkg_name(
106        &mut self,
107        pos: Pos,
108        pkg: Option<PackageKey>,
109        name: String,
110        imported: PackageKey,
111    ) -> ObjKey {
112        let lobj = LangObj::new_pkg_name(pos, pkg, name, imported, self.universe());
113        self.lobjs.insert(lobj)
114    }
115
116    pub fn new_const(
117        &mut self,
118        pos: Pos,
119        pkg: Option<PackageKey>,
120        name: String,
121        typ: Option<TypeKey>,
122        val: constant::Value,
123    ) -> ObjKey {
124        let lobj = LangObj::new_const(pos, pkg, name, typ, val);
125        self.lobjs.insert(lobj)
126    }
127
128    pub fn new_type_name(
129        &mut self,
130        pos: Pos,
131        pkg: Option<PackageKey>,
132        name: String,
133        typ: Option<TypeKey>,
134    ) -> ObjKey {
135        let lobj = LangObj::new_type_name(pos, pkg, name, typ);
136        self.lobjs.insert(lobj)
137    }
138
139    pub fn new_var(
140        &mut self,
141        pos: Pos,
142        pkg: Option<PackageKey>,
143        name: String,
144        typ: Option<TypeKey>,
145    ) -> ObjKey {
146        let lobj = LangObj::new_var(pos, pkg, name, typ);
147        self.lobjs.insert(lobj)
148    }
149
150    pub fn new_param_var(
151        &mut self,
152        pos: Pos,
153        pkg: Option<PackageKey>,
154        name: String,
155        typ: Option<TypeKey>,
156    ) -> ObjKey {
157        let lobj = LangObj::new_param_var(pos, pkg, name, typ);
158        self.lobjs.insert(lobj)
159    }
160
161    pub fn new_field(
162        &mut self,
163        pos: Pos,
164        pkg: Option<PackageKey>,
165        name: String,
166        typ: Option<TypeKey>,
167        embedded: bool,
168    ) -> ObjKey {
169        let lobj = LangObj::new_field(pos, pkg, name, typ, embedded);
170        self.lobjs.insert(lobj)
171    }
172
173    pub fn new_func(
174        &mut self,
175        pos: Pos,
176        pkg: Option<PackageKey>,
177        name: String,
178        typ: Option<TypeKey>,
179    ) -> ObjKey {
180        let lobj = LangObj::new_func(pos, pkg, name, typ);
181        self.lobjs.insert(lobj)
182    }
183
184    pub fn new_label(&mut self, pos: Pos, pkg: Option<PackageKey>, name: String) -> ObjKey {
185        let lobj = LangObj::new_label(pos, pkg, name, self.universe());
186        self.lobjs.insert(lobj)
187    }
188
189    pub fn new_t_basic(&mut self, typ: BasicType, info: BasicInfo, name: &'static str) -> TypeKey {
190        self.types
191            .insert(Type::Basic(BasicDetail::new(typ, info, name)))
192    }
193
194    pub fn new_t_array(&mut self, elem: TypeKey, len: Option<u64>) -> TypeKey {
195        self.types.insert(Type::Array(ArrayDetail::new(elem, len)))
196    }
197
198    pub fn new_t_slice(&mut self, elem: TypeKey) -> TypeKey {
199        self.types.insert(Type::Slice(SliceDetail::new(elem)))
200    }
201
202    pub fn new_t_struct(
203        &mut self,
204        fields: Vec<ObjKey>,
205        tags: Option<Vec<Option<String>>>,
206    ) -> TypeKey {
207        self.types
208            .insert(Type::Struct(StructDetail::new(fields, tags, self)))
209    }
210    pub fn new_t_pointer(&mut self, base: TypeKey) -> TypeKey {
211        self.types.insert(Type::Pointer(PointerDetail::new(base)))
212    }
213
214    pub fn new_t_tuple(&mut self, vars: Vec<ObjKey>) -> TypeKey {
215        self.types.insert(Type::Tuple(TupleDetail::new(vars)))
216    }
217
218    pub fn new_t_signature(
219        &mut self,
220        scope: Option<ScopeKey>,
221        recv: Option<ObjKey>,
222        params: TypeKey,
223        results: TypeKey,
224        variadic: bool,
225    ) -> TypeKey {
226        self.types.insert(Type::Signature(SignatureDetail::new(
227            scope, recv, params, results, variadic, self,
228        )))
229    }
230
231    pub fn new_t_interface(&mut self, methods: Vec<ObjKey>, embeddeds: Vec<TypeKey>) -> TypeKey {
232        let iface = Type::Interface(InterfaceDetail::new(methods, embeddeds, self));
233        self.types.insert(iface)
234    }
235
236    pub fn new_t_empty_interface(&mut self) -> TypeKey {
237        self.types
238            .insert(Type::Interface(InterfaceDetail::new_empty()))
239    }
240
241    pub fn new_t_map(&mut self, key: TypeKey, elem: TypeKey) -> TypeKey {
242        self.types.insert(Type::Map(MapDetail::new(key, elem)))
243    }
244    pub fn new_t_chan(&mut self, dir: ChanDir, elem: TypeKey) -> TypeKey {
245        self.types.insert(Type::Chan(ChanDetail::new(dir, elem)))
246    }
247    pub fn new_t_named(
248        &mut self,
249        obj: Option<ObjKey>,
250        underlying: Option<TypeKey>,
251        methods: Vec<ObjKey>,
252    ) -> TypeKey {
253        self.types.insert(Type::Named(NamedDetail::new(
254            obj, underlying, methods, self,
255        )))
256    }
257}