aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock16
-rw-r--r--crates/gen_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
-rw-r--r--crates/ra_syntax/src/lib.rs173
5 files changed, 184 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f09cf98c8..5912659d4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -46,7 +46,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
46 46
47[[package]] 47[[package]]
48name = "backtrace" 48name = "backtrace"
49version = "0.3.13" 49version = "0.3.14"
50source = "registry+https://github.com/rust-lang/crates.io-index" 50source = "registry+https://github.com/rust-lang/crates.io-index"
51dependencies = [ 51dependencies = [
52 "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 52 "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -319,7 +319,7 @@ name = "error-chain"
319version = "0.12.0" 319version = "0.12.0"
320source = "registry+https://github.com/rust-lang/crates.io-index" 320source = "registry+https://github.com/rust-lang/crates.io-index"
321dependencies = [ 321dependencies = [
322 "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", 322 "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
323] 323]
324 324
325[[package]] 325[[package]]
@@ -327,7 +327,7 @@ name = "failure"
327version = "0.1.5" 327version = "0.1.5"
328source = "registry+https://github.com/rust-lang/crates.io-index" 328source = "registry+https://github.com/rust-lang/crates.io-index"
329dependencies = [ 329dependencies = [
330 "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", 330 "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
331 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 331 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
332] 332]
333 333
@@ -431,7 +431,7 @@ dependencies = [
431 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 431 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
432 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 432 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
433 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 433 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
434 "lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)", 434 "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)",
435 "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", 435 "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
436 "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", 436 "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
437] 437]
@@ -633,7 +633,7 @@ dependencies = [
633 633
634[[package]] 634[[package]]
635name = "lsp-types" 635name = "lsp-types"
636version = "0.55.4" 636version = "0.56.0"
637source = "registry+https://github.com/rust-lang/crates.io-index" 637source = "registry+https://github.com/rust-lang/crates.io-index"
638dependencies = [ 638dependencies = [
639 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 639 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1043,7 +1043,7 @@ dependencies = [
1043 "flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", 1043 "flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
1044 "gen_lsp_server 0.1.0", 1044 "gen_lsp_server 0.1.0",
1045 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1045 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1046 "lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)", 1046 "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)",
1047 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1047 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1048 "ra_arena 0.1.0", 1048 "ra_arena 0.1.0",
1049 "ra_ide_api 0.1.0", 1049 "ra_ide_api 0.1.0",
@@ -1892,7 +1892,7 @@ dependencies = [
1892"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 1892"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
1893"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 1893"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
1894"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" 1894"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
1895"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" 1895"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
1896"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" 1896"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
1897"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1897"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
1898"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" 1898"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a"
@@ -1964,7 +1964,7 @@ dependencies = [
1964"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" 1964"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
1965"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 1965"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
1966"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 1966"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
1967"checksum lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6392b5843615b8a2adeebe87b83fdd29567c0870baba3407a67e6dbfee4712f8" 1967"checksum lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31954f2cf354421e6f99a48fdcfd5c3113c675a0db311960ffdac0b8d45cf09c"
1968"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" 1968"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
1969"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1969"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1970"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" 1970"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml
index a252c911c..9e0d819d0 100644
--- a/crates/gen_lsp_server/Cargo.toml
+++ b/crates/gen_lsp_server/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8description = "Generic LSP server scaffold." 8description = "Generic LSP server scaffold."
9 9
10[dependencies] 10[dependencies]
11lsp-types = "0.55.0" 11lsp-types = "0.56.0"
12log = "0.4.3" 12log = "0.4.3"
13failure = "0.1.4" 13failure = "0.1.4"
14serde_json = "1.0.34" 14serde_json = "1.0.34"
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 6342e0628..ef6dea393 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -15,7 +15,7 @@ crossbeam-channel = "0.3.5"
15flexi_logger = "0.10.0" 15flexi_logger = "0.10.0"
16log = "0.4.3" 16log = "0.4.3"
17url_serde = "0.2.0" 17url_serde = "0.2.0"
18lsp-types = "0.55.0" 18lsp-types = "0.56.0"
19rustc-hash = "1.0" 19rustc-hash = "1.0"
20parking_lot = "0.7.0" 20parking_lot = "0.7.0"
21 21
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 9208ee473..9abd4054e 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -419,7 +419,7 @@ pub fn handle_signature_help(
419 Ok(Some(req::SignatureHelp { 419 Ok(Some(req::SignatureHelp {
420 signatures: vec![sig_info], 420 signatures: vec![sig_info],
421 active_signature: Some(0), 421 active_signature: Some(0),
422 active_parameter: call_info.active_parameter.map(|it| it as u64), 422 active_parameter: call_info.active_parameter.map(|it| it as i64),
423 })) 423 }))
424 } else { 424 } else {
425 Ok(None) 425 Ok(None)
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index dc4b779e8..e7d402446 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -14,6 +14,8 @@
14//! CST). The actual parser live in a separate `ra_parser` crate, thought the 14//! CST). The actual parser live in a separate `ra_parser` crate, thought the
15//! lexer lives in this crate. 15//! lexer lives in this crate.
16//! 16//!
17//! See `api_walkthrough` test in this file for a quick API tour!
18//!
17//! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> 19//! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
18//! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> 20//! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
19 21
@@ -87,3 +89,174 @@ pub fn check_fuzz_invariants(text: &str) {
87 validation::validate_block_structure(root); 89 validation::validate_block_structure(root);
88 let _ = file.errors(); 90 let _ = file.errors();
89} 91}
92
93/// This test does not assert anything and instead just shows off the crate's
94/// API.
95#[test]
96fn api_walkthrough() {
97 use ast::{ModuleItemOwner, NameOwner};
98
99 let source_code = "
100 fn foo() {
101 1 + 1
102 }
103 ";
104 // `SourceFile` is the main entry point.
105 //
106 // Note how `parse` does not return a `Result`: even completely invalid
107 // source code might be parsed.
108 let file = SourceFile::parse(source_code);
109
110 // Due to the way ownership is set up, owned syntax Nodes always live behind
111 // a `TreeArc` smart pointer. `TreeArc` is roughly an `std::sync::Arc` which
112 // points to the whole file instead of an individual node.
113 let file: TreeArc<SourceFile> = file;
114
115 // `SourceFile` is the root of the syntax tree. We can iterate file's items:
116 let mut func = None;
117 for item in file.items() {
118 match item.kind() {
119 ast::ModuleItemKind::FnDef(f) => func = Some(f),
120 _ => unreachable!(),
121 }
122 }
123 // The returned items are always references.
124 let func: &ast::FnDef = func.unwrap();
125
126 // All nodes implement `ToOwned` trait, with `Owned = TreeArc<Self>`.
127 // `to_owned` is a cheap operation: atomic increment.
128 let _owned_func: TreeArc<ast::FnDef> = func.to_owned();
129
130 // Each AST node has a bunch of getters for children. All getters return
131 // `Option`s though, to account for incomplete code. Some getters are common
132 // for several kinds of node. In this case, a trait like `ast::NameOwner`
133 // usually exists. By convention, all ast types should be used with `ast::`
134 // qualifier.
135 let name: Option<&ast::Name> = func.name();
136 let name = name.unwrap();
137 assert_eq!(name.text(), "foo");
138
139 // Let's get the `1 + 1` expression!
140 let block: &ast::Block = func.body().unwrap();
141 let expr: &ast::Expr = block.expr().unwrap();
142
143 // "Enum"-like nodes are represented using the "kind" pattern. It allows us
144 // to match exhaustively against all flavors of nodes, while maintaining
145 // internal representation flexibility. The drawback is that one can't write
146 // nested matches as one pattern.
147 let bin_expr: &ast::BinExpr = match expr.kind() {
148 ast::ExprKind::BinExpr(e) => e,
149 _ => unreachable!(),
150 };
151
152 // Besides the "typed" AST API, there's an untyped CST one as well.
153 // To switch from AST to CST, call `.syntax()` method:
154 let expr_syntax: &SyntaxNode = expr.syntax();
155
156 // Note how `expr` and `bin_expr` are in fact the same node underneath:
157 assert!(std::ptr::eq(expr_syntax, bin_expr.syntax()));
158
159 // To go from CST to AST, `AstNode::cast` function is used:
160 let expr = match ast::Expr::cast(expr_syntax) {
161 Some(e) => e,
162 None => unreachable!(),
163 };
164
165 // Note how expr is also a reference!
166 let expr: &ast::Expr = expr;
167
168 // This is possible because the underlying representation is the same:
169 assert_eq!(
170 expr as *const ast::Expr as *const u8,
171 expr_syntax as *const SyntaxNode as *const u8
172 );
173
174 // The two properties each syntax node has is a `SyntaxKind`:
175 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
176
177 // And text range:
178 assert_eq!(expr_syntax.range(), TextRange::from_to(32.into(), 37.into()));
179
180 // You can get node's text as a `SyntaxText` object, which will traverse the
181 // tree collecting token's text:
182 let text: SyntaxText<'_> = expr_syntax.text();
183 assert_eq!(text.to_string(), "1 + 1");
184
185 // There's a bunch of traversal methods on `SyntaxNode`:
186 assert_eq!(expr_syntax.parent(), Some(block.syntax()));
187 assert_eq!(block.syntax().first_child().map(|it| it.kind()), Some(SyntaxKind::L_CURLY));
188 assert_eq!(expr_syntax.next_sibling().map(|it| it.kind()), Some(SyntaxKind::WHITESPACE));
189
190 // As well as some iterator helpers:
191 let f = expr_syntax.ancestors().find_map(ast::FnDef::cast);
192 assert_eq!(f, Some(&*func));
193 assert!(expr_syntax.siblings(Direction::Next).any(|it| it.kind() == SyntaxKind::R_CURLY));
194 assert_eq!(
195 expr_syntax.descendants().count(),
196 8, // 5 tokens `1`, ` `, `+`, ` `, `!`
197 // 2 child literal expressions: `1`, `1`
198 // 1 the node itself: `1 + 1`
199 );
200
201 // There's also a `preorder` method with a more fine-grained iteration control:
202 let mut buf = String::new();
203 let mut indent = 0;
204 for event in expr_syntax.preorder() {
205 match event {
206 WalkEvent::Enter(node) => {
207 buf += &format!(
208 "{:indent$}{:?} {:?}\n",
209 " ",
210 node.text(),
211 node.kind(),
212 indent = indent
213 );
214 indent += 2;
215 }
216 WalkEvent::Leave(_) => indent -= 2,
217 }
218 }
219 assert_eq!(indent, 0);
220 assert_eq!(
221 buf.trim(),
222 r#"
223"1 + 1" BIN_EXPR
224 "1" LITERAL
225 "1" INT_NUMBER
226 " " WHITESPACE
227 "+" PLUS
228 " " WHITESPACE
229 "1" LITERAL
230 "1" INT_NUMBER
231"#
232 .trim()
233 );
234
235 // To recursively process the tree, there are three approaches:
236 // 1. explicitly call getter methods on AST nodes.
237 // 2. use descendants and `AstNode::cast`.
238 // 3. use descendants and the visitor.
239 //
240 // Here's how the first one looks like:
241 let exprs_cast: Vec<String> = file
242 .syntax()
243 .descendants()
244 .filter_map(ast::Expr::cast)
245 .map(|expr| expr.syntax().text().to_string())
246 .collect();
247
248 // An alternative is to use a visitor. The visitor does not do traversal
249 // automatically (so it's more akin to a generic lambda) and is constructed
250 // from closures. This seems more flexible than a single generated visitor
251 // trait.
252 use algo::visit::{visitor, Visitor};
253 let mut exprs_visit = Vec::new();
254 for node in file.syntax().descendants() {
255 if let Some(result) =
256 visitor().visit::<ast::Expr, _>(|expr| expr.syntax().text().to_string()).accept(node)
257 {
258 exprs_visit.push(result);
259 }
260 }
261 assert_eq!(exprs_cast, exprs_visit);
262}