From 075b1784972d73133650fccc5371d14a71db889f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 20 Aug 2026 12:50:27 -0400 Subject: [PATCH] Test free_token_node in Rust --- spec/propane_spec.rb | 32 ++++++++++++++++++++-- spec/test_tree_delete_token_node_memory.rs | 17 ++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 spec/test_tree_delete_token_node_memory.rs diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index 1b7f318..5df8677 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -2059,9 +2059,36 @@ EOF expect(results.status).to eq 0 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 - write_grammar <> +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 <> Start -> a:a b:b; EOF + end run_propane(language: language) compile("spec/test_tree_delete_token_node_memory.#{language}", language: language) results = run_test(language: language) diff --git a/spec/test_tree_delete_token_node_memory.rs b/spec/test_tree_delete_token_node_memory.rs new file mode 100644 index 0000000..e10ff93 --- /dev/null +++ b/spec/test_tree_delete_token_node_memory.rs @@ -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)); +}