From 514aa3cf853c3c4beef8f827c12328d626f977de Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 16 Oct 2018 20:28:43 +0300 Subject: extract teraron --- crates/teraron/Cargo.toml | 13 ++++++ crates/teraron/src/lib.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++++ crates/tools/Cargo.toml | 4 +- crates/tools/src/lib.rs | 50 ++------------------- crates/tools/src/main.rs | 45 +++++++++---------- 5 files changed, 149 insertions(+), 72 deletions(-) create mode 100644 crates/teraron/Cargo.toml create mode 100644 crates/teraron/src/lib.rs (limited to 'crates') diff --git a/crates/teraron/Cargo.toml b/crates/teraron/Cargo.toml new file mode 100644 index 000000000..7ce9f1aa8 --- /dev/null +++ b/crates/teraron/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "teraron" +version = "0.0.1" +authors = ["Aleksey Kladov "] +repository = "https://github.com/rust-analyzer/teraron" +description = "Genrate Rust code from a .tera template and a .ron data" +license = "MIT OR Apache-2.0" + +[dependencies] +failure = "0.1.2" +tera = "0.11.18" +ron = "0.4.0" +heck = "0.3.0" diff --git a/crates/teraron/src/lib.rs b/crates/teraron/src/lib.rs new file mode 100644 index 000000000..e464ea080 --- /dev/null +++ b/crates/teraron/src/lib.rs @@ -0,0 +1,109 @@ +//! A simple tool to generate rust code by passing a ron value +//! to a tera template + +#[macro_use] +extern crate failure; +extern crate tera; +extern crate ron; +extern crate heck; + +use std::{ + fs, + collections::HashMap, + path::Path, +}; + +use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Mode { + Overwrite, + Verify, +} + +pub use Mode::*; + +/// A helper to update file on disk if it has changed. +/// With verify = false, +pub fn update(path: &Path, contents: &str, mode: Mode) -> Result<(), failure::Error> { + match fs::read_to_string(path) { + Ok(ref old_contents) if old_contents == contents => { + return Ok(()); + } + _ => (), + } + if mode == Verify { + bail!("`{}` is not up-to-date", path.display()); + } + eprintln!("updating {}", path.display()); + fs::write(path, contents)?; + Ok(()) +} + +pub fn generate( + template: &Path, + src: &Path, + mode: Mode, +) -> Result<(), failure::Error> { + assert_eq!( + template.extension().and_then(|it| it.to_str()), Some("tera"), + "template file must have .rs.tera extension", + ); + let file_name = template.file_stem().unwrap().to_str().unwrap(); + assert!( + file_name.ends_with(".rs"), + "template file must have .rs.tera extension", + ); + let tgt = template.with_file_name(file_name); + let template = fs::read_to_string(template)?; + let src: ron::Value = { + let text = fs::read_to_string(src)?; + ron::de::from_str(&text)? + }; + let content = render(&template, src)?; + update( + &tgt, + &content, + mode, + ) +} + +pub fn render( + template: &str, + src: ron::Value, +) -> Result { + let mut tera = mk_tera(); + tera.add_raw_template("_src", template) + .map_err(|e| format_err!("template parsing error: {:?}", e))?; + let res = tera.render("_src", &src) + .map_err(|e| format_err!("template rendering error: {:?}", e))?; + return Ok(res); +} + +fn mk_tera() -> tera::Tera { + let mut res = tera::Tera::default(); + res.register_filter("camel", |arg, _| { + Ok(arg.as_str().unwrap().to_camel_case().into()) + }); + res.register_filter("snake", |arg, _| { + Ok(arg.as_str().unwrap().to_snake_case().into()) + }); + res.register_filter("SCREAM", |arg, _| { + Ok(arg.as_str().unwrap().to_shouty_snake_case().into()) + }); + res.register_function("concat", Box::new(concat)); + res +} + +fn concat(args: HashMap) -> tera::Result { + let mut elements = Vec::new(); + for &key in ["a", "b", "c"].iter() { + let val = match args.get(key) { + Some(val) => val, + None => continue, + }; + let val = val.as_array().unwrap(); + elements.extend(val.iter().cloned()); + } + Ok(tera::Value::Array(elements)) +} diff --git a/crates/tools/Cargo.toml b/crates/tools/Cargo.toml index e2fecc60d..ffd0ab1a5 100644 --- a/crates/tools/Cargo.toml +++ b/crates/tools/Cargo.toml @@ -6,10 +6,8 @@ authors = ["Aleksey Kladov "] publish = false [dependencies] -ron = "0.3.0" +teraron = { path = "../teraron"} walkdir = "2.1.3" itertools = "0.7.8" -tera = "0.11" clap = "2.32.0" failure = "0.1.1" -heck = "0.3.0" diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index 5d5d372bb..63ede5315 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs @@ -1,25 +1,18 @@ extern crate itertools; #[macro_use] extern crate failure; -extern crate heck; -extern crate ron; -extern crate tera; -use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; use itertools::Itertools; use std::{ - collections::HashMap, fs, path::{Path, PathBuf}, }; pub type Result = ::std::result::Result; -const GRAMMAR: &str = "ra_syntax/src/grammar.ron"; -pub const SYNTAX_KINDS: &str = "ra_syntax/src/syntax_kinds/generated.rs"; -pub const SYNTAX_KINDS_TEMPLATE: &str = "ra_syntax/src/syntax_kinds/generated.rs.tera"; -pub const AST: &str = "ra_syntax/src/ast/generated.rs"; -pub const AST_TEMPLATE: &str = "ra_syntax/src/ast/generated.rs.tera"; +pub const GRAMMAR: &str = "ra_syntax/src/grammar.ron"; +pub const SYNTAX_KINDS: &str = "ra_syntax/src/syntax_kinds/generated.rs.tera"; +pub const AST: &str = "ra_syntax/src/ast/generated.rs.tera"; #[derive(Debug)] pub struct Test { @@ -76,43 +69,6 @@ pub fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { Ok(()) } -pub fn render_template(template: &Path) -> Result { - let grammar: ron::value::Value = { - let text = fs::read_to_string(project_root().join(GRAMMAR))?; - ron::de::from_str(&text)? - }; - let template = fs::read_to_string(template)?; - let mut tera = tera::Tera::default(); - tera.add_raw_template("grammar", &template) - .map_err(|e| format_err!("template error: {:?}", e))?; - tera.register_function("concat", Box::new(concat)); - tera.register_filter("camel", |arg, _| { - Ok(arg.as_str().unwrap().to_camel_case().into()) - }); - tera.register_filter("snake", |arg, _| { - Ok(arg.as_str().unwrap().to_snake_case().into()) - }); - tera.register_filter("SCREAM", |arg, _| { - Ok(arg.as_str().unwrap().to_shouty_snake_case().into()) - }); - let ret = tera - .render("grammar", &grammar) - .map_err(|e| format_err!("template error: {:?}", e))?; - return Ok(ret); - - fn concat(args: HashMap) -> tera::Result { - let mut elements = Vec::new(); - for &key in ["a", "b", "c"].iter() { - let val = match args.get(key) { - Some(val) => val, - None => continue, - }; - let val = val.as_array().unwrap(); - elements.extend(val.iter().cloned()); - } - Ok(tera::Value::Array(elements)) - } -} pub fn project_root() -> PathBuf { Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap()) diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs index b662d78df..1bbc43123 100644 --- a/crates/tools/src/main.rs +++ b/crates/tools/src/main.rs @@ -3,6 +3,7 @@ extern crate clap; extern crate failure; extern crate tools; extern crate walkdir; +extern crate teraron; use clap::{App, Arg, SubCommand}; use std::{ @@ -12,9 +13,9 @@ use std::{ process::Command, }; use tools::{ - collect_tests, project_root, render_template, update, Result, Test, AST, AST_TEMPLATE, - SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, + collect_tests, project_root, Result, Test, AST, SYNTAX_KINDS, GRAMMAR, }; +use teraron::{Mode, Verify, Overwrite}; const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar"; const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline"; @@ -32,35 +33,35 @@ fn main() -> Result<()> { .subcommand(SubCommand::with_name("gen-tests")) .subcommand(SubCommand::with_name("install-code")) .get_matches(); + let mode = if matches.is_present("verify") { + Verify + } else { + Overwrite + }; match matches.subcommand() { ("install-code", _) => install_code_extension()?, - (name, Some(matches)) => run_gen_command(name, matches.is_present("verify"))?, - _ => unreachable!(), - } - Ok(()) -} - -fn run_gen_command(name: &str, verify: bool) -> Result<()> { - match name { - "gen-kinds" => { - update( - &project_root().join(SYNTAX_KINDS), - &render_template(&project_root().join(SYNTAX_KINDS_TEMPLATE))?, - verify, + ("gen-tests", _) => gen_tests(mode)?, + ("gen-kinds", _) => { + let grammar = project_root().join(GRAMMAR); + let syntax_kinds = project_root().join(SYNTAX_KINDS); + let ast = project_root().join(AST); + teraron::generate( + &syntax_kinds, + &grammar, + mode, )?; - update( - &project_root().join(AST), - &render_template(&project_root().join(AST_TEMPLATE))?, - verify, + teraron::generate( + &ast, + &grammar, + mode, )?; } - "gen-tests" => gen_tests(verify)?, _ => unreachable!(), } Ok(()) } -fn gen_tests(verify: bool) -> Result<()> { +fn gen_tests(mode: Mode) -> Result<()> { let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; let inline_tests_dir = Path::new(INLINE_TESTS_DIR); @@ -83,7 +84,7 @@ fn gen_tests(verify: bool) -> Result<()> { inline_tests_dir.join(file_name) } }; - update(&path, &test.text, verify)?; + teraron::update(&path, &test.text, mode)?; } Ok(()) } -- cgit v1.2.3 From 0b6d4983de85fcf9f84ed50c9973a1df612e5038 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 16 Oct 2018 20:36:45 +0300 Subject: Switch to published teraron --- crates/teraron/Cargo.toml | 13 ------ crates/teraron/src/lib.rs | 109 ---------------------------------------------- crates/tools/Cargo.toml | 2 +- 3 files changed, 1 insertion(+), 123 deletions(-) delete mode 100644 crates/teraron/Cargo.toml delete mode 100644 crates/teraron/src/lib.rs (limited to 'crates') diff --git a/crates/teraron/Cargo.toml b/crates/teraron/Cargo.toml deleted file mode 100644 index 7ce9f1aa8..000000000 --- a/crates/teraron/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "teraron" -version = "0.0.1" -authors = ["Aleksey Kladov "] -repository = "https://github.com/rust-analyzer/teraron" -description = "Genrate Rust code from a .tera template and a .ron data" -license = "MIT OR Apache-2.0" - -[dependencies] -failure = "0.1.2" -tera = "0.11.18" -ron = "0.4.0" -heck = "0.3.0" diff --git a/crates/teraron/src/lib.rs b/crates/teraron/src/lib.rs deleted file mode 100644 index e464ea080..000000000 --- a/crates/teraron/src/lib.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! A simple tool to generate rust code by passing a ron value -//! to a tera template - -#[macro_use] -extern crate failure; -extern crate tera; -extern crate ron; -extern crate heck; - -use std::{ - fs, - collections::HashMap, - path::Path, -}; - -use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum Mode { - Overwrite, - Verify, -} - -pub use Mode::*; - -/// A helper to update file on disk if it has changed. -/// With verify = false, -pub fn update(path: &Path, contents: &str, mode: Mode) -> Result<(), failure::Error> { - match fs::read_to_string(path) { - Ok(ref old_contents) if old_contents == contents => { - return Ok(()); - } - _ => (), - } - if mode == Verify { - bail!("`{}` is not up-to-date", path.display()); - } - eprintln!("updating {}", path.display()); - fs::write(path, contents)?; - Ok(()) -} - -pub fn generate( - template: &Path, - src: &Path, - mode: Mode, -) -> Result<(), failure::Error> { - assert_eq!( - template.extension().and_then(|it| it.to_str()), Some("tera"), - "template file must have .rs.tera extension", - ); - let file_name = template.file_stem().unwrap().to_str().unwrap(); - assert!( - file_name.ends_with(".rs"), - "template file must have .rs.tera extension", - ); - let tgt = template.with_file_name(file_name); - let template = fs::read_to_string(template)?; - let src: ron::Value = { - let text = fs::read_to_string(src)?; - ron::de::from_str(&text)? - }; - let content = render(&template, src)?; - update( - &tgt, - &content, - mode, - ) -} - -pub fn render( - template: &str, - src: ron::Value, -) -> Result { - let mut tera = mk_tera(); - tera.add_raw_template("_src", template) - .map_err(|e| format_err!("template parsing error: {:?}", e))?; - let res = tera.render("_src", &src) - .map_err(|e| format_err!("template rendering error: {:?}", e))?; - return Ok(res); -} - -fn mk_tera() -> tera::Tera { - let mut res = tera::Tera::default(); - res.register_filter("camel", |arg, _| { - Ok(arg.as_str().unwrap().to_camel_case().into()) - }); - res.register_filter("snake", |arg, _| { - Ok(arg.as_str().unwrap().to_snake_case().into()) - }); - res.register_filter("SCREAM", |arg, _| { - Ok(arg.as_str().unwrap().to_shouty_snake_case().into()) - }); - res.register_function("concat", Box::new(concat)); - res -} - -fn concat(args: HashMap) -> tera::Result { - let mut elements = Vec::new(); - for &key in ["a", "b", "c"].iter() { - let val = match args.get(key) { - Some(val) => val, - None => continue, - }; - let val = val.as_array().unwrap(); - elements.extend(val.iter().cloned()); - } - Ok(tera::Value::Array(elements)) -} diff --git a/crates/tools/Cargo.toml b/crates/tools/Cargo.toml index ffd0ab1a5..41b19c5c6 100644 --- a/crates/tools/Cargo.toml +++ b/crates/tools/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Aleksey Kladov "] publish = false [dependencies] -teraron = { path = "../teraron"} +teraron = "0.0.1" walkdir = "2.1.3" itertools = "0.7.8" clap = "2.32.0" -- cgit v1.2.3 From b43bcd43c604126c2b250a30cc56459be754572a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 16 Oct 2018 20:53:19 +0300 Subject: fix tests --- crates/tools/src/lib.rs | 35 +++++++++++++++++++---------------- crates/tools/src/main.rs | 19 ++----------------- crates/tools/tests/cli.rs | 15 ++------------- 3 files changed, 23 insertions(+), 46 deletions(-) (limited to 'crates') diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index 63ede5315..444745be5 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs @@ -1,13 +1,15 @@ extern crate itertools; -#[macro_use] extern crate failure; +extern crate teraron; -use itertools::Itertools; use std::{ - fs, path::{Path, PathBuf}, }; +use itertools::Itertools; + +pub use teraron::{Mode, Verify, Overwrite}; + pub type Result = ::std::result::Result; pub const GRAMMAR: &str = "ra_syntax/src/grammar.ron"; @@ -54,22 +56,23 @@ pub fn collect_tests(s: &str) -> Vec<(usize, Test)> { res } -pub fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { - match fs::read_to_string(path) { - Ok(ref old_contents) if old_contents == contents => { - return Ok(()); - } - _ => (), - } - if verify { - bail!("`{}` is not up-to-date", path.display()); - } - eprintln!("updating {}", path.display()); - fs::write(path, contents)?; +pub fn generate(mode: Mode) -> Result<()> { + let grammar = project_root().join(GRAMMAR); + let syntax_kinds = project_root().join(SYNTAX_KINDS); + let ast = project_root().join(AST); + teraron::generate( + &syntax_kinds, + &grammar, + mode, + )?; + teraron::generate( + &ast, + &grammar, + mode, + )?; Ok(()) } - pub fn project_root() -> PathBuf { Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap()) .parent() diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs index 1bbc43123..965bc7729 100644 --- a/crates/tools/src/main.rs +++ b/crates/tools/src/main.rs @@ -13,9 +13,8 @@ use std::{ process::Command, }; use tools::{ - collect_tests, project_root, Result, Test, AST, SYNTAX_KINDS, GRAMMAR, + collect_tests, Result, Test, generate, Mode, Overwrite, Verify, }; -use teraron::{Mode, Verify, Overwrite}; const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar"; const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline"; @@ -41,21 +40,7 @@ fn main() -> Result<()> { match matches.subcommand() { ("install-code", _) => install_code_extension()?, ("gen-tests", _) => gen_tests(mode)?, - ("gen-kinds", _) => { - let grammar = project_root().join(GRAMMAR); - let syntax_kinds = project_root().join(SYNTAX_KINDS); - let ast = project_root().join(AST); - teraron::generate( - &syntax_kinds, - &grammar, - mode, - )?; - teraron::generate( - &ast, - &grammar, - mode, - )?; - } + ("gen-kinds", _) => generate(Overwrite)?, _ => unreachable!(), } Ok(()) diff --git a/crates/tools/tests/cli.rs b/crates/tools/tests/cli.rs index 16899bb5f..0bb5d15d8 100644 --- a/crates/tools/tests/cli.rs +++ b/crates/tools/tests/cli.rs @@ -1,23 +1,12 @@ extern crate tools; use tools::{ - project_root, render_template, update, AST, AST_TEMPLATE, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, + generate, Verify }; #[test] fn verify_template_generation() { - if let Err(error) = update( - &project_root().join(SYNTAX_KINDS), - &render_template(&project_root().join(SYNTAX_KINDS_TEMPLATE)).unwrap(), - true, - ) { - panic!("{}. Please update it by running `cargo gen-kinds`", error); - } - if let Err(error) = update( - &project_root().join(AST), - &render_template(&project_root().join(AST_TEMPLATE)).unwrap(), - true, - ) { + if let Err(error) = generate(Verify) { panic!("{}. Please update it by running `cargo gen-kinds`", error); } } -- cgit v1.2.3