diff options
author | Aleksey Kladov <[email protected]> | 2018-08-27 08:01:31 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-27 08:01:31 +0100 |
commit | 8b0298ce095b6dd635f7ed35dc97f1874157040b (patch) | |
tree | 3d6f941f7612ba1800c1e2f9fbb0a94761999be7 /crates | |
parent | 9b69c7df194d5f9081698745ed20414d7c7c2f1c (diff) |
scopes
Diffstat (limited to 'crates')
-rw-r--r-- | crates/libeditor/src/completion.rs | 178 | ||||
-rw-r--r-- | crates/libeditor/tests/test.rs | 3 | ||||
-rw-r--r-- | crates/libsyntax2/src/algo/mod.rs | 2 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/generated.rs | 26 | ||||
-rw-r--r-- | crates/libsyntax2/src/grammar.ron | 9 | ||||
-rw-r--r-- | crates/libsyntax2/src/yellow/mod.rs | 2 | ||||
-rw-r--r-- | crates/libsyntax2/src/yellow/syntax.rs | 10 |
7 files changed, 155 insertions, 75 deletions
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::{ | |||
7 | ancestors, | 7 | ancestors, |
8 | visit::{visitor_ctx, VisitorCtx}, | 8 | visit::{visitor_ctx, VisitorCtx}, |
9 | walk::preorder, | 9 | walk::preorder, |
10 | generate, | ||
10 | }, | 11 | }, |
11 | }; | 12 | }; |
12 | 13 | ||
@@ -27,86 +28,125 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI | |||
27 | file.incremental_reparse(&edit)? | 28 | file.incremental_reparse(&edit)? |
28 | }; | 29 | }; |
29 | let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?; | 30 | let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?; |
30 | Some(complete(name_ref)) | 31 | let fn_def = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next()?; |
32 | let scopes = compute_scopes(fn_def); | ||
33 | Some(complete(name_ref, &scopes)) | ||
31 | } | 34 | } |
32 | 35 | ||
33 | fn complete(name_ref: ast::NameRef) -> Vec<CompletionItem> { | 36 | fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec<CompletionItem> { |
34 | let mut res = Vec::new(); | 37 | scopes.scope_chain(name_ref.syntax()) |
35 | for node in ancestors(name_ref.syntax()) { | 38 | .flat_map(|scope| scopes.entries(scope).iter()) |
36 | process_scope(node, &mut res); | 39 | .map(|entry| CompletionItem { |
37 | } | 40 | name: entry.name().to_string() |
38 | res | ||
39 | } | ||
40 | |||
41 | fn process_scope(node: SyntaxNodeRef, sink: &mut Vec<CompletionItem>) { | ||
42 | let _ = visitor_ctx(sink) | ||
43 | .visit::<ast::Block, _>(|block, sink| { | ||
44 | block.let_stmts() | ||
45 | .filter_map(|it| it.pat()) | ||
46 | .for_each(move |it| process_pat(it, sink)) | ||
47 | }) | ||
48 | .visit::<ast::FnDef, _>(|fn_def, sink| { | ||
49 | fn_def.param_list().into_iter() | ||
50 | .flat_map(|it| it.params()) | ||
51 | .filter_map(|it| it.pat()) | ||
52 | .for_each(move |it| process_pat(it, sink)) | ||
53 | }) | 41 | }) |
54 | .accept(node); | 42 | .collect() |
43 | } | ||
55 | 44 | ||
56 | fn process_pat(pat: ast::Pat, sink: &mut Vec<CompletionItem>) { | 45 | fn compute_scopes(fn_def: ast::FnDef) -> FnScopes { |
57 | let items = preorder(pat.syntax()) | 46 | let mut scopes = FnScopes::new(); |
58 | .filter_map(ast::BindPat::cast) | 47 | let root = scopes.root_scope(); |
59 | .filter_map(ast::BindPat::name) | 48 | fn_def.param_list().into_iter() |
60 | .map(|name| CompletionItem { name: name.text().to_string() }); | 49 | .flat_map(|it| it.params()) |
61 | sink.extend(items); | 50 | .filter_map(|it| it.pat()) |
51 | .for_each(|it| scopes.add_bindings(root, it)); | ||
52 | |||
53 | let mut scope = root; | ||
54 | if let Some(body) = fn_def.body() { | ||
55 | for child in body.syntax().children() { | ||
56 | let _ = visitor_ctx((&mut scopes, &mut scope)) | ||
57 | .visit::<ast::LetStmt, _>(|stmt, (scopes, scope)| { | ||
58 | *scope = scopes.new_scope(*scope); | ||
59 | if let Some(pat) = stmt.pat() { | ||
60 | scopes.add_bindings(*scope, pat); | ||
61 | } | ||
62 | if let Some(expr) = stmt.initializer() { | ||
63 | scopes.set_scope(expr.syntax(), *scope) | ||
64 | } | ||
65 | }) | ||
66 | .visit::<ast::ExprStmt, _>(|expr, (scopes, scope)| { | ||
67 | scopes.set_scope(expr.syntax(), *scope) | ||
68 | }) | ||
69 | .visit::<ast::Expr, _>(|expr, (scopes, scope)| { | ||
70 | scopes.set_scope(expr.syntax(), *scope) | ||
71 | }) | ||
72 | .accept(child); | ||
73 | } | ||
62 | } | 74 | } |
75 | scopes | ||
63 | } | 76 | } |
64 | 77 | ||
65 | // fn compute_scopes(fn_def: ast::FnDef) -> FnScopes { | 78 | type ScopeId = usize; |
66 | // let mut scopes = FnScopes::new(); | ||
67 | // } | ||
68 | |||
69 | // type ScopeId = usize; | ||
70 | 79 | ||
71 | // struct FnScopes { | 80 | struct FnScopes { |
72 | // scopes: Vec<ScopeData>, | 81 | scopes: Vec<ScopeData>, |
73 | // scope_for_expr: HashMap<SyntaxNode, ScopeId>, | 82 | scope_for: HashMap<SyntaxNode, ScopeId>, |
74 | // } | 83 | } |
75 | |||
76 | // impl FnScopes { | ||
77 | // fn new() -> FnScopes { | ||
78 | // FnScopes { | ||
79 | // scopes: vec![], | ||
80 | // scope_for_expr: HashMap::new(), | ||
81 | // } | ||
82 | // } | ||
83 | 84 | ||
84 | // fn new_scope(&mut Self) -> ScopeId { | 85 | impl FnScopes { |
85 | // let res = self.scopes.len(); | 86 | fn new() -> FnScopes { |
86 | // self.scopes.push(ScopeData { parent: None, entries: vec![] }) | 87 | FnScopes { |
87 | // } | 88 | scopes: vec![], |
89 | scope_for: HashMap::new(), | ||
90 | } | ||
91 | } | ||
92 | fn root_scope(&mut self) -> ScopeId { | ||
93 | let res = self.scopes.len(); | ||
94 | self.scopes.push(ScopeData { parent: None, entries: vec![] }); | ||
95 | res | ||
96 | } | ||
97 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
98 | let res = self.scopes.len(); | ||
99 | self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] }); | ||
100 | res | ||
101 | } | ||
102 | fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { | ||
103 | let entries = preorder(pat.syntax()) | ||
104 | .filter_map(ast::BindPat::cast) | ||
105 | .filter_map(ScopeEntry::new); | ||
106 | self.scopes[scope].entries.extend(entries); | ||
107 | } | ||
108 | fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { | ||
109 | self.scope_for.insert(node.owned(), scope); | ||
110 | } | ||
111 | fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | ||
112 | &self.scopes[scope].entries | ||
113 | } | ||
114 | fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { | ||
115 | ancestors(node) | ||
116 | .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope)) | ||
117 | .next() | ||
118 | } | ||
119 | fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a { | ||
120 | generate(self.scope_for(node), move |&scope| self.scopes[scope].parent) | ||
121 | } | ||
122 | } | ||
88 | 123 | ||
89 | // fn set_parent | 124 | struct ScopeData { |
90 | // } | 125 | parent: Option<ScopeId>, |
126 | entries: Vec<ScopeEntry> | ||
127 | } | ||
91 | 128 | ||
92 | // struct ScopeData { | 129 | struct ScopeEntry { |
93 | // parent: Option<ScopeId>, | 130 | syntax: SyntaxNode |
94 | // entries: Vec<ScopeEntry> | 131 | } |
95 | // } | ||
96 | 132 | ||
97 | // struct ScopeEntry { | 133 | impl ScopeEntry { |
98 | // syntax: SyntaxNode | 134 | fn new(pat: ast::BindPat) -> Option<ScopeEntry> { |
99 | // } | 135 | if pat.name().is_some() { |
136 | Some(ScopeEntry { syntax: pat.syntax().owned() }) | ||
137 | } else { | ||
138 | None | ||
139 | } | ||
140 | } | ||
100 | 141 | ||
101 | // impl ScopeEntry { | 142 | fn name(&self) -> SmolStr { |
102 | // fn name(&self) -> SmolStr { | 143 | self.ast().name() |
103 | // self.ast().name() | 144 | .unwrap() |
104 | // .unwrap() | 145 | .text() |
105 | // .text() | 146 | } |
106 | // } | ||
107 | 147 | ||
108 | // fn ast(&self) -> ast::BindPat { | 148 | fn ast(&self) -> ast::BindPat { |
109 | // ast::BindPat::cast(self.syntax.borrowed()) | 149 | ast::BindPat::cast(self.syntax.borrowed()) |
110 | // .unwrap() | 150 | .unwrap() |
111 | // } | 151 | } |
112 | // } | 152 | } |
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() { | |||
268 | do_check(r" | 268 | do_check(r" |
269 | fn quux(x: i32) { | 269 | fn quux(x: i32) { |
270 | let y = 92; | 270 | let y = 92; |
271 | 1 + <|> | 271 | 1 + <|>; |
272 | let z = (); | ||
272 | } | 273 | } |
273 | ", r#"[CompletionItem { name: "y" }, | 274 | ", r#"[CompletionItem { name: "y" }, |
274 | CompletionItem { name: "x" }]"#); | 275 | CompletionItem { name: "x" }]"#); |
diff --git a/crates/libsyntax2/src/algo/mod.rs b/crates/libsyntax2/src/algo/mod.rs index 2640d60ea..7287f5bb2 100644 --- a/crates/libsyntax2/src/algo/mod.rs +++ b/crates/libsyntax2/src/algo/mod.rs | |||
@@ -119,7 +119,7 @@ fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNo | |||
119 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) | 119 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) |
120 | } | 120 | } |
121 | 121 | ||
122 | fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> { | 122 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> { |
123 | ::itertools::unfold(seed, move |slot| { | 123 | ::itertools::unfold(seed, move |slot| { |
124 | slot.take().map(|curr| { | 124 | slot.take().map(|curr| { |
125 | *slot = step(&curr); | 125 | *slot = step(&curr); |
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index 6926c0535..b937fe5a2 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs | |||
@@ -383,6 +383,24 @@ impl<'a> AstNode<'a> for Expr<'a> { | |||
383 | 383 | ||
384 | impl<'a> Expr<'a> {} | 384 | impl<'a> Expr<'a> {} |
385 | 385 | ||
386 | // ExprStmt | ||
387 | #[derive(Debug, Clone, Copy)] | ||
388 | pub struct ExprStmt<'a> { | ||
389 | syntax: SyntaxNodeRef<'a>, | ||
390 | } | ||
391 | |||
392 | impl<'a> AstNode<'a> for ExprStmt<'a> { | ||
393 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { | ||
394 | match syntax.kind() { | ||
395 | EXPR_STMT => Some(ExprStmt { syntax }), | ||
396 | _ => None, | ||
397 | } | ||
398 | } | ||
399 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | ||
400 | } | ||
401 | |||
402 | impl<'a> ExprStmt<'a> {} | ||
403 | |||
386 | // FieldExpr | 404 | // FieldExpr |
387 | #[derive(Debug, Clone, Copy)] | 405 | #[derive(Debug, Clone, Copy)] |
388 | pub struct FieldExpr<'a> { | 406 | pub struct FieldExpr<'a> { |
@@ -442,6 +460,10 @@ impl<'a> FnDef<'a> { | |||
442 | pub fn param_list(self) -> Option<ParamList<'a>> { | 460 | pub fn param_list(self) -> Option<ParamList<'a>> { |
443 | super::child_opt(self) | 461 | super::child_opt(self) |
444 | } | 462 | } |
463 | |||
464 | pub fn body(self) -> Option<Block<'a>> { | ||
465 | super::child_opt(self) | ||
466 | } | ||
445 | } | 467 | } |
446 | 468 | ||
447 | // FnPointerType | 469 | // FnPointerType |
@@ -626,6 +648,10 @@ impl<'a> LetStmt<'a> { | |||
626 | pub fn pat(self) -> Option<Pat<'a>> { | 648 | pub fn pat(self) -> Option<Pat<'a>> { |
627 | super::child_opt(self) | 649 | super::child_opt(self) |
628 | } | 650 | } |
651 | |||
652 | pub fn initializer(self) -> Option<Expr<'a>> { | ||
653 | super::child_opt(self) | ||
654 | } | ||
629 | } | 655 | } |
630 | 656 | ||
631 | // LoopExpr | 657 | // LoopExpr |
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index 3a125ace6..aa2742b3e 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron | |||
@@ -248,7 +248,8 @@ Grammar( | |||
248 | "AttrsOwner", | 248 | "AttrsOwner", |
249 | ], | 249 | ], |
250 | options: [ | 250 | options: [ |
251 | ["param_list", "ParamList"] | 251 | ["param_list", "ParamList"], |
252 | ["body", "Block"], | ||
252 | ], | 253 | ], |
253 | ), | 254 | ), |
254 | "StructDef": ( | 255 | "StructDef": ( |
@@ -431,7 +432,11 @@ Grammar( | |||
431 | "TypeParamList": ( collections: [ ["type_params", "TypeParam" ] ]), | 432 | "TypeParamList": ( collections: [ ["type_params", "TypeParam" ] ]), |
432 | "TypeParam": ( traits: ["NameOwner"] ), | 433 | "TypeParam": ( traits: ["NameOwner"] ), |
433 | "WhereClause": (), | 434 | "WhereClause": (), |
434 | "LetStmt": ( options: [ ["pat", "Pat"] ]), | 435 | "ExprStmt": (), |
436 | "LetStmt": ( options: [ | ||
437 | ["pat", "Pat"], | ||
438 | ["initializer", "Expr"], | ||
439 | ]), | ||
435 | "Block": ( | 440 | "Block": ( |
436 | collections: [ | 441 | collections: [ |
437 | ["let_stmts", "LetStmt"], | 442 | ["let_stmts", "LetStmt"], |
diff --git a/crates/libsyntax2/src/yellow/mod.rs b/crates/libsyntax2/src/yellow/mod.rs index 3c4510fe7..b94c794fe 100644 --- a/crates/libsyntax2/src/yellow/mod.rs +++ b/crates/libsyntax2/src/yellow/mod.rs | |||
@@ -66,7 +66,7 @@ impl SyntaxRoot { | |||
66 | } | 66 | } |
67 | } | 67 | } |
68 | 68 | ||
69 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 69 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] |
70 | pub(crate) struct RedPtr(ptr::NonNull<RedNode>); | 70 | pub(crate) struct RedPtr(ptr::NonNull<RedNode>); |
71 | 71 | ||
72 | unsafe impl Send for RedPtr {} | 72 | unsafe impl Send for RedPtr {} |
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs index 0045598d4..75b6cb7dc 100644 --- a/crates/libsyntax2/src/yellow/syntax.rs +++ b/crates/libsyntax2/src/yellow/syntax.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use std::{fmt, sync::Arc}; | 1 | use std::{ |
2 | fmt, sync::Arc, | ||
3 | hash::{Hasher, Hash}, | ||
4 | }; | ||
2 | 5 | ||
3 | use smol_str::SmolStr; | 6 | use smol_str::SmolStr; |
4 | 7 | ||
@@ -27,6 +30,11 @@ impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> { | |||
27 | } | 30 | } |
28 | 31 | ||
29 | impl<R: TreeRoot> Eq for SyntaxNode<R> {} | 32 | impl<R: TreeRoot> Eq for SyntaxNode<R> {} |
33 | impl<R: TreeRoot> Hash for SyntaxNode<R> { | ||
34 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
35 | self.red.hash(state) | ||
36 | } | ||
37 | } | ||
30 | 38 | ||
31 | pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; | 39 | pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; |
32 | 40 | ||