diff --git a/rust/ruby-rbs/build.rs b/rust/ruby-rbs/build.rs index 64908b998..2e470c7c6 100644 --- a/rust/ruby-rbs/build.rs +++ b/rust/ruby-rbs/build.rs @@ -47,12 +47,17 @@ fn generate(config: &Config) -> Result<(), Box> { // TODO: Go through all of the nodes and generate the structs to back them up for node in &config.nodes { + writeln!(file, "#[allow(dead_code)]")?; // TODO: Remove this once all nodes that need parser are implemented writeln!(file, "pub struct {} {{", node.rust_name)?; + writeln!(file, " parser: *mut rbs_parser_t,")?; if let Some(fields) = &node.fields { for field in fields { match field.c_type.as_str() { "rbs_string" => writeln!(file, " {}: *const rbs_string_t,", field.name)?, "bool" => writeln!(file, " {}: bool,", field.name)?, + "rbs_ast_symbol" => { + writeln!(file, " {}: *const rbs_ast_symbol_t,", field.name)? + } _ => eprintln!("Unknown field type: {}", field.c_type), } } @@ -73,6 +78,15 @@ fn generate(config: &Config) -> Result<(), Box> { writeln!(file, " self.{}", field.name)?; writeln!(file, " }}")?; } + "rbs_ast_symbol" => { + writeln!(file, " pub fn {}(&self) -> RBSSymbol {{", field.name)?; + writeln!( + file, + " RBSSymbol::new(self.{}, self.parser)", + field.name + )?; + writeln!(file, " }}")?; + } _ => eprintln!("Unknown field type: {}", field.c_type), } } diff --git a/rust/ruby-rbs/src/lib.rs b/rust/ruby-rbs/src/lib.rs index 429796483..d90496129 100644 --- a/rust/ruby-rbs/src/lib.rs +++ b/rust/ruby-rbs/src/lib.rs @@ -57,6 +57,32 @@ 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 } + } + + pub fn name(&self) -> &[u8] { + unsafe { + let constant_ptr = rbs_constant_pool_id_to_constant( + &(*self.parser).constant_pool, + (*self.pointer).constant_id, + ); + if constant_ptr.is_null() { + panic!("Constant ID for symbol is not present in the pool"); + } + + let constant = &*constant_ptr; + std::slice::from_raw_parts(constant.start, constant.length) + } + } +} + #[cfg(test)] mod tests { use super::*;