From d29585ebe74b8a26e3e8a21f0f4dcbb048f5ca63 Mon Sep 17 00:00:00 2001 From: Alex Rocha Date: Wed, 26 Nov 2025 17:28:06 -0800 Subject: [PATCH] Refactor Symbol and Keyword as nodes Refactor the previous implementation of Symbol/Keyword handling to treat them as first-class nodes in the build configuration. Instead of manually defining RBSSymbol/RBSKeyword structs, we now inject them into the config.yml node list in build.rs. This allows them to be generated as SymbolNode/KeywordNode variants in the Node enum, enabling polymorphic handling (in Node lists and Hashes) --- rust/ruby-rbs/build.rs | 24 ++++++++++++++++++++---- rust/ruby-rbs/src/lib.rs | 22 ++-------------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/rust/ruby-rbs/build.rs b/rust/ruby-rbs/build.rs index 36883f84c..fb7d61661 100644 --- a/rust/ruby-rbs/build.rs +++ b/rust/ruby-rbs/build.rs @@ -37,6 +37,22 @@ fn main() -> Result<(), Box> { let config_file = File::open(&config_path)?; let mut config: Config = serde_yaml::from_reader(config_file)?; + // Keyword and Symbol represent identifiers (interned strings), not traditional AST nodes. + // However, the C parser defines them in `rbs_node_type` (RBS_KEYWORD, RBS_AST_SYMBOL) and + // treats them as nodes (rbs_node_t*) in many contexts (lists, hashes). + // We inject them into the config so they are generated as structs matching the Node pattern, + // allowing them to be wrapped in the Node enum and handled uniformly in Rust. + config.nodes.push(Node { + name: "RBS::Keyword".to_string(), + rust_name: "KeywordNode".to_string(), + fields: None, + }); + config.nodes.push(Node { + name: "RBS::AST::Symbol".to_string(), + rust_name: "SymbolNode".to_string(), + fields: None, + }); + config.nodes.sort_by(|a, b| a.name.cmp(&b.name)); generate(&config)?; @@ -148,10 +164,10 @@ fn generate(config: &Config) -> Result<(), Box> { writeln!(file, " }}")?; } "rbs_ast_symbol" => { - writeln!(file, " pub fn {}(&self) -> RBSSymbol {{", field.name)?; + writeln!(file, " pub fn {}(&self) -> SymbolNode {{", field.name)?; writeln!( file, - " RBSSymbol::new(unsafe {{ (*self.pointer).{} }}, self.parser)", + " SymbolNode {{ parser: self.parser, pointer: unsafe {{ (*self.pointer).{} }} }}", field.c_name() )?; writeln!(file, " }}")?; @@ -212,10 +228,10 @@ fn generate(config: &Config) -> Result<(), Box> { writeln!(file, " }}")?; } "rbs_keyword" => { - writeln!(file, " pub fn {}(&self) -> RBSKeyword {{", field.name)?; + writeln!(file, " pub fn {}(&self) -> KeywordNode {{", field.name)?; writeln!( file, - " RBSKeyword::new(self.parser, unsafe {{ (*self.pointer).{} }})", + " KeywordNode {{ parser: self.parser, pointer: unsafe {{ (*self.pointer).{} }} }}", field.c_name() )?; writeln!(file, " }}")?; diff --git a/rust/ruby-rbs/src/lib.rs b/rust/ruby-rbs/src/lib.rs index dae6787c2..86e0ff5a3 100644 --- a/rust/ruby-rbs/src/lib.rs +++ b/rust/ruby-rbs/src/lib.rs @@ -169,16 +169,7 @@ impl RBSString { } } -pub struct RBSSymbol { - pointer: *const rbs_ast_symbol_t, - parser: *mut rbs_parser_t, -} - -impl RBSSymbol { - pub fn new(pointer: *const rbs_ast_symbol_t, parser: *mut rbs_parser_t) -> Self { - Self { pointer, parser } - } - +impl SymbolNode { pub fn name(&self) -> &[u8] { unsafe { let constant_ptr = rbs_constant_pool_id_to_constant( @@ -195,16 +186,7 @@ impl RBSSymbol { } } -pub struct RBSKeyword { - parser: *mut rbs_parser_t, - pointer: *const rbs_keyword, -} - -impl RBSKeyword { - pub fn new(parser: *mut rbs_parser_t, pointer: *const rbs_keyword) -> Self { - Self { parser, pointer } - } - +impl KeywordNode { pub fn name(&self) -> &[u8] { unsafe { let constant_ptr = rbs_constant_pool_id_to_constant(