From 7efd2fb796065ed332a4ee47d65e80f08092a25c Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sun, 4 Jun 2023 17:28:24 -0700 Subject: [PATCH] Add a code generator for making tests of the examples. --- build.rs | 79 +++++++++++++++++++++++ examples/basic/{test2.ngr => broken1.ngr} | 0 src/examples.rs | 7 ++ src/lib.rs | 2 + 4 files changed, 88 insertions(+) rename examples/basic/{test2.ngr => broken1.ngr} (100%) create mode 100644 src/examples.rs diff --git a/build.rs b/build.rs index 23c7d3f..db2b647 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,84 @@ extern crate lalrpop; +use std::env; +use std::fs::{self, File}; +use std::io::Write; +use std::path::{Path, PathBuf}; + fn main() { lalrpop::process_root().unwrap(); + if let Err(e) = generate_example_tests() { + eprintln!("Failure building example tests: {}", e); + std::process::exit(3); + } +} + +fn generate_example_tests() -> std::io::Result<()> { + let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR"); + let dest_path = Path::new(&out_dir).join("examples.rs"); + let mut output = File::create(dest_path)?; + + generate_tests(&mut output, PathBuf::from("examples"))?; + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=example.rs"); + Ok(()) +} + +fn generate_tests(f: &mut File, path_so_far: PathBuf) -> std::io::Result<()> { + for entry in fs::read_dir(path_so_far)? { + let entry = entry?; + let file_name = entry + .file_name() + .into_string() + .expect("reasonable file name"); + let name = file_name.trim_end_matches(".ngr"); + + if entry.file_type()?.is_dir() { + writeln!(f, "mod {} {{", name)?; + writeln!(f, " use super::*;")?; + generate_tests(f, entry.path())?; + writeln!(f, "}}")?; + } else { + writeln!(f, "#[test]")?; + writeln!(f, "fn {}() {{", name)?; + writeln!(f, " let mut file_database = SimpleFiles::new();")?; + writeln!( + f, + " let syntax = Syntax::parse_file(&mut file_database, {:?});", + entry.path().display() + )?; + if entry.path().to_string_lossy().contains("broken") { + writeln!(f, " if syntax.is_err() {{")?; + writeln!(f, " return;")?; + writeln!(f, " }}")?; + writeln!(f, " let (errors, _) = syntax.unwrap().validate();")?; + writeln!( + f, + " assert_ne!(errors.len(), 0, \"should have seen an error\");" + )?; + } else { + writeln!( + f, + " let syntax = syntax.expect(\"file should have parsed\");" + )?; + writeln!(f, " let (errors, _) = syntax.validate();")?; + writeln!( + f, + " assert_eq!(errors.len(), 0, \"file should have no validation errors\");" + )?; + writeln!(f, " let syntax_result = syntax.eval();")?; + writeln!(f, " let ir = IR::from(syntax);")?; + writeln!( + f, + " assert_eq!(syntax_result, ir.eval(), \"syntax equivalent to IR\");" + )?; + writeln!(f, " let compiled_result = Backend::::eval(ir);")?; + writeln!(f, " assert_eq!(syntax_result, compiled_result);")?; + } + writeln!(f, "}}")?; + } + } + + Ok(()) } diff --git a/examples/basic/test2.ngr b/examples/basic/broken1.ngr similarity index 100% rename from examples/basic/test2.ngr rename to examples/basic/broken1.ngr diff --git a/src/examples.rs b/src/examples.rs new file mode 100644 index 0000000..47b0bdc --- /dev/null +++ b/src/examples.rs @@ -0,0 +1,7 @@ +use codespan_reporting::files::SimpleFiles; +use crate::backend::Backend; +use crate::ir::Program as IR; +use crate::syntax::Program as Syntax; +use cranelift_jit::JITModule; + +include!(concat!(env!("OUT_DIR"), "/examples.rs")); \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 18ade12..3906811 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,8 @@ //! pub mod backend; pub mod eval; +#[cfg(test)] +mod examples; pub mod ir; pub mod syntax;