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