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}