diff options
author | Aleksey Kladov <[email protected]> | 2018-07-30 14:16:58 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-07-30 14:16:58 +0100 |
commit | 3b6a6f6673041cf9ee315c00f9b0e24e2c067091 (patch) | |
tree | 001e556601e9dd37556338f877759466846c7af0 | |
parent | d39198490f878a9ae395af1cf923fb7375de4548 (diff) |
Add render test functionality
-rw-r--r-- | .cargo/config | 3 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | cli/Cargo.toml | 11 | ||||
-rw-r--r-- | cli/src/main.rs | 68 | ||||
-rw-r--r-- | src/bin/cli.rs | 20 | ||||
-rw-r--r-- | src/parser/grammar/expressions.rs | 4 | ||||
-rw-r--r-- | tools/src/lib.rs | 50 | ||||
-rw-r--r-- | tools/src/main.rs (renamed from tools/src/bin/main.rs) | 45 |
8 files changed, 139 insertions, 64 deletions
diff --git a/.cargo/config b/.cargo/config index 1898d28d3..7903b919c 100644 --- a/.cargo/config +++ b/.cargo/config | |||
@@ -1,4 +1,5 @@ | |||
1 | [alias] | 1 | [alias] |
2 | parse = "run --package tools --bin parse" | ||
3 | gen-kinds = "run --package tools -- gen-kinds" | 2 | gen-kinds = "run --package tools -- gen-kinds" |
4 | gen-tests = "run --package tools -- gen-tests" | 3 | gen-tests = "run --package tools -- gen-tests" |
4 | render-test = "run --package cli -- render-test" | ||
5 | parse = "run --package cli -- parse" | ||
diff --git a/Cargo.toml b/Cargo.toml index 954f3e94b..b89573e2b 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -5,7 +5,7 @@ authors = ["Aleksey Kladov <[email protected]>"] | |||
5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
6 | 6 | ||
7 | [workspace] | 7 | [workspace] |
8 | members = [ "tools" ] | 8 | members = [ "tools", "cli" ] |
9 | 9 | ||
10 | [dependencies] | 10 | [dependencies] |
11 | unicode-xid = "0.1.0" | 11 | unicode-xid = "0.1.0" |
diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 000000000..a259eef63 --- /dev/null +++ b/cli/Cargo.toml | |||
@@ -0,0 +1,11 @@ | |||
1 | [package] | ||
2 | name = "cli" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Aleksey Kladov <[email protected]>"] | ||
5 | publish = false | ||
6 | |||
7 | [dependencies] | ||
8 | clap = "2.32.0" | ||
9 | failure = "0.1.1" | ||
10 | libsyntax2 = { path = "../" } | ||
11 | tools = { path = "../tools" } | ||
diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 000000000..94183c552 --- /dev/null +++ b/cli/src/main.rs | |||
@@ -0,0 +1,68 @@ | |||
1 | extern crate clap; | ||
2 | #[macro_use] | ||
3 | extern crate failure; | ||
4 | extern crate libsyntax2; | ||
5 | extern crate tools; | ||
6 | |||
7 | use std::{fs, path::Path, io::Read}; | ||
8 | use clap::{App, Arg, SubCommand}; | ||
9 | use tools::collect_tests; | ||
10 | |||
11 | type Result<T> = ::std::result::Result<T, failure::Error>; | ||
12 | |||
13 | fn main() -> Result<()> { | ||
14 | let matches = App::new("libsyntax2-cli") | ||
15 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) | ||
16 | .subcommand( | ||
17 | SubCommand::with_name("render-test") | ||
18 | .arg(Arg::with_name("line").long("--line").required(true).takes_value(true)) | ||
19 | .arg(Arg::with_name("file").long("--file").required(true).takes_value(true)) | ||
20 | ) | ||
21 | .subcommand(SubCommand::with_name("parse")) | ||
22 | .get_matches(); | ||
23 | match matches.subcommand() { | ||
24 | ("parse", _) => { | ||
25 | let tree = parse()?; | ||
26 | println!("{}", tree); | ||
27 | }, | ||
28 | ("render-test", Some(matches)) => { | ||
29 | let file = matches.value_of("file").unwrap(); | ||
30 | let file = Path::new(file); | ||
31 | let line: usize = matches.value_of("line").unwrap().parse()?; | ||
32 | let line = line - 1; | ||
33 | let (test, tree) = render_test(file, line)?; | ||
34 | println!("{}\n{}", test, tree); | ||
35 | } | ||
36 | _ => unreachable!(), | ||
37 | } | ||
38 | Ok(()) | ||
39 | |||
40 | } | ||
41 | |||
42 | fn parse() -> Result<String> { | ||
43 | let text = read_stdin()?; | ||
44 | let file = libsyntax2::parse(text); | ||
45 | let tree = libsyntax2::utils::dump_tree(&file); | ||
46 | Ok(tree) | ||
47 | } | ||
48 | |||
49 | fn read_stdin() -> Result<String> { | ||
50 | let mut buff = String::new(); | ||
51 | ::std::io::stdin().read_to_string(&mut buff)?; | ||
52 | Ok(buff) | ||
53 | } | ||
54 | |||
55 | fn render_test(file: &Path, line: usize) -> Result<(String, String)> { | ||
56 | let text = fs::read_to_string(file)?; | ||
57 | let tests = collect_tests(&text); | ||
58 | let test = tests.into_iter().find(|t| { | ||
59 | t.start_line <= line && line <= t.start_line + t.text.lines().count() | ||
60 | }); | ||
61 | let test = match test { | ||
62 | None => bail!("No test found at line {} at {}", line, file.display()), | ||
63 | Some(test) => test, | ||
64 | }; | ||
65 | let file = libsyntax2::parse(test.text.clone()); | ||
66 | let tree = libsyntax2::utils::dump_tree(&file); | ||
67 | Ok((test.text, tree)) | ||
68 | } | ||
diff --git a/src/bin/cli.rs b/src/bin/cli.rs deleted file mode 100644 index 9e513edb2..000000000 --- a/src/bin/cli.rs +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | extern crate libsyntax2; | ||
2 | |||
3 | use std::io::Read; | ||
4 | |||
5 | use libsyntax2::{ | ||
6 | parse, utils::dump_tree | ||
7 | }; | ||
8 | |||
9 | fn main() { | ||
10 | let text = read_input(); | ||
11 | let file = parse(text); | ||
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 | } | ||
diff --git a/src/parser/grammar/expressions.rs b/src/parser/grammar/expressions.rs index 2145b8d8b..40f41535e 100644 --- a/src/parser/grammar/expressions.rs +++ b/src/parser/grammar/expressions.rs | |||
@@ -1,5 +1,9 @@ | |||
1 | use super::*; | 1 | use super::*; |
2 | 2 | ||
3 | // test expr_literals | ||
4 | // fn foo() { | ||
5 | // let _ = 92; | ||
6 | // } | ||
3 | pub(super) fn literal(p: &mut Parser) -> bool { | 7 | pub(super) fn literal(p: &mut Parser) -> bool { |
4 | match p.current() { | 8 | match p.current() { |
5 | TRUE_KW | FALSE_KW | INT_NUMBER | FLOAT_NUMBER | BYTE | CHAR | STRING | RAW_STRING | 9 | TRUE_KW | FALSE_KW | INT_NUMBER | FLOAT_NUMBER | BYTE | CHAR | STRING | RAW_STRING |
diff --git a/tools/src/lib.rs b/tools/src/lib.rs new file mode 100644 index 000000000..157818bdf --- /dev/null +++ b/tools/src/lib.rs | |||
@@ -0,0 +1,50 @@ | |||
1 | extern crate itertools; | ||
2 | use itertools::Itertools; | ||
3 | |||
4 | #[derive(Debug, Eq)] | ||
5 | pub struct Test { | ||
6 | pub start_line: usize, | ||
7 | pub name: String, | ||
8 | pub text: String, | ||
9 | } | ||
10 | |||
11 | impl PartialEq for Test { | ||
12 | fn eq(&self, other: &Test) -> bool { | ||
13 | self.name.eq(&other.name) | ||
14 | } | ||
15 | } | ||
16 | |||
17 | pub fn collect_tests(s: &str) -> Vec<Test> { | ||
18 | let mut res = vec![]; | ||
19 | let prefix = "// "; | ||
20 | let comment_blocks = s | ||
21 | .lines() | ||
22 | .map(str::trim_left) | ||
23 | .enumerate() | ||
24 | .group_by(|(idx, line)| line.starts_with(prefix)); | ||
25 | |||
26 | 'outer: for (is_comment, block) in comment_blocks.into_iter() { | ||
27 | if !is_comment { | ||
28 | continue; | ||
29 | } | ||
30 | let mut block = block.map(|(idx, line)| (idx, &line[prefix.len()..])); | ||
31 | |||
32 | let (start_line, name) = loop { | ||
33 | match block.next() { | ||
34 | Some((idx, line)) if line.starts_with("test ") => { | ||
35 | break (idx, line["test ".len()..].to_string()) | ||
36 | }, | ||
37 | Some(_) => (), | ||
38 | None => continue 'outer, | ||
39 | } | ||
40 | }; | ||
41 | let text: String = itertools::join( | ||
42 | block.map(|(_, line)| line) | ||
43 | .chain(::std::iter::once("")), | ||
44 | "\n" | ||
45 | ); | ||
46 | assert!(!text.trim().is_empty() && text.ends_with("\n")); | ||
47 | res.push(Test { start_line, name, text }) | ||
48 | } | ||
49 | res | ||
50 | } | ||
diff --git a/tools/src/bin/main.rs b/tools/src/main.rs index f4f6e82ae..671f05388 100644 --- a/tools/src/bin/main.rs +++ b/tools/src/main.rs | |||
@@ -1,14 +1,14 @@ | |||
1 | extern crate clap; | 1 | extern crate clap; |
2 | #[macro_use] | 2 | #[macro_use] |
3 | extern crate failure; | 3 | extern crate failure; |
4 | extern crate itertools; | ||
5 | extern crate ron; | 4 | extern crate ron; |
6 | extern crate tera; | 5 | extern crate tera; |
7 | extern crate walkdir; | 6 | extern crate walkdir; |
7 | extern crate tools; | ||
8 | 8 | ||
9 | use clap::{App, Arg, SubCommand}; | ||
10 | use itertools::Itertools; | ||
11 | use std::{collections::HashSet, fs, path::Path}; | 9 | use std::{collections::HashSet, fs, path::Path}; |
10 | use clap::{App, Arg, SubCommand}; | ||
11 | use tools::{collect_tests, Test}; | ||
12 | 12 | ||
13 | type Result<T> = ::std::result::Result<T, failure::Error>; | 13 | type Result<T> = ::std::result::Result<T, failure::Error>; |
14 | 14 | ||
@@ -96,17 +96,6 @@ fn gen_tests(verify: bool) -> Result<()> { | |||
96 | Ok(()) | 96 | Ok(()) |
97 | } | 97 | } |
98 | 98 | ||
99 | #[derive(Debug, Eq)] | ||
100 | struct Test { | ||
101 | name: String, | ||
102 | text: String, | ||
103 | } | ||
104 | |||
105 | impl PartialEq for Test { | ||
106 | fn eq(&self, other: &Test) -> bool { | ||
107 | self.name.eq(&other.name) | ||
108 | } | ||
109 | } | ||
110 | 99 | ||
111 | impl ::std::hash::Hash for Test { | 100 | impl ::std::hash::Hash for Test { |
112 | fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) { | 101 | fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) { |
@@ -135,34 +124,6 @@ fn tests_from_dir(dir: &Path) -> Result<HashSet<Test>> { | |||
135 | Ok(res) | 124 | Ok(res) |
136 | } | 125 | } |
137 | 126 | ||
138 | fn collect_tests(s: &str) -> Vec<Test> { | ||
139 | let mut res = vec![]; | ||
140 | let prefix = "// "; | ||
141 | let comment_blocks = s | ||
142 | .lines() | ||
143 | .map(str::trim_left) | ||
144 | .group_by(|line| line.starts_with(prefix)); | ||
145 | |||
146 | 'outer: for (is_comment, block) in comment_blocks.into_iter() { | ||
147 | if !is_comment { | ||
148 | continue; | ||
149 | } | ||
150 | let mut block = block.map(|line| &line[prefix.len()..]); | ||
151 | |||
152 | let name = loop { | ||
153 | match block.next() { | ||
154 | Some(line) if line.starts_with("test ") => break line["test ".len()..].to_string(), | ||
155 | Some(_) => (), | ||
156 | None => continue 'outer, | ||
157 | } | ||
158 | }; | ||
159 | let text: String = itertools::join(block.chain(::std::iter::once("")), "\n"); | ||
160 | assert!(!text.trim().is_empty() && text.ends_with("\n")); | ||
161 | res.push(Test { name, text }) | ||
162 | } | ||
163 | res | ||
164 | } | ||
165 | |||
166 | fn existing_tests(dir: &Path) -> Result<HashSet<Test>> { | 127 | fn existing_tests(dir: &Path) -> Result<HashSet<Test>> { |
167 | let mut res = HashSet::new(); | 128 | let mut res = HashSet::new(); |
168 | for file in fs::read_dir(dir)? { | 129 | for file in fs::read_dir(dir)? { |