diff options
Diffstat (limited to 'dhall/build.rs')
-rw-r--r-- | dhall/build.rs | 344 |
1 files changed, 1 insertions, 343 deletions
diff --git a/dhall/build.rs b/dhall/build.rs index 660d76a..4fc8545 100644 --- a/dhall/build.rs +++ b/dhall/build.rs @@ -1,351 +1,10 @@ use std::env; -use std::ffi::OsString; use std::fs::{read_to_string, File}; use std::io::{BufRead, BufReader, Write}; -use std::path::{Path, PathBuf}; -use std::rc::Rc; -use walkdir::WalkDir; +use std::path::Path; use abnf_to_pest::render_rules_to_pest; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum FileType { - /// Dhall source file - Text, - /// Dhall binary file - Binary, - /// Text file with hash - Hash, - /// Text file with expected text output - UI, -} - -impl FileType { - fn to_ext(self) -> &'static str { - match self { - FileType::Text => "dhall", - FileType::Binary => "dhallb", - FileType::Hash => "hash", - FileType::UI => "txt", - } - } - fn constructor(self) -> &'static str { - match self { - FileType::Text => "TestFile::Source", - FileType::Binary => "TestFile::Binary", - FileType::Hash => "TestFile::Binary", - FileType::UI => "TestFile::UI", - } - } - fn construct(self, path: &str) -> String { - // e.g. with - // path = "tests/foor/barA" - // returns something like: - // TestFile::Source("tests/foor/barA.dhall") - format!(r#"{}("{}.{}")"#, self.constructor(), path, self.to_ext()) - } -} - -fn dhall_files_in_dir<'a>( - dir: &'a Path, - take_ab_suffix: bool, - filetype: FileType, -) -> impl Iterator<Item = (String, String)> + 'a { - WalkDir::new(dir) - .into_iter() - .filter_map(|e| e.ok()) - .filter_map(move |path| { - let path = path.path().strip_prefix(dir).unwrap(); - let ext = path.extension()?; - if *ext != OsString::from(filetype.to_ext()) { - return None; - } - let path = path.to_string_lossy(); - let path = &path[..path.len() - 1 - ext.len()]; - let path = if take_ab_suffix && &path[path.len() - 1..] != "A" { - return None; - } else if take_ab_suffix { - path[..path.len() - 1].to_owned() - } else { - path.to_owned() - }; - // Transform path into a valid Rust identifier - let name = path.replace("/", "_").replace("-", "_"); - Some((name, path)) - }) -} - -#[derive(Clone)] -struct TestFeature { - /// Name of the module, used in the output of `cargo test` - module_name: &'static str, - /// Directory containing the tests files, relative to the base tests directory - directory: &'static str, - /// Relevant variant of `dhall::tests::Test` - variant: &'static str, - /// Given a file name, whether to only include it in release tests - too_slow_path: Rc<dyn Fn(&str) -> bool>, - /// Given a file name, whether to exclude it - exclude_path: Rc<dyn Fn(&str) -> bool>, - /// Type of the input file - input_type: FileType, - /// Type of the output file, if any - output_type: Option<FileType>, -} - -fn make_test_module( - w: &mut impl Write, // Where to output the generated code - base_paths: &[&Path], - feature: TestFeature, -) -> std::io::Result<()> { - writeln!(w, "mod {} {{", feature.module_name)?; - let take_ab_suffix = feature.output_type.is_some() - && (feature.output_type != Some(FileType::UI) - || feature.module_name == "printer"); - let input_suffix = if take_ab_suffix { "A" } else { "" }; - let output_suffix = if take_ab_suffix { "B" } else { "" }; - - for base_path in base_paths { - let tests_dir = base_path.join(feature.directory); - for (name, path) in - dhall_files_in_dir(&tests_dir, take_ab_suffix, feature.input_type) - { - if (feature.exclude_path)(&path) { - continue; - } - if (feature.too_slow_path)(&path) { - writeln!(w, "#[cfg(not(debug_assertions))]")?; - } - let path = tests_dir.join(path); - let path = path.to_string_lossy(); - - let input = feature - .input_type - .construct(&format!("{}{}", path, input_suffix)); - let output = match feature.output_type { - None => None, - Some(output_type @ FileType::UI) => { - // All ui outputs are in the local `tests/` directory. - let path = PathBuf::from("tests/").join( - PathBuf::from(path.as_ref()) - .strip_prefix(base_path) - .unwrap(), - ); - let path = path.to_str().unwrap(); - let output = output_type - .construct(&format!("{}{}", path, output_suffix)); - Some(output) - } - Some(output_type) => { - let output = output_type - .construct(&format!("{}{}", path, output_suffix)); - Some(output) - } - }; - - let test = match output { - None => format!("{}({})", feature.variant, input), - Some(output) => { - format!("{}({}, {})", feature.variant, input, output) - } - }; - writeln!(w, "make_spec_test!({}, {});", test, name)?; - } - } - writeln!(w, "}}")?; - Ok(()) -} - -fn generate_tests() -> std::io::Result<()> { - // To force regeneration of the test list, `touch dhall/build.rs` - let out_dir = env::var("OUT_DIR").unwrap(); - - let parser_tests_path = Path::new(&out_dir).join("spec_tests.rs"); - let spec_tests_dirs = - vec![Path::new("../dhall-lang/tests/"), Path::new("tests/")]; - - let default_feature = TestFeature { - module_name: "", - directory: "", - variant: "", - too_slow_path: Rc::new(|_path: &str| false), - exclude_path: Rc::new(|_path: &str| false), - input_type: FileType::Text, - output_type: None, - }; - - #[allow(clippy::nonminimal_bool)] - let tests = vec![ - TestFeature { - module_name: "parser_success", - directory: "parser/success/", - variant: "ParserSuccess", - too_slow_path: Rc::new(|path: &str| path == "largeExpression"), - exclude_path: Rc::new(|path: &str| { - false - // Pretty sure the test is incorrect - || path == "unit/import/urls/quotedPathFakeUrlEncode" - }), - output_type: Some(FileType::Binary), - ..default_feature - }, - TestFeature { - module_name: "parser_failure", - directory: "parser/failure/", - variant: "ParserFailure", - output_type: Some(FileType::UI), - ..default_feature.clone() - }, - TestFeature { - module_name: "printer", - directory: "parser/success/", - variant: "Printer", - too_slow_path: Rc::new(|path: &str| path == "largeExpression"), - output_type: Some(FileType::UI), - ..default_feature.clone() - }, - TestFeature { - module_name: "binary_encoding", - directory: "parser/success/", - variant: "BinaryEncoding", - too_slow_path: Rc::new(|path: &str| path == "largeExpression"), - exclude_path: Rc::new(|path: &str| { - false - // Pretty sure the test is incorrect - || path == "unit/import/urls/quotedPathFakeUrlEncode" - // See https://github.com/pyfisch/cbor/issues/109 - || path == "double" - || path == "unit/DoubleLitExponentNoDot" - || path == "unit/DoubleLitSecretelyInt" - }), - output_type: Some(FileType::Binary), - ..default_feature - }, - TestFeature { - module_name: "binary_decoding_success", - directory: "binary-decode/success/", - variant: "BinaryDecodingSuccess", - exclude_path: Rc::new(|path: &str| { - false - // We don't support bignums - || path == "unit/IntegerBigNegative" - || path == "unit/IntegerBigPositive" - || path == "unit/NaturalBig" - }), - input_type: FileType::Binary, - output_type: Some(FileType::Text), - ..default_feature.clone() - }, - TestFeature { - module_name: "binary_decoding_failure", - directory: "binary-decode/failure/", - variant: "BinaryDecodingFailure", - input_type: FileType::Binary, - output_type: Some(FileType::UI), - ..default_feature.clone() - }, - TestFeature { - module_name: "import_success", - directory: "import/success/", - variant: "ImportSuccess", - exclude_path: Rc::new(|path: &str| { - false - // TODO: the standard does not respect https://tools.ietf.org/html/rfc3986#section-5.2 - || path == "unit/asLocation/RemoteCanonicalize4" - // TODO: import headers - || path == "customHeaders" - || path == "headerForwarding" - || path == "noHeaderForwarding" - }), - output_type: Some(FileType::Text), - ..default_feature.clone() - }, - TestFeature { - module_name: "import_failure", - directory: "import/failure/", - variant: "ImportFailure", - exclude_path: Rc::new(|path: &str| { - false - // TODO: import headers - || path == "customHeadersUsingBoundVariable" - }), - output_type: Some(FileType::UI), - ..default_feature.clone() - }, - TestFeature { - module_name: "semantic_hash", - directory: "semantic-hash/success/", - variant: "SemanticHash", - exclude_path: Rc::new(|path: &str| { - false - // We don't support bignums - || path == "simple/integerToDouble" - // See https://github.com/pyfisch/cbor/issues/109 - || path == "prelude/Integer/toDouble/0" - || path == "prelude/Integer/toDouble/1" - || path == "prelude/Natural/toDouble/0" - }), - output_type: Some(FileType::Hash), - ..default_feature.clone() - }, - TestFeature { - module_name: "beta_normalize", - directory: "normalization/success/", - variant: "Normalization", - too_slow_path: Rc::new(|path: &str| path == "remoteSystems"), - exclude_path: Rc::new(|path: &str| { - false - // Cannot typecheck - || path == "unit/Sort" - // We don't support bignums - || path == "simple/integerToDouble" - // TODO: fix Double/show - || path == "prelude/JSON/number/1" - }), - output_type: Some(FileType::Text), - ..default_feature - }, - TestFeature { - module_name: "alpha_normalize", - directory: "alpha-normalization/success/", - variant: "AlphaNormalization", - exclude_path: Rc::new(|path: &str| { - // This test is designed to not typecheck - path == "unit/FunctionNestedBindingXXFree" - }), - output_type: Some(FileType::Text), - ..default_feature.clone() - }, - TestFeature { - module_name: "type_inference_success", - directory: "type-inference/success/", - variant: "TypeInferenceSuccess", - too_slow_path: Rc::new(|path: &str| path == "prelude"), - output_type: Some(FileType::Text), - ..default_feature.clone() - }, - TestFeature { - module_name: "type_inference_failure", - directory: "type-inference/failure/", - variant: "TypeInferenceFailure", - exclude_path: Rc::new(|path: &str| { - false - // TODO: enable free variable checking - || path == "unit/MergeHandlerFreeVar" - }), - output_type: Some(FileType::UI), - ..default_feature - }, - ]; - - let mut file = File::create(parser_tests_path)?; - for test in tests { - make_test_module(&mut file, &spec_tests_dirs, test)?; - } - - Ok(()) -} - fn convert_abnf_to_pest() -> std::io::Result<()> { let out_dir = env::var("OUT_DIR").unwrap(); let abnf_path = "src/syntax/text/dhall.abnf"; @@ -476,6 +135,5 @@ fn generate_pest_parser() -> std::io::Result<()> { fn main() -> std::io::Result<()> { convert_abnf_to_pest()?; generate_pest_parser()?; - generate_tests()?; Ok(()) } |