aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/completion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src/completion.rs')
-rw-r--r--crates/libeditor/src/completion.rs187
1 files changed, 3 insertions, 184 deletions
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs
index 69c039e83..242a3a434 100644
--- a/crates/libeditor/src/completion.rs
+++ b/crates/libeditor/src/completion.rs
@@ -1,20 +1,14 @@
1use std::{
2 fmt,
3 collections::HashMap,
4};
5
6use libsyntax2::{ 1use libsyntax2::{
7 File, TextUnit, AstNode, SyntaxNodeRef, SyntaxNode, SmolStr, 2 File, TextUnit, AstNode,
8 ast::{self, NameOwner}, 3 ast::self,
9 algo::{ 4 algo::{
10 ancestors, 5 ancestors,
11 walk::preorder,
12 generate,
13 }, 6 },
14}; 7};
15 8
16use { 9use {
17 AtomEdit, find_node_at_offset, 10 AtomEdit, find_node_at_offset,
11 scope::{FnScopes, compute_scopes},
18}; 12};
19 13
20#[derive(Debug)] 14#[derive(Debug)]
@@ -43,178 +37,3 @@ fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec<CompletionItem> {
43 }) 37 })
44 .collect() 38 .collect()
45} 39}
46
47fn compute_scopes(fn_def: ast::FnDef) -> FnScopes {
48 let mut scopes = FnScopes::new();
49 let root = scopes.root_scope();
50 fn_def.param_list().into_iter()
51 .flat_map(|it| it.params())
52 .filter_map(|it| it.pat())
53 .for_each(|it| scopes.add_bindings(root, it));
54
55 if let Some(body) = fn_def.body() {
56 compute_block_scopes(body, &mut scopes, root)
57 }
58 scopes
59}
60
61fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
62 for stmt in block.statements() {
63 match stmt {
64 ast::Stmt::LetStmt(stmt) => {
65 scope = scopes.new_scope(scope);
66 if let Some(pat) = stmt.pat() {
67 scopes.add_bindings(scope, pat);
68 }
69 if let Some(expr) = stmt.initializer() {
70 scopes.set_scope(expr.syntax(), scope)
71 }
72 }
73 ast::Stmt::ExprStmt(expr_stmt) => {
74 if let Some(expr) = expr_stmt.expr() {
75 scopes.set_scope(expr.syntax(), scope);
76 compute_expr_scopes(expr, scopes, scope);
77 }
78 }
79 }
80 }
81 if let Some(expr) = block.expr() {
82 scopes.set_scope(expr.syntax(), scope);
83 compute_expr_scopes(expr, scopes, scope);
84 }
85}
86
87fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
88 match expr {
89 ast::Expr::IfExpr(e) => {
90 let cond_scope = e.condition().and_then(|cond| {
91 compute_cond_scopes(cond, scopes, scope)
92 });
93 if let Some(block) = e.then_branch() {
94 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
95 }
96 if let Some(block) = e.else_branch() {
97 compute_block_scopes(block, scopes, scope);
98 }
99 },
100 ast::Expr::WhileExpr(e) => {
101 let cond_scope = e.condition().and_then(|cond| {
102 compute_cond_scopes(cond, scopes, scope)
103 });
104 if let Some(block) = e.body() {
105 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
106 }
107 },
108 ast::Expr::BlockExpr(e) => {
109 if let Some(block) = e.block() {
110 compute_block_scopes(block, scopes, scope);
111 }
112 }
113 // ForExpr(e) => TODO,
114 _ => {
115 expr.syntax().children()
116 .filter_map(ast::Expr::cast)
117 .for_each(|expr| compute_expr_scopes(expr, scopes, scope))
118 }
119 };
120
121 fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
122 if let Some(expr) = cond.expr() {
123 compute_expr_scopes(expr, scopes, scope);
124 }
125 if let Some(pat) = cond.pat() {
126 let s = scopes.new_scope(scope);
127 scopes.add_bindings(s, pat);
128 Some(s)
129 } else {
130 None
131 }
132 }
133}
134
135type ScopeId = usize;
136
137#[derive(Debug)]
138struct FnScopes {
139 scopes: Vec<ScopeData>,
140 scope_for: HashMap<SyntaxNode, ScopeId>,
141}
142
143impl FnScopes {
144 fn new() -> FnScopes {
145 FnScopes {
146 scopes: vec![],
147 scope_for: HashMap::new(),
148 }
149 }
150 fn root_scope(&mut self) -> ScopeId {
151 let res = self.scopes.len();
152 self.scopes.push(ScopeData { parent: None, entries: vec![] });
153 res
154 }
155 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
156 let res = self.scopes.len();
157 self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
158 res
159 }
160 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
161 let entries = preorder(pat.syntax())
162 .filter_map(ast::BindPat::cast)
163 .filter_map(ScopeEntry::new);
164 self.scopes[scope].entries.extend(entries);
165 }
166 fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
167 self.scope_for.insert(node.owned(), scope);
168 }
169 fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
170 &self.scopes[scope].entries
171 }
172 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
173 ancestors(node)
174 .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
175 .next()
176 }
177 fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
178 generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
179 }
180}
181
182#[derive(Debug)]
183struct ScopeData {
184 parent: Option<ScopeId>,
185 entries: Vec<ScopeEntry>
186}
187
188struct ScopeEntry {
189 syntax: SyntaxNode
190}
191
192impl ScopeEntry {
193 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
194 if pat.name().is_some() {
195 Some(ScopeEntry { syntax: pat.syntax().owned() })
196 } else {
197 None
198 }
199 }
200
201 fn name(&self) -> SmolStr {
202 self.ast().name()
203 .unwrap()
204 .text()
205 }
206
207 fn ast(&self) -> ast::BindPat {
208 ast::BindPat::cast(self.syntax.borrowed())
209 .unwrap()
210 }
211}
212
213impl fmt::Debug for ScopeEntry {
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 f.debug_struct("ScopeEntry")
216 .field("name", &self.name())
217 .field("syntax", &self.syntax)
218 .finish()
219 }
220}