Work on auto CST parser tests.
This commit is contained in:
parent
41693788fc
commit
024baf2064
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -169,6 +169,17 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cst-test-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deimos"
|
||||
version = "0.1.0"
|
||||
@ -176,6 +187,7 @@ dependencies = [
|
||||
"ast-generator",
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"cst-test-generator",
|
||||
"indoc",
|
||||
"log",
|
||||
"pest",
|
||||
|
||||
@ -21,7 +21,8 @@ indoc = "2.0.6"
|
||||
|
||||
[build-dependencies]
|
||||
ast-generator = { path = "ast-generator" }
|
||||
cst-test-generator = { path = "cst-test-generator" }
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["ast-generator"]
|
||||
members = ["ast-generator", "cst-test-generator"]
|
||||
|
||||
19
build.rs
19
build.rs
@ -1,9 +1,18 @@
|
||||
use cst_test_generator::generate_test_files;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
println!("cargo:rerun-if-changed=src/parser/deimos.pest");
|
||||
// let out_dir = env::var("OUT_DIR").unwrap();
|
||||
// let out_dir_path = Path::new(&out_dir);
|
||||
// let testing_txt_path = out_dir_path.join("testing.rs");
|
||||
// let output = test_dump();
|
||||
// write(&testing_txt_path, output)?;
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let out_dir_path = Path::new(&out_dir);
|
||||
let parser_tests_dir = out_dir_path.join("src").join("parser").join("tests");
|
||||
fs::create_dir_all(&parser_tests_dir)?;
|
||||
let files = generate_test_files(Path::new("src/parser/tests"))?;
|
||||
for parser_test_file in &files {
|
||||
let file_path = parser_tests_dir.join(&parser_test_file.file_name);
|
||||
fs::write(file_path, &parser_test_file.contents)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
11
cst-test-generator/Cargo.toml
Normal file
11
cst-test-generator/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "cst-test-generator"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
convert_case = "0.8.0"
|
||||
prettyplease = "0.2.37"
|
||||
proc-macro2 = "1.0.101"
|
||||
quote = "1.0.40"
|
||||
syn = "2.0.106"
|
||||
115
cst-test-generator/src/lib.rs
Normal file
115
cst-test-generator/src/lib.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use convert_case::{Case, Casing};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use std::path::Path;
|
||||
use std::{fs, io};
|
||||
use syn::File;
|
||||
|
||||
pub struct ParserTestFile {
|
||||
pub file_name: String,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
pub fn generate_test_files(tests_dir: &Path) -> io::Result<Vec<ParserTestFile>> {
|
||||
let mut files: Vec<ParserTestFile> = vec![];
|
||||
let mut test_module_names: Vec<String> = vec![];
|
||||
|
||||
// generate test file for each sub dir
|
||||
for sub_dir in fs::read_dir(tests_dir)? {
|
||||
let sub_dir = sub_dir?;
|
||||
let sub_dir_path = sub_dir.path();
|
||||
if sub_dir_path.is_dir() {
|
||||
let sub_dir_file_name = sub_dir.file_name();
|
||||
let sub_dir_string = sub_dir_file_name.to_string_lossy();
|
||||
test_module_names.push(sub_dir_string.to_string());
|
||||
|
||||
let sub_dir_pascal = sub_dir_string.to_case(Case::Pascal);
|
||||
let rule_ident = format_ident!("{}", sub_dir_pascal);
|
||||
|
||||
let mut tests: Vec<TokenStream> = vec![];
|
||||
for test_file in fs::read_dir(sub_dir_path)? {
|
||||
let test_file = test_file?;
|
||||
let test_file_name = test_file.file_name();
|
||||
let test_ident = format_ident!("{}", test_file_name.to_string_lossy());
|
||||
|
||||
let src_input = fs::read_to_string(test_file.path())?;
|
||||
|
||||
let test = quote! {
|
||||
#[test]
|
||||
fn #test_ident() {
|
||||
parses_to(Rule::#rule_ident, #src_input)
|
||||
}
|
||||
};
|
||||
|
||||
tests.push(test);
|
||||
}
|
||||
|
||||
let tests_mod_ident = format_ident!("{}_tests", sub_dir.file_name().to_string_lossy());
|
||||
let test_file_contents = quote! {
|
||||
#[cfg(test)]
|
||||
mod #tests_mod_ident {
|
||||
use crate::parser::Rule;
|
||||
use crate::parser::tests::parses_to;
|
||||
|
||||
#(#tests)*
|
||||
}
|
||||
};
|
||||
let parsed: File = syn::parse2(test_file_contents).unwrap();
|
||||
let contents = prettyplease::unparse(&parsed);
|
||||
|
||||
let file_name = sub_dir.file_name().to_string_lossy().to_string() + ".rs";
|
||||
files.push(ParserTestFile {
|
||||
file_name,
|
||||
contents,
|
||||
})
|
||||
} else {
|
||||
println!("Warning: not a directory: {:?}", sub_dir_path);
|
||||
}
|
||||
}
|
||||
|
||||
let test_mod_statements = test_module_names
|
||||
.iter()
|
||||
.map(|name| format_ident!("{}", name))
|
||||
.map(|module_ident| quote! { mod #module_ident; })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// generate main mod.rs file
|
||||
let main_mod = quote! {
|
||||
use crate::parser::DeimosParser;
|
||||
use crate::parser::Rule;
|
||||
use pest_derive::Parser;
|
||||
|
||||
#(#test_mod_statements)*
|
||||
|
||||
pub(crate) fn parses_to(rule: Rule, input: &str) {
|
||||
let parse_result = DeimosParser::parse(rule, input);
|
||||
if let Err(e) = parse_result {
|
||||
panic!("Parsing failed.\n{}", e);
|
||||
} else {
|
||||
let mut pairs = parse_result.unwrap();
|
||||
if input.trim() != pairs.as_str().trim() {
|
||||
panic!(
|
||||
"Parsing did not consume entire input. Consumed only:\n{}",
|
||||
pairs.as_str().trim()
|
||||
);
|
||||
}
|
||||
let first = pairs.next().unwrap();
|
||||
if rule != pair.as_rule() {
|
||||
panic!(
|
||||
"Expected {} but found {:?}.",
|
||||
stringify!(rule),
|
||||
pair.as_rule()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let mod_file_parsed: File = syn::parse2(main_mod).unwrap();
|
||||
let mod_file_contents = prettyplease::unparse(&mod_file_parsed);
|
||||
files.push(ParserTestFile {
|
||||
file_name: String::from("mod.rs"),
|
||||
contents: mod_file_contents,
|
||||
});
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
@ -107,46 +107,46 @@ mod deimos_parser_tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_statement() {
|
||||
parses_to(
|
||||
Rule::IfElseStatement,
|
||||
indoc! {"
|
||||
if (foo == 42) {
|
||||
bar()
|
||||
} else {
|
||||
baz()
|
||||
}"},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_if_statement() {
|
||||
parses_to(
|
||||
Rule::IfElseStatement,
|
||||
indoc! {"
|
||||
if (foo == 42) {
|
||||
bar()
|
||||
} else if (foo == 16) {
|
||||
baz()
|
||||
}"},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_if_else_statement() {
|
||||
parses_to(
|
||||
Rule::IfElseStatement,
|
||||
indoc! {"
|
||||
if (foo == 42) {
|
||||
foo()
|
||||
} else if (foo == 16) {
|
||||
baz()
|
||||
} else {
|
||||
fizz()
|
||||
}"},
|
||||
)
|
||||
}
|
||||
// #[test]
|
||||
// fn if_else_statement() {
|
||||
// parses_to(
|
||||
// Rule::IfElseStatement,
|
||||
// indoc! {"
|
||||
// if (foo == 42) {
|
||||
// bar()
|
||||
// } else {
|
||||
// baz()
|
||||
// }"},
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn if_else_if_statement() {
|
||||
// parses_to(
|
||||
// Rule::IfElseStatement,
|
||||
// indoc! {"
|
||||
// if (foo == 42) {
|
||||
// bar()
|
||||
// } else if (foo == 16) {
|
||||
// baz()
|
||||
// }"},
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn if_else_if_else_statement() {
|
||||
// parses_to(
|
||||
// Rule::IfElseStatement,
|
||||
// indoc! {"
|
||||
// if (foo == 42) {
|
||||
// foo()
|
||||
// } else if (foo == 16) {
|
||||
// baz()
|
||||
// } else {
|
||||
// fizz()
|
||||
// }"},
|
||||
// )
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn while_statement() {
|
||||
|
||||
1
src/parser/tests/backtick_string/empty
Normal file
1
src/parser/tests/backtick_string/empty
Normal file
@ -0,0 +1 @@
|
||||
``
|
||||
1
src/parser/tests/backtick_string/expressions
Normal file
1
src/parser/tests/backtick_string/expressions
Normal file
@ -0,0 +1 @@
|
||||
`${greeting}, ${world}!`
|
||||
1
src/parser/tests/backtick_string/no_expressions
Normal file
1
src/parser/tests/backtick_string/no_expressions
Normal file
@ -0,0 +1 @@
|
||||
`Hello, World!`
|
||||
Loading…
Reference in New Issue
Block a user