diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-02-03 09:54:52 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-02-03 09:54:52 +0000 |
commit | 3c70ae2e26f654ce536f00fde8c159e4ebe6901a (patch) | |
tree | 89fe4c9e08b76f69d39f4a565848c4ba054b6da7 /tools/src | |
parent | 6d9753bf548b22ab1a54462f72c9c0bf4ff69382 (diff) | |
parent | 9435ea4b8e990521ee7a6206b6106bb3ce392746 (diff) |
Merge #38
38: Move tools to a separate package r=matklad a=matklad
Diffstat (limited to 'tools/src')
-rw-r--r-- | tools/src/bin/gen.rs | 118 | ||||
-rw-r--r-- | tools/src/bin/parse.rs | 20 |
2 files changed, 138 insertions, 0 deletions
diff --git a/tools/src/bin/gen.rs b/tools/src/bin/gen.rs new file mode 100644 index 000000000..17cdea7a1 --- /dev/null +++ b/tools/src/bin/gen.rs | |||
@@ -0,0 +1,118 @@ | |||
1 | extern crate serde; | ||
2 | #[macro_use] | ||
3 | extern crate serde_derive; | ||
4 | |||
5 | extern crate file; | ||
6 | extern crate ron; | ||
7 | |||
8 | use std::path::PathBuf; | ||
9 | use std::fmt::Write; | ||
10 | |||
11 | fn main() { | ||
12 | let grammar = Grammar::read(); | ||
13 | let text = grammar.to_syntax_kinds(); | ||
14 | let target = generated_file(); | ||
15 | if text != file::get_text(&target).unwrap_or_default() { | ||
16 | file::put_text(&target, &text).unwrap(); | ||
17 | } | ||
18 | } | ||
19 | |||
20 | #[derive(Deserialize)] | ||
21 | struct Grammar { | ||
22 | keywords: Vec<String>, | ||
23 | tokens: Vec<String>, | ||
24 | nodes: Vec<String>, | ||
25 | } | ||
26 | |||
27 | impl Grammar { | ||
28 | fn read() -> Grammar { | ||
29 | let text = file::get_text(&grammar_file()).unwrap(); | ||
30 | ron::de::from_str(&text).unwrap() | ||
31 | } | ||
32 | |||
33 | fn to_syntax_kinds(&self) -> String { | ||
34 | let mut acc = String::new(); | ||
35 | acc.push_str("#![allow(bad_style, missing_docs, unreachable_pub)]\n"); | ||
36 | acc.push_str("#![cfg_attr(rustfmt, rustfmt_skip)]\n"); | ||
37 | acc.push_str("//! Generated from grammar.ron\n"); | ||
38 | acc.push_str("use tree::SyntaxInfo;\n"); | ||
39 | acc.push_str("\n"); | ||
40 | |||
41 | let syntax_kinds: Vec<String> = self.keywords | ||
42 | .iter() | ||
43 | .map(|kw| kw_token(kw)) | ||
44 | .chain(self.tokens.iter().cloned()) | ||
45 | .chain(self.nodes.iter().cloned()) | ||
46 | .collect(); | ||
47 | |||
48 | // enum SyntaxKind | ||
49 | acc.push_str("/// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`.\n"); | ||
50 | acc.push_str("#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); | ||
51 | acc.push_str("pub enum SyntaxKind {\n"); | ||
52 | for kind in syntax_kinds.iter() { | ||
53 | write!(acc, " {},\n", scream(kind)).unwrap(); | ||
54 | } | ||
55 | acc.push_str("\n"); | ||
56 | acc.push_str(" // Technical SyntaxKinds: they appear temporally during parsing,\n"); | ||
57 | acc.push_str(" // but never end up in the final tree\n"); | ||
58 | acc.push_str(" #[doc(hidden)]\n"); | ||
59 | acc.push_str(" TOMBSTONE,\n"); | ||
60 | acc.push_str(" #[doc(hidden)]\n"); | ||
61 | acc.push_str(" EOF,\n"); | ||
62 | acc.push_str("}\n"); | ||
63 | acc.push_str("pub(crate) use self::SyntaxKind::*;\n"); | ||
64 | acc.push_str("\n"); | ||
65 | |||
66 | // fn info | ||
67 | acc.push_str("impl SyntaxKind {\n"); | ||
68 | acc.push_str(" pub(crate) fn info(self) -> &'static SyntaxInfo {\n"); | ||
69 | acc.push_str(" match self {\n"); | ||
70 | for kind in syntax_kinds.iter() { | ||
71 | let sname = scream(kind); | ||
72 | write!( | ||
73 | acc, | ||
74 | " {sname} => &SyntaxInfo {{ name: \"{sname}\" }},\n", | ||
75 | sname = sname | ||
76 | ).unwrap(); | ||
77 | } | ||
78 | acc.push_str("\n"); | ||
79 | acc.push_str(" TOMBSTONE => &SyntaxInfo { name: \"TOMBSTONE\" },\n"); | ||
80 | acc.push_str(" EOF => &SyntaxInfo { name: \"EOF\" },\n"); | ||
81 | acc.push_str(" }\n"); | ||
82 | acc.push_str(" }\n"); | ||
83 | acc.push_str("}\n"); | ||
84 | acc.push_str("\n"); | ||
85 | |||
86 | // fn ident_to_keyword | ||
87 | acc.push_str("pub(crate) fn ident_to_keyword(ident: &str) -> Option<SyntaxKind> {\n"); | ||
88 | acc.push_str(" match ident {\n"); | ||
89 | for kw in self.keywords.iter() { | ||
90 | write!(acc, " {:?} => Some({}),\n", kw, kw_token(kw)).unwrap(); | ||
91 | } | ||
92 | acc.push_str(" _ => None,\n"); | ||
93 | acc.push_str(" }\n"); | ||
94 | acc.push_str("}\n"); | ||
95 | acc | ||
96 | } | ||
97 | } | ||
98 | |||
99 | fn grammar_file() -> PathBuf { | ||
100 | base_dir().join("grammar.ron") | ||
101 | } | ||
102 | |||
103 | fn generated_file() -> PathBuf { | ||
104 | base_dir().join("src/syntax_kinds.rs") | ||
105 | } | ||
106 | |||
107 | fn scream(word: &str) -> String { | ||
108 | word.chars().map(|c| c.to_ascii_uppercase()).collect() | ||
109 | } | ||
110 | |||
111 | fn kw_token(keyword: &str) -> String { | ||
112 | format!("{}_KW", scream(keyword)) | ||
113 | } | ||
114 | |||
115 | fn base_dir() -> PathBuf { | ||
116 | let dir = env!("CARGO_MANIFEST_DIR"); | ||
117 | PathBuf::from(dir).parent().unwrap().to_owned() | ||
118 | } | ||
diff --git a/tools/src/bin/parse.rs b/tools/src/bin/parse.rs new file mode 100644 index 000000000..af1325bfc --- /dev/null +++ b/tools/src/bin/parse.rs | |||
@@ -0,0 +1,20 @@ | |||
1 | extern crate libsyntax2; | ||
2 | |||
3 | use std::io::Read; | ||
4 | |||
5 | use libsyntax2::{parse, tokenize}; | ||
6 | use libsyntax2::utils::dump_tree; | ||
7 | |||
8 | fn main() { | ||
9 | let text = read_input(); | ||
10 | let tokens = tokenize(&text); | ||
11 | let file = parse(text, &tokens); | ||
12 | let tree = dump_tree(&file); | ||
13 | println!("{}", tree); | ||
14 | } | ||
15 | |||
16 | fn read_input() -> String { | ||
17 | let mut buff = String::new(); | ||
18 | ::std::io::stdin().read_to_string(&mut buff).unwrap(); | ||
19 | buff | ||
20 | } | ||