|
1 | | -use crate::{cargo, config, json_gen}; |
| 1 | +use crate::{cargo, config}; |
2 | 2 | use anyhow::Context; |
3 | 3 | use log::{error, info}; |
4 | 4 | use ra_ap_hir::{Semantics, attach_db}; |
5 | 5 | use ra_ap_ide::{Analysis, AnalysisHost, LineIndex, RootDatabase}; |
6 | | -use ra_ap_syntax::{AstNode, SyntaxNode}; |
| 6 | +use ra_ap_syntax::{AstNode, NodeOrToken, SyntaxNode, SyntaxToken}; |
7 | 7 | use ra_ap_vfs::{FileId, VfsPath}; |
8 | 8 | use serde::Serialize; |
9 | 9 | use std::path::Path; |
10 | 10 |
|
| 11 | +/// Per-file envelope wrapping the AST. |
| 12 | +#[derive(Serialize)] |
| 13 | +#[serde(rename_all = "camelCase")] |
| 14 | +pub(crate) struct RustAstGenJsonFile { |
| 15 | + pub(crate) relative_file_path: String, |
| 16 | + pub(crate) full_file_path: String, |
| 17 | + pub(crate) content: String, |
| 18 | + pub(crate) loc: u32, |
| 19 | + pub(crate) children: Vec<RustAstGenJsonNode>, |
| 20 | +} |
| 21 | + |
| 22 | +/// A single node or token in the AST. |
11 | 23 | #[derive(Serialize)] |
12 | 24 | #[serde(rename_all = "camelCase")] |
13 | 25 | pub(crate) struct RustAstGenJsonNode { |
14 | 26 | pub(crate) node_kind: String, |
| 27 | + pub(crate) range: RustAstGenJsonNodeRange, |
| 28 | + pub(crate) children: Vec<RustAstGenJsonNode>, |
| 29 | +} |
| 30 | + |
| 31 | +/// Source location range for a node/token. |
| 32 | +#[derive(Serialize)] |
| 33 | +#[serde(rename_all = "camelCase")] |
| 34 | +pub(crate) struct RustAstGenJsonNodeRange { |
15 | 35 | pub(crate) start_offset: u32, |
16 | 36 | pub(crate) end_offset: u32, |
17 | 37 | pub(crate) start_line: u32, |
18 | 38 | pub(crate) start_column: u32, |
19 | | - pub(crate) children: Vec<RustAstGenJsonNode>, |
20 | 39 | } |
21 | 40 |
|
22 | | -pub(crate) fn make_json_node(node: &SyntaxNode, line_index: &LineIndex) -> RustAstGenJsonNode { |
23 | | - let node_kind = format!("{:?}", node.kind()); |
24 | | - |
25 | | - // Note, LineIndex is 0-based (in both line and column) |
26 | | - let text_range = node.text_range(); |
27 | | - let start = text_range.start(); |
28 | | - let end = text_range.end(); |
29 | | - let start_line_col = line_index.line_col(start); |
30 | | - let start_line = start_line_col.line; |
31 | | - let start_column = start_line_col.col; |
32 | | - let start_offset = u32::from(start); |
33 | | - let end_offset = u32::from(end); |
34 | | - |
35 | | - let children = node |
36 | | - .children() |
37 | | - .map(|child| make_json_node(&child, &line_index)) |
38 | | - .collect::<Vec<RustAstGenJsonNode>>(); |
39 | | - |
40 | | - RustAstGenJsonNode { |
41 | | - node_kind, |
42 | | - start_offset, |
43 | | - end_offset, |
44 | | - start_line, |
45 | | - start_column, |
46 | | - children, |
| 41 | +impl RustAstGenJsonNodeRange { |
| 42 | + pub(crate) fn from_node(node: &SyntaxNode, line_index: &LineIndex) -> Self { |
| 43 | + let text_range = node.text_range(); |
| 44 | + let start = text_range.start(); |
| 45 | + let end = text_range.end(); |
| 46 | + let start_line_col = line_index.line_col(start); |
| 47 | + |
| 48 | + Self { |
| 49 | + start_offset: u32::from(start), |
| 50 | + end_offset: u32::from(end), |
| 51 | + start_line: start_line_col.line, |
| 52 | + start_column: start_line_col.col, |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + pub(crate) fn from_token(token: &SyntaxToken, line_index: &LineIndex) -> Self { |
| 57 | + let text_range = token.text_range(); |
| 58 | + let start = text_range.start(); |
| 59 | + let end = text_range.end(); |
| 60 | + let start_line_col = line_index.line_col(start); |
| 61 | + |
| 62 | + Self { |
| 63 | + start_offset: u32::from(start), |
| 64 | + end_offset: u32::from(end), |
| 65 | + start_line: start_line_col.line, |
| 66 | + start_column: start_line_col.col, |
| 67 | + } |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +impl RustAstGenJsonNode { |
| 72 | + pub(crate) fn from_node(node: &SyntaxNode, line_index: &LineIndex) -> Self { |
| 73 | + let node_kind = format!("{:?}", node.kind()); |
| 74 | + let range = RustAstGenJsonNodeRange::from_node(node, line_index); |
| 75 | + let children = node |
| 76 | + .children_with_tokens() |
| 77 | + .filter(|child| !child.kind().is_trivia()) |
| 78 | + .map(|node_or_token| match node_or_token { |
| 79 | + NodeOrToken::Node(child_node) => Self::from_node(&child_node, line_index), |
| 80 | + NodeOrToken::Token(child_token) => { |
| 81 | + RustAstGenJsonNode::from_token(&child_token, line_index) |
| 82 | + } |
| 83 | + }) |
| 84 | + .collect(); |
| 85 | + |
| 86 | + Self { |
| 87 | + node_kind, |
| 88 | + range, |
| 89 | + children, |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + pub(crate) fn from_token(token: &SyntaxToken, line_index: &LineIndex) -> Self { |
| 94 | + let node_kind = format!("{:?}", token.kind()); |
| 95 | + let range = RustAstGenJsonNodeRange::from_token(token, line_index); |
| 96 | + let children = vec![]; |
| 97 | + |
| 98 | + Self { |
| 99 | + node_kind, |
| 100 | + range, |
| 101 | + children, |
| 102 | + } |
47 | 103 | } |
48 | 104 | } |
49 | 105 |
|
@@ -111,13 +167,30 @@ fn process_file( |
111 | 167 |
|
112 | 168 | info!("building the JSON tree: {}", input_file_path.display()); |
113 | 169 |
|
114 | | - let rust_ast_gen_json_node = json_gen::make_json_node(&syntax_tree, &file_line_index); |
| 170 | + let json_root = RustAstGenJsonNode::from_node(&syntax_tree, &file_line_index); |
| 171 | + let contents = syntax_tree.text().to_string(); |
| 172 | + let loc = file_line_index |
| 173 | + .line_col(syntax_tree.text_range().end()) |
| 174 | + .line; |
| 175 | + // TODO: we already have similar in config. Refactor |
| 176 | + let relative_path = input_file_path |
| 177 | + .strip_prefix(&config.input_dir_full_path) |
| 178 | + .with_context(|| format!("failed to strip prefix: {:?}", input_file_path))?; |
| 179 | + |
| 180 | + let envelope = RustAstGenJsonFile { |
| 181 | + relative_file_path: relative_path.to_string_lossy().to_string(), |
| 182 | + full_file_path: input_file_path.to_string_lossy().to_string(), |
| 183 | + content: contents, |
| 184 | + loc, |
| 185 | + children: vec![json_root], |
| 186 | + }; |
| 187 | + |
115 | 188 | let output_file = config.make_output_path_for_input_file(&input_file_path.to_path_buf())?; |
116 | 189 |
|
117 | 190 | info!("writing to: {}", output_file.display()); |
118 | 191 |
|
119 | | - let json_tree = serde_json::to_string_pretty(&rust_ast_gen_json_node)?; |
120 | | - json_gen::write_json_to_file(&json_tree, &output_file)?; |
| 192 | + let json_tree = serde_json::to_string_pretty(&envelope)?; |
| 193 | + write_json_to_file(&json_tree, &output_file)?; |
121 | 194 |
|
122 | 195 | Ok(()) |
123 | 196 | } |
0 commit comments