From 51bfbdf7ae24d749daa84c10e1ef3d0db51caffb Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Wed, 25 Dec 2024 21:17:03 +0100 Subject: [PATCH] tests are now autogenerated from the readme, this makes test names DRY I want to reduce friction of adding new tests as much as possible Signed-off-by: Jakub Doka --- .gitignore | 1 + lang/README.md | 46 +++---- lang/build.rs | 35 ++++++ lang/src/lib.rs | 33 +----- lang/src/son.rs | 112 +----------------- .../son_tests_generic_function_in_struct.txt | 0 6 files changed, 69 insertions(+), 158 deletions(-) create mode 100644 lang/build.rs create mode 100644 lang/tests/son_tests_generic_function_in_struct.txt diff --git a/.gitignore b/.gitignore index 0fa01081..84b44e1a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ db.sqlite-journal /depell/src/static-pages/*.html #**/*-sv.rs /bytecode/src/instrs.rs +/lang/src/testcases.rs diff --git a/lang/README.md b/lang/README.md index 8a46cd3f..09122ac5 100644 --- a/lang/README.md +++ b/lang/README.md @@ -736,28 +736,6 @@ main := fn(): uint { ### Incomplete Examples -#### string_array -```hb - -main := fn(): uint { - strings := (^u8).["abcdefshijklmnop\0".ptr, "abcdefghijklnnop\0".ptr, "abcdefshijklmnop\0".ptr, "abcdefghijklmnop\0".ptr, "abcdefghijflmnop\0".ptr, "dbcdefghijklmnop\0".ptr, "abcdefghijklmnop\0".ptr] - return *strings[0] -} -``` - -#### comptime_pointers -```hb -main := fn(): uint { - $integer := 7 - modify(&integer) - return integer -} - -modify := fn($num: ^uint): void { - $: *num = 0 -} -``` - #### fb_driver ```hb arm_fb_ptr := fn(): uint return 100 @@ -798,6 +776,30 @@ main := fn(): uint { ### Purely Testing Examples +#### string_array +```hb + +main := fn(): uint { + strings := (^u8).["abcdefshijklmnop\0".ptr, "abcdefghijklnnop\0".ptr, "abcdefshijklmnop\0".ptr, "abcdefghijklmnop\0".ptr, "abcdefghijflmnop\0".ptr, "dbcdefghijklmnop\0".ptr, "abcdefghijklmnop\0".ptr] + return *strings[0] +} +``` + +#### generic_function_in_struct +```hb +A := struct { + a: uint, + b := fn(self: ^Self, $T: type, c: T): T { + return c + } +} + +main := fn(): uint { + a := A.(100) + return a.b(uint, 100) +} +``` + #### len_never_goes_down ```hb chars := fn(iter: []u8): struct { diff --git a/lang/build.rs b/lang/build.rs new file mode 100644 index 00000000..de3f37c8 --- /dev/null +++ b/lang/build.rs @@ -0,0 +1,35 @@ +use std::{fmt::Write, iter}; + +fn main() { + const TEST_FILE: &str = "src/testcases.rs"; + const INPUT: &str = include_str!("./README.md"); + + let mut out = String::new(); + for (name, code) in block_iter(INPUT) { + let name = name.replace(' ', "_"); + _ = writeln!( + out, + "#[test] fn {name}() {{ run_codegen_test(\"{name}\", r##\"{code}\"##) }}" + ); + } + + std::fs::write(TEST_FILE, out).unwrap(); +} + +fn block_iter(mut input: &str) -> impl Iterator { + const CASE_PREFIX: &str = "#### "; + const CASE_SUFFIX: &str = "\n```hb"; + + iter::from_fn(move || loop { + let pos = input.find(CASE_PREFIX)?; + input = unsafe { input.get_unchecked(pos + CASE_PREFIX.len()..) }; + let Some((test_name, rest)) = input.split_once(CASE_SUFFIX) else { continue }; + if !test_name.chars().all(|c| c.is_alphanumeric() || c == '_') { + continue; + } + input = rest; + let (body, rest) = input.split_once("```").unwrap_or((input, "")); + input = rest; + break Some((test_name, body)); + }) +} diff --git a/lang/src/lib.rs b/lang/src/lib.rs index fad931c4..525e7abb 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -401,10 +401,10 @@ impl Default for FnvHasher { #[cfg(test)] pub fn run_test( - name: &'static str, - ident: &'static str, - input: &'static str, - test: fn(&'static str, &'static str, &mut alloc::string::String), + name: &str, + ident: &str, + input: &str, + test: fn(&str, &str, &mut alloc::string::String), ) { use std::{ io::Write, @@ -483,31 +483,6 @@ fn test_parse_files( std::{borrow::ToOwned, string::ToString}, }; - fn find_block<'a>(mut input: &'a str, test_name: &str) -> &'a str { - const CASE_PREFIX: &str = "#### "; - const CASE_SUFFIX: &str = "\n```hb"; - loop { - let Some(pos) = input.find(CASE_PREFIX) else { - unreachable!("test {test_name} not found"); - }; - - input = unsafe { input.get_unchecked(pos + CASE_PREFIX.len()..) }; - if !input.starts_with(test_name) { - continue; - } - input = unsafe { input.get_unchecked(test_name.len()..) }; - if !input.starts_with(CASE_SUFFIX) { - continue; - } - input = unsafe { input.get_unchecked(CASE_SUFFIX.len()..) }; - - let end = input.find("```").unwrap_or(input.len()); - break unsafe { input.get_unchecked(..end) }; - } - } - - let input = find_block(input, ident); - let mut module_map = Vec::new(); let mut embed_map = Vec::new(); let mut last_start = 0; diff --git a/lang/src/son.rs b/lang/src/son.rs index 10d23d1d..98121045 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -4389,7 +4389,7 @@ mod tests { core::fmt::Write, }; - fn generate(ident: &'static str, input: &'static str, output: &mut String) { + fn generate(ident: &str, input: &str, output: &mut String) { _ = log::set_logger(&crate::fs::Logger); log::set_max_level(log::LevelFilter::Info); //log::set_max_level(log::LevelFilter::Trace); @@ -4423,111 +4423,9 @@ mod tests { } } - crate::run_tests! { generate: - // Tour Examples - main_fn; - arithmetic; - floating_point_arithmetic; - functions; - comments; - if_statements; - variables; - hex_octal_binary_literals; - loops; - pointers; - structs; - tuples; - struct_scopes; - enums; - unions; - nullable_types; - struct_operators; - global_variables; - constants; - directives; - c_strings; - struct_patterns; - arrays; - slices; - inline; - idk; - generic_functions; - die; - defer; - unrolled_loops; - - // Incomplete Examples; - //comptime_pointers; - generic_types; - fb_driver; - - // Purely Testing Examples; - len_never_goes_down; - slice_to_global_pointer; - subsclice_bug; - string_array; - proper_ident_propagation; - method_receiver_by_value; - comparing_floating_points; - pointer_comparison; - different_function_destinations; - triggering_store_in_divergent_branch; - wrong_dead_code_elimination; - memory_swap; - very_nested_loops; - generic_type_mishap; - storing_into_nullable_struct; - scheduling_block_did_dirty; - null_check_returning_small_global; - null_check_in_the_loop; - stack_provenance; - advanced_floating_point_arithmetic; - nullable_structure; - needless_unwrap; - inlining_issues; - null_check_test; - only_break_loop; - reading_idk; - nonexistent_ident_import; - big_array_crash; - returning_global_struct; - small_struct_bitcast; - small_struct_assignment; - intcast_store; - string_flip; - signed_to_unsigned_upcast; - wide_ret; - comptime_min_reg_leak; - different_types; - struct_return_from_module_function; - sort_something_viredly; - struct_in_register; - comptime_function_from_another_file; - inline_test; - inlined_generic_functions; - some_generic_code; - integer_inference_issues; - writing_into_string; - request_page; - tests_ptr_to_ptr_copy; - global_variable_wiredness; - inline_return_stack; - - // Just Testing Optimizations; - elide_stack_offsets_for_parameters_correctly; - const_folding_with_arg; - branch_assignments; - exhaustive_loop_testing; - pointer_opts; - conditional_stores; - loop_stores; - dead_code_in_loop; - infinite_loop_after_peephole; - aliasing_overoptimization; - global_aliasing_overptimization; - overwrite_aliasing_overoptimization; - more_if_opts; - optional_from_eca; - returning_optional_issues; + fn run_codegen_test(name: &str, input: &str) { + crate::run_test(&format!("{}::{}", module_path!(), name), name, input, generate); } + + include!("./testcases.rs"); } diff --git a/lang/tests/son_tests_generic_function_in_struct.txt b/lang/tests/son_tests_generic_function_in_struct.txt new file mode 100644 index 00000000..e69de29b