1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#![allow(dead_code)]
use super::objects::{ObjKey, ScopeKey, TCObjects};
use goscript_parser::position;
use std::collections::HashMap;
use std::fmt;
/// A Scope maintains a set of objects and links to its containing
/// (parent) and contained (children) scopes. Objects may be inserted
/// and looked up by name.
pub struct Scope {
parent: Option<ScopeKey>,
children: Vec<ScopeKey>,
elems: HashMap<String, ObjKey>,
pos: position::Pos, // scope pos; may be invalid
end: position::Pos,
comment: String, // for debugging only
is_func: bool, // set if this is a function scope (internal use only)
}
impl Scope {
pub fn new(
parent: Option<ScopeKey>,
pos: position::Pos,
end: position::Pos,
comment: String,
is_func: bool,
) -> Scope {
Scope {
parent: parent,
children: Vec::new(),
elems: HashMap::new(),
pos: pos,
end: end,
comment: comment,
is_func: is_func,
}
}
pub fn add_child(&mut self, child: ScopeKey) {
self.children.push(child)
}
pub fn parent(&self) -> &Option<ScopeKey> {
&self.parent
}
pub fn children(&self) -> &Vec<ScopeKey> {
&self.children
}
pub fn elems(&self) -> &HashMap<String, ObjKey> {
&self.elems
}
/// len returns the number of scope elements.
pub fn len(&self) -> usize {
self.elems.len()
}
pub fn pos(&self) -> position::Pos {
self.pos
}
pub fn set_pos(&mut self, p: position::Pos) {
self.pos = p;
}
pub fn end(&self) -> position::Pos {
self.end
}
pub fn set_end(&mut self, e: position::Pos) {
self.end = e;
}
pub fn is_func(&self) -> bool {
self.is_func
}
pub fn contains(&self, pos: position::Pos) -> bool {
self.pos <= pos && pos <= self.end
}
/// name returns the scope's element names in sorted order.
pub fn name(&self) -> Vec<String> {
let mut keys: Vec<String> = self.elems.keys().map(|x| x.clone()).collect();
keys.sort();
keys
}
pub fn innermost(&self, _pos: position::Pos) -> Option<ScopeKey> {
unimplemented!() // used by Eval() which is not used?
}
pub fn lookup(&self, name: &str) -> Option<&ObjKey> {
self.elems.get(name)
}
/// lookup_parent follows the parent chain of scopes starting with self until
/// it finds a scope where lookup(name) returns a is_some() object, and then
/// returns that scope and object. If a position pos is provided,
/// only objects that were declared at or before pos are considered.
/// If no such scope and object exists, it returns None.
///
/// Note that obj.parent() may be different from the returned scope if the
/// object was inserted into the scope and already had a parent at that
/// time (see insert, below). This can only happen for dot-imported objects
/// whose scope is the scope of the package that exported them.
pub fn lookup_parent(
self_key: &ScopeKey,
name: &str,
pos: Option<position::Pos>,
objs: &TCObjects,
) -> Option<(ScopeKey, ObjKey)> {
let mut scope_key = *self_key;
let mut s = &objs.scopes[*self_key];
loop {
if let Some(okey) = s.lookup(name) {
if pos.is_none() || *(objs.lobjs[*okey].scope_pos()) <= s.pos {
return Some((scope_key, *okey));
}
}
if let Some(skey) = s.parent {
scope_key = skey;
s = &objs.scopes[skey];
} else {
break;
}
}
None
}
/// insert attempts to insert an object obj into scope s.
/// If s already contains an alternative object alt with
/// the same name, insert leaves s unchanged and returns alt.
/// Otherwise it inserts obj, sets the object's parent scope
/// if not already set, and returns None.
pub fn insert(self_key: ScopeKey, okey: ObjKey, objs: &mut TCObjects) -> Option<ObjKey> {
let scope = &mut objs.scopes[self_key];
let lang_obj = &mut objs.lobjs[okey];
if let Some(obj) = scope.lookup(lang_obj.name()) {
return Some(*obj);
}
scope.elems.insert(lang_obj.name().clone(), okey);
if lang_obj.parent().is_none() {
lang_obj.set_parent(Some(self_key));
}
None
}
/// fmt formats a string representation for the scope.
/// with the scope elements sorted by name.
/// The level of indentation is controlled by n >= 0, with
/// n == 0 for no indentation.
fn fmt(&self, f: &mut fmt::Formatter<'_>, n: usize) -> fmt::Result {
let ind = ". ";
let indn = ind.repeat(n);
write!(f, "{}{} scope \n", indn, self.comment)?;
let mut indn1 = indn.clone();
indn1.push_str(ind);
for name in self.elems.keys() {
write!(f, "{}{}\n", &indn1, name)?;
}
Ok(())
}
}
// ----------------------------------------------------------------------------
// utilities
/// fmt_scope_full formats the scope including it's children.
pub fn fmt_scope_full(
skey: &ScopeKey,
f: &mut fmt::Formatter<'_>,
n: usize,
objs: &TCObjects,
) -> fmt::Result {
let ind = ". ";
let indn = ind.repeat(n);
let sval = &objs.scopes[*skey];
write!(f, "{}{} scope {:?}\n", indn, sval.comment, skey)?;
sval.fmt(f, n)?;
for child in sval.children.iter() {
fmt_scope_full(child, f, n + 1, objs)?;
}
Ok(())
}
impl fmt::Display for Scope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.fmt(f, 0)
}
}