aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/scope.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-28 16:22:52 +0100
committerAleksey Kladov <[email protected]>2018-08-28 16:22:59 +0100
commitd34588bf83898870d7f9b4b49ac2a5f71c77dabb (patch)
treea0b6eb7b41cb586d1c10e408a4791edf7c341a1f /crates/libeditor/src/scope.rs
parent748a4cacd24d9ecdca995e66117a10a1562e7d5d (diff)
create module smartly
Diffstat (limited to 'crates/libeditor/src/scope.rs')
-rw-r--r--crates/libeditor/src/scope.rs191
1 files changed, 0 insertions, 191 deletions
diff --git a/crates/libeditor/src/scope.rs b/crates/libeditor/src/scope.rs
deleted file mode 100644
index 3d398a74c..000000000
--- a/crates/libeditor/src/scope.rs
+++ /dev/null
@@ -1,191 +0,0 @@
1use std::{
2 fmt,
3 collections::HashMap,
4};
5
6use libsyntax2::{
7 SyntaxNodeRef, SyntaxNode, SmolStr, AstNode,
8 ast::{self, NameOwner},
9 algo::{ancestors, generate, walk::preorder}
10};
11
12fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
13 for stmt in block.statements() {
14 match stmt {
15 ast::Stmt::LetStmt(stmt) => {
16 scope = scopes.new_scope(scope);
17 if let Some(pat) = stmt.pat() {
18 scopes.add_bindings(scope, pat);
19 }
20 if let Some(expr) = stmt.initializer() {
21 scopes.set_scope(expr.syntax(), scope)
22 }
23 }
24 ast::Stmt::ExprStmt(expr_stmt) => {
25 if let Some(expr) = expr_stmt.expr() {
26 scopes.set_scope(expr.syntax(), scope);
27 compute_expr_scopes(expr, scopes, scope);
28 }
29 }
30 }
31 }
32 if let Some(expr) = block.expr() {
33 scopes.set_scope(expr.syntax(), scope);
34 compute_expr_scopes(expr, scopes, scope);
35 }
36}
37
38fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
39 match expr {
40 ast::Expr::IfExpr(e) => {
41 let cond_scope = e.condition().and_then(|cond| {
42 compute_cond_scopes(cond, scopes, scope)
43 });
44 if let Some(block) = e.then_branch() {
45 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
46 }
47 if let Some(block) = e.else_branch() {
48 compute_block_scopes(block, scopes, scope);
49 }
50 },
51 ast::Expr::WhileExpr(e) => {
52 let cond_scope = e.condition().and_then(|cond| {
53 compute_cond_scopes(cond, scopes, scope)
54 });
55 if let Some(block) = e.body() {
56 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
57 }
58 },
59 ast::Expr::BlockExpr(e) => {
60 if let Some(block) = e.block() {
61 compute_block_scopes(block, scopes, scope);
62 }
63 }
64 ast::Expr::ForExpr(e) => {
65 if let Some(expr) = e.iterable() {
66 compute_expr_scopes(expr, scopes, scope);
67 }
68 let mut scope = scope;
69 if let Some(pat) = e.pat() {
70 scope = scopes.new_scope(scope);
71 scopes.add_bindings(scope, pat);
72 }
73 if let Some(block) = e.body() {
74 compute_block_scopes(block, scopes, scope);
75 }
76 },
77 _ => {
78 expr.syntax().children()
79 .filter_map(ast::Expr::cast)
80 .for_each(|expr| compute_expr_scopes(expr, scopes, scope))
81 }
82 };
83
84 fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
85 if let Some(expr) = cond.expr() {
86 compute_expr_scopes(expr, scopes, scope);
87 }
88 if let Some(pat) = cond.pat() {
89 let s = scopes.new_scope(scope);
90 scopes.add_bindings(s, pat);
91 Some(s)
92 } else {
93 None
94 }
95 }
96}
97
98type ScopeId = usize;
99
100#[derive(Debug)]
101pub struct FnScopes {
102 scopes: Vec<ScopeData>,
103 scope_for: HashMap<SyntaxNode, ScopeId>,
104}
105
106impl FnScopes {
107 pub fn new(fn_def: ast::FnDef) -> FnScopes {
108 let mut scopes = FnScopes {
109 scopes: Vec::new(),
110 scope_for: HashMap::new()
111 };
112 let root = scopes.root_scope();
113 fn_def.param_list().into_iter()
114 .flat_map(|it| it.params())
115 .filter_map(|it| it.pat())
116 .for_each(|it| scopes.add_bindings(root, it));
117
118 if let Some(body) = fn_def.body() {
119 compute_block_scopes(body, &mut scopes, root)
120 }
121 scopes
122 }
123 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
124 &self.scopes[scope].entries
125 }
126 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
127 generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
128 }
129 fn root_scope(&mut self) -> ScopeId {
130 let res = self.scopes.len();
131 self.scopes.push(ScopeData { parent: None, entries: vec![] });
132 res
133 }
134 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
135 let res = self.scopes.len();
136 self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
137 res
138 }
139 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
140 let entries = preorder(pat.syntax())
141 .filter_map(ast::BindPat::cast)
142 .filter_map(ScopeEntry::new);
143 self.scopes[scope].entries.extend(entries);
144 }
145 fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
146 self.scope_for.insert(node.owned(), scope);
147 }
148 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
149 ancestors(node)
150 .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
151 .next()
152 }
153}
154
155#[derive(Debug)]
156struct ScopeData {
157 parent: Option<ScopeId>,
158 entries: Vec<ScopeEntry>
159}
160
161pub struct ScopeEntry {
162 syntax: SyntaxNode
163}
164
165impl ScopeEntry {
166 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
167 if pat.name().is_some() {
168 Some(ScopeEntry { syntax: pat.syntax().owned() })
169 } else {
170 None
171 }
172 }
173 pub fn name(&self) -> SmolStr {
174 self.ast().name()
175 .unwrap()
176 .text()
177 }
178 fn ast(&self) -> ast::BindPat {
179 ast::BindPat::cast(self.syntax.borrowed())
180 .unwrap()
181 }
182}
183
184impl fmt::Debug for ScopeEntry {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 f.debug_struct("ScopeEntry")
187 .field("name", &self.name())
188 .field("syntax", &self.syntax)
189 .finish()
190 }
191}