From 2fc09ddc59881b39d63c49cafa5a8ff6e5219e4a Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Thu, 6 Nov 2025 22:13:41 +0100 Subject: [PATCH] Rust: Call `herb_analyze_parse_tree` in `parse` --- rust/Cargo.toml | 1 + rust/build.rs | 1 + rust/src/ffi.rs | 5 +- rust/src/herb.rs | 2 + .../snapshot_test__parse_output.snap | 225 +++++++++--------- 5 files changed, 117 insertions(+), 117 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index e9404ad13..4d0129997 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -25,6 +25,7 @@ colored = "2" [dev-dependencies] insta = "1.40" +cargo-insta = "1.43.2" [build-dependencies] cc = "1.0" diff --git a/rust/build.rs b/rust/build.rs index 6defd4137..cd414ad01 100644 --- a/rust/build.rs +++ b/rust/build.rs @@ -39,6 +39,7 @@ fn main() { build.compile("herb"); let bindings = bindgen::Builder::default() + .header(src_dir.join("include/analyze.h").to_str().unwrap()) .header(src_dir.join("include/herb.h").to_str().unwrap()) .header(src_dir.join("include/ast_nodes.h").to_str().unwrap()) .header(src_dir.join("include/errors.h").to_str().unwrap()) diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index 5a2c98e50..52950f061 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -1,4 +1,5 @@ pub use crate::bindings::{ - ast_node_free, element_source_to_string, hb_array_get, hb_array_size, hb_string_T, herb_extract, - herb_free_tokens, herb_lex, herb_parse, herb_prism_version, herb_version, token_type_to_string, + ast_node_free, element_source_to_string, hb_array_get, hb_array_size, hb_string_T, + herb_analyze_parse_tree, herb_extract, herb_free_tokens, herb_lex, herb_parse, + herb_prism_version, herb_version, token_type_to_string, }; diff --git a/rust/src/herb.rs b/rust/src/herb.rs index b5e692eb5..cab8679ce 100644 --- a/rust/src/herb.rs +++ b/rust/src/herb.rs @@ -39,6 +39,8 @@ pub fn parse(source: &str) -> Result { return Err("Failed to parse source".to_string()); } + crate::ffi::herb_analyze_parse_tree(ast, c_source.as_ptr()); + let document_node = crate::ast::convert_document_node(ast as *const std::ffi::c_void) .ok_or_else(|| "Failed to convert AST".to_string())?; diff --git a/rust/tests/snapshots/snapshot_test__parse_output.snap b/rust/tests/snapshots/snapshot_test__parse_output.snap index 02d76cc48..1e113d574 100644 --- a/rust/tests/snapshots/snapshot_test__parse_output.snap +++ b/rust/tests/snapshots/snapshot_test__parse_output.snap @@ -3,7 +3,7 @@ source: tests/snapshot_test.rs expression: output --- @ DocumentNode (location: (1:0)-(12:0)) -└── children: (12 items) +└── children: (4 items) ├── @ HTMLElementNode (location: (1:0)-(1:18)) │ ├── open_tag: │ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:18)) @@ -31,126 +31,121 @@ expression: output ├── @ HTMLTextNode (location: (1:18)-(3:0)) │ └── content: "\n\n" │ - ├── @ ERBContentNode (location: (3:0)-(3:15)) + ├── @ ERBIfNode (location: (3:0)-(11:9)) │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) │ ├── content: " if valid? " (location: (3:2)-(3:13)) │ ├── tag_closing: "%>" (location: (3:13)-(3:15)) - │ ├── parsed: false - │ └── valid: false - │ - ├── @ HTMLTextNode (location: (3:15)-(4:2)) - │ └── content: "\n " - │ - ├── @ HTMLElementNode (location: (4:2)-(6:7)) - │ ├── open_tag: - │ │ └── @ HTMLOpenTagNode (location: (4:2)-(4:37)) - │ │ ├── tag_opening: "<" (location: (4:2)-(4:3)) - │ │ ├── tag_name: "h1" (location: (4:3)-(4:5)) - │ │ ├── tag_closing: ">" (location: (4:36)-(4:37)) - │ │ ├── children: (1 item) - │ │ │ └── @ HTMLAttributeNode (location: (4:6)-(4:36)) - │ │ │ ├── name: - │ │ │ │ └── @ HTMLAttributeNameNode (location: (4:6)-(4:11)) - │ │ │ │ └── children: (1 item) - │ │ │ │ └── @ LiteralNode (location: (4:6)-(4:11)) - │ │ │ │ └── content: "class" - │ │ │ │ - │ │ │ ├── equals: "=" (location: (4:11)-(4:12)) - │ │ │ └── value: - │ │ │ └── @ HTMLAttributeValueNode (location: (4:12)-(4:36)) - │ │ │ ├── open_quote: "\"" (location: (4:12)-(4:13)) - │ │ │ ├── children: (1 item) - │ │ │ │ └── @ LiteralNode (location: (4:13)-(4:35)) - │ │ │ │ └── content: "bg-green-500 text-gray" - │ │ │ ├── close_quote: "\"" (location: (4:35)-(4:36)) - │ │ │ └── quoted: true - │ │ └── is_void: false - │ │ - │ ├── tag_name: "h1" (location: (4:3)-(4:5)) - │ ├── body: (3 items) - │ │ ├── @ HTMLTextNode (location: (4:37)-(5:4)) - │ │ │ └── content: "\n " + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (3:15)-(4:2)) + │ │ │ └── content: "\n " │ │ │ - │ │ ├── @ ERBContentNode (location: (5:4)-(5:18)) - │ │ │ ├── tag_opening: "<%=" (location: (5:4)-(5:7)) - │ │ │ ├── content: " \"Valid\" " (location: (5:7)-(5:16)) - │ │ │ ├── tag_closing: "%>" (location: (5:16)-(5:18)) - │ │ │ ├── parsed: false - │ │ │ └── valid: false + │ │ ├── @ HTMLElementNode (location: (4:2)-(6:7)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (4:2)-(4:37)) + │ │ │ │ ├── tag_opening: "<" (location: (4:2)-(4:3)) + │ │ │ │ ├── tag_name: "h1" (location: (4:3)-(4:5)) + │ │ │ │ ├── tag_closing: ">" (location: (4:36)-(4:37)) + │ │ │ │ ├── children: (1 item) + │ │ │ │ │ └── @ HTMLAttributeNode (location: (4:6)-(4:36)) + │ │ │ │ │ ├── name: + │ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (4:6)-(4:11)) + │ │ │ │ │ │ └── children: (1 item) + │ │ │ │ │ │ └── @ LiteralNode (location: (4:6)-(4:11)) + │ │ │ │ │ │ └── content: "class" + │ │ │ │ │ │ + │ │ │ │ │ ├── equals: "=" (location: (4:11)-(4:12)) + │ │ │ │ │ └── value: + │ │ │ │ │ └── @ HTMLAttributeValueNode (location: (4:12)-(4:36)) + │ │ │ │ │ ├── open_quote: "\"" (location: (4:12)-(4:13)) + │ │ │ │ │ ├── children: (1 item) + │ │ │ │ │ │ └── @ LiteralNode (location: (4:13)-(4:35)) + │ │ │ │ │ │ └── content: "bg-green-500 text-gray" + │ │ │ │ │ ├── close_quote: "\"" (location: (4:35)-(4:36)) + │ │ │ │ │ └── quoted: true + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "h1" (location: (4:3)-(4:5)) + │ │ │ ├── body: (3 items) + │ │ │ │ ├── @ HTMLTextNode (location: (4:37)-(5:4)) + │ │ │ │ │ └── content: "\n " + │ │ │ │ │ + │ │ │ │ ├── @ ERBContentNode (location: (5:4)-(5:18)) + │ │ │ │ │ ├── tag_opening: "<%=" (location: (5:4)-(5:7)) + │ │ │ │ │ ├── content: " \"Valid\" " (location: (5:7)-(5:16)) + │ │ │ │ │ ├── tag_closing: "%>" (location: (5:16)-(5:18)) + │ │ │ │ │ ├── parsed: true + │ │ │ │ │ └── valid: true + │ │ │ │ │ + │ │ │ │ └── @ HTMLTextNode (location: (5:18)-(6:2)) + │ │ │ │ └── content: "\n " + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (6:2)-(6:7)) + │ │ │ │ ├── tag_opening: "" (location: (6:6)-(6:7)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" │ │ │ - │ │ └── @ HTMLTextNode (location: (5:18)-(6:2)) - │ │ └── content: "\n " - │ ├── close_tag: - │ │ └── @ HTMLCloseTagNode (location: (6:2)-(6:7)) - │ │ ├── tag_opening: "" (location: (6:6)-(6:7)) + │ │ └── @ HTMLTextNode (location: (6:7)-(7:0)) + │ │ └── content: "\n" + │ ├── subsequent: + │ │ └── @ ERBElseNode (location: (7:0)-(11:0)) + │ │ ├── tag_opening: "<%" (location: (7:0)-(7:2)) + │ │ ├── content: " else " (location: (7:2)-(7:8)) + │ │ ├── tag_closing: "%>" (location: (7:8)-(7:10)) + │ │ └── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (7:10)-(8:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (8:2)-(10:7)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (8:2)-(8:36)) + │ │ │ │ ├── tag_opening: "<" (location: (8:2)-(8:3)) + │ │ │ │ ├── tag_name: "h1" (location: (8:3)-(8:5)) + │ │ │ │ ├── tag_closing: ">" (location: (8:35)-(8:36)) + │ │ │ │ ├── children: (1 item) + │ │ │ │ │ └── @ HTMLAttributeNode (location: (8:6)-(8:35)) + │ │ │ │ │ ├── name: + │ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (8:6)-(8:11)) + │ │ │ │ │ │ └── children: (1 item) + │ │ │ │ │ │ └── @ LiteralNode (location: (8:6)-(8:11)) + │ │ │ │ │ │ └── content: "class" + │ │ │ │ │ │ + │ │ │ │ │ ├── equals: "=" (location: (8:11)-(8:12)) + │ │ │ │ │ └── value: + │ │ │ │ │ └── @ HTMLAttributeValueNode (location: (8:12)-(8:35)) + │ │ │ │ │ ├── open_quote: "\"" (location: (8:12)-(8:13)) + │ │ │ │ │ ├── children: (1 item) + │ │ │ │ │ │ └── @ LiteralNode (location: (8:13)-(8:34)) + │ │ │ │ │ │ └── content: "bg-red-500 text-black" + │ │ │ │ │ ├── close_quote: "\"" (location: (8:34)-(8:35)) + │ │ │ │ │ └── quoted: true + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "h1" (location: (8:3)-(8:5)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ HTMLTextNode (location: (8:36)-(10:2)) + │ │ │ │ └── content: "\n Invalid\n " + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (10:2)-(10:7)) + │ │ │ │ ├── tag_opening: "" (location: (10:6)-(10:7)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (10:7)-(11:0)) + │ │ └── content: "\n" │ │ - │ ├── is_void: false - │ └── source: "HTML" - │ - ├── @ HTMLTextNode (location: (6:7)-(7:0)) - │ └── content: "\n" - │ - ├── @ ERBContentNode (location: (7:0)-(7:10)) - │ ├── tag_opening: "<%" (location: (7:0)-(7:2)) - │ ├── content: " else " (location: (7:2)-(7:8)) - │ ├── tag_closing: "%>" (location: (7:8)-(7:10)) - │ ├── parsed: false - │ └── valid: false - │ - ├── @ HTMLTextNode (location: (7:10)-(8:2)) - │ └── content: "\n " - │ - ├── @ HTMLElementNode (location: (8:2)-(10:7)) - │ ├── open_tag: - │ │ └── @ HTMLOpenTagNode (location: (8:2)-(8:36)) - │ │ ├── tag_opening: "<" (location: (8:2)-(8:3)) - │ │ ├── tag_name: "h1" (location: (8:3)-(8:5)) - │ │ ├── tag_closing: ">" (location: (8:35)-(8:36)) - │ │ ├── children: (1 item) - │ │ │ └── @ HTMLAttributeNode (location: (8:6)-(8:35)) - │ │ │ ├── name: - │ │ │ │ └── @ HTMLAttributeNameNode (location: (8:6)-(8:11)) - │ │ │ │ └── children: (1 item) - │ │ │ │ └── @ LiteralNode (location: (8:6)-(8:11)) - │ │ │ │ └── content: "class" - │ │ │ │ - │ │ │ ├── equals: "=" (location: (8:11)-(8:12)) - │ │ │ └── value: - │ │ │ └── @ HTMLAttributeValueNode (location: (8:12)-(8:35)) - │ │ │ ├── open_quote: "\"" (location: (8:12)-(8:13)) - │ │ │ ├── children: (1 item) - │ │ │ │ └── @ LiteralNode (location: (8:13)-(8:34)) - │ │ │ │ └── content: "bg-red-500 text-black" - │ │ │ ├── close_quote: "\"" (location: (8:34)-(8:35)) - │ │ │ └── quoted: true - │ │ └── is_void: false - │ │ - │ ├── tag_name: "h1" (location: (8:3)-(8:5)) - │ ├── body: (1 item) - │ │ └── @ HTMLTextNode (location: (8:36)-(10:2)) - │ │ └── content: "\n Invalid\n " - │ ├── close_tag: - │ │ └── @ HTMLCloseTagNode (location: (10:2)-(10:7)) - │ │ ├── tag_opening: "" (location: (10:6)-(10:7)) - │ │ - │ ├── is_void: false - │ └── source: "HTML" - │ - ├── @ HTMLTextNode (location: (10:7)-(11:0)) - │ └── content: "\n" - │ - ├── @ ERBContentNode (location: (11:0)-(11:9)) - │ ├── tag_opening: "<%" (location: (11:0)-(11:2)) - │ ├── content: " end " (location: (11:2)-(11:7)) - │ ├── tag_closing: "%>" (location: (11:7)-(11:9)) - │ ├── parsed: false - │ └── valid: false + │ └── end_node: + │ └── @ ERBEndNode (location: (11:0)-(11:9)) + │ ├── tag_opening: "<%" (location: (11:0)-(11:2)) + │ ├── content: " end " (location: (11:2)-(11:7)) + │ └── tag_closing: "%>" (location: (11:7)-(11:9)) │ └── @ HTMLTextNode (location: (11:9)-(12:0)) └── content: "\n"