diff options
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/tools/src/lib.rs | 67 | ||||
| -rw-r--r-- | crates/tools/src/main.rs | 62 | ||||
| -rw-r--r-- | crates/tools/tests/cli.rs | 16 |
3 files changed, 86 insertions, 59 deletions
diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index 97a56a31f..352f4d135 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs | |||
| @@ -1,6 +1,19 @@ | |||
| 1 | extern crate itertools; | 1 | extern crate itertools; |
| 2 | #[macro_use] | ||
| 3 | extern crate failure; | ||
| 4 | extern crate ron; | ||
| 5 | extern crate tera; | ||
| 6 | extern crate heck; | ||
| 2 | 7 | ||
| 8 | use std::{ | ||
| 9 | collections::HashMap, | ||
| 10 | fs, | ||
| 11 | path::Path, | ||
| 12 | }; | ||
| 3 | use itertools::Itertools; | 13 | use itertools::Itertools; |
| 14 | use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; | ||
| 15 | |||
| 16 | type Result<T> = ::std::result::Result<T, failure::Error>; | ||
| 4 | 17 | ||
| 5 | #[derive(Debug)] | 18 | #[derive(Debug)] |
| 6 | pub struct Test { | 19 | pub struct Test { |
| @@ -41,3 +54,57 @@ pub fn collect_tests(s: &str) -> Vec<(usize, Test)> { | |||
| 41 | } | 54 | } |
| 42 | res | 55 | res |
| 43 | } | 56 | } |
| 57 | |||
| 58 | |||
| 59 | pub fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { | ||
| 60 | match fs::read_to_string(path) { | ||
| 61 | Ok(ref old_contents) if old_contents == contents => { | ||
| 62 | return Ok(()); | ||
| 63 | } | ||
| 64 | _ => (), | ||
| 65 | } | ||
| 66 | if verify { | ||
| 67 | bail!("`{}` is not up-to-date", path.display()); | ||
| 68 | } | ||
| 69 | eprintln!("updating {}", path.display()); | ||
| 70 | fs::write(path, contents)?; | ||
| 71 | Ok(()) | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn render_template(template: &str, grammarfile: &str) -> Result<String> { | ||
| 75 | let grammar: ron::value::Value = { | ||
| 76 | let text = fs::read_to_string(grammarfile)?; | ||
| 77 | ron::de::from_str(&text)? | ||
| 78 | }; | ||
| 79 | let template = fs::read_to_string(template)?; | ||
| 80 | let mut tera = tera::Tera::default(); | ||
| 81 | tera.add_raw_template("grammar", &template) | ||
| 82 | .map_err(|e| format_err!("template error: {:?}", e))?; | ||
| 83 | tera.register_function("concat", Box::new(concat)); | ||
| 84 | tera.register_filter("camel", |arg, _| { | ||
| 85 | Ok(arg.as_str().unwrap().to_camel_case().into()) | ||
| 86 | }); | ||
| 87 | tera.register_filter("snake", |arg, _| { | ||
| 88 | Ok(arg.as_str().unwrap().to_snake_case().into()) | ||
| 89 | }); | ||
| 90 | tera.register_filter("SCREAM", |arg, _| { | ||
| 91 | Ok(arg.as_str().unwrap().to_shouty_snake_case().into()) | ||
| 92 | }); | ||
| 93 | let ret = tera | ||
| 94 | .render("grammar", &grammar) | ||
| 95 | .map_err(|e| format_err!("template error: {:?}", e))?; | ||
| 96 | return Ok(ret); | ||
| 97 | |||
| 98 | fn concat(args: HashMap<String, tera::Value>) -> tera::Result<tera::Value> { | ||
| 99 | let mut elements = Vec::new(); | ||
| 100 | for &key in ["a", "b", "c"].iter() { | ||
| 101 | let val = match args.get(key) { | ||
| 102 | Some(val) => val, | ||
| 103 | None => continue, | ||
| 104 | }; | ||
| 105 | let val = val.as_array().unwrap(); | ||
| 106 | elements.extend(val.iter().cloned()); | ||
| 107 | } | ||
| 108 | Ok(tera::Value::Array(elements)) | ||
| 109 | } | ||
| 110 | } | ||
diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs index ee900553c..cf5e662b0 100644 --- a/crates/tools/src/main.rs +++ b/crates/tools/src/main.rs | |||
| @@ -1,21 +1,17 @@ | |||
| 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 ron; | ||
| 5 | extern crate tera; | ||
| 6 | extern crate tools; | 4 | extern crate tools; |
| 7 | extern crate walkdir; | 5 | extern crate walkdir; |
| 8 | extern crate heck; | ||
| 9 | 6 | ||
| 10 | use clap::{App, Arg, SubCommand}; | 7 | use clap::{App, Arg, SubCommand}; |
| 11 | use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; | ||
| 12 | use std::{ | 8 | use std::{ |
| 13 | collections::HashMap, | 9 | collections::HashMap, |
| 14 | fs, | 10 | fs, |
| 15 | path::{Path, PathBuf}, | 11 | path::{Path, PathBuf}, |
| 16 | process::Command, | 12 | process::Command, |
| 17 | }; | 13 | }; |
| 18 | use tools::{collect_tests, Test}; | 14 | use tools::{Test, collect_tests, render_template, update}; |
| 19 | 15 | ||
| 20 | type Result<T> = ::std::result::Result<T, failure::Error>; | 16 | type Result<T> = ::std::result::Result<T, failure::Error>; |
| 21 | 17 | ||
| @@ -51,8 +47,8 @@ fn main() -> Result<()> { | |||
| 51 | fn run_gen_command(name: &str, verify: bool) -> Result<()> { | 47 | fn run_gen_command(name: &str, verify: bool) -> Result<()> { |
| 52 | match name { | 48 | match name { |
| 53 | "gen-kinds" => { | 49 | "gen-kinds" => { |
| 54 | update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE)?, verify)?; | 50 | update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE, GRAMMAR)?, verify)?; |
| 55 | update(Path::new(AST), &render_template(AST_TEMPLATE)?, verify)?; | 51 | update(Path::new(AST), &render_template(AST_TEMPLATE, GRAMMAR)?, verify)?; |
| 56 | }, | 52 | }, |
| 57 | "gen-tests" => { | 53 | "gen-tests" => { |
| 58 | gen_tests(verify)? | 54 | gen_tests(verify)? |
| @@ -62,58 +58,6 @@ fn run_gen_command(name: &str, verify: bool) -> Result<()> { | |||
| 62 | Ok(()) | 58 | Ok(()) |
| 63 | } | 59 | } |
| 64 | 60 | ||
| 65 | fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { | ||
| 66 | match fs::read_to_string(path) { | ||
| 67 | Ok(ref old_contents) if old_contents == contents => { | ||
| 68 | return Ok(()); | ||
| 69 | } | ||
| 70 | _ => (), | ||
| 71 | } | ||
| 72 | if verify { | ||
| 73 | bail!("`{}` is not up-to-date", path.display()); | ||
| 74 | } | ||
| 75 | eprintln!("updating {}", path.display()); | ||
| 76 | fs::write(path, contents)?; | ||
| 77 | Ok(()) | ||
| 78 | } | ||
| 79 | |||
| 80 | fn render_template(template: &str) -> Result<String> { | ||
| 81 | let grammar: ron::value::Value = { | ||
| 82 | let text = fs::read_to_string(GRAMMAR)?; | ||
| 83 | ron::de::from_str(&text)? | ||
| 84 | }; | ||
| 85 | let template = fs::read_to_string(template)?; | ||
| 86 | let mut tera = tera::Tera::default(); | ||
| 87 | tera.add_raw_template("grammar", &template) | ||
| 88 | .map_err(|e| format_err!("template error: {:?}", e))?; | ||
| 89 | tera.register_function("concat", Box::new(concat)); | ||
| 90 | tera.register_filter("camel", |arg, _| { | ||
| 91 | Ok(arg.as_str().unwrap().to_camel_case().into()) | ||
| 92 | }); | ||
| 93 | tera.register_filter("snake", |arg, _| { | ||
| 94 | Ok(arg.as_str().unwrap().to_snake_case().into()) | ||
| 95 | }); | ||
| 96 | tera.register_filter("SCREAM", |arg, _| { | ||
| 97 | Ok(arg.as_str().unwrap().to_shouty_snake_case().into()) | ||
| 98 | }); | ||
| 99 | let ret = tera | ||
| 100 | .render("grammar", &grammar) | ||
| 101 | .map_err(|e| format_err!("template error: {:?}", e))?; | ||
| 102 | return Ok(ret); | ||
| 103 | |||
| 104 | fn concat(args: HashMap<String, tera::Value>) -> tera::Result<tera::Value> { | ||
| 105 | let mut elements = Vec::new(); | ||
| 106 | for &key in ["a", "b", "c"].iter() { | ||
| 107 | let val = match args.get(key) { | ||
| 108 | Some(val) => val, | ||
| 109 | None => continue, | ||
| 110 | }; | ||
| 111 | let val = val.as_array().unwrap(); | ||
| 112 | elements.extend(val.iter().cloned()); | ||
| 113 | } | ||
| 114 | Ok(tera::Value::Array(elements)) | ||
| 115 | } | ||
| 116 | } | ||
| 117 | 61 | ||
| 118 | fn gen_tests(verify: bool) -> Result<()> { | 62 | fn gen_tests(verify: bool) -> Result<()> { |
| 119 | let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; | 63 | let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; |
diff --git a/crates/tools/tests/cli.rs b/crates/tools/tests/cli.rs new file mode 100644 index 000000000..26d9a991c --- /dev/null +++ b/crates/tools/tests/cli.rs | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | extern crate tools; | ||
| 2 | |||
| 3 | use std::path::Path; | ||
| 4 | use tools::{render_template, update}; | ||
| 5 | |||
| 6 | const GRAMMAR: &str = "../ra_syntax/src/grammar.ron"; | ||
| 7 | const SYNTAX_KINDS: &str = "../ra_syntax/src/syntax_kinds/generated.rs"; | ||
| 8 | const SYNTAX_KINDS_TEMPLATE: &str = "../ra_syntax/src/syntax_kinds/generated.rs.tera"; | ||
| 9 | const AST: &str = "../ra_syntax/src/ast/generated.rs"; | ||
| 10 | const AST_TEMPLATE: &str = "../ra_syntax/src/ast/generated.rs.tera"; | ||
| 11 | |||
| 12 | #[test] | ||
| 13 | fn verify_template_generation() { | ||
| 14 | update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE, GRAMMAR).unwrap(), true).unwrap(); | ||
| 15 | update(Path::new(AST), &render_template(AST_TEMPLATE, GRAMMAR).unwrap(), true).unwrap(); | ||
| 16 | } \ No newline at end of file | ||
