goscript_types/
obj.rs

1#![allow(dead_code)]
2use super::constant;
3use super::objects::{ObjKey, PackageKey, ScopeKey, TCObjects, TypeKey};
4use super::package::Package;
5use super::typ;
6use super::universe;
7use super::universe::Universe;
8use goscript_parser::ast;
9use goscript_parser::position;
10use std::borrow::Cow;
11use std::collections::HashMap;
12use std::fmt;
13use std::fmt::Write;
14
15#[derive(Clone, Debug, PartialEq)]
16pub struct VarProperty {
17    pub embedded: bool,
18    pub is_field: bool,
19    pub used: bool,
20}
21
22impl VarProperty {
23    pub fn new(embedded: bool, field: bool, used: bool) -> VarProperty {
24        VarProperty {
25            embedded: embedded,
26            is_field: field,
27            used: used,
28        }
29    }
30}
31
32/// EntityType defines the types of LangObj entities
33///
34#[derive(Clone, Debug, PartialEq)]
35pub enum EntityType {
36    /// A PkgName represents an imported Go package.
37    PkgName(PackageKey, bool), // the bool is for used
38    /// A Const represents a declared constant.
39    Const(constant::Value),
40    /// A TypeName represents a name for a (defined or alias) type.
41    TypeName,
42    /// A Variable represents a declared variable (including function
43    /// parameters and results, and struct fields).
44    Var(VarProperty),
45    /// A Func represents a declared function, concrete method, or abstract
46    /// (interface) method. Its Type() is always a *Signature.
47    /// An abstract method may belong to many interfaces due to embedding.
48    Func(bool), // has_ptr_recv, only valid for methods that don't have a type yet
49    /// A Label represents a declared label.
50    /// Labels don't have a type.
51    Label(bool), // bool for used
52    /// A Builtin represents a built-in function.
53    /// Builtins don't have a valid type.
54    Builtin(universe::Builtin),
55    /// Nil represents the predeclared value nil.
56    Nil,
57}
58
59impl EntityType {
60    pub fn is_pkg_name(&self) -> bool {
61        match self {
62            EntityType::PkgName(_, _) => true,
63            _ => false,
64        }
65    }
66
67    pub fn is_const(&self) -> bool {
68        match self {
69            EntityType::Const(_) => true,
70            _ => false,
71        }
72    }
73
74    pub fn is_type_name(&self) -> bool {
75        match self {
76            EntityType::TypeName => true,
77            _ => false,
78        }
79    }
80
81    pub fn is_var(&self) -> bool {
82        match self {
83            EntityType::Var(_) => true,
84            _ => false,
85        }
86    }
87
88    pub fn is_func(&self) -> bool {
89        match self {
90            EntityType::Func(_) => true,
91            _ => false,
92        }
93    }
94
95    pub fn is_label(&self) -> bool {
96        match self {
97            EntityType::Label(_) => true,
98            _ => false,
99        }
100    }
101
102    pub fn is_builtin(&self) -> bool {
103        match self {
104            EntityType::Builtin(_) => true,
105            _ => false,
106        }
107    }
108
109    pub fn is_nil(&self) -> bool {
110        match self {
111            EntityType::Nil => true,
112            _ => false,
113        }
114    }
115
116    pub fn is_dependency(&self) -> bool {
117        match self {
118            EntityType::Const(_) | EntityType::Var(_) | EntityType::Func(_) => true,
119            _ => false,
120        }
121    }
122
123    pub fn func_has_ptr_recv(&self) -> bool {
124        match self {
125            EntityType::Func(h) => *h,
126            _ => unreachable!(),
127        }
128    }
129
130    pub fn func_set_has_ptr_recv(&mut self, has: bool) {
131        match self {
132            EntityType::Func(h) => {
133                *h = has;
134            }
135            _ => unreachable!(),
136        }
137    }
138
139    pub fn var_property_mut(&mut self) -> &mut VarProperty {
140        match self {
141            EntityType::Var(prop) => prop,
142            _ => unreachable!(),
143        }
144    }
145
146    pub fn label_used(&self) -> bool {
147        match self {
148            EntityType::Label(u) => *u,
149            _ => unreachable!(),
150        }
151    }
152
153    pub fn label_set_used(&mut self, used: bool) {
154        match self {
155            EntityType::Label(u) => {
156                *u = used;
157            }
158            _ => unreachable!(),
159        }
160    }
161}
162
163#[derive(Copy, Clone, Debug, PartialEq, Eq)]
164pub enum ObjColor {
165    White,
166    Black,
167    Gray(usize),
168}
169
170impl fmt::Display for ObjColor {
171    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172        match self {
173            ObjColor::White => f.write_str("white"),
174            ObjColor::Black => f.write_str("black"),
175            ObjColor::Gray(_) => f.write_str("gray"),
176        }
177    }
178}
179
180// ----------------------------------------------------------------------------
181// LangObj
182//
183/// A LangObj describes a named language entity such as a package,
184/// constant, type, variable, function (incl. methods), or label.
185///
186#[derive(Clone, Debug)]
187pub struct LangObj {
188    entity_type: EntityType,
189    parent: Option<ScopeKey>,
190    pos: position::Pos,
191    pkg: Option<PackageKey>,
192    name: String,
193    typ: Option<TypeKey>,
194    order: u32,
195    color: ObjColor,
196    scope_pos: position::Pos,
197}
198
199impl LangObj {
200    pub fn new_pkg_name(
201        pos: position::Pos,
202        pkg: Option<PackageKey>,
203        name: String,
204        imported: PackageKey,
205        univ: &Universe,
206    ) -> LangObj {
207        let t = univ.types()[&typ::BasicType::Invalid];
208        LangObj::new(
209            EntityType::PkgName(imported, false),
210            pos,
211            pkg,
212            name,
213            Some(t),
214        )
215    }
216
217    pub fn new_const(
218        pos: position::Pos,
219        pkg: Option<PackageKey>,
220        name: String,
221        typ: Option<TypeKey>,
222        val: constant::Value,
223    ) -> LangObj {
224        LangObj::new(EntityType::Const(val), pos, pkg, name, typ)
225    }
226
227    pub fn new_type_name(
228        pos: position::Pos,
229        pkg: Option<PackageKey>,
230        name: String,
231        typ: Option<TypeKey>,
232    ) -> LangObj {
233        LangObj::new(EntityType::TypeName, pos, pkg, name, typ)
234    }
235
236    pub fn new_var(
237        pos: position::Pos,
238        pkg: Option<PackageKey>,
239        name: String,
240        typ: Option<TypeKey>,
241    ) -> LangObj {
242        LangObj::new(
243            EntityType::Var(VarProperty::new(false, false, false)),
244            pos,
245            pkg,
246            name,
247            typ,
248        )
249    }
250
251    pub fn new_param_var(
252        pos: position::Pos,
253        pkg: Option<PackageKey>,
254        name: String,
255        typ: Option<TypeKey>,
256    ) -> LangObj {
257        LangObj::new(
258            EntityType::Var(VarProperty::new(false, false, true)),
259            pos,
260            pkg,
261            name,
262            typ,
263        )
264    }
265
266    pub fn new_field(
267        pos: position::Pos,
268        pkg: Option<PackageKey>,
269        name: String,
270        typ: Option<TypeKey>,
271        embedded: bool,
272    ) -> LangObj {
273        LangObj::new(
274            EntityType::Var(VarProperty::new(embedded, true, false)),
275            pos,
276            pkg,
277            name,
278            typ,
279        )
280    }
281
282    pub fn new_func(
283        pos: position::Pos,
284        pkg: Option<PackageKey>,
285        name: String,
286        typ: Option<TypeKey>,
287    ) -> LangObj {
288        LangObj::new(EntityType::Func(false), pos, pkg, name, typ)
289    }
290
291    pub fn new_label(
292        pos: position::Pos,
293        pkg: Option<PackageKey>,
294        name: String,
295        univ: &Universe,
296    ) -> LangObj {
297        let t = univ.types()[&typ::BasicType::Invalid];
298        LangObj::new(EntityType::Label(false), pos, pkg, name, Some(t))
299    }
300
301    pub fn new_builtin(f: universe::Builtin, name: String, typ: TypeKey) -> LangObj {
302        LangObj::new(EntityType::Builtin(f), 0, None, name, Some(typ))
303    }
304
305    pub fn new_nil(typ: TypeKey) -> LangObj {
306        LangObj::new(EntityType::Nil, 0, None, "nil".to_owned(), Some(typ))
307    }
308
309    pub fn entity_type(&self) -> &EntityType {
310        &self.entity_type
311    }
312
313    pub fn entity_type_mut(&mut self) -> &mut EntityType {
314        &mut self.entity_type
315    }
316
317    pub fn parent(&self) -> Option<ScopeKey> {
318        self.parent
319    }
320
321    pub fn pos(&self) -> position::Pos {
322        self.pos
323    }
324
325    pub fn name(&self) -> &String {
326        &self.name
327    }
328
329    pub fn typ(&self) -> Option<TypeKey> {
330        self.typ
331    }
332
333    pub fn pkg(&self) -> Option<PackageKey> {
334        self.pkg
335    }
336
337    pub fn exported(&self) -> bool {
338        ast::is_exported(&self.name)
339    }
340
341    pub fn id(&self, objs: &TCObjects) -> Cow<str> {
342        let pkg = self.pkg.map(|x| &objs.pkgs[x]);
343        get_id(pkg, &self.name)
344    }
345
346    pub fn order(&self) -> u32 {
347        self.order
348    }
349
350    pub fn color(&self) -> ObjColor {
351        self.color
352    }
353
354    pub fn set_type(&mut self, typ: Option<TypeKey>) {
355        self.typ = typ
356    }
357
358    pub fn set_pkg(&mut self, pkg: Option<PackageKey>) {
359        self.pkg = pkg;
360    }
361
362    pub fn set_parent(&mut self, parent: Option<ScopeKey>) {
363        self.parent = parent
364    }
365
366    pub fn scope_pos(&self) -> &position::Pos {
367        &self.scope_pos
368    }
369
370    pub fn set_order(&mut self, order: u32) {
371        assert!(order > 0);
372        self.order = order;
373    }
374
375    pub fn set_color(&mut self, color: ObjColor) {
376        assert!(color != ObjColor::White);
377        self.color = color
378    }
379
380    pub fn set_scope_pos(&mut self, pos: position::Pos) {
381        self.scope_pos = pos
382    }
383
384    pub fn same_id(&self, pkg: Option<PackageKey>, name: &str, objs: &TCObjects) -> bool {
385        // spec:
386        // "Two identifiers are different if they are spelled differently,
387        // or if they appear in different packages and are not exported.
388        // Otherwise, they are the same."
389        if name != self.name {
390            false
391        } else if self.exported() {
392            true
393        } else if pkg.is_none() || self.pkg.is_none() {
394            pkg == self.pkg
395        } else {
396            let a = &objs.pkgs[pkg.unwrap()];
397            let b = &objs.pkgs[self.pkg.unwrap()];
398            a.path() == b.path()
399        }
400    }
401
402    pub fn pkg_name_imported(&self) -> PackageKey {
403        match &self.entity_type {
404            EntityType::PkgName(imported, _) => *imported,
405            _ => unreachable!(),
406        }
407    }
408
409    pub fn const_val(&self) -> &constant::Value {
410        match &self.entity_type {
411            EntityType::Const(val) => val,
412            _ => unreachable!(),
413        }
414    }
415
416    pub fn set_const_val(&mut self, v: constant::Value) {
417        match &mut self.entity_type {
418            EntityType::Const(val) => *val = v,
419            _ => unreachable!(),
420        }
421    }
422
423    pub fn var_embedded(&self) -> bool {
424        match &self.entity_type {
425            EntityType::Var(prop) => prop.embedded,
426            _ => unreachable!(),
427        }
428    }
429
430    pub fn var_is_field(&self) -> bool {
431        match &self.entity_type {
432            EntityType::Var(prop) => prop.is_field,
433            _ => unreachable!(),
434        }
435    }
436
437    pub fn func_fmt_name(&self, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
438        match &self.entity_type {
439            EntityType::Func(_) => fmt_func_name(self, f, objs),
440            _ => unreachable!(),
441        }
442    }
443
444    pub fn func_scope(&self) -> &ScopeKey {
445        unimplemented!()
446    }
447
448    fn new(
449        entity_type: EntityType,
450        pos: position::Pos,
451        pkg: Option<PackageKey>,
452        name: String,
453        typ: Option<TypeKey>,
454    ) -> LangObj {
455        LangObj {
456            entity_type: entity_type,
457            parent: None,
458            pos: pos,
459            pkg: pkg,
460            name: name,
461            typ: typ,
462            order: 0,
463            color: color_for_typ(typ),
464            scope_pos: 0,
465        }
466    }
467}
468
469pub fn type_name_is_alias(okey: ObjKey, objs: &TCObjects) -> bool {
470    let lobj = &objs.lobjs[okey];
471    match lobj.entity_type {
472        EntityType::TypeName => match lobj.typ {
473            Some(t) => {
474                let ty = &objs.types[t];
475                match ty {
476                    typ::Type::Basic(detail) => {
477                        let universe = objs.universe();
478                        // unsafe.Pointer is not an alias.
479                        if lobj.pkg() == Some(*universe.unsafe_pkg()) {
480                            false
481                        } else {
482                            // Any user-defined type name for a basic type is an alias for a
483                            // basic type (because basic types are pre-declared in the Universe
484                            // scope, outside any package scope), and so is any type name with
485                            // a different name than the name of the basic type it refers to.
486                            // Additionally, we need to look for "byte" and "rune" because they
487                            // are aliases but have the same names (for better error messages).
488                            lobj.pkg().is_some()
489                                || detail.name() != lobj.name()
490                                || t == *universe.byte()
491                                || t == *universe.rune()
492                        }
493                    }
494                    typ::Type::Named(detail) => *detail.obj() != Some(okey),
495                    _ => true,
496                }
497            }
498            None => false,
499        },
500        _ => unreachable!(),
501    }
502}
503
504// ----------------------------------------------------------------------------
505// ObjSet
506//
507/// An ObjSet is a set of objects identified by their unique id.
508pub struct ObjSet(HashMap<String, ObjKey>);
509
510impl ObjSet {
511    pub fn new() -> ObjSet {
512        ObjSet(HashMap::new())
513    }
514
515    pub fn insert(&self, okey: ObjKey, objs: &TCObjects) -> Option<&ObjKey> {
516        let obj = &objs.lobjs[okey];
517        let id = obj.id(objs);
518        self.0.get(id.as_ref())
519    }
520}
521
522// ----------------------------------------------------------------------------
523// utilities
524
525pub fn get_id<'a>(pkg: Option<&Package>, name: &'a str) -> Cow<'a, str> {
526    if ast::is_exported(name) {
527        return Cow::Borrowed(name);
528    }
529    let path = if let Some(p) = pkg {
530        if !p.path().is_empty() {
531            p.path()
532        } else {
533            "_"
534        }
535    } else {
536        "_"
537    };
538    Cow::Owned(format!("{}.{}", path, name))
539}
540
541pub fn fmt_obj(okey: ObjKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
542    let obj = &objs.lobjs[okey];
543    match obj.entity_type() {
544        EntityType::PkgName(imported, _) => {
545            write!(f, "package {}", obj.name())?;
546            let path = objs.pkgs[*imported].path();
547            if path != obj.name() {
548                write!(f, " ('{}')", path)?;
549            }
550        }
551        EntityType::Const(_) => {
552            f.write_str("const")?;
553            fmt_obj_name(okey, f, objs)?;
554            fmt_obj_type(okey, f, objs)?;
555        }
556        EntityType::TypeName => {
557            f.write_str("type")?;
558            fmt_obj_name(okey, f, objs)?;
559            fmt_obj_type(okey, f, objs)?;
560        }
561        EntityType::Var(prop) => {
562            f.write_str(if prop.is_field { "field" } else { "var" })?;
563            fmt_obj_name(okey, f, objs)?;
564            fmt_obj_type(okey, f, objs)?;
565        }
566        EntityType::Func(_) => {
567            f.write_str("func ")?;
568            fmt_func_name(obj, f, objs)?;
569            if let Some(t) = obj.typ() {
570                typ::fmt_signature(t, f, objs)?;
571            }
572        }
573        EntityType::Label(_) => {
574            f.write_str("label")?;
575            fmt_obj_name(okey, f, objs)?;
576        }
577        EntityType::Builtin(_) => {
578            f.write_str("builtin")?;
579            fmt_obj_name(okey, f, objs)?;
580        }
581        EntityType::Nil => f.write_str("nil")?,
582    }
583    Ok(())
584}
585
586fn fmt_obj_name(okey: ObjKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
587    f.write_char(' ')?;
588    let obj = &objs.lobjs[okey];
589    if let Some(p) = obj.pkg {
590        let pkg_val = &objs.pkgs[p];
591        if let Some(k) = objs.scopes[*pkg_val.scope()].lookup(obj.name()) {
592            if *k == okey {
593                pkg_val.fmt_with_qualifier(f, objs.fmt_qualifier.as_ref())?;
594            }
595        }
596    }
597    f.write_str(obj.name())
598}
599
600fn fmt_obj_type(okey: ObjKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
601    let obj = &objs.lobjs[okey];
602    if obj.typ().is_none() {
603        return Ok(());
604    }
605    let mut obj_typ = obj.typ().unwrap();
606    if obj.entity_type().is_type_name() {
607        let typ_val = &objs.types[obj.typ().unwrap()];
608        if typ_val.try_as_basic().is_some() {
609            return Ok(());
610        }
611        if type_name_is_alias(okey, objs) {
612            f.write_str(" =")?;
613        } else {
614            obj_typ = typ::underlying_type(obj_typ, objs);
615        }
616    }
617    f.write_char(' ')?;
618    typ::fmt_type(Some(obj_typ), f, objs)
619}
620
621fn fmt_func_name(func: &LangObj, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
622    if let Some(t) = func.typ() {
623        let sig = objs.types[t].try_as_signature().unwrap();
624        if let Some(r) = sig.recv() {
625            f.write_char('(')?;
626            typ::fmt_type(objs.lobjs[*r].typ(), f, objs)?;
627            f.write_str(").")?;
628        } else {
629            if let Some(p) = func.pkg() {
630                objs.pkgs[p].fmt_with_qualifier(f, objs.fmt_qualifier.as_ref())?;
631            }
632        }
633    }
634    f.write_str(func.name())
635}
636
637fn color_for_typ(typ: Option<TypeKey>) -> ObjColor {
638    match typ {
639        Some(_) => ObjColor::Black,
640        None => ObjColor::White,
641    }
642}