diff --git a/.gitignore b/.gitignore index 18a3835..57cc700 100644 --- a/.gitignore +++ b/.gitignore @@ -2,50 +2,3 @@ target *~ TAGS lalrpop/src/parser/lrgrammar.rs - -doc/calculator/src/calculator1.rs -doc/calculator/src/calculator2.rs -doc/calculator/src/calculator2b.rs -doc/calculator/src/calculator3.rs -doc/calculator/src/calculator4.rs -doc/calculator/src/calculator5.rs -doc/calculator/src/calculator6.rs -doc/pascal/lalrpop/src/pascal.rs -doc/whitespace/src/parser.rs - -lalrpop-test/src/error.rs -lalrpop-test/src/error_issue_113.rs -lalrpop-test/src/error_issue_278.rs -lalrpop-test/src/error_issue_261.rs -lalrpop-test/src/error_recovery.rs -lalrpop-test/src/error_recovery_pull_182.rs -lalrpop-test/src/error_recovery_issue_240.rs -lalrpop-test/src/error_recovery_lock_in.rs -lalrpop-test/src/error_recovery_lalr_loop.rs -lalrpop-test/src/error_recovery_span.rs -lalrpop-test/src/error_recovery_type_in_macro.rs -lalrpop-test/src/expr.rs -lalrpop-test/src/expr_arena.rs -lalrpop-test/src/expr_generic.rs -lalrpop-test/src/expr_intern_tok.rs -lalrpop-test/src/expr_lalr.rs -lalrpop-test/src/expr_module_attributes.rs -lalrpop-test/src/generics_issue_104.rs -lalrpop-test/src/inline.rs -lalrpop-test/src/intern_tok.rs -lalrpop-test/src/issue_55.rs -lalrpop-test/src/lifetime_tok.rs -lalrpop-test/src/loc.rs -lalrpop-test/src/loc_issue_90.rs -lalrpop-test/src/sub.rs -lalrpop-test/src/sub_ascent.rs -lalrpop-test/src/sub_table.rs -lalrpop-test/src/unit.rs -lalrpop-test/src/use_super.rs -lalrpop-test/src/no_clone_tok.rs -lalrpop-test/src/partial_parse.rs -lalrpop-test/src/match_alternatives.rs -lalrpop-test/src/match_section.rs -lalrpop-test/src/expr_module_attributes.rs -lalrpop-test/src/associated_types.rs -lalrpop-test/src/where_clause_with_forall.rs diff --git a/doc/calculator/src/main.rs b/doc/calculator/src/main.rs index 4a79b5e..cafdbc3 100644 --- a/doc/calculator/src/main.rs +++ b/doc/calculator/src/main.rs @@ -1,6 +1,6 @@ -extern crate lalrpop_util; +#[macro_use] extern crate lalrpop_util; -pub mod calculator1; // synthesized by LALRPOP +lalrpop_mod!(pub calculator1); // syntesized by LALRPOP #[test] fn calculator1() { @@ -10,7 +10,7 @@ fn calculator1() { assert!(calculator1::TermParser::new().parse("((22)").is_err()); } -pub mod calculator2; +lalrpop_mod!(pub calculator2); #[test] fn calculator2() { @@ -20,7 +20,7 @@ fn calculator2() { assert!(calculator2::TermParser::new().parse("((22)").is_err()); } -pub mod calculator2b; +lalrpop_mod!(pub calculator2b); #[test] fn calculator2b() { @@ -37,7 +37,7 @@ fn calculator2b() { assert_eq!(result, "222"); } -pub mod calculator3; +lalrpop_mod!(pub calculator3); #[cfg_attr(not(test), allow(unused_macros))] macro_rules! test3 { @@ -56,7 +56,7 @@ fn calculator3() { test3!(22 * (44 + 66) / 3); } -pub mod calculator4; +lalrpop_mod!(pub calculator4); pub mod ast; #[test] @@ -67,7 +67,7 @@ fn calculator4() { assert_eq!(&format!("{:?}", expr), "((22 * 44) + 66)"); } -pub mod calculator5; +lalrpop_mod!(pub calculator5); #[test] fn calculator5() { @@ -95,7 +95,7 @@ fn calculator5() { assert_eq!(&format!("{:?}", expr), "[((22 * 44) + 66), (13 * 3)]"); } -pub mod calculator6; +lalrpop_mod!(pub calculator6); #[test] fn calculator6() { diff --git a/doc/pascal/lalrpop/build.rs b/doc/pascal/lalrpop/build.rs index cb856e3..39efd67 100644 --- a/doc/pascal/lalrpop/build.rs +++ b/doc/pascal/lalrpop/build.rs @@ -3,7 +3,6 @@ extern crate lalrpop; fn main() { lalrpop::Configuration::new() .emit_comments(true) - .use_cargo_dir_conventions() .process_current_dir() .unwrap(); } diff --git a/doc/pascal/lalrpop/src/main.rs b/doc/pascal/lalrpop/src/main.rs index 4e28f9e..cbc41de 100644 --- a/doc/pascal/lalrpop/src/main.rs +++ b/doc/pascal/lalrpop/src/main.rs @@ -2,6 +2,7 @@ extern crate docopt; #[macro_use] extern crate serde_derive; extern crate serde; +#[macro_use] extern crate lalrpop_util; use docopt::Docopt; use std::env; @@ -9,7 +10,7 @@ use std::io::Read; use std::fs::File; use std::time::Instant; -mod pascal; +lalrpop_mod!(pascal); fn main() { let args: Args = Docopt::new(USAGE) diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 5b12bac..7cf2ac8 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -14,6 +14,6 @@ - [Error recovery](tutorial/008_error_recovery.md) - [Writing a custom lexer](lexer_tutorial/index.md) - [Advanced setup](advanced_setup.md) - - [Using the Cargo `OUT_DIR`](out_dir.md) + - [Generate in source tree](generate_in_source.md) ----------- [Contributors](misc/contributors.md) diff --git a/doc/src/generate_in_source.md b/doc/src/generate_in_source.md new file mode 100644 index 0000000..adde21b --- /dev/null +++ b/doc/src/generate_in_source.md @@ -0,0 +1,19 @@ +Up to version 0.15, LALRPOP was generating its files in the same directory +of the input files. Since 0.16, files are generated in the Cargo's +**output directory**. + +If you want to keep the previous behaviour, you can use `generate_in_source_tree` +in your configuration: + +```rust +extern crate lalrpop; + +fn main() { + lalrpop::Configuration::new() + .generate_in_source_tree() + .process(); +} +``` + +For each `foo.lalrpop` file you can simply have `mod foo;` in your source tree. +The `lalrpop_mod` macro is not useful in this mode. diff --git a/doc/src/out_dir.md b/doc/src/out_dir.md deleted file mode 100644 index 60a0834..0000000 --- a/doc/src/out_dir.md +++ /dev/null @@ -1,24 +0,0 @@ -One common request is to have LALRPOP generate its files into Cargo's -**output directory**, rather than storing them 'in-place' within the -module tree. This can be done through the following configuration: - -```rust -extern crate lalrpop; - -fn main() { - lalrpop::Configuration::new() - .use_cargo_dir_conventions() - .process(); -} -``` - -In addition, because the modules are generated out of the `src` -directory, for each `foo.lalrpop` file you can't simply have `mod -foo;` in your source. Instead, you must put the following in the -parent module: - -```rust -include!(concat!(env!("OUT_DIR"), "/path/to/foo.rs")); -``` - -Here the `path/to/foo.rs` should be relative to the `src` directory. diff --git a/doc/src/tutorial/002_paren_numbers.md b/doc/src/tutorial/002_paren_numbers.md index ed88937..394bfc5 100644 --- a/doc/src/tutorial/002_paren_numbers.md +++ b/doc/src/tutorial/002_paren_numbers.md @@ -101,7 +101,9 @@ our [`main.rs`][main] file which uses this struct to test our `Term` nonterminal: ```rust -pub mod calculator1; // synthesized by LALRPOP +#[macro_use] extern crate lalrpop_util; + +lalrpop_mod!(pub calculator1); // synthesized by LALRPOP #[test] fn calculator1() { diff --git a/doc/src/tutorial/007_macros.md b/doc/src/tutorial/007_macros.md index 72e0102..ee28548 100644 --- a/doc/src/tutorial/007_macros.md +++ b/doc/src/tutorial/007_macros.md @@ -103,7 +103,9 @@ FactorOp: Opcode = { And, of course, we have to add some tests to [main.rs file][main]: ```rust -pub mod calculator5; +#[macro_use] extern crate lalrpop_util; + +lalrpop_mod!(pub calculator5); #[test] fn calculator5() { diff --git a/doc/whitespace/src/lib.rs b/doc/whitespace/src/lib.rs index e767aec..f7c78e3 100644 --- a/doc/whitespace/src/lib.rs +++ b/doc/whitespace/src/lib.rs @@ -1,8 +1,11 @@ +#[macro_use] extern crate lalrpop_util; + pub mod lexer; -pub mod parser; pub mod ast; pub mod eval; +lalrpop_mod!(pub parser); + pub fn compile(input: &str) -> Result { match parser::ProgramParser::new().parse(lexer::Lexer::new(input)) { Ok(s) => Ok(ast::Program::new(s)), diff --git a/lalrpop-test/src/expr_module_attributes.lalrpop b/lalrpop-test/src/expr_module_attributes.lalrpop index 94fd3c5..bdecb0f 100644 --- a/lalrpop-test/src/expr_module_attributes.lalrpop +++ b/lalrpop-test/src/expr_module_attributes.lalrpop @@ -1,4 +1,3 @@ -#![cfg_attr(feature = "cargo-clippy", allow(clippy))] grammar(scale: i32); use util::tok::Tok; diff --git a/lalrpop-test/src/lib.rs b/lalrpop-test/src/lib.rs index 81c165a..2763fd3 100644 --- a/lalrpop-test/src/lib.rs +++ b/lalrpop-test/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(test), allow(dead_code, unused_imports))] extern crate diff; -extern crate lalrpop_util; +#[macro_use] extern crate lalrpop_util; use std::cell::RefCell; @@ -11,105 +11,105 @@ use util::tok::Tok; /// Tests that actions can return the grammar's type parameters' associated /// types. -mod associated_types; +lalrpop_mod!(associated_types); mod associated_types_lib; /// demonstration from the Greene text; one of the simplest grammars /// that still ensures we get parse tree correct -mod sub; +lalrpop_mod!(sub); /// test something other than test-all -mod sub_ascent; -mod sub_table; +lalrpop_mod!(sub_ascent); +lalrpop_mod!(sub_table); /// more interesting demonstration of parsing full expressions -mod expr; +lalrpop_mod!(expr); /// more interesting demonstration of parsing full expressions, using LALR not LR -mod expr_lalr; +lalrpop_mod!(expr_lalr); /// more interesting demonstration of parsing full expressions, using intern tok -mod expr_intern_tok; +lalrpop_mod!(expr_intern_tok); /// tests #![attributes] for generated module #[allow(dead_code, unknown_lints)] -mod expr_module_attributes; +lalrpop_mod!(expr_module_attributes); /// test that passes in lifetime/type/formal parameters and threads /// them through, building an AST from the result -mod expr_arena; +lalrpop_mod!(expr_arena); /// definitions of the AST mod expr_arena_ast; /// expr defined with a generic type `F` -mod expr_generic; +lalrpop_mod!(expr_generic); -mod generics_issue_104; +lalrpop_mod!(generics_issue_104); mod generics_issue_104_lib; /// Grammar parameterized by `F` with where clause `where F: for<'a> FnMut(&'a /// str)`. -mod where_clause_with_forall; +lalrpop_mod!(where_clause_with_forall); /// test of inlining -mod inline; +lalrpop_mod!(inline); /// test that exercises internal token generation, as well as locations and spans -mod intern_tok; +lalrpop_mod!(intern_tok); /// test that exercises using a lifetime parameter in the token type -mod lifetime_tok; +lalrpop_mod!(lifetime_tok); /// library for lifetime_tok test mod lifetime_tok_lib; /// test that exercises locations and spans -mod loc; +lalrpop_mod!(loc); /// regression test for location issue #90 -mod loc_issue_90; +lalrpop_mod!(loc_issue_90); mod loc_issue_90_lib; /// test that uses `super` in paths in various places -mod use_super; +lalrpop_mod!(use_super); /// Custom error type (issue #113) #[derive(Debug, PartialEq)] pub struct MyCustomError(char); /// test that exercises locations, spans, and custom errors -mod error; -mod error_issue_113; +lalrpop_mod!(error); +lalrpop_mod!(error_issue_113); /// Test error recovery -mod error_recovery; -mod error_recovery_pull_182; -mod error_recovery_issue_240; -mod error_recovery_lalr_loop; -mod error_recovery_lock_in; -mod error_recovery_span; -mod error_recovery_type_in_macro; +lalrpop_mod!(error_recovery); +lalrpop_mod!(error_recovery_pull_182); +lalrpop_mod!(error_recovery_issue_240); +lalrpop_mod!(error_recovery_lalr_loop); +lalrpop_mod!(error_recovery_lock_in); +lalrpop_mod!(error_recovery_span); +lalrpop_mod!(error_recovery_type_in_macro); /// test for inlining expansion issue #55 -mod issue_55; +lalrpop_mod!(issue_55); /// test for unit action code -mod unit; +lalrpop_mod!(unit); /// test for match section -mod match_section; -mod match_alternatives; +lalrpop_mod!(match_section); +lalrpop_mod!(match_alternatives); /// regression test for issue #253. -mod partial_parse; +lalrpop_mod!(partial_parse); /// regression test for issue #278. -mod error_issue_278; +lalrpop_mod!(error_issue_278); // Check that error recovery (which requires cloneable tokens) is not created if it is not used #[allow(unused)] -mod no_clone_tok; +lalrpop_mod!(no_clone_tok); mod util; diff --git a/lalrpop-util/src/lib.rs b/lalrpop-util/src/lib.rs index db17d5b..6ccc01b 100644 --- a/lalrpop-util/src/lib.rs +++ b/lalrpop-util/src/lib.rs @@ -143,6 +143,35 @@ pub struct ErrorRecovery { pub dropped_tokens: Vec<(L, T, L)>, } +/// Define a module using the generated parse from a `.lalrpop` file. +/// +/// You have to specify the name of the module and the path of the file +/// generated by LALRPOP. If the input is in the root directory, you can +/// omit it. +/// +/// # Example +/// ```ignore +/// // load parser in src/parser.lalrpop +/// lalrpop_mod!(parser); +/// +/// // load parser in src/lex/parser.lalrpop +/// lalrpop_mod!(parser, "/lex/parser.rs"); +/// +/// // define a public module +/// lalrpop_mod!(pub parser); +/// ``` + +#[macro_export] +macro_rules! lalrpop_mod { + ($modname:ident) => { lalrpop_mod!($modname, concat!("/", stringify!($modname), ".rs")); }; + + (pub $modname:ident) => { lalrpop_mod!(pub $modname, concat!("/", stringify!($modname), ".rs")); }; + + ($modname:ident, $source:expr) => { mod $modname { include!(concat!(env!("OUT_DIR"), $source)); } }; + + (pub $modname:ident, $source:expr) => { pub mod $modname { include!(concat!(env!("OUT_DIR"), $source)); } }; +} + #[cfg(test)] mod tests { use super::*; diff --git a/lalrpop/src/api/mod.rs b/lalrpop/src/api/mod.rs index b3c3d5b..843e6de 100644 --- a/lalrpop/src/api/mod.rs +++ b/lalrpop/src/api/mod.rs @@ -76,6 +76,20 @@ impl Configuration { self } + /// Write output files in the same directory of the input files. + /// + /// If this option is enabled, you have to load the parser as a module: + /// + /// ```no_run + /// mod parser; // synthesized from parser.lalrpop + /// ``` + /// + /// This was the default behaviour up to version 0.15. + pub fn generate_in_source_tree(&mut self) -> &mut Self { + self.set_in_dir(Path::new(".")) + .set_out_dir(Path::new(".")) + } + /// If true, always convert `.lalrpop` files into `.rs` files, even if the /// `.rs` file is newer. Default is false. pub fn force_build(&mut self, val: bool) -> &mut Configuration { @@ -149,7 +163,25 @@ impl Configuration { /// Process all `.lalrpop` files in `path`. pub fn process_dir>(&self, path: P) -> Result<(), Box> { - let session = Rc::new(self.session.clone()); + let mut session = self.session.clone(); + + // If in/out dir are empty, use cargo conventions by default. + // See https://github.com/lalrpop/lalrpop/issues/280 + if session.in_dir.is_none() { + let mut in_dir = try!(env::current_dir()); + in_dir.push("src"); + session.in_dir = Some(in_dir); + } + + if session.out_dir.is_none() { + let out_dir = match env::var_os("OUT_DIR") { + Some(var) => var, + None => return Err("missing OUT_DIR variable")?, + }; + session.out_dir = Some(PathBuf::from(out_dir)); + } + + let session = Rc::new(session); try!(build::process_dir(session, path)); Ok(()) }