aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-27 08:01:31 +0100
committerAleksey Kladov <[email protected]>2018-08-27 08:01:31 +0100
commit8b0298ce095b6dd635f7ed35dc97f1874157040b (patch)
tree3d6f941f7612ba1800c1e2f9fbb0a94761999be7 /crates
parent9b69c7df194d5f9081698745ed20414d7c7c2f1c (diff)
scopes
Diffstat (limited to 'crates')
-rw-r--r--crates/libeditor/src/completion.rs178
-rw-r--r--crates/libeditor/tests/test.rs3
-rw-r--r--crates/libsyntax2/src/algo/mod.rs2
-rw-r--r--crates/libsyntax2/src/ast/generated.rs26
-rw-r--r--crates/libsyntax2/src/grammar.ron9
-rw-r--r--crates/libsyntax2/src/yellow/mod.rs2
-rw-r--r--crates/libsyntax2/src/yellow/syntax.rs10
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
33fn complete(name_ref: ast::NameRef) -> Vec<CompletionItem> { 36fn 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
41fn 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>) { 45fn 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 { 78type ScopeId = usize;
66// let mut scopes = FnScopes::new();
67// }
68
69// type ScopeId = usize;
70 79
71// struct FnScopes { 80struct 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 { 85impl 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 124struct ScopeData {
90// } 125 parent: Option<ScopeId>,
126 entries: Vec<ScopeEntry>
127}
91 128
92// struct ScopeData { 129struct ScopeEntry {
93// parent: Option<ScopeId>, 130 syntax: SyntaxNode
94// entries: Vec<ScopeEntry> 131}
95// }
96 132
97// struct ScopeEntry { 133impl 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"
269fn quux(x: i32) { 269fn 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
122fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> { 122pub 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
384impl<'a> Expr<'a> {} 384impl<'a> Expr<'a> {}
385 385
386// ExprStmt
387#[derive(Debug, Clone, Copy)]
388pub struct ExprStmt<'a> {
389 syntax: SyntaxNodeRef<'a>,
390}
391
392impl<'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
402impl<'a> ExprStmt<'a> {}
403
386// FieldExpr 404// FieldExpr
387#[derive(Debug, Clone, Copy)] 405#[derive(Debug, Clone, Copy)]
388pub struct FieldExpr<'a> { 406pub 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)]
70pub(crate) struct RedPtr(ptr::NonNull<RedNode>); 70pub(crate) struct RedPtr(ptr::NonNull<RedNode>);
71 71
72unsafe impl Send for RedPtr {} 72unsafe 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 @@
1use std::{fmt, sync::Arc}; 1use std::{
2 fmt, sync::Arc,
3 hash::{Hasher, Hash},
4};
2 5
3use smol_str::SmolStr; 6use smol_str::SmolStr;
4 7
@@ -27,6 +30,11 @@ impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
27} 30}
28 31
29impl<R: TreeRoot> Eq for SyntaxNode<R> {} 32impl<R: TreeRoot> Eq for SyntaxNode<R> {}
33impl<R: TreeRoot> Hash for SyntaxNode<R> {
34 fn hash<H: Hasher>(&self, state: &mut H) {
35 self.red.hash(state)
36 }
37}
30 38
31pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; 39pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
32 40