diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:19:53 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:20:13 +0100 |
commit | 7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch) | |
tree | bdb47765991cb973b2cd5481a088fac636bd326c /xtask/src | |
parent | ca464650eeaca6195891199a93f4f76cf3e7e697 (diff) | |
parent | e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'xtask/src')
-rw-r--r-- | xtask/src/ast_src.rs | 22 | ||||
-rw-r--r-- | xtask/src/codegen.rs | 49 | ||||
-rw-r--r-- | xtask/src/codegen/gen_assists_docs.rs | 10 | ||||
-rw-r--r-- | xtask/src/codegen/gen_feature_docs.rs | 4 | ||||
-rw-r--r-- | xtask/src/codegen/gen_features.rs | 50 | ||||
-rw-r--r-- | xtask/src/codegen/gen_parser_tests.rs | 8 | ||||
-rw-r--r-- | xtask/src/codegen/gen_syntax.rs | 104 | ||||
-rw-r--r-- | xtask/src/codegen/rust.ungram | 621 | ||||
-rw-r--r-- | xtask/src/lib.rs | 58 | ||||
-rw-r--r-- | xtask/src/main.rs | 14 | ||||
-rw-r--r-- | xtask/src/metrics.rs | 132 | ||||
-rw-r--r-- | xtask/src/pre_cache.rs | 80 |
12 files changed, 613 insertions, 539 deletions
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 114898e38..adc191254 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
@@ -113,12 +113,12 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
113 | "TUPLE_TYPE", | 113 | "TUPLE_TYPE", |
114 | "NEVER_TYPE", | 114 | "NEVER_TYPE", |
115 | "PATH_TYPE", | 115 | "PATH_TYPE", |
116 | "POINTER_TYPE", | 116 | "PTR_TYPE", |
117 | "ARRAY_TYPE", | 117 | "ARRAY_TYPE", |
118 | "SLICE_TYPE", | 118 | "SLICE_TYPE", |
119 | "REFERENCE_TYPE", | 119 | "REF_TYPE", |
120 | "PLACEHOLDER_TYPE", | 120 | "INFER_TYPE", |
121 | "FN_POINTER_TYPE", | 121 | "FN_PTR_TYPE", |
122 | "FOR_TYPE", | 122 | "FOR_TYPE", |
123 | "IMPL_TRAIT_TYPE", | 123 | "IMPL_TRAIT_TYPE", |
124 | "DYN_TRAIT_TYPE", | 124 | "DYN_TRAIT_TYPE", |
@@ -126,13 +126,13 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
126 | "PAREN_PAT", | 126 | "PAREN_PAT", |
127 | "REF_PAT", | 127 | "REF_PAT", |
128 | "BOX_PAT", | 128 | "BOX_PAT", |
129 | "BIND_PAT", | 129 | "IDENT_PAT", |
130 | "PLACEHOLDER_PAT", | 130 | "WILDCARD_PAT", |
131 | "DOT_DOT_PAT", | 131 | "REST_PAT", |
132 | "PATH_PAT", | 132 | "PATH_PAT", |
133 | "RECORD_PAT", | 133 | "RECORD_PAT", |
134 | "RECORD_FIELD_PAT_LIST", | 134 | "RECORD_PAT_FIELD_LIST", |
135 | "RECORD_FIELD_PAT", | 135 | "RECORD_PAT_FIELD", |
136 | "TUPLE_STRUCT_PAT", | 136 | "TUPLE_STRUCT_PAT", |
137 | "TUPLE_PAT", | 137 | "TUPLE_PAT", |
138 | "SLICE_PAT", | 138 | "SLICE_PAT", |
@@ -144,7 +144,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
144 | "ARRAY_EXPR", | 144 | "ARRAY_EXPR", |
145 | "PAREN_EXPR", | 145 | "PAREN_EXPR", |
146 | "PATH_EXPR", | 146 | "PATH_EXPR", |
147 | "LAMBDA_EXPR", | 147 | "CLOSURE_EXPR", |
148 | "IF_EXPR", | 148 | "IF_EXPR", |
149 | "WHILE_EXPR", | 149 | "WHILE_EXPR", |
150 | "CONDITION", | 150 | "CONDITION", |
@@ -208,7 +208,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
208 | "LIFETIME_PARAM", | 208 | "LIFETIME_PARAM", |
209 | "TYPE_PARAM", | 209 | "TYPE_PARAM", |
210 | "CONST_PARAM", | 210 | "CONST_PARAM", |
211 | "TYPE_ARG_LIST", | 211 | "GENERIC_ARG_LIST", |
212 | "LIFETIME_ARG", | 212 | "LIFETIME_ARG", |
213 | "TYPE_ARG", | 213 | "TYPE_ARG", |
214 | "ASSOC_TYPE_ARG", | 214 | "ASSOC_TYPE_ARG", |
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index f5f4b964a..45b17bb48 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs | |||
@@ -9,38 +9,51 @@ mod gen_syntax; | |||
9 | mod gen_parser_tests; | 9 | mod gen_parser_tests; |
10 | mod gen_assists_docs; | 10 | mod gen_assists_docs; |
11 | mod gen_feature_docs; | 11 | mod gen_feature_docs; |
12 | mod gen_features; | ||
12 | 13 | ||
13 | use std::{ | 14 | use std::{ |
14 | fmt, mem, | 15 | fmt, mem, |
15 | path::{Path, PathBuf}, | 16 | path::{Path, PathBuf}, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | use crate::{not_bash::fs2, project_root, Result}; | 19 | use crate::{ |
20 | ensure_rustfmt, | ||
21 | not_bash::{fs2, pushenv, run}, | ||
22 | project_root, Result, | ||
23 | }; | ||
19 | 24 | ||
20 | pub use self::{ | 25 | pub use self::{ |
21 | gen_assists_docs::{generate_assists_docs, generate_assists_tests}, | 26 | gen_assists_docs::{generate_assists_docs, generate_assists_tests}, |
22 | gen_feature_docs::generate_feature_docs, | 27 | gen_feature_docs::generate_feature_docs, |
28 | gen_features::generate_features, | ||
23 | gen_parser_tests::generate_parser_tests, | 29 | gen_parser_tests::generate_parser_tests, |
24 | gen_syntax::generate_syntax, | 30 | gen_syntax::generate_syntax, |
25 | }; | 31 | }; |
26 | 32 | ||
27 | const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar"; | ||
28 | const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/ok"; | ||
29 | const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/err"; | ||
30 | |||
31 | const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/generated.rs"; | ||
32 | const AST_NODES: &str = "crates/ra_syntax/src/ast/generated/nodes.rs"; | ||
33 | const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs"; | ||
34 | |||
35 | const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; | ||
36 | const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs"; | ||
37 | |||
38 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 33 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
39 | pub enum Mode { | 34 | pub enum Mode { |
40 | Overwrite, | 35 | Overwrite, |
41 | Verify, | 36 | Verify, |
42 | } | 37 | } |
43 | 38 | ||
39 | pub struct CodegenCmd { | ||
40 | pub features: bool, | ||
41 | } | ||
42 | |||
43 | impl CodegenCmd { | ||
44 | pub fn run(self) -> Result<()> { | ||
45 | if self.features { | ||
46 | generate_features(Mode::Overwrite)?; | ||
47 | } | ||
48 | generate_syntax(Mode::Overwrite)?; | ||
49 | generate_parser_tests(Mode::Overwrite)?; | ||
50 | generate_assists_tests(Mode::Overwrite)?; | ||
51 | generate_assists_docs(Mode::Overwrite)?; | ||
52 | generate_feature_docs(Mode::Overwrite)?; | ||
53 | Ok(()) | ||
54 | } | ||
55 | } | ||
56 | |||
44 | /// A helper to update file on disk if it has changed. | 57 | /// A helper to update file on disk if it has changed. |
45 | /// With verify = false, | 58 | /// With verify = false, |
46 | fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | 59 | fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { |
@@ -62,6 +75,18 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | |||
62 | } | 75 | } |
63 | } | 76 | } |
64 | 77 | ||
78 | const PREAMBLE: &str = "Generated file, do not edit by hand, see `xtask/src/codegen`"; | ||
79 | |||
80 | fn reformat(text: impl std::fmt::Display) -> Result<String> { | ||
81 | let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); | ||
82 | ensure_rustfmt()?; | ||
83 | let stdout = run!( | ||
84 | "rustfmt --config-path {} --config fn_single_line=true", project_root().join("rustfmt.toml").display(); | ||
85 | <text.to_string().as_bytes() | ||
86 | )?; | ||
87 | Ok(format!("//! {}\n\n{}\n", PREAMBLE, stdout)) | ||
88 | } | ||
89 | |||
65 | fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { | 90 | fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { |
66 | do_extract_comment_blocks(text, false).into_iter().map(|(_line, block)| block).collect() | 91 | do_extract_comment_blocks(text, false).into_iter().map(|(_line, block)| block).collect() |
67 | } | 92 | } |
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 526941f73..f0ded8b87 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use std::{fmt, fs, path::Path}; | 3 | use std::{fmt, fs, path::Path}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode}, | 6 | codegen::{self, extract_comment_blocks_with_empty_lines, reformat, Location, Mode, PREAMBLE}, |
7 | project_root, rust_files, Result, | 7 | project_root, rust_files, Result, |
8 | }; | 8 | }; |
9 | 9 | ||
@@ -15,7 +15,7 @@ pub fn generate_assists_tests(mode: Mode) -> Result<()> { | |||
15 | pub fn generate_assists_docs(mode: Mode) -> Result<()> { | 15 | pub fn generate_assists_docs(mode: Mode) -> Result<()> { |
16 | let assists = Assist::collect()?; | 16 | let assists = Assist::collect()?; |
17 | let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); | 17 | let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); |
18 | let contents = contents.trim().to_string() + "\n"; | 18 | let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); |
19 | let dst = project_root().join("docs/user/generated_assists.adoc"); | 19 | let dst = project_root().join("docs/user/generated_assists.adoc"); |
20 | codegen::update(&dst, &contents, mode) | 20 | codegen::update(&dst, &contents, mode) |
21 | } | 21 | } |
@@ -32,7 +32,7 @@ struct Assist { | |||
32 | impl Assist { | 32 | impl Assist { |
33 | fn collect() -> Result<Vec<Assist>> { | 33 | fn collect() -> Result<Vec<Assist>> { |
34 | let mut res = Vec::new(); | 34 | let mut res = Vec::new(); |
35 | for path in rust_files(&project_root().join(codegen::ASSISTS_DIR)) { | 35 | for path in rust_files(&project_root().join("crates/assists/src/handlers")) { |
36 | collect_file(&mut res, path.as_path())?; | 36 | collect_file(&mut res, path.as_path())?; |
37 | } | 37 | } |
38 | res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); | 38 | res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); |
@@ -134,8 +134,8 @@ r#####" | |||
134 | 134 | ||
135 | buf.push_str(&test) | 135 | buf.push_str(&test) |
136 | } | 136 | } |
137 | let buf = crate::reformat(buf)?; | 137 | let buf = reformat(buf)?; |
138 | codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) | 138 | codegen::update(&project_root().join("crates/assists/src/tests/generated.rs"), &buf, mode) |
139 | } | 139 | } |
140 | 140 | ||
141 | fn hide_hash_comments(text: &str) -> String { | 141 | fn hide_hash_comments(text: &str) -> String { |
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs index 31bc3839d..3f0013e82 100644 --- a/xtask/src/codegen/gen_feature_docs.rs +++ b/xtask/src/codegen/gen_feature_docs.rs | |||
@@ -3,14 +3,14 @@ | |||
3 | use std::{fmt, fs, path::PathBuf}; | 3 | use std::{fmt, fs, path::PathBuf}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode}, | 6 | codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode, PREAMBLE}, |
7 | project_root, rust_files, Result, | 7 | project_root, rust_files, Result, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | pub fn generate_feature_docs(mode: Mode) -> Result<()> { | 10 | pub fn generate_feature_docs(mode: Mode) -> Result<()> { |
11 | let features = Feature::collect()?; | 11 | let features = Feature::collect()?; |
12 | let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); | 12 | let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); |
13 | let contents = contents.trim().to_string() + "\n"; | 13 | let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); |
14 | let dst = project_root().join("docs/user/generated_features.adoc"); | 14 | let dst = project_root().join("docs/user/generated_features.adoc"); |
15 | codegen::update(&dst, &contents, mode)?; | 15 | codegen::update(&dst, &contents, mode)?; |
16 | Ok(()) | 16 | Ok(()) |
diff --git a/xtask/src/codegen/gen_features.rs b/xtask/src/codegen/gen_features.rs new file mode 100644 index 000000000..78268308b --- /dev/null +++ b/xtask/src/codegen/gen_features.rs | |||
@@ -0,0 +1,50 @@ | |||
1 | //! Generates descriptors structure for unstable feature from Unstable Book | ||
2 | use std::path::{Path, PathBuf}; | ||
3 | |||
4 | use quote::quote; | ||
5 | use walkdir::WalkDir; | ||
6 | |||
7 | use crate::{ | ||
8 | codegen::{project_root, reformat, update, Mode, Result}, | ||
9 | not_bash::{fs2, run}, | ||
10 | }; | ||
11 | |||
12 | pub fn generate_features(mode: Mode) -> Result<()> { | ||
13 | if !Path::new("./target/rust").exists() { | ||
14 | run!("git clone https://github.com/rust-lang/rust ./target/rust")?; | ||
15 | } | ||
16 | |||
17 | let contents = generate_descriptor("./target/rust/src/doc/unstable-book/src".into())?; | ||
18 | |||
19 | let destination = project_root().join("crates/ide/src/completion/generated_features.rs"); | ||
20 | update(destination.as_path(), &contents, mode)?; | ||
21 | |||
22 | Ok(()) | ||
23 | } | ||
24 | |||
25 | fn generate_descriptor(src_dir: PathBuf) -> Result<String> { | ||
26 | let definitions = ["language-features", "library-features"] | ||
27 | .iter() | ||
28 | .flat_map(|it| WalkDir::new(src_dir.join(it))) | ||
29 | .filter_map(|e| e.ok()) | ||
30 | .filter(|entry| { | ||
31 | // Get all `.md ` files | ||
32 | entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "md" | ||
33 | }) | ||
34 | .map(|entry| { | ||
35 | let path = entry.path(); | ||
36 | let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_"); | ||
37 | let doc = fs2::read_to_string(path).unwrap(); | ||
38 | |||
39 | quote! { LintCompletion { label: #feature_ident, description: #doc } } | ||
40 | }); | ||
41 | |||
42 | let ts = quote! { | ||
43 | use crate::completion::complete_attribute::LintCompletion; | ||
44 | |||
45 | pub(super) const FEATURES: &[LintCompletion] = &[ | ||
46 | #(#definitions),* | ||
47 | ]; | ||
48 | }; | ||
49 | reformat(ts) | ||
50 | } | ||
diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs index 2977da2fa..96fdd9216 100644 --- a/xtask/src/codegen/gen_parser_tests.rs +++ b/xtask/src/codegen/gen_parser_tests.rs | |||
@@ -8,12 +8,12 @@ use std::{ | |||
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | codegen::{self, extract_comment_blocks, update, Mode}, | 11 | codegen::{extract_comment_blocks, update, Mode}, |
12 | project_root, Result, | 12 | project_root, Result, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub fn generate_parser_tests(mode: Mode) -> Result<()> { | 15 | pub fn generate_parser_tests(mode: Mode) -> Result<()> { |
16 | let tests = tests_from_dir(&project_root().join(Path::new(codegen::GRAMMAR_DIR)))?; | 16 | let tests = tests_from_dir(&project_root().join(Path::new("crates/parser/src/grammar")))?; |
17 | fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> { | 17 | fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> { |
18 | let tests_dir = project_root().join(into); | 18 | let tests_dir = project_root().join(into); |
19 | if !tests_dir.is_dir() { | 19 | if !tests_dir.is_dir() { |
@@ -39,8 +39,8 @@ pub fn generate_parser_tests(mode: Mode) -> Result<()> { | |||
39 | } | 39 | } |
40 | Ok(()) | 40 | Ok(()) |
41 | } | 41 | } |
42 | install_tests(&tests.ok, codegen::OK_INLINE_TESTS_DIR, mode)?; | 42 | install_tests(&tests.ok, "crates/syntax/test_data/parser/inline/ok", mode)?; |
43 | install_tests(&tests.err, codegen::ERR_INLINE_TESTS_DIR, mode) | 43 | install_tests(&tests.err, "crates/syntax/test_data/parser/inline/err", mode) |
44 | } | 44 | } |
45 | 45 | ||
46 | #[derive(Debug)] | 46 | #[derive(Debug)] |
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index 45b788bdb..200e8aa50 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module generates AST datatype used by rust-analyzer. | 1 | //! This module generates AST datatype used by rust-analyzer. |
2 | //! | 2 | //! |
3 | //! Specifically, it generates the `SyntaxKind` enum and a number of newtype | 3 | //! Specifically, it generates the `SyntaxKind` enum and a number of newtype |
4 | //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. | 4 | //! wrappers around `SyntaxNode` which implement `syntax::AstNode`. |
5 | 5 | ||
6 | use std::{ | 6 | use std::{ |
7 | collections::{BTreeSet, HashSet}, | 7 | collections::{BTreeSet, HashSet}, |
@@ -10,29 +10,27 @@ use std::{ | |||
10 | 10 | ||
11 | use proc_macro2::{Punct, Spacing}; | 11 | use proc_macro2::{Punct, Spacing}; |
12 | use quote::{format_ident, quote}; | 12 | use quote::{format_ident, quote}; |
13 | use ungrammar::{Grammar, Rule}; | 13 | use ungrammar::{rust_grammar, Grammar, Rule}; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, | 16 | ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, |
17 | codegen::{self, update, Mode}, | 17 | codegen::{reformat, update, Mode}, |
18 | project_root, Result, | 18 | project_root, Result, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | pub fn generate_syntax(mode: Mode) -> Result<()> { | 21 | pub fn generate_syntax(mode: Mode) -> Result<()> { |
22 | let grammar = include_str!("rust.ungram") | 22 | let grammar = rust_grammar(); |
23 | .parse::<Grammar>() | ||
24 | .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err)); | ||
25 | let ast = lower(&grammar); | 23 | let ast = lower(&grammar); |
26 | 24 | ||
27 | let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); | 25 | let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs"); |
28 | let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; | 26 | let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; |
29 | update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; | 27 | update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; |
30 | 28 | ||
31 | let ast_tokens_file = project_root().join(codegen::AST_TOKENS); | 29 | let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs"); |
32 | let contents = generate_tokens(&ast)?; | 30 | let contents = generate_tokens(&ast)?; |
33 | update(ast_tokens_file.as_path(), &contents, mode)?; | 31 | update(ast_tokens_file.as_path(), &contents, mode)?; |
34 | 32 | ||
35 | let ast_nodes_file = project_root().join(codegen::AST_NODES); | 33 | let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs"); |
36 | let contents = generate_nodes(KINDS_SRC, &ast)?; | 34 | let contents = generate_nodes(KINDS_SRC, &ast)?; |
37 | update(ast_nodes_file.as_path(), &contents, mode)?; | 35 | update(ast_nodes_file.as_path(), &contents, mode)?; |
38 | 36 | ||
@@ -63,7 +61,7 @@ fn generate_tokens(grammar: &AstSrc) -> Result<String> { | |||
63 | } | 61 | } |
64 | }); | 62 | }); |
65 | 63 | ||
66 | let pretty = crate::reformat(quote! { | 64 | let pretty = reformat(quote! { |
67 | use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken}; | 65 | use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken}; |
68 | #(#tokens)* | 66 | #(#tokens)* |
69 | })? | 67 | })? |
@@ -153,25 +151,10 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> { | |||
153 | quote!(impl ast::#trait_name for #name {}) | 151 | quote!(impl ast::#trait_name for #name {}) |
154 | }); | 152 | }); |
155 | 153 | ||
156 | ( | 154 | let ast_node = if en.name == "Stmt" { |
155 | quote! {} | ||
156 | } else { | ||
157 | quote! { | 157 | quote! { |
158 | #[pretty_doc_comment_placeholder_workaround] | ||
159 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
160 | pub enum #name { | ||
161 | #(#variants(#variants),)* | ||
162 | } | ||
163 | |||
164 | #(#traits)* | ||
165 | }, | ||
166 | quote! { | ||
167 | #( | ||
168 | impl From<#variants> for #name { | ||
169 | fn from(node: #variants) -> #name { | ||
170 | #name::#variants(node) | ||
171 | } | ||
172 | } | ||
173 | )* | ||
174 | |||
175 | impl AstNode for #name { | 158 | impl AstNode for #name { |
176 | fn can_cast(kind: SyntaxKind) -> bool { | 159 | fn can_cast(kind: SyntaxKind) -> bool { |
177 | match kind { | 160 | match kind { |
@@ -196,6 +179,28 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> { | |||
196 | } | 179 | } |
197 | } | 180 | } |
198 | } | 181 | } |
182 | } | ||
183 | }; | ||
184 | |||
185 | ( | ||
186 | quote! { | ||
187 | #[pretty_doc_comment_placeholder_workaround] | ||
188 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
189 | pub enum #name { | ||
190 | #(#variants(#variants),)* | ||
191 | } | ||
192 | |||
193 | #(#traits)* | ||
194 | }, | ||
195 | quote! { | ||
196 | #( | ||
197 | impl From<#variants> for #name { | ||
198 | fn from(node: #variants) -> #name { | ||
199 | #name::#variants(node) | ||
200 | } | ||
201 | } | ||
202 | )* | ||
203 | #ast_node | ||
199 | }, | 204 | }, |
200 | ) | 205 | ) |
201 | }) | 206 | }) |
@@ -256,7 +261,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> { | |||
256 | } | 261 | } |
257 | } | 262 | } |
258 | 263 | ||
259 | let pretty = crate::reformat(res)?; | 264 | let pretty = reformat(res)?; |
260 | Ok(pretty) | 265 | Ok(pretty) |
261 | } | 266 | } |
262 | 267 | ||
@@ -378,7 +383,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> { | |||
378 | } | 383 | } |
379 | }; | 384 | }; |
380 | 385 | ||
381 | crate::reformat(ast) | 386 | reformat(ast) |
382 | } | 387 | } |
383 | 388 | ||
384 | fn to_upper_snake_case(s: &str) -> String { | 389 | fn to_upper_snake_case(s: &str) -> String { |
@@ -472,11 +477,18 @@ impl Field { | |||
472 | "#" => "pound", | 477 | "#" => "pound", |
473 | "?" => "question_mark", | 478 | "?" => "question_mark", |
474 | "," => "comma", | 479 | "," => "comma", |
480 | "|" => "pipe", | ||
475 | _ => name, | 481 | _ => name, |
476 | }; | 482 | }; |
477 | format_ident!("{}_token", name) | 483 | format_ident!("{}_token", name) |
478 | } | 484 | } |
479 | Field::Node { name, .. } => format_ident!("{}", name), | 485 | Field::Node { name, .. } => { |
486 | if name == "type" { | ||
487 | format_ident!("ty") | ||
488 | } else { | ||
489 | format_ident!("{}", name) | ||
490 | } | ||
491 | } | ||
480 | } | 492 | } |
481 | } | 493 | } |
482 | fn ty(&self) -> proc_macro2::Ident { | 494 | fn ty(&self) -> proc_macro2::Ident { |
@@ -491,13 +503,7 @@ fn lower(grammar: &Grammar) -> AstSrc { | |||
491 | let mut res = AstSrc::default(); | 503 | let mut res = AstSrc::default(); |
492 | res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; | 504 | res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; |
493 | 505 | ||
494 | let nodes = grammar | 506 | let nodes = grammar.iter().collect::<Vec<_>>(); |
495 | .iter() | ||
496 | .filter(|&node| match grammar[node].rule { | ||
497 | Rule::Node(it) if it == node => false, | ||
498 | _ => true, | ||
499 | }) | ||
500 | .collect::<Vec<_>>(); | ||
501 | 507 | ||
502 | for &node in &nodes { | 508 | for &node in &nodes { |
503 | let name = grammar[node].name.clone(); | 509 | let name = grammar[node].name.clone(); |
@@ -531,6 +537,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> { | |||
531 | for alternative in alternatives { | 537 | for alternative in alternatives { |
532 | match alternative { | 538 | match alternative { |
533 | Rule::Node(it) => variants.push(grammar[*it].name.clone()), | 539 | Rule::Node(it) => variants.push(grammar[*it].name.clone()), |
540 | Rule::Token(it) if grammar[*it].name == ";" => (), | ||
534 | _ => return None, | 541 | _ => return None, |
535 | } | 542 | } |
536 | } | 543 | } |
@@ -572,6 +579,24 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r | |||
572 | } | 579 | } |
573 | Rule::Labeled { label: l, rule } => { | 580 | Rule::Labeled { label: l, rule } => { |
574 | assert!(label.is_none()); | 581 | assert!(label.is_none()); |
582 | let manually_implemented = matches!( | ||
583 | l.as_str(), | ||
584 | "lhs" | ||
585 | | "rhs" | ||
586 | | "then_branch" | ||
587 | | "else_branch" | ||
588 | | "start" | ||
589 | | "end" | ||
590 | | "op" | ||
591 | | "index" | ||
592 | | "base" | ||
593 | | "value" | ||
594 | | "trait" | ||
595 | | "self_ty" | ||
596 | ); | ||
597 | if manually_implemented { | ||
598 | return; | ||
599 | } | ||
575 | lower_rule(acc, grammar, Some(l), rule); | 600 | lower_rule(acc, grammar, Some(l), rule); |
576 | } | 601 | } |
577 | Rule::Seq(rules) | Rule::Alt(rules) => { | 602 | Rule::Seq(rules) | Rule::Alt(rules) => { |
@@ -687,6 +712,9 @@ fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str | |||
687 | 712 | ||
688 | fn extract_enum_traits(ast: &mut AstSrc) { | 713 | fn extract_enum_traits(ast: &mut AstSrc) { |
689 | for enm in &mut ast.enums { | 714 | for enm in &mut ast.enums { |
715 | if enm.name == "Stmt" { | ||
716 | continue; | ||
717 | } | ||
690 | let nodes = &ast.nodes; | 718 | let nodes = &ast.nodes; |
691 | let mut variant_traits = enm | 719 | let mut variant_traits = enm |
692 | .variants | 720 | .variants |
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram index 375df301f..aca23890c 100644 --- a/xtask/src/codegen/rust.ungram +++ b/xtask/src/codegen/rust.ungram | |||
@@ -1,3 +1,63 @@ | |||
1 | //*************************// | ||
2 | // Names, Paths and Macros // | ||
3 | //*************************// | ||
4 | |||
5 | Name = | ||
6 | 'ident' | ||
7 | |||
8 | NameRef = | ||
9 | 'ident' | 'int_number' | ||
10 | |||
11 | Path = | ||
12 | (qualifier:Path '::')? segment:PathSegment | ||
13 | |||
14 | PathSegment = | ||
15 | 'crate' | 'self' | 'super' | ||
16 | | '::' NameRef | ||
17 | | NameRef GenericArgList? | ||
18 | | NameRef ParamList RetType? | ||
19 | | '<' PathType ('as' PathType)? '>' | ||
20 | |||
21 | GenericArgList = | ||
22 | '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' | ||
23 | |||
24 | GenericArg = | ||
25 | TypeArg | ||
26 | | AssocTypeArg | ||
27 | | LifetimeArg | ||
28 | | ConstArg | ||
29 | |||
30 | TypeArg = | ||
31 | Type | ||
32 | |||
33 | AssocTypeArg = | ||
34 | NameRef (':' TypeBoundList | '=' Type) | ||
35 | |||
36 | LifetimeArg = | ||
37 | 'lifetime' | ||
38 | |||
39 | ConstArg = | ||
40 | Expr | ||
41 | |||
42 | MacroCall = | ||
43 | Attr* Path '!' Name? TokenTree ';'? | ||
44 | |||
45 | TokenTree = | ||
46 | '(' ')' | ||
47 | | '{' '}' | ||
48 | | '[' ']' | ||
49 | |||
50 | MacroItems = | ||
51 | Item* | ||
52 | |||
53 | MacroStmts = | ||
54 | statements:Stmt* | ||
55 | Expr? | ||
56 | |||
57 | //*************************// | ||
58 | // Items // | ||
59 | //*************************// | ||
60 | |||
1 | SourceFile = | 61 | SourceFile = |
2 | 'shebang'? | 62 | 'shebang'? |
3 | Attr* | 63 | Attr* |
@@ -61,22 +121,22 @@ ParamList = | |||
61 | SelfParam = | 121 | SelfParam = |
62 | Attr* ( | 122 | Attr* ( |
63 | ('&' 'lifetime'?)? 'mut'? 'self' | 123 | ('&' 'lifetime'?)? 'mut'? 'self' |
64 | | 'mut'? 'self' ':' ty:TypeRef | 124 | | 'mut'? 'self' ':' Type |
65 | ) | 125 | ) |
66 | 126 | ||
67 | Param = | 127 | Param = |
68 | Attr* ( | 128 | Attr* ( |
69 | Pat (':' ty:TypeRef) | 129 | Pat (':' Type) |
70 | | ty:TypeRef | 130 | | Type |
71 | | '...' | 131 | | '...' |
72 | ) | 132 | ) |
73 | 133 | ||
74 | RetType = | 134 | RetType = |
75 | '->' ty:TypeRef | 135 | '->' Type |
76 | 136 | ||
77 | TypeAlias = | 137 | TypeAlias = |
78 | Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause? | 138 | Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause? |
79 | '=' ty:TypeRef ';' | 139 | '=' Type ';' |
80 | 140 | ||
81 | Struct = | 141 | Struct = |
82 | Attr* Visibility? 'struct' Name GenericParamList? ( | 142 | Attr* Visibility? 'struct' Name GenericParamList? ( |
@@ -88,13 +148,13 @@ RecordFieldList = | |||
88 | '{' fields:(RecordField (',' RecordField)* ','?)? '}' | 148 | '{' fields:(RecordField (',' RecordField)* ','?)? '}' |
89 | 149 | ||
90 | RecordField = | 150 | RecordField = |
91 | Attr* Visibility? Name ':' ty:TypeRef | 151 | Attr* Visibility? Name ':' Type |
92 | 152 | ||
93 | TupleFieldList = | 153 | TupleFieldList = |
94 | '(' fields:(TupleField (',' TupleField)* ','?)? ')' | 154 | '(' fields:(TupleField (',' TupleField)* ','?)? ')' |
95 | 155 | ||
96 | TupleField = | 156 | TupleField = |
97 | Attr* Visibility? ty:TypeRef | 157 | Attr* Visibility? Type |
98 | 158 | ||
99 | FieldList = | 159 | FieldList = |
100 | RecordFieldList | 160 | RecordFieldList |
@@ -114,12 +174,17 @@ Union = | |||
114 | Attr* Visibility? 'union' Name GenericParamList? WhereClause? | 174 | Attr* Visibility? 'union' Name GenericParamList? WhereClause? |
115 | RecordFieldList | 175 | RecordFieldList |
116 | 176 | ||
177 | AdtDef = | ||
178 | Enum | ||
179 | | Struct | ||
180 | | Union | ||
181 | |||
117 | Const = | 182 | Const = |
118 | Attr* Visibility? 'default'? 'const' (Name | '_') ':' ty:TypeRef | 183 | Attr* Visibility? 'default'? 'const' (Name | '_') ':' Type |
119 | '=' body:Expr ';' | 184 | '=' body:Expr ';' |
120 | 185 | ||
121 | Static = | 186 | Static = |
122 | Attr* Visibility? 'static'? 'mut'? Name ':' ty:TypeRef | 187 | Attr* Visibility? 'static'? 'mut'? Name ':' Type |
123 | '=' body:Expr ';' | 188 | '=' body:Expr ';' |
124 | 189 | ||
125 | Trait = | 190 | Trait = |
@@ -131,18 +196,17 @@ AssocItemList = | |||
131 | '{' Attr* AssocItem* '}' | 196 | '{' Attr* AssocItem* '}' |
132 | 197 | ||
133 | AssocItem = | 198 | AssocItem = |
134 | Fn | 199 | Const |
135 | | TypeAlias | 200 | | Fn |
136 | | Const | ||
137 | | MacroCall | 201 | | MacroCall |
202 | | TypeAlias | ||
138 | 203 | ||
139 | Impl = | 204 | Impl = |
140 | Attr* Visibility? | 205 | Attr* Visibility? |
141 | 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? ( | 206 | 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? |
142 | TypeRef | 207 | ('!'? target_trait:Type 'for')? target_type:Type |
143 | | '!'? TypeRef 'for' TypeRef | 208 | WhereClause? |
144 | ) WhereClause? | 209 | AssocItemList |
145 | AssocItemList | ||
146 | 210 | ||
147 | ExternBlock = | 211 | ExternBlock = |
148 | Attr* Abi ExternItemList | 212 | Attr* Abi ExternItemList |
@@ -157,20 +221,26 @@ GenericParamList = | |||
157 | '<' (GenericParam (',' GenericParam)* ','?)? '>' | 221 | '<' (GenericParam (',' GenericParam)* ','?)? '>' |
158 | 222 | ||
159 | GenericParam = | 223 | GenericParam = |
160 | LifetimeParam | 224 | ConstParam |
225 | | LifetimeParam | ||
161 | | TypeParam | 226 | | TypeParam |
162 | | ConstParam | ||
163 | 227 | ||
164 | TypeParam = | 228 | TypeParam = |
165 | Attr* Name (':' TypeBoundList?)? | 229 | Attr* Name (':' TypeBoundList?)? |
166 | ('=' default_type:TypeRef)? | 230 | ('=' default_type:Type)? |
167 | 231 | ||
168 | ConstParam = | 232 | ConstParam = |
169 | Attr* 'const' Name ':' ty:TypeRef | 233 | Attr* 'const' Name ':' Type |
170 | ('=' default_val:Expr)? | 234 | ('=' default_val:Expr)? |
171 | 235 | ||
172 | LifetimeParam = | 236 | LifetimeParam = |
173 | Attr* 'lifetime' | 237 | Attr* 'lifetime' (':' TypeBoundList?)? |
238 | |||
239 | WhereClause = | ||
240 | 'where' predicates:(WherePred (',' WherePred)* ','?) | ||
241 | |||
242 | WherePred = | ||
243 | ('for' GenericParamList)? ('lifetime' | Type) ':' TypeBoundList | ||
174 | 244 | ||
175 | Visibility = | 245 | Visibility = |
176 | 'pub' ('(' | 246 | 'pub' ('(' |
@@ -183,362 +253,335 @@ Visibility = | |||
183 | Attr = | 253 | Attr = |
184 | '#' '!'? '[' Path ('=' Literal | TokenTree)? ']' | 254 | '#' '!'? '[' Path ('=' Literal | TokenTree)? ']' |
185 | 255 | ||
186 | ParenType = | 256 | //****************************// |
187 | '(' ty:TypeRef ')' | 257 | // Statements and Expressions // |
258 | //****************************// | ||
188 | 259 | ||
189 | TupleType = | 260 | Stmt = |
190 | '(' fields:TypeRef* ')' | 261 | ExprStmt |
262 | | Item | ||
263 | | LetStmt | ||
191 | 264 | ||
192 | NeverType = | 265 | LetStmt = |
193 | '!' | 266 | Attr* 'let' Pat (':' Type)? |
267 | '=' initializer:Expr ';' | ||
194 | 268 | ||
195 | PathType = | 269 | ExprStmt = |
196 | Path | 270 | Attr* Expr ';'? |
197 | 271 | ||
198 | PointerType = | 272 | Expr = |
199 | '*' ('const' | 'mut') ty:TypeRef | 273 | ArrayExpr |
274 | | AwaitExpr | ||
275 | | BinExpr | ||
276 | | BlockExpr | ||
277 | | BoxExpr | ||
278 | | BreakExpr | ||
279 | | CallExpr | ||
280 | | CastExpr | ||
281 | | ClosureExpr | ||
282 | | ContinueExpr | ||
283 | | EffectExpr | ||
284 | | FieldExpr | ||
285 | | ForExpr | ||
286 | | IfExpr | ||
287 | | IndexExpr | ||
288 | | Literal | ||
289 | | LoopExpr | ||
290 | | MacroCall | ||
291 | | MatchExpr | ||
292 | | MethodCallExpr | ||
293 | | ParenExpr | ||
294 | | PathExpr | ||
295 | | PrefixExpr | ||
296 | | RangeExpr | ||
297 | | RecordExpr | ||
298 | | RefExpr | ||
299 | | ReturnExpr | ||
300 | | TryExpr | ||
301 | | TupleExpr | ||
302 | | WhileExpr | ||
200 | 303 | ||
201 | ArrayType = | 304 | Literal = |
202 | '[' ty:TypeRef ';' Expr ']' | 305 | Attr* value:( |
306 | 'int_number' | 'float_number' | ||
307 | | 'string' | 'raw_string' | ||
308 | | 'byte_string' | 'raw_byte_string' | ||
309 | | 'true' | 'false' | ||
310 | | 'char' | 'byte' | ||
311 | ) | ||
203 | 312 | ||
204 | SliceType = | 313 | PathExpr = |
205 | '[' ty:TypeRef ']' | 314 | Attr* Path |
206 | 315 | ||
207 | ReferenceType = | 316 | BlockExpr = |
208 | '&' 'lifetime'? 'mut'? ty:TypeRef | 317 | '{' |
318 | Attr* | ||
319 | statements:Stmt* | ||
320 | Expr? | ||
321 | '}' | ||
209 | 322 | ||
210 | PlaceholderType = | 323 | RefExpr = |
211 | '_' | 324 | Attr* '&' ('raw' |'mut' | 'const') Expr |
212 | 325 | ||
213 | FnPointerType = | 326 | TryExpr = |
214 | Abi 'unsafe'? 'fn' ParamList RetType? | 327 | Attr* Expr '?' |
215 | 328 | ||
216 | ForType = | 329 | EffectExpr = |
217 | 'for' GenericParamList ty:TypeRef | 330 | Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr |
218 | 331 | ||
219 | ImplTraitType = | 332 | PrefixExpr = |
220 | 'impl' TypeBoundList | 333 | Attr* op:('-' | '!' | '*') Expr |
221 | 334 | ||
222 | DynTraitType = | 335 | BinExpr = |
223 | 'dyn' TypeBoundList | 336 | Attr* |
337 | lhs:Expr | ||
338 | op:( | ||
339 | '||' | '&&' | ||
340 | | '==' | '!=' | '<=' | '>=' | '<' | '>' | ||
341 | | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&' | ||
342 | | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^=' | ||
343 | ) | ||
344 | rhs:Expr | ||
224 | 345 | ||
225 | TupleExpr = | 346 | CastExpr = |
226 | Attr* '(' Expr* ')' | 347 | Attr* Expr 'as' Type |
348 | |||
349 | ParenExpr = | ||
350 | Attr* '(' Attr* Expr ')' | ||
227 | 351 | ||
228 | ArrayExpr = | 352 | ArrayExpr = |
229 | Attr* '[' (Expr* | Expr ';' Expr) ']' | 353 | Attr* '[' Attr* ( |
354 | (Expr (',' Expr)* ','?)? | ||
355 | | Expr ';' Expr | ||
356 | ) ']' | ||
230 | 357 | ||
231 | ParenExpr = | 358 | IndexExpr = |
232 | Attr* '(' Expr ')' | 359 | Attr* base:Expr '[' index:Expr ']' |
233 | 360 | ||
234 | PathExpr = | 361 | TupleExpr = |
235 | Path | 362 | Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')' |
363 | |||
364 | RecordExpr = | ||
365 | Path RecordExprFieldList | ||
366 | |||
367 | RecordExprFieldList = | ||
368 | '{' | ||
369 | Attr* | ||
370 | fields:(RecordExprField (',' RecordExprField)* ','?) | ||
371 | ('..' spread:Expr)? | ||
372 | '}' | ||
373 | |||
374 | RecordExprField = | ||
375 | Attr* NameRef (':' Expr)? | ||
376 | |||
377 | CallExpr = | ||
378 | Attr* Expr ArgList | ||
379 | |||
380 | ArgList = | ||
381 | '(' args:(Expr (',' Expr)* ','?)? ')' | ||
382 | |||
383 | MethodCallExpr = | ||
384 | Attr* Expr '.' NameRef GenericArgList? ArgList | ||
385 | |||
386 | FieldExpr = | ||
387 | Attr* Expr '.' NameRef | ||
236 | 388 | ||
237 | LambdaExpr = | 389 | ClosureExpr = |
238 | Attr* 'static'? 'async'? 'move'? ParamList RetType? | 390 | Attr* 'static'? 'async'? 'move'? ParamList RetType? |
239 | body:Expr | 391 | body:Expr |
240 | 392 | ||
241 | IfExpr = | 393 | IfExpr = |
242 | Attr* 'if' Condition | 394 | Attr* 'if' Condition then_branch:BlockExpr |
395 | ('else' else_branch:(IfExpr | BlockExpr))? | ||
243 | 396 | ||
244 | Condition = | 397 | Condition = |
245 | 'let' Pat '=' Expr | 398 | 'let' Pat '=' Expr |
246 | | Expr | 399 | | Expr |
247 | 400 | ||
248 | EffectExpr = | ||
249 | Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr | ||
250 | |||
251 | LoopExpr = | 401 | LoopExpr = |
252 | Attr* Label? 'loop' | 402 | Attr* Label? 'loop' |
253 | loop_body:BlockExpr? | 403 | loop_body:BlockExpr |
254 | 404 | ||
255 | ForExpr = | 405 | ForExpr = |
256 | Attr* Label? 'for' Pat 'in' iterable:Expr | 406 | Attr* Label? 'for' Pat 'in' iterable:Expr |
257 | loop_body:BlockExpr? | 407 | loop_body:BlockExpr |
258 | 408 | ||
259 | WhileExpr = | 409 | WhileExpr = |
260 | Attr* Label? 'while' Condition | 410 | Attr* Label? 'while' Condition |
261 | loop_body:BlockExpr? | 411 | loop_body:BlockExpr |
262 | 412 | ||
263 | ContinueExpr = | 413 | Label = |
264 | Attr* 'continue' 'lifetime'? | 414 | 'lifetime' |
265 | 415 | ||
266 | BreakExpr = | 416 | BreakExpr = |
267 | Attr* 'break' 'lifetime'? Expr? | 417 | Attr* 'break' 'lifetime'? Expr? |
268 | 418 | ||
269 | Label = | 419 | ContinueExpr = |
270 | 'lifetime' | 420 | Attr* 'continue' 'lifetime'? |
271 | |||
272 | BlockExpr = | ||
273 | Attr* Label | ||
274 | '{' | ||
275 | Item* | ||
276 | statements:Stmt* | ||
277 | Expr? | ||
278 | '}' | ||
279 | 421 | ||
280 | ReturnExpr = | 422 | RangeExpr = |
281 | Attr* 'return' Expr | 423 | Attr* start:Expr? op:('..' | '..=') end:Expr? |
282 | 424 | ||
283 | CallExpr = | 425 | MatchExpr = |
284 | Attr* Expr ArgList | 426 | Attr* 'match' Expr MatchArmList |
285 | 427 | ||
286 | MethodCallExpr = | 428 | MatchArmList = |
287 | Attr* Expr '.' NameRef TypeArgList? ArgList | 429 | '{' |
430 | Attr* | ||
431 | arms:MatchArm* | ||
432 | '}' | ||
288 | 433 | ||
289 | ArgList = | 434 | MatchArm = |
290 | '(' args:Expr* ')' | 435 | Attr* Pat guard:MatchGuard? '=>' Expr ','? |
291 | 436 | ||
292 | FieldExpr = | 437 | MatchGuard = |
293 | Attr* Expr '.' NameRef | 438 | 'if' Expr |
294 | 439 | ||
295 | IndexExpr = | 440 | ReturnExpr = |
296 | Attr* '[' ']' | 441 | Attr* 'return' Expr? |
297 | 442 | ||
298 | AwaitExpr = | 443 | AwaitExpr = |
299 | Attr* Expr '.' 'await' | 444 | Attr* Expr '.' 'await' |
300 | 445 | ||
301 | TryExpr = | ||
302 | Attr* Expr '?' | ||
303 | |||
304 | CastExpr = | ||
305 | Attr* Expr 'as' ty:TypeRef | ||
306 | |||
307 | RefExpr = | ||
308 | Attr* '&' ('raw' | 'mut' | 'const') Expr | ||
309 | |||
310 | PrefixExpr = | ||
311 | Attr* Expr | ||
312 | |||
313 | BoxExpr = | 446 | BoxExpr = |
314 | Attr* 'box' Expr | 447 | Attr* 'box' Expr |
315 | 448 | ||
316 | RangeExpr = | 449 | //*************************// |
317 | Attr* | 450 | // Types // |
451 | //*************************// | ||
318 | 452 | ||
319 | BinExpr = | 453 | Type = |
320 | Attr* | 454 | ArrayType |
321 | 455 | | DynTraitType | |
322 | Literal = | 456 | | FnPointerType |
323 | 'int_number' | 457 | | ForType |
458 | | ImplTraitType | ||
459 | | InferType | ||
460 | | NeverType | ||
461 | | ParenType | ||
462 | | PathType | ||
463 | | PointerType | ||
464 | | ReferenceType | ||
465 | | SliceType | ||
466 | | TupleType | ||
324 | 467 | ||
325 | MatchExpr = | 468 | ParenType = |
326 | Attr* 'match' Expr MatchArmList | 469 | '(' Type ')' |
327 | 470 | ||
328 | MatchArmList = | 471 | NeverType = |
329 | '{' arms:MatchArm* '}' | 472 | '!' |
330 | 473 | ||
331 | MatchArm = | 474 | PathType = |
332 | Attr* Pat guard:MatchGuard? '=>' Expr | 475 | Path |
333 | 476 | ||
334 | MatchGuard = | 477 | TupleType = |
335 | 'if' Expr | 478 | '(' fields:(Type (',' Type)* ','?)? ')' |
336 | 479 | ||
337 | RecordExpr = | 480 | PointerType = |
338 | Path RecordExprFieldList | 481 | '*' ('const' | 'mut') Type |
339 | 482 | ||
340 | RecordExprFieldList = | 483 | ReferenceType = |
341 | '{' | 484 | '&' 'lifetime'? 'mut'? Type |
342 | fields:RecordExprField* | ||
343 | ('..' spread:Expr)? | ||
344 | '}' | ||
345 | 485 | ||
346 | RecordExprField = | 486 | ArrayType = |
347 | Attr* NameRef (':' Expr)? | 487 | '[' Type ';' Expr ']' |
348 | 488 | ||
349 | OrPat = | 489 | SliceType = |
350 | Pat* | 490 | '[' Type ']' |
351 | 491 | ||
352 | ParenPat = | 492 | InferType = |
353 | '(' Pat ')' | 493 | '_' |
354 | 494 | ||
355 | RefPat = | 495 | FnPointerType = |
356 | '&' 'mut'? Pat | 496 | 'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType? |
357 | 497 | ||
358 | BoxPat = | 498 | ForType = |
359 | 'box' Path | 499 | 'for' GenericParamList Type |
360 | 500 | ||
361 | BindPat = | 501 | ImplTraitType = |
362 | Attr* 'ref'? 'mut'? Name ('@' Pat)? | 502 | 'impl' TypeBoundList |
363 | 503 | ||
364 | PlaceholderPat = | 504 | DynTraitType = |
365 | '_' | 505 | 'dyn' TypeBoundList |
366 | 506 | ||
367 | DotDotPat = | 507 | TypeBoundList = |
368 | '..' | 508 | bounds:(TypeBound ('+' TypeBound)* '+'?) |
369 | 509 | ||
370 | PathPat = | 510 | TypeBound = |
371 | Path | 511 | 'lifetime' |
512 | | '?'? Type | ||
372 | 513 | ||
373 | SlicePat = | 514 | //************************// |
374 | '[' args:Pat* ']' | 515 | // Patterns // |
516 | //************************// | ||
375 | 517 | ||
376 | RangePat = | 518 | Pat = |
377 | '..' | '..=' | 519 | IdentPat |
520 | | BoxPat | ||
521 | | RestPat | ||
522 | | LiteralPat | ||
523 | | MacroPat | ||
524 | | OrPat | ||
525 | | ParenPat | ||
526 | | PathPat | ||
527 | | WildcardPat | ||
528 | | RangePat | ||
529 | | RecordPat | ||
530 | | RefPat | ||
531 | | SlicePat | ||
532 | | TuplePat | ||
533 | | TupleStructPat | ||
378 | 534 | ||
379 | LiteralPat = | 535 | LiteralPat = |
380 | Literal | 536 | Literal |
381 | 537 | ||
382 | MacroPat = | 538 | IdentPat = |
383 | MacroCall | 539 | Attr* 'ref'? 'mut'? Name ('@' Pat)? |
540 | |||
541 | WildcardPat = | ||
542 | '_' | ||
543 | |||
544 | RangePat = | ||
545 | start:Pat op:('..' | '..=') end:Pat | ||
546 | |||
547 | RefPat = | ||
548 | '&' 'mut'? Pat | ||
384 | 549 | ||
385 | RecordPat = | 550 | RecordPat = |
386 | Path RecordFieldPatList | 551 | Path RecordPatFieldList |
387 | 552 | ||
388 | RecordFieldPatList = | 553 | RecordPatFieldList = |
389 | '{' | 554 | '{' |
390 | record_field_pats:RecordFieldPat* | 555 | fields:(RecordPatField (',' RecordPatField)* ','?) |
391 | BindPat* | ||
392 | '..'? | 556 | '..'? |
393 | '}' | 557 | '}' |
394 | 558 | ||
395 | RecordFieldPat = | 559 | RecordPatField = |
396 | Attr* NameRef ':' Pat | 560 | Attr* (NameRef ':')? Pat |
397 | 561 | ||
398 | TupleStructPat = | 562 | TupleStructPat = |
399 | Path '(' args:Pat* ')' | 563 | Path '(' fields:(Pat (',' Pat)* ','?)? ')' |
400 | 564 | ||
401 | TuplePat = | 565 | TuplePat = |
402 | '(' args:Pat* ')' | 566 | '(' fields:(Pat (',' Pat)* ','?)? ')' |
403 | |||
404 | Name = | ||
405 | 'ident' | ||
406 | |||
407 | NameRef = | ||
408 | 'ident' | 'int_number' | ||
409 | |||
410 | MacroCall = | ||
411 | Attr* Path '!' Name? TokenTree ';'? | ||
412 | |||
413 | MacroDef = | ||
414 | Name TokenTree | ||
415 | |||
416 | TokenTree = | ||
417 | '(' ')' | '{' '}' | '[' ']' | ||
418 | |||
419 | MacroItems = | ||
420 | Item* | ||
421 | |||
422 | MacroStmts = | ||
423 | statements:Stmt* | ||
424 | Expr? | ||
425 | |||
426 | TypeBound = | ||
427 | 'lifetime' | 'const'? TypeRef | ||
428 | |||
429 | TypeBoundList = | ||
430 | bounds:TypeBound* | ||
431 | |||
432 | WherePred = | ||
433 | ('for' GenericParamList)? ('lifetime' | TypeRef) ':' TypeBoundList | ||
434 | |||
435 | WhereClause = | ||
436 | 'where' predicates:WherePred* | ||
437 | |||
438 | ExprStmt = | ||
439 | Attr* Expr ';' | ||
440 | |||
441 | LetStmt = | ||
442 | Attr* 'let' Pat (':' ty:TypeRef) | ||
443 | '=' initializer:Expr ';' | ||
444 | |||
445 | Path = | ||
446 | (qualifier:Path '::')? segment:PathSegment | ||
447 | |||
448 | PathSegment = | ||
449 | '::' | 'crate' | 'self' | 'super' | ||
450 | | '<' NameRef TypeArgList ParamList RetType PathType '>' | ||
451 | |||
452 | TypeArgList = | ||
453 | '::'? '<' | ||
454 | TypeArg* | ||
455 | LifetimeArg* | ||
456 | AssocTypeArg* | ||
457 | ConstArg* | ||
458 | '>' | ||
459 | 567 | ||
460 | TypeArg = | 568 | ParenPat = |
461 | TypeRef | 569 | '(' Pat ')' |
462 | |||
463 | AssocTypeArg = | ||
464 | NameRef (':' TypeBoundList | '=' TypeRef) | ||
465 | |||
466 | LifetimeArg = | ||
467 | 'lifetime' | ||
468 | 570 | ||
469 | ConstArg = | 571 | SlicePat = |
470 | Literal | BlockExpr BlockExpr | 572 | '[' (Pat (',' Pat)* ','?)? ']' |
471 | 573 | ||
472 | AdtDef = | 574 | PathPat = |
473 | Struct | 575 | Path |
474 | | Enum | ||
475 | | Union | ||
476 | 576 | ||
477 | TypeRef = | 577 | OrPat = |
478 | ParenType | 578 | (Pat ('|' Pat)* '|'?) |
479 | | TupleType | ||
480 | | NeverType | ||
481 | | PathType | ||
482 | | PointerType | ||
483 | | ArrayType | ||
484 | | SliceType | ||
485 | | ReferenceType | ||
486 | | PlaceholderType | ||
487 | | FnPointerType | ||
488 | | ForType | ||
489 | | ImplTraitType | ||
490 | | DynTraitType | ||
491 | 579 | ||
492 | Stmt = | 580 | BoxPat = |
493 | LetStmt | 581 | 'box' Pat |
494 | | ExprStmt | ||
495 | 582 | ||
496 | Pat = | 583 | RestPat = |
497 | OrPat | 584 | '..' |
498 | | ParenPat | ||
499 | | RefPat | ||
500 | | BoxPat | ||
501 | | BindPat | ||
502 | | PlaceholderPat | ||
503 | | DotDotPat | ||
504 | | PathPat | ||
505 | | RecordPat | ||
506 | | TupleStructPat | ||
507 | | TuplePat | ||
508 | | SlicePat | ||
509 | | RangePat | ||
510 | | LiteralPat | ||
511 | | MacroPat | ||
512 | 585 | ||
513 | Expr = | 586 | MacroPat = |
514 | TupleExpr | 587 | MacroCall |
515 | | ArrayExpr | ||
516 | | ParenExpr | ||
517 | | PathExpr | ||
518 | | LambdaExpr | ||
519 | | IfExpr | ||
520 | | LoopExpr | ||
521 | | ForExpr | ||
522 | | WhileExpr | ||
523 | | ContinueExpr | ||
524 | | BreakExpr | ||
525 | | Label | ||
526 | | BlockExpr | ||
527 | | ReturnExpr | ||
528 | | MatchExpr | ||
529 | | RecordExpr | ||
530 | | CallExpr | ||
531 | | IndexExpr | ||
532 | | MethodCallExpr | ||
533 | | FieldExpr | ||
534 | | AwaitExpr | ||
535 | | TryExpr | ||
536 | | EffectExpr | ||
537 | | CastExpr | ||
538 | | RefExpr | ||
539 | | PrefixExpr | ||
540 | | RangeExpr | ||
541 | | BinExpr | ||
542 | | Literal | ||
543 | | MacroCall | ||
544 | | BoxExpr | ||
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 2fdb08f2e..e790d995f 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -3,14 +3,15 @@ | |||
3 | //! See https://github.com/matklad/cargo-xtask/ | 3 | //! See https://github.com/matklad/cargo-xtask/ |
4 | 4 | ||
5 | pub mod not_bash; | 5 | pub mod not_bash; |
6 | pub mod codegen; | ||
7 | mod ast_src; | ||
8 | |||
6 | pub mod install; | 9 | pub mod install; |
7 | pub mod release; | 10 | pub mod release; |
8 | pub mod dist; | 11 | pub mod dist; |
9 | pub mod pre_commit; | 12 | pub mod pre_commit; |
10 | pub mod metrics; | 13 | pub mod metrics; |
11 | 14 | pub mod pre_cache; | |
12 | pub mod codegen; | ||
13 | mod ast_src; | ||
14 | 15 | ||
15 | use std::{ | 16 | use std::{ |
16 | env, | 17 | env, |
@@ -21,7 +22,7 @@ use walkdir::{DirEntry, WalkDir}; | |||
21 | 22 | ||
22 | use crate::{ | 23 | use crate::{ |
23 | codegen::Mode, | 24 | codegen::Mode, |
24 | not_bash::{fs2, pushd, pushenv, rm_rf}, | 25 | not_bash::{pushd, pushenv}, |
25 | }; | 26 | }; |
26 | 27 | ||
27 | pub use anyhow::{bail, Context as _, Result}; | 28 | pub use anyhow::{bail, Context as _, Result}; |
@@ -62,17 +63,6 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> { | |||
62 | Ok(()) | 63 | Ok(()) |
63 | } | 64 | } |
64 | 65 | ||
65 | fn reformat(text: impl std::fmt::Display) -> Result<String> { | ||
66 | let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); | ||
67 | ensure_rustfmt()?; | ||
68 | let stdout = run!( | ||
69 | "rustfmt --config-path {} --config fn_single_line=true", project_root().join("rustfmt.toml").display(); | ||
70 | <text.to_string().as_bytes() | ||
71 | )?; | ||
72 | let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`"; | ||
73 | Ok(format!("//! {}\n\n{}\n", preamble, stdout)) | ||
74 | } | ||
75 | |||
76 | fn ensure_rustfmt() -> Result<()> { | 66 | fn ensure_rustfmt() -> Result<()> { |
77 | let out = run!("rustfmt --version")?; | 67 | let out = run!("rustfmt --version")?; |
78 | if !out.contains("stable") { | 68 | if !out.contains("stable") { |
@@ -103,7 +93,7 @@ pub fn run_clippy() -> Result<()> { | |||
103 | } | 93 | } |
104 | 94 | ||
105 | pub fn run_fuzzer() -> Result<()> { | 95 | pub fn run_fuzzer() -> Result<()> { |
106 | let _d = pushd("./crates/ra_syntax"); | 96 | let _d = pushd("./crates/syntax"); |
107 | let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly"); | 97 | let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly"); |
108 | if run!("cargo fuzz --help").is_err() { | 98 | if run!("cargo fuzz --help").is_err() { |
109 | run!("cargo install cargo-fuzz")?; | 99 | run!("cargo install cargo-fuzz")?; |
@@ -119,42 +109,6 @@ pub fn run_fuzzer() -> Result<()> { | |||
119 | Ok(()) | 109 | Ok(()) |
120 | } | 110 | } |
121 | 111 | ||
122 | /// Cleans the `./target` dir after the build such that only | ||
123 | /// dependencies are cached on CI. | ||
124 | pub fn run_pre_cache() -> Result<()> { | ||
125 | let slow_tests_cookie = Path::new("./target/.slow_tests_cookie"); | ||
126 | if !slow_tests_cookie.exists() { | ||
127 | panic!("slow tests were skipped on CI!") | ||
128 | } | ||
129 | rm_rf(slow_tests_cookie)?; | ||
130 | |||
131 | for entry in Path::new("./target/debug").read_dir()? { | ||
132 | let entry = entry?; | ||
133 | if entry.file_type().map(|it| it.is_file()).ok() == Some(true) { | ||
134 | // Can't delete yourself on windows :-( | ||
135 | if !entry.path().ends_with("xtask.exe") { | ||
136 | rm_rf(&entry.path())? | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | fs2::remove_file("./target/.rustc_info.json")?; | ||
142 | let to_delete = ["ra_", "heavy_test", "xtask"]; | ||
143 | for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() { | ||
144 | for entry in Path::new(dir).read_dir()? { | ||
145 | let entry = entry?; | ||
146 | if to_delete.iter().any(|&it| entry.path().display().to_string().contains(it)) { | ||
147 | // Can't delete yourself on windows :-( | ||
148 | if !entry.path().ends_with("xtask.exe") { | ||
149 | rm_rf(&entry.path())? | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | Ok(()) | ||
156 | } | ||
157 | |||
158 | fn is_release_tag(tag: &str) -> bool { | 112 | fn is_release_tag(tag: &str) -> bool { |
159 | tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit()) | 113 | tag.len() == "2020-02-24".len() && tag.starts_with(|c: char| c.is_ascii_digit()) |
160 | } | 114 | } |
diff --git a/xtask/src/main.rs b/xtask/src/main.rs index b69b884e5..3f4aa5497 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | use std::env; | 11 | use std::env; |
12 | 12 | ||
13 | use codegen::CodegenCmd; | ||
13 | use pico_args::Arguments; | 14 | use pico_args::Arguments; |
14 | use xtask::{ | 15 | use xtask::{ |
15 | codegen::{self, Mode}, | 16 | codegen::{self, Mode}, |
@@ -17,9 +18,10 @@ use xtask::{ | |||
17 | install::{ClientOpt, InstallCmd, Malloc, ServerOpt}, | 18 | install::{ClientOpt, InstallCmd, Malloc, ServerOpt}, |
18 | metrics::MetricsCmd, | 19 | metrics::MetricsCmd, |
19 | not_bash::pushd, | 20 | not_bash::pushd, |
21 | pre_cache::PreCacheCmd, | ||
20 | pre_commit, project_root, | 22 | pre_commit, project_root, |
21 | release::{PromoteCmd, ReleaseCmd}, | 23 | release::{PromoteCmd, ReleaseCmd}, |
22 | run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result, | 24 | run_clippy, run_fuzzer, run_rustfmt, Result, |
23 | }; | 25 | }; |
24 | 26 | ||
25 | fn main() -> Result<()> { | 27 | fn main() -> Result<()> { |
@@ -74,13 +76,9 @@ FLAGS: | |||
74 | .run() | 76 | .run() |
75 | } | 77 | } |
76 | "codegen" => { | 78 | "codegen" => { |
79 | let features = args.contains("--features"); | ||
77 | args.finish()?; | 80 | args.finish()?; |
78 | codegen::generate_syntax(Mode::Overwrite)?; | 81 | CodegenCmd { features }.run() |
79 | codegen::generate_parser_tests(Mode::Overwrite)?; | ||
80 | codegen::generate_assists_tests(Mode::Overwrite)?; | ||
81 | codegen::generate_assists_docs(Mode::Overwrite)?; | ||
82 | codegen::generate_feature_docs(Mode::Overwrite)?; | ||
83 | Ok(()) | ||
84 | } | 82 | } |
85 | "format" => { | 83 | "format" => { |
86 | args.finish()?; | 84 | args.finish()?; |
@@ -100,7 +98,7 @@ FLAGS: | |||
100 | } | 98 | } |
101 | "pre-cache" => { | 99 | "pre-cache" => { |
102 | args.finish()?; | 100 | args.finish()?; |
103 | run_pre_cache() | 101 | PreCacheCmd.run() |
104 | } | 102 | } |
105 | "release" => { | 103 | "release" => { |
106 | let dry_run = args.contains("--dry-run"); | 104 | let dry_run = args.contains("--dry-run"); |
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index 9ac3fa51d..4bade2c7e 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | collections::BTreeMap, | 2 | collections::BTreeMap, |
3 | env, | 3 | env, |
4 | fmt::{self, Write as _}, | ||
5 | io::Write as _, | 4 | io::Write as _, |
6 | path::Path, | 5 | path::Path, |
7 | time::{Instant, SystemTime, UNIX_EPOCH}, | 6 | time::{Instant, SystemTime, UNIX_EPOCH}, |
@@ -127,40 +126,21 @@ impl Metrics { | |||
127 | self.metrics.insert(name.into(), (value, unit)); | 126 | self.metrics.insert(name.into(), (value, unit)); |
128 | } | 127 | } |
129 | 128 | ||
130 | fn json(&self) -> Json { | 129 | fn json(&self) -> String { |
131 | let mut json = Json::default(); | 130 | let mut buf = String::new(); |
132 | self.to_json(&mut json); | 131 | self.to_json(write_json::object(&mut buf)); |
133 | json | 132 | buf |
134 | } | 133 | } |
135 | fn to_json(&self, json: &mut Json) { | ||
136 | json.begin_object(); | ||
137 | { | ||
138 | json.field("host"); | ||
139 | self.host.to_json(json); | ||
140 | |||
141 | json.field("timestamp"); | ||
142 | let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); | ||
143 | json.number(timestamp.as_secs() as f64); | ||
144 | 134 | ||
145 | json.field("revision"); | 135 | fn to_json(&self, mut obj: write_json::Object<'_>) { |
146 | json.string(&self.revision); | 136 | self.host.to_json(obj.object("host")); |
147 | 137 | let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); | |
148 | json.field("metrics"); | 138 | obj.number("timestamp", timestamp.as_secs() as f64); |
149 | json.begin_object(); | 139 | obj.string("revision", &self.revision); |
150 | { | 140 | let mut metrics = obj.object("metrics"); |
151 | for (k, (value, unit)) in &self.metrics { | 141 | for (k, (value, unit)) in &self.metrics { |
152 | json.field(k); | 142 | metrics.array(k).number(*value as f64).string(unit); |
153 | json.begin_array(); | ||
154 | { | ||
155 | json.number(*value as f64); | ||
156 | json.string(unit); | ||
157 | } | ||
158 | json.end_array(); | ||
159 | } | ||
160 | } | ||
161 | json.end_object() | ||
162 | } | 143 | } |
163 | json.end_object(); | ||
164 | } | 144 | } |
165 | } | 145 | } |
166 | 146 | ||
@@ -189,91 +169,7 @@ impl Host { | |||
189 | Ok(line[field.len()..].trim().to_string()) | 169 | Ok(line[field.len()..].trim().to_string()) |
190 | } | 170 | } |
191 | } | 171 | } |
192 | fn to_json(&self, json: &mut Json) { | 172 | fn to_json(&self, mut obj: write_json::Object<'_>) { |
193 | json.begin_object(); | 173 | obj.string("os", &self.os).string("cpu", &self.cpu).string("mem", &self.mem); |
194 | { | ||
195 | json.field("os"); | ||
196 | json.string(&self.os); | ||
197 | |||
198 | json.field("cpu"); | ||
199 | json.string(&self.cpu); | ||
200 | |||
201 | json.field("mem"); | ||
202 | json.string(&self.mem); | ||
203 | } | ||
204 | json.end_object(); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | struct State { | ||
209 | obj: bool, | ||
210 | first: bool, | ||
211 | } | ||
212 | |||
213 | #[derive(Default)] | ||
214 | struct Json { | ||
215 | stack: Vec<State>, | ||
216 | buf: String, | ||
217 | } | ||
218 | |||
219 | impl Json { | ||
220 | fn begin_object(&mut self) { | ||
221 | self.stack.push(State { obj: true, first: true }); | ||
222 | self.buf.push('{'); | ||
223 | } | ||
224 | fn end_object(&mut self) { | ||
225 | self.stack.pop(); | ||
226 | self.buf.push('}') | ||
227 | } | ||
228 | fn begin_array(&mut self) { | ||
229 | self.stack.push(State { obj: false, first: true }); | ||
230 | self.buf.push('['); | ||
231 | } | ||
232 | fn end_array(&mut self) { | ||
233 | self.stack.pop(); | ||
234 | self.buf.push(']') | ||
235 | } | ||
236 | fn field(&mut self, name: &str) { | ||
237 | self.object_comma(); | ||
238 | self.string_token(name); | ||
239 | self.buf.push(':'); | ||
240 | } | ||
241 | fn string(&mut self, value: &str) { | ||
242 | self.array_comma(); | ||
243 | self.string_token(value); | ||
244 | } | ||
245 | fn string_token(&mut self, value: &str) { | ||
246 | self.buf.push('"'); | ||
247 | self.buf.extend(value.escape_default()); | ||
248 | self.buf.push('"'); | ||
249 | } | ||
250 | fn number(&mut self, value: f64) { | ||
251 | self.array_comma(); | ||
252 | write!(self.buf, "{}", value).unwrap(); | ||
253 | } | ||
254 | |||
255 | fn array_comma(&mut self) { | ||
256 | let state = self.stack.last_mut().unwrap(); | ||
257 | if state.obj { | ||
258 | return; | ||
259 | } | ||
260 | if !state.first { | ||
261 | self.buf.push(','); | ||
262 | } | ||
263 | state.first = false; | ||
264 | } | ||
265 | |||
266 | fn object_comma(&mut self) { | ||
267 | let state = self.stack.last_mut().unwrap(); | ||
268 | if !state.first { | ||
269 | self.buf.push(','); | ||
270 | } | ||
271 | state.first = false; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | impl fmt::Display for Json { | ||
276 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
277 | write!(f, "{}", self.buf) | ||
278 | } | 174 | } |
279 | } | 175 | } |
diff --git a/xtask/src/pre_cache.rs b/xtask/src/pre_cache.rs new file mode 100644 index 000000000..47ba6ba24 --- /dev/null +++ b/xtask/src/pre_cache.rs | |||
@@ -0,0 +1,80 @@ | |||
1 | use std::{ | ||
2 | fs::FileType, | ||
3 | path::{Path, PathBuf}, | ||
4 | }; | ||
5 | |||
6 | use anyhow::Result; | ||
7 | |||
8 | use crate::not_bash::{fs2, rm_rf}; | ||
9 | |||
10 | pub struct PreCacheCmd; | ||
11 | |||
12 | impl PreCacheCmd { | ||
13 | /// Cleans the `./target` dir after the build such that only | ||
14 | /// dependencies are cached on CI. | ||
15 | pub fn run(self) -> Result<()> { | ||
16 | let slow_tests_cookie = Path::new("./target/.slow_tests_cookie"); | ||
17 | if !slow_tests_cookie.exists() { | ||
18 | panic!("slow tests were skipped on CI!") | ||
19 | } | ||
20 | rm_rf(slow_tests_cookie)?; | ||
21 | |||
22 | for path in read_dir("./target/debug", FileType::is_file)? { | ||
23 | // Can't delete yourself on windows :-( | ||
24 | if !path.ends_with("xtask.exe") { | ||
25 | rm_rf(&path)? | ||
26 | } | ||
27 | } | ||
28 | |||
29 | fs2::remove_file("./target/.rustc_info.json")?; | ||
30 | |||
31 | let to_delete = read_dir("./crates", FileType::is_dir)? | ||
32 | .into_iter() | ||
33 | .map(|path| path.file_name().unwrap().to_string_lossy().replace('-', "_")) | ||
34 | .collect::<Vec<_>>(); | ||
35 | |||
36 | for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() { | ||
37 | for path in read_dir(dir, |_file_type| true)? { | ||
38 | if path.ends_with("xtask.exe") { | ||
39 | continue; | ||
40 | } | ||
41 | let file_name = path.file_name().unwrap().to_string_lossy(); | ||
42 | let (stem, _) = match rsplit_once(&file_name, '-') { | ||
43 | Some(it) => it, | ||
44 | None => { | ||
45 | rm_rf(path)?; | ||
46 | continue; | ||
47 | } | ||
48 | }; | ||
49 | let stem = stem.replace('-', "_"); | ||
50 | if to_delete.contains(&stem) { | ||
51 | rm_rf(path)?; | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | |||
56 | Ok(()) | ||
57 | } | ||
58 | } | ||
59 | fn read_dir(path: impl AsRef<Path>, cond: impl Fn(&FileType) -> bool) -> Result<Vec<PathBuf>> { | ||
60 | read_dir_impl(path.as_ref(), &cond) | ||
61 | } | ||
62 | |||
63 | fn read_dir_impl(path: &Path, cond: &dyn Fn(&FileType) -> bool) -> Result<Vec<PathBuf>> { | ||
64 | let mut res = Vec::new(); | ||
65 | for entry in path.read_dir()? { | ||
66 | let entry = entry?; | ||
67 | let file_type = entry.file_type()?; | ||
68 | if cond(&file_type) { | ||
69 | res.push(entry.path()) | ||
70 | } | ||
71 | } | ||
72 | Ok(res) | ||
73 | } | ||
74 | |||
75 | fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
76 | let mut split = haystack.rsplitn(2, delim); | ||
77 | let suffix = split.next()?; | ||
78 | let prefix = split.next()?; | ||
79 | Some((prefix, suffix)) | ||
80 | } | ||