Skip to content

Commit 001405c

Browse files
committed
Add test demonstrating AST traversal and type checking (#61)
Adds `test_parse_integer()` which parses an integer literal type alias and traverses the AST (`TypeAlias` -> `LiteralType` -> `Integer`) using pattern matching to verify node types and extract values. This validates that the generated node wrappers enable AST traversal in pure Rust with proper type safety. Also adds `Debug` derives and refactors memory management by returning `SignatureNode` instead of raw pointer, with `Drop` impl to free parser.
1 parent 4761339 commit 001405c

2 files changed

Lines changed: 37 additions & 3 deletions

File tree

rust/ruby-rbs/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {
8989
// TODO: Go through all of the nodes and generate the structs to back them up
9090
for node in &config.nodes {
9191
writeln!(file, "#[allow(dead_code)]")?; // TODO: Remove this once all nodes that need parser are implemented
92+
writeln!(file, "#[derive(Debug)]")?;
9293
writeln!(file, "pub struct {} {{", node.rust_name)?;
9394
writeln!(file, " parser: *mut rbs_parser_t,")?;
9495
writeln!(
@@ -188,6 +189,7 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {
188189
}
189190

190191
// Generate the Node enum to wrap all of the structs
192+
writeln!(file, "#[derive(Debug)]")?;
191193
writeln!(file, "pub enum Node {{")?;
192194
for node in &config.nodes {
193195
let variant_name = node

rust/ruby-rbs/src/lib.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ static INIT: Once = Once::new();
1313
/// let signature = parse(rbs_code.as_bytes());
1414
/// assert!(signature.is_ok(), "Failed to parse RBS signature");
1515
/// ```
16-
pub fn parse(rbs_code: &[u8]) -> Result<*mut rbs_signature_t, String> {
16+
pub fn parse(rbs_code: &[u8]) -> Result<SignatureNode, String> {
1717
unsafe {
1818
INIT.call_once(|| {
1919
rbs_constant_pool_init(RBS_GLOBAL_CONSTANT_POOL, 26);
@@ -30,16 +30,27 @@ pub fn parse(rbs_code: &[u8]) -> Result<*mut rbs_signature_t, String> {
3030
let mut signature: *mut rbs_signature_t = std::ptr::null_mut();
3131
let result = rbs_parse_signature(parser, &mut signature);
3232

33-
rbs_parser_free(parser);
33+
let signature_node = SignatureNode {
34+
parser,
35+
pointer: signature,
36+
};
3437

3538
if result {
36-
Ok(signature)
39+
Ok(signature_node)
3740
} else {
3841
Err(String::from("Failed to parse RBS signature"))
3942
}
4043
}
4144
}
4245

46+
impl Drop for SignatureNode {
47+
fn drop(&mut self) {
48+
unsafe {
49+
rbs_parser_free(self.parser);
50+
}
51+
}
52+
}
53+
4354
pub struct NodeListIter {
4455
parser: *mut rbs_parser_t,
4556
current: *mut rbs_node_list_node_t,
@@ -140,6 +151,7 @@ impl RBSLocationList {
140151
}
141152
}
142153

154+
#[derive(Debug)]
143155
pub struct RBSString {
144156
pointer: *const rbs_string_t,
145157
}
@@ -223,4 +235,24 @@ mod tests {
223235
let signature2 = parse(rbs_code2.as_bytes());
224236
assert!(signature2.is_ok(), "Failed to parse RBS signature");
225237
}
238+
239+
#[test]
240+
fn test_parse_integer() {
241+
let rbs_code = r#"type foo = 1"#;
242+
let signature = parse(rbs_code.as_bytes());
243+
assert!(signature.is_ok(), "Failed to parse RBS signature");
244+
245+
let signature_node = signature.unwrap();
246+
if let Node::TypeAlias(node) = signature_node.declarations().iter().next().unwrap()
247+
&& let Node::LiteralType(literal) = node.type_()
248+
&& let Node::Integer(integer) = literal.literal()
249+
{
250+
assert_eq!(
251+
"1".to_string(),
252+
String::from_utf8(integer.string_representation().as_bytes().to_vec()).unwrap()
253+
);
254+
} else {
255+
panic!("No literal type node found");
256+
}
257+
}
226258
}

0 commit comments

Comments
 (0)