From 8b0298ce095b6dd635f7ed35dc97f1874157040b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Aug 2018 10:01:31 +0300 Subject: scopes --- crates/libeditor/src/completion.rs | 178 +++++++++++++++++++++++-------------- crates/libeditor/tests/test.rs | 3 +- 2 files changed, 111 insertions(+), 70 deletions(-) (limited to 'crates/libeditor') diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs index 351781ec4..6335dba17 100644 --- a/crates/libeditor/src/completion.rs +++ b/crates/libeditor/src/completion.rs @@ -7,6 +7,7 @@ use libsyntax2::{ ancestors, visit::{visitor_ctx, VisitorCtx}, walk::preorder, + generate, }, }; @@ -27,86 +28,125 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option(file.syntax(), offset)?; - Some(complete(name_ref)) + let fn_def = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next()?; + let scopes = compute_scopes(fn_def); + Some(complete(name_ref, &scopes)) } -fn complete(name_ref: ast::NameRef) -> Vec { - let mut res = Vec::new(); - for node in ancestors(name_ref.syntax()) { - process_scope(node, &mut res); - } - res -} - -fn process_scope(node: SyntaxNodeRef, sink: &mut Vec) { - let _ = visitor_ctx(sink) - .visit::(|block, sink| { - block.let_stmts() - .filter_map(|it| it.pat()) - .for_each(move |it| process_pat(it, sink)) - }) - .visit::(|fn_def, sink| { - fn_def.param_list().into_iter() - .flat_map(|it| it.params()) - .filter_map(|it| it.pat()) - .for_each(move |it| process_pat(it, sink)) +fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec { + scopes.scope_chain(name_ref.syntax()) + .flat_map(|scope| scopes.entries(scope).iter()) + .map(|entry| CompletionItem { + name: entry.name().to_string() }) - .accept(node); + .collect() +} - fn process_pat(pat: ast::Pat, sink: &mut Vec) { - let items = preorder(pat.syntax()) - .filter_map(ast::BindPat::cast) - .filter_map(ast::BindPat::name) - .map(|name| CompletionItem { name: name.text().to_string() }); - sink.extend(items); +fn compute_scopes(fn_def: ast::FnDef) -> FnScopes { + let mut scopes = FnScopes::new(); + let root = scopes.root_scope(); + fn_def.param_list().into_iter() + .flat_map(|it| it.params()) + .filter_map(|it| it.pat()) + .for_each(|it| scopes.add_bindings(root, it)); + + let mut scope = root; + if let Some(body) = fn_def.body() { + for child in body.syntax().children() { + let _ = visitor_ctx((&mut scopes, &mut scope)) + .visit::(|stmt, (scopes, scope)| { + *scope = scopes.new_scope(*scope); + if let Some(pat) = stmt.pat() { + scopes.add_bindings(*scope, pat); + } + if let Some(expr) = stmt.initializer() { + scopes.set_scope(expr.syntax(), *scope) + } + }) + .visit::(|expr, (scopes, scope)| { + scopes.set_scope(expr.syntax(), *scope) + }) + .visit::(|expr, (scopes, scope)| { + scopes.set_scope(expr.syntax(), *scope) + }) + .accept(child); + } } + scopes } -// fn compute_scopes(fn_def: ast::FnDef) -> FnScopes { -// let mut scopes = FnScopes::new(); -// } - -// type ScopeId = usize; +type ScopeId = usize; -// struct FnScopes { -// scopes: Vec, -// scope_for_expr: HashMap, -// } - -// impl FnScopes { -// fn new() -> FnScopes { -// FnScopes { -// scopes: vec![], -// scope_for_expr: HashMap::new(), -// } -// } +struct FnScopes { + scopes: Vec, + scope_for: HashMap, +} -// fn new_scope(&mut Self) -> ScopeId { -// let res = self.scopes.len(); -// self.scopes.push(ScopeData { parent: None, entries: vec![] }) -// } +impl FnScopes { + fn new() -> FnScopes { + FnScopes { + scopes: vec![], + scope_for: HashMap::new(), + } + } + fn root_scope(&mut self) -> ScopeId { + let res = self.scopes.len(); + self.scopes.push(ScopeData { parent: None, entries: vec![] }); + res + } + fn new_scope(&mut self, parent: ScopeId) -> ScopeId { + let res = self.scopes.len(); + self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] }); + res + } + fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { + let entries = preorder(pat.syntax()) + .filter_map(ast::BindPat::cast) + .filter_map(ScopeEntry::new); + self.scopes[scope].entries.extend(entries); + } + fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { + self.scope_for.insert(node.owned(), scope); + } + fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { + &self.scopes[scope].entries + } + fn scope_for(&self, node: SyntaxNodeRef) -> Option { + ancestors(node) + .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope)) + .next() + } + fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator + 'a { + generate(self.scope_for(node), move |&scope| self.scopes[scope].parent) + } +} -// fn set_parent -// } +struct ScopeData { + parent: Option, + entries: Vec +} -// struct ScopeData { -// parent: Option, -// entries: Vec -// } +struct ScopeEntry { + syntax: SyntaxNode +} -// struct ScopeEntry { -// syntax: SyntaxNode -// } +impl ScopeEntry { + fn new(pat: ast::BindPat) -> Option { + if pat.name().is_some() { + Some(ScopeEntry { syntax: pat.syntax().owned() }) + } else { + None + } + } -// impl ScopeEntry { -// fn name(&self) -> SmolStr { -// self.ast().name() -// .unwrap() -// .text() -// } + fn name(&self) -> SmolStr { + self.ast().name() + .unwrap() + .text() + } -// fn ast(&self) -> ast::BindPat { -// ast::BindPat::cast(self.syntax.borrowed()) -// .unwrap() -// } -// } + fn ast(&self) -> ast::BindPat { + ast::BindPat::cast(self.syntax.borrowed()) + .unwrap() + } +} diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs index ecdc149c7..7979bfffe 100644 --- a/crates/libeditor/tests/test.rs +++ b/crates/libeditor/tests/test.rs @@ -268,7 +268,8 @@ fn test_completion() { do_check(r" fn quux(x: i32) { let y = 92; - 1 + <|> + 1 + <|>; + let z = (); } ", r#"[CompletionItem { name: "y" }, CompletionItem { name: "x" }]"#); -- cgit v1.2.3