Unnamed repository; edit this file 'description' to name the repository.
Add basic edition inline parser test support
Lukas Wirth 2024-07-19
parent 7a5bf92 · commit 713c47f
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs2
-rw-r--r--crates/parser/src/tests.rs26
-rw-r--r--crates/parser/src/tests/top_entries.rs2
-rw-r--r--crates/parser/test_data/generated/runner.rs13
-rw-r--r--crates/parser/test_data/parser/inline/err/gen_blocks.rast139
-rw-r--r--crates/parser/test_data/parser/inline/ok/gen_blocks.rast101
-rw-r--r--crates/parser/test_data/parser/inline/ok/gen_blocks.rs (renamed from crates/parser/test_data/parser/inline/err/gen_blocks.rs)1
-rw-r--r--xtask/src/codegen/parser_inline_tests.rs73
8 files changed, 185 insertions, 172 deletions
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index 54c874d06c..3d7d85a539 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -145,7 +145,7 @@ pub(super) fn atom_expr(
stmt_list(p);
m.complete(p, BLOCK_EXPR)
}
- // test_err gen_blocks
+ // test gen_blocks 2024
// pub fn main() {
// gen { yield ""; };
// async gen { yield ""; };
diff --git a/crates/parser/src/tests.rs b/crates/parser/src/tests.rs
index e0042fbdec..b4b6759e90 100644
--- a/crates/parser/src/tests.rs
+++ b/crates/parser/src/tests.rs
@@ -51,7 +51,7 @@ fn lex(text: &str) -> String {
fn parse_ok() {
for case in TestCase::list("parser/ok") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
- let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text, Edition::CURRENT);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
}
@@ -61,16 +61,16 @@ fn parse_ok() {
fn parse_err() {
for case in TestCase::list("parser/err") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
- let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text, Edition::CURRENT);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)
}
}
-fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) {
- let lexed = LexedStr::new(Edition::CURRENT, text);
+fn parse(entry: TopEntryPoint, text: &str, edition: Edition) -> (String, bool) {
+ let lexed = LexedStr::new(edition, text);
let input = lexed.to_input();
- let output = entry.parse(&input, Edition::CURRENT);
+ let output = entry.parse(&input, edition);
let mut buf = String::new();
let mut errors = Vec::new();
@@ -153,9 +153,19 @@ impl TestCase {
#[track_caller]
fn run_and_expect_no_errors(path: &str) {
+ run_and_expect_no_errors_with_edition(path, Edition::CURRENT)
+}
+
+#[track_caller]
+fn run_and_expect_errors(path: &str) {
+ run_and_expect_errors_with_edition(path, Edition::CURRENT)
+}
+
+#[track_caller]
+fn run_and_expect_no_errors_with_edition(path: &str, edition: Edition) {
let path = PathBuf::from(path);
let text = std::fs::read_to_string(&path).unwrap();
- let (actual, errors) = parse(TopEntryPoint::SourceFile, &text);
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &text, edition);
assert!(!errors, "errors in an OK file {}:\n{actual}", path.display());
let mut p = PathBuf::from("..");
p.push(path);
@@ -164,10 +174,10 @@ fn run_and_expect_no_errors(path: &str) {
}
#[track_caller]
-fn run_and_expect_errors(path: &str) {
+fn run_and_expect_errors_with_edition(path: &str, edition: Edition) {
let path = PathBuf::from(path);
let text = std::fs::read_to_string(&path).unwrap();
- let (actual, errors) = parse(TopEntryPoint::SourceFile, &text);
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &text, edition);
assert!(errors, "no errors in an ERR file {}:\n{actual}", path.display());
let mut p = PathBuf::from("..");
p.push(path);
diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs
index 49dd9e293b..c56bf0b644 100644
--- a/crates/parser/src/tests/top_entries.rs
+++ b/crates/parser/src/tests/top_entries.rs
@@ -307,6 +307,6 @@ fn expr() {
#[track_caller]
fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
- let (parsed, _errors) = super::parse(entry, input);
+ let (parsed, _errors) = super::parse(entry, input, crate::Edition::CURRENT);
expect.assert_eq(&parsed)
}
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index f82d1ed320..aa8210541a 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -1,5 +1,5 @@
mod ok {
- use crate::tests::run_and_expect_no_errors;
+ use crate::tests::*;
#[test]
fn anonymous_const() {
run_and_expect_no_errors("test_data/parser/inline/ok/anonymous_const.rs");
@@ -267,6 +267,13 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/function_where_clause.rs");
}
#[test]
+ fn gen_blocks() {
+ run_and_expect_no_errors_with_edition(
+ "test_data/parser/inline/ok/gen_blocks.rs",
+ crate::Edition::Edition2024,
+ );
+ }
+ #[test]
fn generic_arg() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg.rs"); }
#[test]
fn generic_param_attribute() {
@@ -666,7 +673,7 @@ mod ok {
fn yield_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/yield_expr.rs"); }
}
mod err {
- use crate::tests::run_and_expect_errors;
+ use crate::tests::*;
#[test]
fn angled_path_without_qual() {
run_and_expect_errors("test_data/parser/inline/err/angled_path_without_qual.rs");
@@ -708,8 +715,6 @@ mod err {
run_and_expect_errors("test_data/parser/inline/err/fn_pointer_type_missing_fn.rs");
}
#[test]
- fn gen_blocks() { run_and_expect_errors("test_data/parser/inline/err/gen_blocks.rs"); }
- #[test]
fn gen_fn() { run_and_expect_errors("test_data/parser/inline/err/gen_fn.rs"); }
#[test]
fn generic_arg_list_recover() {
diff --git a/crates/parser/test_data/parser/inline/err/gen_blocks.rast b/crates/parser/test_data/parser/inline/err/gen_blocks.rast
deleted file mode 100644
index 08a85891ed..0000000000
--- a/crates/parser/test_data/parser/inline/err/gen_blocks.rast
+++ /dev/null
@@ -1,139 +0,0 @@
-SOURCE_FILE
- FN
- VISIBILITY
- PUB_KW "pub"
- WHITESPACE " "
- FN_KW "fn"
- WHITESPACE " "
- NAME
- IDENT "main"
- PARAM_LIST
- L_PAREN "("
- R_PAREN ")"
- WHITESPACE " "
- BLOCK_EXPR
- STMT_LIST
- L_CURLY "{"
- WHITESPACE "\n "
- EXPR_STMT
- RECORD_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "gen"
- WHITESPACE " "
- RECORD_EXPR_FIELD_LIST
- L_CURLY "{"
- WHITESPACE " "
- ERROR
- YIELD_KW "yield"
- WHITESPACE " "
- ERROR
- STRING "\"\""
- ERROR
- SEMICOLON ";"
- WHITESPACE " "
- R_CURLY "}"
- SEMICOLON ";"
- WHITESPACE "\n "
- ERROR
- ASYNC_KW "async"
- WHITESPACE " "
- EXPR_STMT
- RECORD_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "gen"
- WHITESPACE " "
- RECORD_EXPR_FIELD_LIST
- L_CURLY "{"
- WHITESPACE " "
- ERROR
- YIELD_KW "yield"
- WHITESPACE " "
- ERROR
- STRING "\"\""
- ERROR
- SEMICOLON ";"
- WHITESPACE " "
- R_CURLY "}"
- SEMICOLON ";"
- WHITESPACE "\n "
- EXPR_STMT
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "gen"
- WHITESPACE " "
- EXPR_STMT
- CLOSURE_EXPR
- MOVE_KW "move"
- WHITESPACE " "
- EXPR_STMT
- BLOCK_EXPR
- STMT_LIST
- L_CURLY "{"
- WHITESPACE " "
- EXPR_STMT
- YIELD_EXPR
- YIELD_KW "yield"
- WHITESPACE " "
- LITERAL
- STRING "\"\""
- SEMICOLON ";"
- WHITESPACE " "
- R_CURLY "}"
- SEMICOLON ";"
- WHITESPACE "\n "
- ERROR
- ASYNC_KW "async"
- WHITESPACE " "
- EXPR_STMT
- PATH_EXPR
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "gen"
- WHITESPACE " "
- EXPR_STMT
- CLOSURE_EXPR
- MOVE_KW "move"
- WHITESPACE " "
- EXPR_STMT
- BLOCK_EXPR
- STMT_LIST
- L_CURLY "{"
- WHITESPACE " "
- EXPR_STMT
- YIELD_EXPR
- YIELD_KW "yield"
- WHITESPACE " "
- LITERAL
- STRING "\"\""
- SEMICOLON ";"
- WHITESPACE " "
- R_CURLY "}"
- SEMICOLON ";"
- WHITESPACE "\n"
- R_CURLY "}"
- WHITESPACE "\n"
-error 26: expected identifier
-error 31: expected COMMA
-error 32: expected identifier
-error 34: expected COMMA
-error 34: expected identifier
-error 48: expected fn, trait or impl
-error 55: expected identifier
-error 60: expected COMMA
-error 61: expected identifier
-error 63: expected COMMA
-error 63: expected identifier
-error 75: expected SEMICOLON
-error 80: expected `|`
-error 80: expected SEMICOLON
-error 105: expected fn, trait or impl
-error 109: expected SEMICOLON
-error 114: expected `|`
-error 114: expected SEMICOLON
diff --git a/crates/parser/test_data/parser/inline/ok/gen_blocks.rast b/crates/parser/test_data/parser/inline/ok/gen_blocks.rast
new file mode 100644
index 0000000000..6e8df9897e
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/gen_blocks.rast
@@ -0,0 +1,101 @@
+SOURCE_FILE
+ FN
+ COMMENT "// 2024"
+ WHITESPACE "\n"
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ GEN_KW "gen"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ YIELD_EXPR
+ YIELD_KW "yield"
+ WHITESPACE " "
+ LITERAL
+ STRING "\"\""
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ GEN_KW "gen"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ YIELD_EXPR
+ YIELD_KW "yield"
+ WHITESPACE " "
+ LITERAL
+ STRING "\"\""
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ GEN_KW "gen"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ YIELD_EXPR
+ YIELD_KW "yield"
+ WHITESPACE " "
+ LITERAL
+ STRING "\"\""
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ GEN_KW "gen"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ YIELD_EXPR
+ YIELD_KW "yield"
+ WHITESPACE " "
+ LITERAL
+ STRING "\"\""
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/err/gen_blocks.rs b/crates/parser/test_data/parser/inline/ok/gen_blocks.rs
index f7687331d6..669b434973 100644
--- a/crates/parser/test_data/parser/inline/err/gen_blocks.rs
+++ b/crates/parser/test_data/parser/inline/ok/gen_blocks.rs
@@ -1,3 +1,4 @@
+// 2024
pub fn main() {
gen { yield ""; };
async gen { yield ""; };
diff --git a/xtask/src/codegen/parser_inline_tests.rs b/xtask/src/codegen/parser_inline_tests.rs
index 3a9073b4e4..f9f73df8eb 100644
--- a/xtask/src/codegen/parser_inline_tests.rs
+++ b/xtask/src/codegen/parser_inline_tests.rs
@@ -34,38 +34,60 @@ pub(crate) fn generate(check: bool) {
install_tests(&tests.err, &format!("{PARSER_TEST_DATA_INLINE}/err"), check).unwrap();
if some_file_was_updated {
- let _ = fs::File::open(&format!("{PARSER_CRATE_ROOT}/src/tests.rs"))
+ let _ = fs::File::open(format!("{PARSER_CRATE_ROOT}/src/tests.rs"))
.unwrap()
.set_modified(SystemTime::now());
- let ok_tests = tests.ok.keys().sorted().map(|k| {
- let test_name = quote::format_ident!("{}", k);
+ let ok_tests = tests.ok.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
+ let test_name = quote::format_ident!("{}", test.name);
let test_file = format!("test_data/parser/inline/ok/{test_name}.rs");
+ let (test_func, args) = match &test.edition {
+ Some(edition) => {
+ let edition = quote::format_ident!("Edition{edition}");
+ (
+ quote::format_ident!("run_and_expect_no_errors_with_edition"),
+ quote::quote! {#test_file, crate::Edition::#edition},
+ )
+ }
+ None => {
+ (quote::format_ident!("run_and_expect_no_errors"), quote::quote! {#test_file})
+ }
+ };
quote::quote! {
#[test]
fn #test_name() {
- run_and_expect_no_errors(#test_file);
+ #test_func(#args);
}
}
});
- let err_tests = tests.err.keys().sorted().map(|k| {
- let test_name = quote::format_ident!("{}", k);
+ let err_tests = tests.err.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
+ let test_name = quote::format_ident!("{}", test.name);
let test_file = format!("test_data/parser/inline/err/{test_name}.rs");
+ let (test_func, args) = match &test.edition {
+ Some(edition) => {
+ let edition = quote::format_ident!("Edition{edition}");
+ (
+ quote::format_ident!("run_and_expect_errors_with_edition"),
+ quote::quote! {#test_file, crate::Edition::#edition},
+ )
+ }
+ None => (quote::format_ident!("run_and_expect_errors"), quote::quote! {#test_file}),
+ };
quote::quote! {
#[test]
fn #test_name() {
- run_and_expect_errors(#test_file);
+ #test_func(#args);
}
}
});
let output = quote::quote! {
mod ok {
- use crate::tests::run_and_expect_no_errors;
+ use crate::tests::*;
#(#ok_tests)*
}
mod err {
- use crate::tests::run_and_expect_errors;
+ use crate::tests::*;
#(#err_tests)*
}
};
@@ -107,9 +129,10 @@ fn install_tests(tests: &HashMap<String, Test>, into: &str, check: bool) -> Resu
#[derive(Debug)]
struct Test {
- pub name: String,
- pub text: String,
- pub kind: TestKind,
+ name: String,
+ text: String,
+ kind: TestKind,
+ edition: Option<String>,
}
#[derive(Copy, Clone, Debug)]
@@ -120,8 +143,8 @@ enum TestKind {
#[derive(Default, Debug)]
struct Tests {
- pub ok: HashMap<String, Test>,
- pub err: HashMap<String, Test>,
+ ok: HashMap<String, Test>,
+ err: HashMap<String, Test>,
}
fn collect_tests(s: &str) -> Vec<Test> {
@@ -135,14 +158,24 @@ fn collect_tests(s: &str) -> Vec<Test> {
} else {
continue;
};
- let text: String = comment_block.contents[1..]
- .iter()
- .cloned()
+ let (name, edition) = match *name.split(' ').collect_vec().as_slice() {
+ [name, edition] => {
+ assert!(!edition.contains(' '));
+ (name.to_owned(), Some(edition.to_owned()))
+ }
+ [name] => (name.to_owned(), None),
+ _ => panic!("invalid test name: {:?}", name),
+ };
+ let text: String = edition
+ .as_ref()
+ .map(|edition| format!("// {edition}"))
+ .into_iter()
+ .chain(comment_block.contents[1..].iter().cloned())
.chain(iter::once(String::new()))
.collect::<Vec<_>>()
.join("\n");
assert!(!text.trim().is_empty() && text.ends_with('\n'));
- res.push(Test { name, text, kind })
+ res.push(Test { name, edition, text, kind })
}
res
}
@@ -180,7 +213,9 @@ fn existing_tests(dir: &Path, ok: TestKind) -> Result<HashMap<String, (PathBuf,
if rust_file {
let name = path.file_stem().map(|x| x.to_string_lossy().to_string()).unwrap();
let text = fs::read_to_string(&path)?;
- let test = Test { name: name.clone(), text, kind: ok };
+ let edition =
+ text.lines().next().and_then(|it| it.strip_prefix("// ")).map(ToOwned::to_owned);
+ let test = Test { name: name.clone(), text, kind: ok, edition };
if let Some(old) = res.insert(name, (path, test)) {
println!("Duplicate test: {:?}", old);
}