go_types/
selection.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::objects::{ObjKey, TCObjects, TypeKey};
14use super::typ;
15use std::fmt;
16use std::fmt::Write;
17
18/// SelectionKind describes the kind of a selector expression x.f
19/// (excluding qualified identifiers).
20#[derive(Clone, Debug)]
21pub enum SelectionKind {
22    FieldVal,   // x.f is a struct field selector
23    MethodVal,  // x.f is a method selector
24    MethodExpr, // x.f is a method expression
25}
26
27/// A Selection describes a selector expression x.f.
28/// For the declarations:
29///
30///	type T struct{ x int; E }
31///	type E struct{}
32///	func (e E) m() {}
33///	var p *T
34///
35/// the following relations exist:
36///
37///	Selector    Kind          Recv    Obj    Type               Index     Indirect
38///
39///	p.x         FieldVal      T       x      int                {0}       true
40///	p.m         MethodVal     *T      m      func (e *T) m()    {1, 0}    true
41///	T.m         MethodExpr    T       m      func m(_ T)        {1, 0}    false
42///
43#[derive(Clone, Debug)]
44pub struct Selection {
45    kind: SelectionKind,
46    recv: Option<TypeKey>, // type of x
47    obj: ObjKey,           // object denoted by x.f
48    indices: Vec<usize>,   // path from x to x.f
49    indirect: bool,        // set if there was any pointer indirection on the path
50    typ: Option<TypeKey>,  // evaluation delayed
51    id: String,
52}
53
54impl Selection {
55    pub fn new(
56        kind: SelectionKind,
57        recv: Option<TypeKey>,
58        obj: ObjKey,
59        indices: Vec<usize>,
60        indirect: bool,
61        objs: &TCObjects,
62    ) -> Selection {
63        Selection {
64            kind: kind,
65            recv: recv,
66            obj: obj,
67            indices: indices,
68            indirect: indirect,
69            typ: None,
70            id: objs.lobjs[obj].id(objs).to_string(),
71        }
72    }
73
74    pub fn init_type(&mut self, objs: &mut TCObjects) {
75        self.typ = Some(self.eval_type(objs));
76    }
77
78    pub fn kind(&self) -> &SelectionKind {
79        &self.kind
80    }
81
82    pub fn recv(&self) -> Option<TypeKey> {
83        self.recv
84    }
85
86    pub fn obj(&self) -> ObjKey {
87        self.obj
88    }
89
90    /// typ must be called after init is called
91    pub fn typ(&self) -> TypeKey {
92        self.typ.unwrap()
93    }
94
95    pub fn id(&self) -> &String {
96        &self.id
97    }
98
99    /// indices describes the path from x to f in x.f.
100    /// The last indices entry is the field or method indices of the type declaring f;
101    /// either:
102    ///
103    ///	1) the list of declared methods of a named type; or
104    ///	2) the list of methods of an interface type; or
105    ///	3) the list of fields of a struct type.
106    ///
107    /// The earlier indices entries are the indices of the embedded fields implicitly
108    /// traversed to get from (the type of) x to f, starting at embedding depth 0.
109    pub fn indices(&self) -> &Vec<usize> {
110        &self.indices
111    }
112
113    /// Indirect reports whether any pointer indirection was required to get from
114    /// x to f in x.f.
115    pub fn indirect(&self) -> &bool {
116        &self.indirect
117    }
118
119    pub fn fmt(&self, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
120        f.write_str(match self.kind {
121            SelectionKind::FieldVal => "field (",
122            SelectionKind::MethodVal => "method (",
123            SelectionKind::MethodExpr => "method expr (",
124        })?;
125        typ::fmt_type(self.recv(), f, objs)?;
126        write!(f, ") {}", objs.lobjs[self.obj].name())?;
127        match self.kind {
128            SelectionKind::FieldVal => {
129                f.write_char(' ')?;
130                typ::fmt_type(Some(self.typ()), f, objs)?;
131            }
132            _ => typ::fmt_signature(self.typ(), f, objs)?,
133        }
134        Ok(())
135    }
136
137    /// eval_type evaluates the type of x.f, which may be different from the type of f.
138    /// See Selection for more information.
139    fn eval_type(&self, objs: &mut TCObjects) -> TypeKey {
140        let obj = &objs.lobjs[self.obj];
141        match self.kind {
142            SelectionKind::FieldVal => obj.typ().unwrap(),
143            SelectionKind::MethodVal => {
144                let t = &objs.types[obj.typ().unwrap()];
145                let mut sig = *t.try_as_signature().unwrap();
146                let mut new_recv = objs.lobjs[sig.recv().unwrap()].clone();
147                new_recv.set_type(self.recv);
148                sig.set_recv(Some(objs.lobjs.insert(new_recv)));
149                objs.types.insert(typ::Type::Signature(sig))
150            }
151            SelectionKind::MethodExpr => {
152                let t = &objs.types[obj.typ().unwrap()];
153                let mut sig = *t.try_as_signature().unwrap();
154                let mut arg0 = objs.lobjs[sig.recv().unwrap()].clone();
155                arg0.set_type(self.recv);
156                let arg0key = objs.lobjs.insert(arg0);
157                sig.set_recv(None);
158                let mut params = vec![arg0key];
159                let tup = &mut objs.types[sig.params()].try_as_tuple_mut().unwrap();
160                params.append(&mut tup.vars().clone());
161                sig.set_params(objs.new_t_tuple(params));
162                objs.types.insert(typ::Type::Signature(sig))
163            }
164        }
165    }
166}