Test free_token_node in Rust

This commit is contained in:
Josh Holtrop 2026-08-20 12:50:27 -04:00
parent 7a8b4ad640
commit 075b178497
2 changed files with 47 additions and 2 deletions

View File

@ -2059,9 +2059,36 @@ EOF
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
if %w[c cpp].include?(language) # D is excluded since it is garbage collected, so Propane does not emit a
# free_token_node code block for it.
if %w[c cpp rust].include?(language)
it "allows a user function to free token node memory in tree mode" do it "allows a user function to free token node memory in tree mode" do
write_grammar <<EOF if language == "rust"
write_grammar <<EOF
<<
use std::sync::atomic::{AtomicU32, Ordering};
/** Number of token nodes freed by the free_token_node code block. */
pub static FREED: AtomicU32 = AtomicU32::new(0);
>>
tree;
free_token_node <<
if !${token.pvalue}.is_null() {
unsafe { drop(Box::from_raw(${token.pvalue})); }
FREED.fetch_add(1, Ordering::SeqCst);
}
>>
ptype *mut i32;
token a <<
$$ = Box::into_raw(Box::new(1));
>>
token b <<
$$ = Box::into_raw(Box::new(2));
>>
Start -> a:a b:b;
EOF
else
write_grammar <<EOF
tree; tree;
free_token_node << free_token_node <<
free(${token.pvalue}); free(${token.pvalue});
@ -2077,6 +2104,7 @@ token b <<
>> >>
Start -> a:a b:b; Start -> a:a b:b;
EOF EOF
end
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_delete_token_node_memory.#{language}", language: language) compile("spec/test_tree_delete_token_node_memory.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)

View File

@ -0,0 +1,17 @@
use testparser::*;
use std::sync::atomic::Ordering;
fn main() {
let mut context = p_context_new(b"ab");
assert_eq!(P_SUCCESS, p_parse(&mut context));
let start = p_result(&context);
assert!(start.a().valid());
assert_eq!(1, unsafe { *start.a().pvalue() });
assert!(start.b().valid());
assert_eq!(2, unsafe { *start.b().pvalue() });
/* The free_token_node code block runs from p_context_delete(), not before. */
assert_eq!(0, FREED.load(Ordering::SeqCst));
p_context_delete(context);
assert_eq!(2, FREED.load(Ordering::SeqCst));
}