aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-07-30 14:16:58 +0100
committerAleksey Kladov <[email protected]>2018-07-30 14:16:58 +0100
commit3b6a6f6673041cf9ee315c00f9b0e24e2c067091 (patch)
tree001e556601e9dd37556338f877759466846c7af0
parentd39198490f878a9ae395af1cf923fb7375de4548 (diff)
Add render test functionality
-rw-r--r--.cargo/config3
-rw-r--r--Cargo.toml2
-rw-r--r--cli/Cargo.toml11
-rw-r--r--cli/src/main.rs68
-rw-r--r--src/bin/cli.rs20
-rw-r--r--src/parser/grammar/expressions.rs4
-rw-r--r--tools/src/lib.rs50
-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]
2parse = "run --package tools --bin parse"
3gen-kinds = "run --package tools -- gen-kinds" 2gen-kinds = "run --package tools -- gen-kinds"
4gen-tests = "run --package tools -- gen-tests" 3gen-tests = "run --package tools -- gen-tests"
4render-test = "run --package cli -- render-test"
5parse = "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]>"]
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[workspace] 7[workspace]
8members = [ "tools" ] 8members = [ "tools", "cli" ]
9 9
10[dependencies] 10[dependencies]
11unicode-xid = "0.1.0" 11unicode-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]
2name = "cli"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5publish = false
6
7[dependencies]
8clap = "2.32.0"
9failure = "0.1.1"
10libsyntax2 = { path = "../" }
11tools = { 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 @@
1extern crate clap;
2#[macro_use]
3extern crate failure;
4extern crate libsyntax2;
5extern crate tools;
6
7use std::{fs, path::Path, io::Read};
8use clap::{App, Arg, SubCommand};
9use tools::collect_tests;
10
11type Result<T> = ::std::result::Result<T, failure::Error>;
12
13fn 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
42fn 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
49fn read_stdin() -> Result<String> {
50 let mut buff = String::new();
51 ::std::io::stdin().read_to_string(&mut buff)?;
52 Ok(buff)
53}
54
55fn 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 @@
1extern crate libsyntax2;
2
3use std::io::Read;
4
5use libsyntax2::{
6 parse, utils::dump_tree
7};
8
9fn main() {
10 let text = read_input();
11 let file = parse(text);
12 let tree = dump_tree(&file);
13 println!("{}", tree);
14}
15
16fn 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 @@
1use super::*; 1use super::*;
2 2
3// test expr_literals
4// fn foo() {
5// let _ = 92;
6// }
3pub(super) fn literal(p: &mut Parser) -> bool { 7pub(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 @@
1extern crate itertools;
2use itertools::Itertools;
3
4#[derive(Debug, Eq)]
5pub struct Test {
6 pub start_line: usize,
7 pub name: String,
8 pub text: String,
9}
10
11impl PartialEq for Test {
12 fn eq(&self, other: &Test) -> bool {
13 self.name.eq(&other.name)
14 }
15}
16
17pub 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 @@
1extern crate clap; 1extern crate clap;
2#[macro_use] 2#[macro_use]
3extern crate failure; 3extern crate failure;
4extern crate itertools;
5extern crate ron; 4extern crate ron;
6extern crate tera; 5extern crate tera;
7extern crate walkdir; 6extern crate walkdir;
7extern crate tools;
8 8
9use clap::{App, Arg, SubCommand};
10use itertools::Itertools;
11use std::{collections::HashSet, fs, path::Path}; 9use std::{collections::HashSet, fs, path::Path};
10use clap::{App, Arg, SubCommand};
11use tools::{collect_tests, Test};
12 12
13type Result<T> = ::std::result::Result<T, failure::Error>; 13type 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)]
100struct Test {
101 name: String,
102 text: String,
103}
104
105impl PartialEq for Test {
106 fn eq(&self, other: &Test) -> bool {
107 self.name.eq(&other.name)
108 }
109}
110 99
111impl ::std::hash::Hash for Test { 100impl ::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
138fn 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
166fn existing_tests(dir: &Path) -> Result<HashSet<Test>> { 127fn 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)? {