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