Skip to main content

perl_parser_pest/
pure_rust_parser.rs

1//! Pure Rust Perl parser implementation
2//!
3//! This module provides a complete Rust-native implementation of the Perl parser
4//! using Pest for grammar parsing, without any dependency on tree-sitter's C code.
5
6use crate::pratt_parser::PrattParser;
7use pest::{
8    Parser,
9    iterators::{Pair, Pairs},
10};
11use pest_derive::Parser;
12use regex::Regex;
13use stacker;
14use std::sync::{Arc, LazyLock};
15
16#[derive(Parser)]
17#[grammar = "grammar.pest"]
18pub struct PerlParser;
19
20// The Rule type is generated by pest_derive
21
22// The Rule enum is generated by pest_derive in this module
23
24/// AST node types for the pure Rust parser
25#[derive(Debug, Clone, PartialEq)]
26pub enum AstNode {
27    // Program structure
28    Program(Vec<AstNode>),
29    Statement(Box<AstNode>),
30    Block(Vec<AstNode>),
31
32    // Declarations
33    VariableDeclaration {
34        scope: Arc<str>,
35        variables: Vec<AstNode>,
36        initializer: Option<Box<AstNode>>,
37    },
38    SubDeclaration {
39        name: Arc<str>,
40        prototype: Option<Arc<str>>,
41        attributes: Vec<Arc<str>>,
42        body: Box<AstNode>,
43    },
44    FormatDeclaration {
45        name: Arc<str>,
46        format_lines: Vec<Arc<str>>,
47    },
48    PackageDeclaration {
49        name: Arc<str>,
50        version: Option<Arc<str>>,
51        block: Option<Box<AstNode>>,
52    },
53    UseStatement {
54        module: Arc<str>,
55        version: Option<Arc<str>>,
56        import_list: Vec<Arc<str>>,
57    },
58    RequireStatement {
59        module: Arc<str>,
60    },
61
62    // Control flow
63    IfStatement {
64        condition: Box<AstNode>,
65        then_block: Box<AstNode>,
66        elsif_clauses: Vec<(AstNode, AstNode)>,
67        else_block: Option<Box<AstNode>>,
68    },
69    UnlessStatement {
70        condition: Box<AstNode>,
71        block: Box<AstNode>,
72        else_block: Option<Box<AstNode>>,
73    },
74    GivenStatement {
75        expression: Box<AstNode>,
76        when_clauses: Vec<(AstNode, AstNode)>,
77        default_block: Option<Box<AstNode>>,
78    },
79    WhileStatement {
80        label: Option<Arc<str>>,
81        condition: Box<AstNode>,
82        block: Box<AstNode>,
83    },
84    UntilStatement {
85        label: Option<Arc<str>>,
86        condition: Box<AstNode>,
87        block: Box<AstNode>,
88    },
89    ForStatement {
90        label: Option<Arc<str>>,
91        init: Option<Box<AstNode>>,
92        condition: Option<Box<AstNode>>,
93        update: Option<Box<AstNode>>,
94        block: Box<AstNode>,
95    },
96    ForeachStatement {
97        label: Option<Arc<str>>,
98        variable: Option<Box<AstNode>>,
99        list: Box<AstNode>,
100        block: Box<AstNode>,
101    },
102
103    // Expressions
104    BinaryOp {
105        op: Arc<str>,
106        left: Box<AstNode>,
107        right: Box<AstNode>,
108    },
109    UnaryOp {
110        op: Arc<str>,
111        operand: Box<AstNode>,
112    },
113    TernaryOp {
114        condition: Box<AstNode>,
115        true_expr: Box<AstNode>,
116        false_expr: Box<AstNode>,
117    },
118    PostfixDereference {
119        expr: Box<AstNode>,
120        deref_type: Arc<str>,
121    },
122    Dereference {
123        expr: Box<AstNode>,
124        deref_type: Arc<str>,
125    },
126    TypeglobSlotAccess {
127        typeglob: Box<AstNode>,
128        slot: Arc<str>,
129    },
130    Assignment {
131        target: Box<AstNode>,
132        op: Arc<str>,
133        value: Box<AstNode>,
134    },
135    FunctionCall {
136        function: Box<AstNode>,
137        args: Vec<AstNode>,
138    },
139    MethodCall {
140        object: Box<AstNode>,
141        method: Arc<str>,
142        args: Vec<AstNode>,
143    },
144    BuiltinListOp {
145        name: Arc<str>,
146        args: Vec<AstNode>,
147    },
148    ArrayAccess {
149        array: Box<AstNode>,
150        index: Box<AstNode>,
151    },
152    HashAccess {
153        hash: Box<AstNode>,
154        key: Box<AstNode>,
155    },
156
157    // Variables
158    ScalarVariable(Arc<str>),
159    ArrayVariable(Arc<str>),
160    HashVariable(Arc<str>),
161    TypeglobVariable(Arc<str>),
162
163    // References
164    ScalarReference(Arc<str>),
165    ArrayReference(Arc<str>),
166    HashReference(Arc<str>),
167    SubroutineReference(Arc<str>),
168    GlobReference(Arc<str>),
169    ArrayElement {
170        array: Arc<str>,
171        index: Box<AstNode>,
172    },
173    HashElement {
174        hash: Arc<str>,
175        key: Box<AstNode>,
176    },
177
178    // Literals
179    Number(Arc<str>),
180    String(Arc<str>),
181    Identifier(Arc<str>),
182    SpecialLiteral(Arc<str>),
183    Bareword(Arc<str>),
184    EmptyExpression,
185    Regex {
186        pattern: Arc<str>,
187        flags: Arc<str>,
188        named_groups: Vec<Arc<str>>,
189    },
190    Substitution {
191        pattern: Arc<str>,
192        replacement: Arc<str>,
193        flags: Arc<str>,
194    },
195    Transliteration {
196        search_list: Arc<str>,
197        replace_list: Arc<str>,
198        flags: Arc<str>,
199    },
200    ReturnStatement {
201        value: Option<Box<AstNode>>,
202    },
203    LastStatement {
204        label: Option<Arc<str>>,
205    },
206    NextStatement {
207        label: Option<Arc<str>>,
208    },
209    TieStatement {
210        variable: Box<AstNode>,
211        class: Box<AstNode>,
212        args: Vec<AstNode>,
213    },
214    UntieStatement {
215        variable: Box<AstNode>,
216    },
217    TiedExpression {
218        variable: Box<AstNode>,
219    },
220
221    // Other
222    Comment(Arc<str>),
223    Label(Arc<str>),
224    LabeledBlock {
225        label: Arc<str>,
226        block: Box<AstNode>,
227    },
228    AnonymousSub {
229        prototype: Option<Arc<str>>,
230        body: Box<AstNode>,
231    },
232    List(Vec<AstNode>),
233    ArrayRef(Vec<AstNode>),
234    HashRef(Vec<AstNode>),
235
236    // Additional Perl constructs
237    BeginBlock(Box<AstNode>),
238    EndBlock(Box<AstNode>),
239    CheckBlock(Box<AstNode>),
240    InitBlock(Box<AstNode>),
241    UnitcheckBlock(Box<AstNode>),
242
243    // Quoting constructs
244    QwList(Vec<Arc<str>>),
245    QqString(Arc<str>),
246    QxString(Arc<str>),
247    QrRegex {
248        pattern: Arc<str>,
249        flags: Arc<str>,
250        named_groups: Vec<Arc<str>>,
251    },
252    InterpolatedString(Vec<AstNode>),
253
254    // Here documents
255    Heredoc {
256        marker: Arc<str>,
257        indented: bool,
258        quoted: bool,
259        content: Arc<str>,
260    },
261
262    // File operations
263    Glob(Arc<str>),
264    Readline {
265        filehandle: Option<Arc<str>>,
266    },
267
268    // Special constructs
269    DoBlock(Box<AstNode>),
270    EvalBlock(Box<AstNode>),
271    EvalString(Box<AstNode>),
272    GotoStatement {
273        target: Arc<str>,
274    },
275
276    // Data sections
277    DataSection(Arc<str>),
278    EndSection(Arc<str>),
279
280    // POD
281    Pod(Arc<str>),
282
283    // Modern Perl features
284    TryCatch {
285        try_block: Box<AstNode>,
286        catch_clauses: Vec<(Option<Arc<str>>, AstNode)>, // (parameter, block)
287        finally_block: Option<Box<AstNode>>,
288    },
289    DeferStatement(Box<AstNode>),
290
291    // Error recovery
292    ErrorNode {
293        message: Arc<str>,
294        content: Arc<str>,
295    },
296    ClassDeclaration {
297        name: Arc<str>,
298        version: Option<Arc<str>>,
299        superclass: Option<Arc<str>>,
300        body: Vec<AstNode>,
301    },
302    FieldDeclaration {
303        name: Arc<str>,
304        attributes: Vec<Arc<str>>,
305        default: Option<Box<AstNode>>,
306    },
307    MethodDeclaration {
308        name: Arc<str>,
309        signature: Option<Arc<str>>,
310        attributes: Vec<Arc<str>>,
311        body: Box<AstNode>,
312    },
313    RoleDeclaration {
314        name: Arc<str>,
315        body: Box<AstNode>,
316    },
317}
318
319/// Pure Rust Perl parser implementation
320pub struct PureRustPerlParser {
321    _pratt_parser: PrattParser,
322}
323
324impl PureRustPerlParser {
325    pub fn new() -> Self {
326        Self { _pratt_parser: PrattParser::new() }
327    }
328
329    #[inline(always)]
330    pub fn parse(&mut self, source: &str) -> Result<AstNode, Box<dyn std::error::Error>> {
331        let normalized = Self::normalize_source(source);
332
333        match <PerlParser as Parser<Rule>>::parse(Rule::program, &normalized) {
334            Ok(pairs) => self.build_ast(pairs),
335            Err(e) => {
336                // Attempt partial parsing by trying to parse individual statements
337                self.parse_with_recovery(&normalized, e)
338            }
339        }
340    }
341
342    fn normalize_source(source: &str) -> String {
343        static SIMPLE_SCALAR_DEREF_RE: LazyLock<Option<Regex>> =
344            LazyLock::new(|| Regex::new(r"\$\$(?P<name>[A-Za-z_][A-Za-z0-9_:]*)").ok());
345        static ASSIGN_BITNOT_RE: LazyLock<Option<Regex>> =
346            LazyLock::new(|| Regex::new(r"=\s+~\s*(?P<expr>\$[A-Za-z_][A-Za-z0-9_:]*)").ok());
347
348        // These are fixed patterns; if one ever fails to compile, skip normalization
349        // rather than panicking inside production parser code.
350        let Some(scalar_deref_re) = SIMPLE_SCALAR_DEREF_RE.as_ref() else {
351            return source.to_string();
352        };
353        let Some(assign_bitnot_re) = ASSIGN_BITNOT_RE.as_ref() else {
354            return source.to_string();
355        };
356
357        let normalized_derefs = scalar_deref_re
358            .replace_all(source, |caps: &regex::Captures<'_>| {
359                let variable = format!("${}", &caps["name"]);
360                format!("${{{}}}", variable)
361            })
362            .into_owned();
363
364        assign_bitnot_re
365            .replace_all(&normalized_derefs, |caps: &regex::Captures<'_>| {
366                format!("= bitnot({})", &caps["expr"])
367            })
368            .into_owned()
369    }
370
371    fn parse_with_recovery(
372        &mut self,
373        source: &str,
374        original_error: pest::error::Error<Rule>,
375    ) -> Result<AstNode, Box<dyn std::error::Error>> {
376        let mut statements = Vec::new();
377        let lines: Vec<&str> = source.lines().collect();
378        let mut current_block = String::new();
379        let mut brace_count: i32 = 0;
380        let mut in_single_quote = false;
381        let mut in_double_quote = false;
382
383        for line in lines {
384            current_block.push_str(line);
385            current_block.push('\n');
386
387            // Count braces outside of string literals (state persists across lines)
388            {
389                let mut escaped = false;
390                for ch in line.chars() {
391                    if escaped {
392                        escaped = false;
393                        continue;
394                    }
395                    if ch == '\\' {
396                        escaped = true;
397                        continue;
398                    }
399                    match ch {
400                        '\'' if !in_double_quote => in_single_quote = !in_single_quote,
401                        '"' if !in_single_quote => in_double_quote = !in_double_quote,
402                        '{' if !in_single_quote && !in_double_quote => brace_count += 1,
403                        '}' if !in_single_quote && !in_double_quote => brace_count -= 1,
404                        _ => {}
405                    }
406                }
407            }
408
409            // Try to parse when we have balanced braces or at semicolons
410            if (brace_count == 0 && (line.trim().ends_with(';') || line.trim().ends_with('}')))
411                || line.trim().is_empty()
412            {
413                let trimmed = current_block.trim();
414                if !trimmed.is_empty() && !trimmed.starts_with('#') {
415                    // Try to parse as a complete statement with semicolon
416                    let with_semi = if !trimmed.ends_with(';') && !trimmed.ends_with('}') {
417                        format!("{};", trimmed)
418                    } else {
419                        trimmed.to_string()
420                    };
421
422                    if let Ok(pairs) =
423                        <PerlParser as Parser<Rule>>::parse(Rule::statements, &with_semi)
424                    {
425                        for pair in pairs {
426                            for inner_pair in pair.into_inner() {
427                                if let Some(node) = self.build_node(inner_pair).unwrap_or(None) {
428                                    statements.push(node);
429                                }
430                            }
431                        }
432                        current_block.clear();
433                        in_single_quote = false;
434                        in_double_quote = false;
435                    } else {
436                        // If that fails, skip and continue
437                        current_block.clear();
438                        in_single_quote = false;
439                        in_double_quote = false;
440                    }
441                } else if trimmed.starts_with('#') {
442                    // Handle comments
443                    statements.push(AstNode::Comment(Arc::from(trimmed)));
444                    current_block.clear();
445                }
446            }
447        }
448
449        if statements.is_empty() {
450            Err(Box::new(original_error))
451        } else {
452            Ok(AstNode::Program(statements))
453        }
454    }
455
456    fn extract_named_groups(&self, pattern: &str) -> Vec<Arc<str>> {
457        let mut groups = Vec::new();
458        let chars: Vec<char> = pattern.chars().collect();
459        let mut i = 0;
460
461        while i < chars.len() {
462            if i + 3 < chars.len() && chars[i..i + 3] == ['(', '?', '<'] {
463                // Found start of named group
464                i += 3;
465                let mut name = String::new();
466                while i < chars.len() && chars[i] != '>' {
467                    name.push(chars[i]);
468                    i += 1;
469                }
470                if !name.is_empty() {
471                    groups.push(Arc::from(name));
472                }
473            }
474            i += 1;
475        }
476
477        groups
478    }
479
480    pub fn build_ast(&mut self, pairs: Pairs<Rule>) -> Result<AstNode, Box<dyn std::error::Error>> {
481        let mut nodes = Vec::new();
482        for pair in pairs {
483            if let Some(node) = self.build_node(pair)? {
484                nodes.push(node);
485            }
486        }
487        if nodes.len() == 1 {
488            nodes.pop().ok_or_else(|| "Empty nodes".into())
489        } else {
490            Ok(AstNode::Program(nodes))
491        }
492    }
493
494    /// Public wrapper that uses stacker to grow the stack as needed.
495    ///
496    /// This remains public so bridge consumers (for example `tree-sitter-perl-rs`
497    /// with `v2-pest-microcrate`) can continue calling internal v2 build paths.
498    #[inline]
499    pub fn build_node(
500        &mut self,
501        pair: Pair<Rule>,
502    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
503        // Use stacker to grow stack if needed, with 512KB red zone
504        const STACK_RED_ZONE: usize = 512 * 1024; // 512KB
505        const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB growth
506        stacker::maybe_grow(STACK_RED_ZONE, STACK_SIZE, || self.build_node_impl(pair))
507    }
508
509    /// Actual implementation of build_node
510    #[inline]
511    fn build_node_impl(
512        &mut self,
513        pair: Pair<Rule>,
514    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
515        match pair.as_rule() {
516            // Fast-path rules
517            Rule::simple_assignment => {
518                let mut inner = pair.into_inner();
519                let var_pair = inner.next().ok_or("Missing variable in simple assignment")?;
520                let var = self.build_node(var_pair)?.ok_or("Failed to build variable node")?;
521                let val_pair = inner.next().ok_or("Missing value in simple assignment")?;
522                let value = self.build_node(val_pair)?.ok_or("Failed to build value node")?;
523                Ok(Some(AstNode::Assignment {
524                    target: Box::new(var),
525                    op: Arc::from("="),
526                    value: Box::new(value),
527                }))
528            }
529            Rule::simple_method_call => {
530                // This is an atomic rule, parse from the string directly
531                let text = pair.as_str();
532                // Format: variable -> identifier ( ) ;
533                let parts: Vec<&str> = text.split("->").collect();
534                if parts.len() == 2 {
535                    let var_part = parts[0].trim();
536                    let method_part = parts[1].trim();
537
538                    // Extract method name (before parentheses)
539                    let method_name = method_part.split('(').next().unwrap_or("").trim();
540
541                    // Create a simple variable node for the object
542                    let object = if var_part.starts_with('$') {
543                        AstNode::ScalarVariable(Arc::from(var_part))
544                    } else {
545                        AstNode::Identifier(Arc::from(var_part))
546                    };
547
548                    Ok(Some(AstNode::MethodCall {
549                        object: Box::new(object),
550                        method: Arc::from(method_name),
551                        args: vec![],
552                    }))
553                } else {
554                    Ok(None)
555                }
556            }
557            Rule::simple_function_call => {
558                // This is an atomic rule, parse from the string directly
559                let text = pair.as_str();
560                // Format: identifier ( literal/variable ) ;
561                let parts: Vec<&str> = text.split('(').collect();
562                if parts.len() >= 2 {
563                    let func_name = parts[0].trim();
564                    let func = AstNode::Identifier(Arc::from(func_name));
565
566                    // Extract argument if present
567                    let args = if let Some(arg_part) = parts.get(1) {
568                        let arg_text = arg_part.trim_end_matches(");").trim_end_matches(';').trim();
569                        if !arg_text.is_empty() {
570                            let arg = if arg_text.starts_with('$') {
571                                AstNode::ScalarVariable(Arc::from(arg_text))
572                            } else if arg_text.starts_with('"') || arg_text.starts_with('\'') {
573                                AstNode::String(Arc::from(arg_text))
574                            } else if arg_text.chars().all(|c| c.is_numeric() || c == '.') {
575                                AstNode::Number(Arc::from(arg_text))
576                            } else {
577                                AstNode::Identifier(Arc::from(arg_text))
578                            };
579                            vec![arg]
580                        } else {
581                            vec![]
582                        }
583                    } else {
584                        vec![]
585                    };
586
587                    Ok(Some(AstNode::FunctionCall { function: Box::new(func), args }))
588                } else {
589                    Ok(None)
590                }
591            }
592            Rule::program => {
593                let mut statements = Vec::new();
594                for inner in pair.into_inner() {
595                    if let Some(node) = self.build_node(inner)? {
596                        statements.push(node);
597                    }
598                }
599                Ok(Some(AstNode::Program(statements)))
600            }
601            Rule::statements => {
602                let mut statements = Vec::new();
603                for inner in pair.into_inner() {
604                    if let Some(node) = self.build_node(inner)? {
605                        statements.push(node);
606                    }
607                }
608                Ok(Some(AstNode::Program(statements)))
609            }
610            Rule::statement => {
611                let inner = pair.into_inner().next().ok_or("Empty statement")?;
612                self.build_node(inner)
613            }
614            Rule::modified_statement => {
615                let mut inner = pair.into_inner();
616                let expr_pair = inner.next().ok_or("Missing expression in modified statement")?;
617                let expr = self.build_node(expr_pair)?;
618                let modifier = inner.next().ok_or("Missing modifier in modified statement")?;
619
620                // Extract modifier type and condition from the statement_modifier
621                let modifier_str = modifier.as_str();
622                let (modifier_type, condition_expr) =
623                    if let Some(rest) = modifier_str.strip_prefix("if ") {
624                        ("if", rest)
625                    } else if let Some(rest) = modifier_str.strip_prefix("unless ") {
626                        ("unless", rest)
627                    } else if let Some(rest) = modifier_str.strip_prefix("while ") {
628                        ("while", rest)
629                    } else if let Some(rest) = modifier_str.strip_prefix("until ") {
630                        ("until", rest)
631                    } else if let Some(rest) = modifier_str.strip_prefix("for ") {
632                        ("for", rest)
633                    } else if let Some(rest) = modifier_str.strip_prefix("foreach ") {
634                        ("foreach", rest)
635                    } else {
636                        return Ok(expr);
637                    };
638
639                // For now, create a simple identifier for the condition
640                // In a real implementation, we'd parse the condition expression
641                let condition = Some(AstNode::Identifier(Arc::from(condition_expr.trim())));
642
643                if let (Some(expr), Some(condition)) = (expr, condition) {
644                    match modifier_type {
645                        "if" => Ok(Some(AstNode::IfStatement {
646                            condition: Box::new(condition),
647                            then_block: Box::new(expr),
648                            elsif_clauses: Vec::new(),
649                            else_block: None,
650                        })),
651                        "unless" => Ok(Some(AstNode::UnlessStatement {
652                            condition: Box::new(condition),
653                            block: Box::new(expr),
654                            else_block: None,
655                        })),
656                        "while" => Ok(Some(AstNode::WhileStatement {
657                            label: None,
658                            condition: Box::new(condition),
659                            block: Box::new(expr),
660                        })),
661                        "until" => Ok(Some(AstNode::UntilStatement {
662                            label: None,
663                            condition: Box::new(condition),
664                            block: Box::new(expr),
665                        })),
666                        "for" | "foreach" => Ok(Some(AstNode::ForStatement {
667                            init: None,
668                            condition: Some(Box::new(condition)),
669                            update: None,
670                            block: Box::new(expr),
671                            label: None,
672                        })),
673                        _ => Ok(Some(AstNode::Statement(Box::new(expr)))),
674                    }
675                } else {
676                    Ok(None)
677                }
678            }
679            Rule::expression_statement => {
680                let inner = pair.into_inner().next().ok_or("Empty expression statement")?;
681                if let Some(expr) = self.build_node(inner)? {
682                    Ok(Some(AstNode::Statement(Box::new(expr))))
683                } else {
684                    Ok(None)
685                }
686            }
687            Rule::declaration_statement => {
688                let inner = pair.into_inner().next().ok_or("Empty declaration statement")?;
689                self.build_node(inner)
690            }
691            Rule::variable_declaration => {
692                let mut inner = pair.into_inner();
693                let scope_pair = inner.next().ok_or("Missing scope in variable declaration")?;
694                let scope = Arc::from(scope_pair.as_str());
695                let mut variables = Vec::new();
696                let mut initializer = None;
697
698                for p in inner {
699                    match p.as_rule() {
700                        Rule::variable_list => {
701                            for var in p.into_inner() {
702                                if let Some(v) = self.build_node(var)? {
703                                    variables.push(v);
704                                }
705                            }
706                        }
707                        Rule::expression => {
708                            initializer = self.build_node(p)?.map(Box::new);
709                        }
710                        _ => {}
711                    }
712                }
713
714                Ok(Some(AstNode::VariableDeclaration { scope, variables, initializer }))
715            }
716            Rule::sub_declaration => {
717                let inner = pair.into_inner();
718                let mut _sub_modifier = None;
719                let mut name = Arc::from("");
720                let mut prototype = None;
721                let mut attributes = Vec::new();
722                let mut body = None;
723
724                for p in inner {
725                    match p.as_rule() {
726                        Rule::sub_modifier => {
727                            _sub_modifier = Some(p.as_str().to_string());
728                        }
729                        Rule::identifier => {
730                            name = Arc::from(p.as_str());
731                        }
732                        Rule::prototype => {
733                            prototype = Some(Arc::from(p.as_str()));
734                        }
735                        Rule::signature => {
736                            prototype = Some(Arc::from(p.as_str()));
737                        }
738                        Rule::attributes => {
739                            for attr in p.into_inner() {
740                                attributes.push(Arc::from(attr.as_str()));
741                            }
742                        }
743                        Rule::block => {
744                            body = self.build_node(p)?.map(Box::new);
745                        }
746                        _ => {}
747                    }
748                }
749
750                Ok(Some(AstNode::SubDeclaration {
751                    name,
752                    prototype,
753                    attributes,
754                    body: body.unwrap_or_else(|| Box::new(AstNode::Block(vec![]))),
755                }))
756            }
757            Rule::glob => {
758                let inner = pair.into_inner().next().ok_or("Empty glob")?; // glob_pattern
759                Ok(Some(AstNode::Glob(Arc::from(inner.as_str()))))
760            }
761            Rule::readline => {
762                let mut filehandle = None;
763                for p in pair.into_inner() {
764                    if p.as_rule() == Rule::filehandle {
765                        filehandle = Some(Arc::from(p.as_str()));
766                    }
767                }
768                Ok(Some(AstNode::Readline { filehandle }))
769            }
770            Rule::format_declaration => {
771                let inner = pair.into_inner();
772                let mut name = Arc::from("");
773                let mut format_lines = Vec::new();
774
775                for p in inner {
776                    match p.as_rule() {
777                        Rule::format_name => {
778                            name = Arc::from(p.as_str());
779                        }
780                        Rule::format_lines => {
781                            for line in p.into_inner() {
782                                if line.as_rule() == Rule::format_line {
783                                    format_lines.push(Arc::from(line.as_str()));
784                                }
785                            }
786                        }
787                        _ => {}
788                    }
789                }
790
791                Ok(Some(AstNode::FormatDeclaration { name, format_lines }))
792            }
793            Rule::if_statement => {
794                let mut inner = pair.into_inner();
795                // The first item should be the expression (condition)
796                let cond_pair = inner.next().ok_or("Missing condition in if statement")?;
797                let condition =
798                    Box::new(self.build_node(cond_pair)?.ok_or("Failed to build condition node")?);
799                // The second item should be the block
800                let block_pair = inner.next().ok_or("Missing block in if statement")?;
801                let then_block =
802                    Box::new(self.build_node(block_pair)?.ok_or("Failed to build block node")?);
803                let mut elsif_clauses = Vec::new();
804                let mut else_block = None;
805
806                for p in inner {
807                    match p.as_rule() {
808                        Rule::elsif_clause => {
809                            let mut elsif_inner = p.into_inner();
810                            // First is the condition expression
811                            let cond_pair =
812                                elsif_inner.next().ok_or("Missing condition in elsif")?;
813                            let cond = self
814                                .build_node(cond_pair)?
815                                .ok_or("Failed to build elsif condition")?;
816                            // Second is the block
817                            let block_pair = elsif_inner.next().ok_or("Missing block in elsif")?;
818                            let block = self
819                                .build_node(block_pair)?
820                                .ok_or("Failed to build elsif block")?;
821                            elsif_clauses.push((cond, block));
822                        }
823                        Rule::else_clause => {
824                            let mut else_inner = p.into_inner();
825                            // The only item should be the block
826                            let else_pair = else_inner.next().ok_or("Missing block in else")?;
827                            else_block = self.build_node(else_pair)?.map(Box::new);
828                        }
829                        _ => {}
830                    }
831                }
832
833                Ok(Some(AstNode::IfStatement { condition, then_block, elsif_clauses, else_block }))
834            }
835            Rule::tie_statement => {
836                let mut inner = pair.into_inner();
837                let var_pair = inner.next().ok_or("Missing variable in tie statement")?;
838                let variable =
839                    Box::new(self.build_node(var_pair)?.ok_or("Failed to build variable node")?);
840                let class_pair = inner.next().ok_or("Missing class in tie statement")?;
841                let class =
842                    Box::new(self.build_node(class_pair)?.ok_or("Failed to build class node")?);
843                let mut args = Vec::new();
844
845                for arg in inner {
846                    if let Some(node) = self.build_node(arg)? {
847                        args.push(node);
848                    }
849                }
850
851                Ok(Some(AstNode::TieStatement { variable, class, args }))
852            }
853            Rule::untie_statement => {
854                let mut inner = pair.into_inner();
855                let var_pair = inner.next().ok_or("Missing variable in untie statement")?;
856                let variable =
857                    Box::new(self.build_node(var_pair)?.ok_or("Failed to build variable node")?);
858
859                Ok(Some(AstNode::UntieStatement { variable }))
860            }
861            Rule::tied_statement => {
862                let mut inner = pair.into_inner();
863                let var_pair = inner.next().ok_or("Missing variable in tied statement")?;
864                let variable =
865                    Box::new(self.build_node(var_pair)?.ok_or("Failed to build variable node")?);
866
867                Ok(Some(AstNode::TiedExpression { variable }))
868            }
869            Rule::given_statement => {
870                let mut inner = pair.into_inner();
871                let expr_pair = inner.next().ok_or("Missing expression in given statement")?;
872                let expression =
873                    Box::new(self.build_node(expr_pair)?.ok_or("Failed to build expression node")?);
874                let given_block = inner.next().ok_or("Missing block in given statement")?;
875
876                let mut when_clauses = Vec::new();
877                let mut default_block = None;
878
879                for p in given_block.into_inner() {
880                    match p.as_rule() {
881                        Rule::when_clause => {
882                            let mut when_inner = p.into_inner();
883                            let when_cond_pair =
884                                when_inner.next().ok_or("Missing condition in when clause")?;
885                            let cond_inner_pair =
886                                when_cond_pair.into_inner().next().ok_or("Empty when condition")?;
887                            let cond = self
888                                .build_node(cond_inner_pair)?
889                                .ok_or("Failed to build when condition")?;
890                            let block_pair =
891                                when_inner.next().ok_or("Missing block in when clause")?;
892                            let block =
893                                self.build_node(block_pair)?.ok_or("Failed to build when block")?;
894                            when_clauses.push((cond, block));
895                        }
896                        Rule::default_clause => {
897                            let mut default_inner = p.into_inner();
898                            let default_pair =
899                                default_inner.next().ok_or("Missing block in default clause")?;
900                            default_block = Some(Box::new(
901                                self.build_node(default_pair)?
902                                    .ok_or("Failed to build default block")?,
903                            ));
904                        }
905                        _ => {}
906                    }
907                }
908
909                Ok(Some(AstNode::GivenStatement { expression, when_clauses, default_block }))
910            }
911            Rule::block => {
912                let mut statements = Vec::new();
913                for inner in pair.into_inner() {
914                    if inner.as_rule() == Rule::statements {
915                        for stmt in inner.into_inner() {
916                            if let Some(node) = self.build_node(stmt)? {
917                                statements.push(node);
918                            }
919                        }
920                    }
921                }
922                Ok(Some(AstNode::Block(statements)))
923            }
924            Rule::anonymous_sub => {
925                let inner = pair.into_inner();
926                let mut prototype = None;
927                let mut attributes: Vec<Arc<str>> = Vec::new();
928                let mut body = None;
929
930                for p in inner {
931                    match p.as_rule() {
932                        Rule::prototype => {
933                            prototype = Some(Arc::from(p.as_str()));
934                        }
935                        Rule::attributes => {
936                            for attr in p.into_inner() {
937                                attributes.push(Arc::from(attr.as_str()));
938                            }
939                        }
940                        Rule::block => {
941                            body = self.build_node(p)?.map(Box::new);
942                        }
943                        _ => {}
944                    }
945                }
946
947                Ok(Some(AstNode::AnonymousSub {
948                    prototype,
949                    body: body.unwrap_or_else(|| Box::new(AstNode::Block(vec![]))),
950                }))
951            }
952            Rule::expression => self.build_expression(pair),
953            Rule::logical_or_expression => {
954                self.build_binary_expression(pair, Rule::logical_or_expression)
955            }
956            Rule::logical_xor_expression => {
957                self.build_binary_expression(pair, Rule::logical_xor_expression)
958            }
959            Rule::defined_or_expression => {
960                self.build_binary_expression(pair, Rule::defined_or_expression)
961            }
962            Rule::logical_and_expression => {
963                self.build_binary_expression(pair, Rule::logical_and_expression)
964            }
965            Rule::equality_expression => {
966                self.build_binary_expression(pair, Rule::equality_expression)
967            }
968            Rule::relational_expression => {
969                self.build_binary_expression(pair, Rule::relational_expression)
970            }
971            Rule::isa_expression => self.build_binary_expression(pair, Rule::isa_expression),
972            Rule::bitwise_expression => {
973                self.build_binary_expression(pair, Rule::bitwise_expression)
974            }
975            Rule::bitwise_string_expression => {
976                self.build_binary_expression(pair, Rule::bitwise_string_expression)
977            }
978            Rule::range_expression => self.build_binary_expression(pair, Rule::range_expression),
979            Rule::additive_expression => {
980                self.build_binary_expression(pair, Rule::additive_expression)
981            }
982            Rule::multiplicative_expression => {
983                self.build_binary_expression(pair, Rule::multiplicative_expression)
984            }
985            Rule::exponential_expression => {
986                self.build_binary_expression(pair, Rule::exponential_expression)
987            }
988            Rule::assignment_expression => {
989                let mut inner = pair.into_inner();
990                if let (Some(target_pair), Some(op_pair), Some(value_pair)) =
991                    (inner.next(), inner.next(), inner.next())
992                {
993                    let target =
994                        Box::new(self.build_node(target_pair)?.unwrap_or(AstNode::EmptyExpression));
995                    let op_str = op_pair.as_str();
996                    let op = if op_str == "_DIV_=" {
997                        Arc::from("/=")
998                    } else if op_str.contains("_DIV_") {
999                        Arc::from(op_str.replace("_DIV_", "/"))
1000                    } else {
1001                        Arc::from(op_str)
1002                    };
1003                    let value =
1004                        Box::new(self.build_node(value_pair)?.unwrap_or(AstNode::EmptyExpression));
1005                    Ok(Some(AstNode::Assignment { target, op, value }))
1006                } else {
1007                    Ok(None)
1008                }
1009            }
1010            Rule::unary_expression => {
1011                let mut inner = pair.into_inner();
1012                let first = inner.next().ok_or("Empty unary expression")?;
1013
1014                // Check if it's an operator or operand
1015                match first.as_rule() {
1016                    Rule::postfix_expression | Rule::reference => {
1017                        // No unary operator, just pass through
1018                        self.build_node(first)
1019                    }
1020                    Rule::file_test_operator => {
1021                        // It's an operator
1022                        let op = Arc::from(first.as_str());
1023                        if let Some(next_pair) = inner.next() {
1024                            if let Some(operand_node) = self.build_node(next_pair)? {
1025                                let operand = Box::new(operand_node);
1026                                Ok(Some(AstNode::UnaryOp { op, operand }))
1027                            } else {
1028                                Ok(None)
1029                            }
1030                        } else {
1031                            Ok(None)
1032                        }
1033                    }
1034                    _ => {
1035                        // It's an operator
1036                        let op = Arc::from(first.as_str());
1037                        if let Some(next_pair) = inner.next() {
1038                            if let Some(operand_node) = self.build_node(next_pair)? {
1039                                let operand = Box::new(operand_node);
1040                                Ok(Some(AstNode::UnaryOp { op, operand }))
1041                            } else {
1042                                Ok(None)
1043                            }
1044                        } else {
1045                            Ok(None)
1046                        }
1047                    }
1048                }
1049            }
1050            Rule::postfix_expression => {
1051                let mut inner = pair.into_inner();
1052                let expr_pair = inner.next().ok_or("Empty postfix expression")?;
1053                let mut expr =
1054                    self.build_node(expr_pair)?.ok_or("Failed to build base expression")?;
1055
1056                for postfix_op in inner {
1057                    if postfix_op.as_rule() == Rule::postfix_dereference {
1058                        let op_inner =
1059                            postfix_op.into_inner().next().ok_or("Empty postfix dereference")?;
1060                        match op_inner.as_rule() {
1061                            Rule::postfix_dereference => {
1062                                let deref_str = op_inner.as_str();
1063                                // Extract the dereference type after "->"
1064                                let deref_type = deref_str.strip_prefix("->").unwrap_or(deref_str);
1065                                expr = AstNode::PostfixDereference {
1066                                    expr: Box::new(expr),
1067                                    deref_type: Arc::from(deref_type),
1068                                };
1069                            }
1070                            Rule::method_call => {
1071                                let method_inner = op_inner.into_inner();
1072                                let mut method = Arc::from("");
1073                                let mut args = Vec::new();
1074
1075                                for p in method_inner {
1076                                    match p.as_rule() {
1077                                        Rule::method_name => {
1078                                            method = Arc::from(p.as_str());
1079                                        }
1080                                        Rule::function_args => {
1081                                            if let Some(arg_list) = p.into_inner().next() {
1082                                                args = self.parse_arg_list(arg_list)?;
1083                                            }
1084                                        }
1085                                        _ => {}
1086                                    }
1087                                }
1088
1089                                expr = AstNode::MethodCall { object: Box::new(expr), method, args };
1090                            }
1091                            Rule::typeglob_slot_access => {
1092                                let slot_pair = op_inner
1093                                    .into_inner()
1094                                    .next()
1095                                    .ok_or("Empty typeglob slot access")?;
1096                                let slot = Arc::from(slot_pair.as_str());
1097                                expr =
1098                                    AstNode::TypeglobSlotAccess { typeglob: Box::new(expr), slot };
1099                            }
1100                            Rule::array_access => {
1101                                let index_pair =
1102                                    op_inner.into_inner().next().ok_or("Empty array access")?;
1103                                let index_expr = self
1104                                    .build_node(index_pair)?
1105                                    .ok_or("Failed to build array index node")?;
1106                                expr = AstNode::ArrayAccess {
1107                                    array: Box::new(expr),
1108                                    index: Box::new(index_expr),
1109                                };
1110                            }
1111                            Rule::hash_access => {
1112                                let key_pair =
1113                                    op_inner.into_inner().next().ok_or("Empty hash access")?;
1114                                let key_expr = self
1115                                    .build_node(key_pair)?
1116                                    .ok_or("Failed to build hash key node")?;
1117                                expr = AstNode::HashAccess {
1118                                    hash: Box::new(expr),
1119                                    key: Box::new(key_expr),
1120                                };
1121                            }
1122                            Rule::function_call => {
1123                                let args = if let Some(args_pair) = op_inner.into_inner().next() {
1124                                    self.parse_arg_list(args_pair)?
1125                                } else {
1126                                    Vec::new()
1127                                };
1128                                expr = AstNode::FunctionCall { function: Box::new(expr), args };
1129                            }
1130                            _ => {}
1131                        }
1132                    }
1133                }
1134
1135                Ok(Some(expr))
1136            }
1137            Rule::scalar_variable => Ok(Some(AstNode::ScalarVariable(Arc::from(pair.as_str())))),
1138            Rule::array_variable => Ok(Some(AstNode::ArrayVariable(Arc::from(pair.as_str())))),
1139            Rule::hash_variable => Ok(Some(AstNode::HashVariable(Arc::from(pair.as_str())))),
1140            Rule::typeglob_variable => {
1141                Ok(Some(AstNode::TypeglobVariable(Arc::from(pair.as_str()))))
1142            }
1143            Rule::number => Ok(Some(AstNode::Number(Arc::from(pair.as_str())))),
1144            Rule::identifier => Ok(Some(AstNode::Identifier(Arc::from(pair.as_str())))),
1145            Rule::qualified_name => Ok(Some(AstNode::Identifier(Arc::from(pair.as_str())))),
1146            Rule::qualified_name_or_identifier => {
1147                Ok(Some(AstNode::Identifier(Arc::from(pair.as_str()))))
1148            }
1149            Rule::class_method_call => {
1150                let inner = pair.into_inner();
1151                let mut parts = Vec::new();
1152                let mut args = Vec::new();
1153
1154                for p in inner {
1155                    match p.as_rule() {
1156                        Rule::identifier => {
1157                            parts.push(p.as_str());
1158                        }
1159                        Rule::method_name => {
1160                            parts.push(p.as_str());
1161                        }
1162                        Rule::function_args => {
1163                            if let Some(arg_list) = p.into_inner().next() {
1164                                for arg_pair in arg_list.into_inner() {
1165                                    if let Ok(Some(arg)) = self.build_node(arg_pair) {
1166                                        args.push(arg);
1167                                    }
1168                                }
1169                            }
1170                        }
1171                        _ => {}
1172                    }
1173                }
1174
1175                // Build qualified name from parts except the last one which is the method
1176                if parts.len() >= 2 {
1177                    let method_name = Arc::from(parts.pop().ok_or("Empty parts list")?);
1178                    let class_name = parts.join("::");
1179                    let class_node = AstNode::Identifier(Arc::from(class_name));
1180
1181                    Ok(Some(AstNode::MethodCall {
1182                        object: Box::new(class_node),
1183                        method: method_name,
1184                        args,
1185                    }))
1186                } else {
1187                    // Fallback for malformed class method calls
1188                    Ok(Some(AstNode::Identifier(Arc::from(""))))
1189                }
1190            }
1191            Rule::user_function_call => {
1192                let inner = pair.into_inner();
1193                let mut name = Arc::from("");
1194                let mut args = Vec::new();
1195
1196                for p in inner {
1197                    match p.as_rule() {
1198                        Rule::identifier => {
1199                            name = Arc::from(p.as_str());
1200                        }
1201                        Rule::list_op_args => {
1202                            for arg_pair in p.into_inner() {
1203                                if arg_pair.as_rule() == Rule::list_op_arg {
1204                                    for expr_pair in arg_pair.into_inner() {
1205                                        if let Ok(Some(arg)) = self.build_node(expr_pair) {
1206                                            args.push(arg);
1207                                        }
1208                                    }
1209                                }
1210                            }
1211                        }
1212                        _ => {}
1213                    }
1214                }
1215
1216                Ok(Some(AstNode::FunctionCall {
1217                    function: Box::new(AstNode::Identifier(name)),
1218                    args,
1219                }))
1220            }
1221            Rule::builtin_list_op => {
1222                let inner = pair.into_inner();
1223                let mut name = Arc::from("");
1224                let mut args = Vec::new();
1225
1226                for p in inner {
1227                    match p.as_rule() {
1228                        Rule::builtin_list_op_name => {
1229                            name = Arc::from(p.as_str().trim());
1230                        }
1231                        Rule::list_op_args => {
1232                            for arg_pair in p.into_inner() {
1233                                if arg_pair.as_rule() == Rule::list_op_arg {
1234                                    for expr_pair in arg_pair.into_inner() {
1235                                        if let Ok(Some(arg)) = self.build_node(expr_pair) {
1236                                            args.push(arg);
1237                                        }
1238                                    }
1239                                }
1240                            }
1241                        }
1242                        _ => {}
1243                    }
1244                }
1245
1246                Ok(Some(AstNode::BuiltinListOp { name, args }))
1247            }
1248            Rule::special_literal => Ok(Some(AstNode::SpecialLiteral(Arc::from(pair.as_str())))),
1249            Rule::string => {
1250                // string can be single or double quoted, need to check inner
1251                let inner_pairs: Vec<_> = pair.into_inner().collect();
1252                if let Some(inner) = inner_pairs.into_iter().next() {
1253                    self.build_node(inner)
1254                } else {
1255                    Ok(Some(AstNode::String(Arc::from(""))))
1256                }
1257            }
1258            Rule::single_quoted_string => Ok(Some(AstNode::String(Arc::from(pair.as_str())))),
1259            Rule::double_quoted_string => {
1260                // Parse interpolated content
1261                let mut parts = Vec::new();
1262
1263                if let Some(content_pair) = pair.into_inner().next() {
1264                    // double_string_content
1265                    for part in content_pair.into_inner() {
1266                        // Each part is a double_string_part
1267                        for inner in part.into_inner() {
1268                            match inner.as_rule() {
1269                                Rule::double_string_chars => {
1270                                    parts.push(AstNode::String(Arc::from(inner.as_str())));
1271                                }
1272                                Rule::interpolation => {
1273                                    if let Ok(Some(interp_node)) = self.build_node(inner) {
1274                                        parts.push(interp_node);
1275                                    }
1276                                }
1277                                _ => {}
1278                            }
1279                        }
1280                    }
1281
1282                    if parts.is_empty() {
1283                        Ok(Some(AstNode::String(Arc::from(""))))
1284                    } else if parts.len() == 1 && matches!(parts[0], AstNode::String(_)) {
1285                        Ok(Some(parts.into_iter().next().ok_or("Empty parts list")?))
1286                    } else {
1287                        Ok(Some(AstNode::InterpolatedString(parts)))
1288                    }
1289                } else {
1290                    // Empty string
1291                    Ok(Some(AstNode::String(Arc::from(""))))
1292                }
1293            }
1294            Rule::q_string => {
1295                // q strings don't interpolate, so we just return the whole construct as a string
1296                // Special handling for heredoc placeholders
1297                let content = pair.as_str();
1298                if content.contains("__HEREDOC__") {
1299                    // Extract actual heredoc content from q{__HEREDOC__content__HEREDOC__}
1300                    if let Some(start_idx) = content.find("{__HEREDOC__")
1301                        && let Some(end_idx) = content.rfind("__HEREDOC__}")
1302                    {
1303                        let heredoc_content = &content[start_idx + 12..end_idx];
1304                        return Ok(Some(AstNode::String(Arc::from(heredoc_content))));
1305                    }
1306                }
1307                Ok(Some(AstNode::String(Arc::from(content))))
1308            }
1309            Rule::qq_string => {
1310                // qq strings interpolate, so we mark them differently
1311                // Special handling for heredoc placeholders
1312                let content = pair.as_str();
1313                if content.contains("__HEREDOC__") {
1314                    // Extract actual heredoc content from qq{__HEREDOC__content__HEREDOC__}
1315                    if let Some(start_idx) = content.find("{__HEREDOC__")
1316                        && let Some(end_idx) = content.rfind("__HEREDOC__}")
1317                    {
1318                        let heredoc_content = &content[start_idx + 12..end_idx];
1319                        return Ok(Some(AstNode::QqString(Arc::from(heredoc_content))));
1320                    }
1321                }
1322                Ok(Some(AstNode::QqString(Arc::from(content))))
1323            }
1324            Rule::qx_string => {
1325                // qx strings are for command execution
1326                Ok(Some(AstNode::QxString(Arc::from(pair.as_str()))))
1327            }
1328            Rule::backtick_string => {
1329                // Backtick strings are also for command execution
1330                Ok(Some(AstNode::QxString(Arc::from(pair.as_str()))))
1331            }
1332            Rule::heredoc_placeholder => {
1333                // Heredoc placeholders are replaced with actual content during post-processing
1334                Ok(Some(AstNode::String(Arc::from(pair.as_str()))))
1335            }
1336            Rule::heredoc => {
1337                let inner = pair.into_inner();
1338                let mut indented = false;
1339                let mut marker = Arc::from("");
1340                let mut quoted = false;
1341
1342                for p in inner {
1343                    match p.as_rule() {
1344                        Rule::heredoc_indented => {
1345                            indented = true;
1346                        }
1347                        Rule::heredoc_delimiter => {
1348                            let delimiter_str = p.as_str();
1349                            let delimiter_inner = p.into_inner().next();
1350                            if let Some(d) = delimiter_inner {
1351                                match d.as_rule() {
1352                                    Rule::heredoc_single_quoted => {
1353                                        quoted = true;
1354                                        marker = Arc::from(d.as_str().trim_matches('\''));
1355                                    }
1356                                    Rule::heredoc_double_quoted => {
1357                                        marker = Arc::from(d.as_str().trim_matches('"'));
1358                                    }
1359                                    Rule::heredoc_backtick => {
1360                                        marker = Arc::from(d.as_str().trim_matches('`'));
1361                                    }
1362                                    Rule::heredoc_escaped => {
1363                                        marker = Arc::from(d.as_str().trim_start_matches('\\'));
1364                                    }
1365                                    Rule::bare_heredoc_delimiter => {
1366                                        marker = Arc::from(d.as_str());
1367                                    }
1368                                    _ => {}
1369                                }
1370                            } else {
1371                                marker = Arc::from(delimiter_str);
1372                            }
1373                        }
1374                        _ => {}
1375                    }
1376                }
1377
1378                // Note: In a real implementation, we would need to collect the heredoc content
1379                // from subsequent lines until we find the marker. For now, we just create
1380                // a placeholder.
1381                Ok(Some(AstNode::Heredoc {
1382                    marker,
1383                    indented,
1384                    quoted,
1385                    content: Arc::from(""), // This would be filled by a stateful parser
1386                }))
1387            }
1388            Rule::list => {
1389                let mut elements = Vec::new();
1390                for inner in pair.into_inner() {
1391                    if inner.as_rule() == Rule::list_elements {
1392                        for elem in inner.into_inner() {
1393                            if let Some(node) = self.build_node(elem)? {
1394                                elements.push(node);
1395                            }
1396                        }
1397                    }
1398                }
1399                Ok(Some(AstNode::List(elements)))
1400            }
1401            Rule::array_ref => {
1402                let mut elements = Vec::new();
1403                for inner in pair.into_inner() {
1404                    if inner.as_rule() == Rule::list_elements {
1405                        for elem in inner.into_inner() {
1406                            if let Some(node) = self.build_node(elem)? {
1407                                elements.push(node);
1408                            }
1409                        }
1410                    }
1411                }
1412                Ok(Some(AstNode::ArrayRef(elements)))
1413            }
1414            Rule::hash_ref => {
1415                let mut elements = Vec::new();
1416                for inner in pair.into_inner() {
1417                    if inner.as_rule() == Rule::hash_elements {
1418                        for elem in inner.into_inner() {
1419                            if let Some(node) = self.build_node(elem)? {
1420                                elements.push(node);
1421                            }
1422                        }
1423                    }
1424                }
1425                Ok(Some(AstNode::HashRef(elements)))
1426            }
1427            Rule::begin_block => {
1428                let inner = pair.into_inner().next().ok_or("Empty begin block")?; // get the block
1429                let block = self.build_node(inner)?.map(Box::new);
1430                Ok(block.map(AstNode::BeginBlock))
1431            }
1432            Rule::end_block => {
1433                let inner = pair.into_inner().next().ok_or("Empty end block")?; // get the block
1434                let block = self.build_node(inner)?.map(Box::new);
1435                Ok(block.map(AstNode::EndBlock))
1436            }
1437            Rule::check_block => {
1438                let inner = pair.into_inner().next().ok_or("Empty check block")?; // get the block
1439                let block = self.build_node(inner)?.map(Box::new);
1440                Ok(block.map(AstNode::CheckBlock))
1441            }
1442            Rule::init_block => {
1443                let inner = pair.into_inner().next().ok_or("Empty init block")?; // get the block
1444                let block = self.build_node(inner)?.map(Box::new);
1445                Ok(block.map(AstNode::InitBlock))
1446            }
1447            Rule::unitcheck_block => {
1448                let inner = pair.into_inner().next().ok_or("Empty unitcheck block")?; // get the block
1449                let block = self.build_node(inner)?.map(Box::new);
1450                Ok(block.map(AstNode::UnitcheckBlock))
1451            }
1452            Rule::qw_list => {
1453                let mut words = Vec::new();
1454                for inner in pair.into_inner() {
1455                    match inner.as_rule() {
1456                        Rule::qw_paren_items
1457                        | Rule::qw_bracket_items
1458                        | Rule::qw_brace_items
1459                        | Rule::qw_angle_items
1460                        | Rule::qw_delimited_items => {
1461                            // Split the content by whitespace
1462                            let content = inner.as_str();
1463                            words.extend(content.split_whitespace().map(Arc::from));
1464                        }
1465                        _ => {}
1466                    }
1467                }
1468                Ok(Some(AstNode::QwList(words)))
1469            }
1470            Rule::do_block => {
1471                let inner = pair.into_inner().next().ok_or("Empty do block")?;
1472                let expr = self.build_node(inner)?.map(Box::new);
1473                Ok(expr.map(AstNode::DoBlock))
1474            }
1475            Rule::eval_statement => {
1476                let inner = pair.into_inner().next().ok_or("Empty eval statement")?;
1477                let expr = self.build_node(inner)?;
1478                Ok(expr.map(|e| match e {
1479                    AstNode::Block(_) => AstNode::EvalBlock(Box::new(e)),
1480                    _ => AstNode::EvalString(Box::new(e)),
1481                }))
1482            }
1483            Rule::goto_statement => {
1484                let inner = pair.into_inner().next().ok_or("Empty goto statement")?;
1485                let target = match inner.as_rule() {
1486                    Rule::goto_target => Arc::from(inner.as_str()),
1487                    _ => {
1488                        // For expressions, we need to evaluate them
1489                        if let Some(expr) = self.build_node(inner)? {
1490                            Arc::from(format!("{:?}", expr)) // Simple representation for now
1491                        } else {
1492                            Arc::from("")
1493                        }
1494                    }
1495                };
1496                Ok(Some(AstNode::GotoStatement { target }))
1497            }
1498            Rule::try_catch_statement => {
1499                let mut inner = pair.into_inner();
1500                let try_pair = inner.next().ok_or("Missing try block")?;
1501                let try_block =
1502                    Box::new(self.build_node(try_pair)?.ok_or("Failed to build try block")?);
1503                let mut catch_clauses = Vec::new();
1504                let mut finally_block = None;
1505
1506                for p in inner {
1507                    match p.as_rule() {
1508                        Rule::catch_clause => {
1509                            let catch_inner = p.into_inner();
1510                            let mut param = None;
1511                            let mut block = None;
1512
1513                            for cp in catch_inner {
1514                                match cp.as_rule() {
1515                                    Rule::catch_parameter => {
1516                                        param = Some(Arc::from(cp.as_str()));
1517                                    }
1518                                    Rule::block => {
1519                                        block = Some(
1520                                            self.build_node(cp)?
1521                                                .ok_or("Failed to build catch block")?,
1522                                        );
1523                                    }
1524                                    _ => {}
1525                                }
1526                            }
1527
1528                            if let Some(b) = block {
1529                                catch_clauses.push((param, b));
1530                            }
1531                        }
1532                        Rule::finally_clause => {
1533                            let mut finally_inner = p.into_inner();
1534                            if let Some(block_pair) = finally_inner.next() {
1535                                finally_block = Some(Box::new(
1536                                    self.build_node(block_pair)?
1537                                        .ok_or("Failed to build finally block")?,
1538                                ));
1539                            }
1540                        }
1541                        _ => {}
1542                    }
1543                }
1544
1545                Ok(Some(AstNode::TryCatch { try_block, catch_clauses, finally_block }))
1546            }
1547            Rule::defer_statement => {
1548                let mut inner = pair.into_inner();
1549                let block_pair = inner.next().ok_or("Missing block in defer statement")?;
1550                let block =
1551                    Box::new(self.build_node(block_pair)?.ok_or("Failed to build defer block")?);
1552                Ok(Some(AstNode::DeferStatement(block)))
1553            }
1554            Rule::class_declaration => {
1555                let mut inner = pair.into_inner();
1556                let name_pair = inner.next().ok_or("Missing class name")?;
1557                let name = Arc::from(name_pair.as_str());
1558                let mut version = None;
1559                let mut superclass = None;
1560                let mut body = Vec::new();
1561
1562                for p in inner {
1563                    match p.as_rule() {
1564                        Rule::version => {
1565                            version = Some(Arc::from(p.as_str()));
1566                        }
1567                        Rule::superclass => {
1568                            let super_pair =
1569                                p.into_inner().next().ok_or("Missing superclass name")?;
1570                            superclass = Some(Arc::from(super_pair.as_str()));
1571                        }
1572                        Rule::class_body => {
1573                            for member in p.into_inner() {
1574                                if let Some(node) = self.build_node(member)? {
1575                                    body.push(node);
1576                                }
1577                            }
1578                        }
1579                        _ => {}
1580                    }
1581                }
1582
1583                Ok(Some(AstNode::ClassDeclaration { name, version, superclass, body }))
1584            }
1585            Rule::method_declaration => {
1586                let mut inner = pair.into_inner();
1587                let name_pair = inner.next().ok_or("Missing method name")?;
1588                let name = Arc::from(name_pair.as_str());
1589                let mut signature = None;
1590                let mut attributes = Vec::new();
1591                let mut body = None;
1592
1593                for p in inner {
1594                    match p.as_rule() {
1595                        Rule::signature => {
1596                            signature = Some(Arc::from(p.as_str()));
1597                        }
1598                        Rule::attributes => {
1599                            for attr in p.into_inner() {
1600                                attributes.push(Arc::from(attr.as_str()));
1601                            }
1602                        }
1603                        Rule::block => {
1604                            body = Some(Box::new(
1605                                self.build_node(p)?.ok_or("Failed to build method body")?,
1606                            ));
1607                        }
1608                        _ => {}
1609                    }
1610                }
1611
1612                Ok(Some(AstNode::MethodDeclaration {
1613                    name,
1614                    signature,
1615                    attributes,
1616                    body: body.unwrap_or_else(|| Box::new(AstNode::Block(vec![]))),
1617                }))
1618            }
1619            Rule::field_declaration => {
1620                let mut inner = pair.into_inner();
1621                let name_pair = inner.next().ok_or("Missing field name")?;
1622                let name = Arc::from(name_pair.as_str());
1623                let mut attributes = Vec::new();
1624                let mut default = None;
1625
1626                for p in inner {
1627                    match p.as_rule() {
1628                        Rule::field_attributes => {
1629                            for attr in p.into_inner() {
1630                                attributes.push(Arc::from(attr.as_str()));
1631                            }
1632                        }
1633                        Rule::default_value => {
1634                            if let Some(expr) = p.into_inner().next() {
1635                                default = Some(Box::new(
1636                                    self.build_node(expr)?
1637                                        .ok_or("Failed to build field default value")?,
1638                                ));
1639                            }
1640                        }
1641                        _ => {}
1642                    }
1643                }
1644
1645                Ok(Some(AstNode::FieldDeclaration { name, attributes, default }))
1646            }
1647            Rule::return_statement => {
1648                let mut inner = pair.into_inner();
1649                // Return statement might have an optional expression
1650                if let Some(expr_pair) = inner.next() {
1651                    if expr_pair.as_rule() != Rule::semicolon {
1652                        let expr = self.build_node(expr_pair)?;
1653                        Ok(Some(AstNode::ReturnStatement { value: expr.map(Box::new) }))
1654                    } else {
1655                        Ok(Some(AstNode::ReturnStatement { value: None }))
1656                    }
1657                } else {
1658                    Ok(Some(AstNode::ReturnStatement { value: None }))
1659                }
1660            }
1661            Rule::pod_section => Ok(Some(AstNode::Pod(Arc::from(pair.as_str())))),
1662            Rule::data_section => Ok(Some(AstNode::DataSection(Arc::from(pair.as_str())))),
1663            Rule::end_section => Ok(Some(AstNode::EndSection(Arc::from(pair.as_str())))),
1664            Rule::labeled_block => {
1665                let mut inner = pair.into_inner();
1666                let label_pair = inner.next().ok_or("Missing label in labeled block")?;
1667                let label = Arc::from(label_pair.as_str().trim_end_matches(':'));
1668                let block_pair = inner.next().ok_or("Missing block in labeled block")?;
1669                let block = self.build_node(block_pair)?.map(Box::new);
1670                Ok(block.map(|b| AstNode::LabeledBlock { label, block: b }))
1671            }
1672            Rule::comment => Ok(Some(AstNode::Comment(Arc::from(pair.as_str())))),
1673            Rule::semicolon | Rule::WHITESPACE => Ok(None),
1674            Rule::standalone_expression => {
1675                let inner = pair.into_inner().next().ok_or("Empty standalone expression")?;
1676                self.build_node(inner)
1677            }
1678            Rule::regex => {
1679                let mut inner = pair.into_inner();
1680                if let Some(first) = inner.next() {
1681                    match first.as_rule() {
1682                        Rule::match_regex => {
1683                            let mut match_inner = first.into_inner();
1684                            let pattern = match_inner
1685                                .next()
1686                                .map(|p| Arc::from(p.as_str()))
1687                                .unwrap_or_else(|| Arc::from(""));
1688                            let flags = match_inner
1689                                .next()
1690                                .map(|p| Arc::from(p.as_str()))
1691                                .unwrap_or_else(|| Arc::from(""));
1692
1693                            // Extract named groups from pattern
1694                            let named_groups = self.extract_named_groups(&pattern);
1695
1696                            Ok(Some(AstNode::Regex { pattern, flags, named_groups }))
1697                        }
1698                        _ => {
1699                            let pattern = Arc::from(first.as_str());
1700                            let flags = inner
1701                                .next()
1702                                .map(|p| Arc::from(p.as_str()))
1703                                .unwrap_or_else(|| Arc::from(""));
1704                            let named_groups = self.extract_named_groups(&pattern);
1705                            Ok(Some(AstNode::Regex { pattern, flags, named_groups }))
1706                        }
1707                    }
1708                } else {
1709                    Ok(Some(AstNode::Regex {
1710                        pattern: Arc::from(""),
1711                        flags: Arc::from(""),
1712                        named_groups: Vec::new(),
1713                    }))
1714                }
1715            }
1716            Rule::substitution => {
1717                let inner = pair.into_inner();
1718                let mut pattern = Arc::from("");
1719                let mut replacement = Arc::from("");
1720                let mut flags = Arc::from("");
1721
1722                for p in inner {
1723                    match p.as_rule() {
1724                        Rule::sub_pattern => {
1725                            pattern = Arc::from(p.as_str());
1726                        }
1727                        Rule::replacement => {
1728                            replacement = Arc::from(p.as_str());
1729                        }
1730                        Rule::regex_flags => {
1731                            flags = Arc::from(p.as_str());
1732                        }
1733                        _ => {}
1734                    }
1735                }
1736
1737                Ok(Some(AstNode::Substitution { pattern, replacement, flags }))
1738            }
1739            Rule::transliteration => {
1740                let inner = pair.into_inner();
1741                let mut search_list = Arc::from("");
1742                let mut replace_list = Arc::from("");
1743                let mut flags = Arc::from("");
1744
1745                for p in inner {
1746                    match p.as_rule() {
1747                        Rule::search_list => {
1748                            search_list = Arc::from(p.as_str());
1749                        }
1750                        Rule::replace_list => {
1751                            replace_list = Arc::from(p.as_str());
1752                        }
1753                        Rule::trans_flags => {
1754                            flags = Arc::from(p.as_str());
1755                        }
1756                        _ => {}
1757                    }
1758                }
1759
1760                Ok(Some(AstNode::Transliteration { search_list, replace_list, flags }))
1761            }
1762            Rule::while_statement => {
1763                let inner = pair.into_inner();
1764                let mut label = None;
1765                let mut condition = None;
1766                let mut block = None;
1767
1768                for p in inner {
1769                    match p.as_rule() {
1770                        Rule::label => {
1771                            label = Some(Arc::from(p.as_str().trim_end_matches(':')));
1772                        }
1773                        Rule::expression => {
1774                            condition = Some(Box::new(
1775                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1776                            ));
1777                        }
1778                        Rule::block => {
1779                            block = Some(Box::new(
1780                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1781                            ));
1782                        }
1783                        _ => {}
1784                    }
1785                }
1786
1787                Ok(Some(AstNode::WhileStatement {
1788                    label,
1789                    condition: condition.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1790                    block: block.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1791                }))
1792            }
1793            Rule::until_statement => {
1794                let inner = pair.into_inner();
1795                let mut label = None;
1796                let mut condition = None;
1797                let mut block = None;
1798
1799                for p in inner {
1800                    match p.as_rule() {
1801                        Rule::label => {
1802                            label = Some(Arc::from(p.as_str().trim_end_matches(':')));
1803                        }
1804                        Rule::expression => {
1805                            condition = Some(Box::new(
1806                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1807                            ));
1808                        }
1809                        Rule::block => {
1810                            block = Some(Box::new(
1811                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1812                            ));
1813                        }
1814                        _ => {}
1815                    }
1816                }
1817
1818                Ok(Some(AstNode::UntilStatement {
1819                    label,
1820                    condition: condition.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1821                    block: block.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1822                }))
1823            }
1824            Rule::unless_statement => {
1825                let mut inner = pair.into_inner();
1826                let cond_pair = inner.next().ok_or("Missing condition in unless statement")?;
1827                let condition =
1828                    Box::new(self.build_node(cond_pair)?.unwrap_or(AstNode::EmptyExpression));
1829                let block_pair = inner.next().ok_or("Missing block in unless statement")?;
1830                let block =
1831                    Box::new(self.build_node(block_pair)?.unwrap_or(AstNode::EmptyExpression));
1832                let mut else_block = None;
1833
1834                // Check for else clause
1835                if let Some(else_clause) = inner.next()
1836                    && else_clause.as_rule() == Rule::else_clause
1837                {
1838                    let mut else_inner = else_clause.into_inner();
1839                    if let Some(else_block_pair) = else_inner.next() {
1840                        else_block = Some(Box::new(
1841                            self.build_node(else_block_pair)?.unwrap_or(AstNode::EmptyExpression),
1842                        ));
1843                    }
1844                }
1845
1846                Ok(Some(AstNode::UnlessStatement { condition, block, else_block }))
1847            }
1848            Rule::foreach_statement => {
1849                let inner = pair.into_inner();
1850                let mut label = None;
1851                let mut variable = None;
1852                let mut list = None;
1853                let mut block = None;
1854                let mut declarator = None;
1855
1856                for p in inner {
1857                    match p.as_rule() {
1858                        Rule::label => {
1859                            label = Some(Arc::from(p.as_str().trim_end_matches(':')));
1860                        }
1861                        Rule::loop_variable_declarator => {
1862                            declarator = Some(Arc::from(p.as_str()));
1863                        }
1864                        Rule::variable => {
1865                            variable = Some(Box::new(
1866                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1867                            ));
1868                        }
1869                        Rule::expression => {
1870                            list = Some(Box::new(
1871                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1872                            ));
1873                        }
1874                        Rule::block => {
1875                            block = Some(Box::new(
1876                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1877                            ));
1878                        }
1879                        _ => {}
1880                    }
1881                }
1882
1883                let final_variable = if let Some(decl) = declarator {
1884                    variable.map(|var| {
1885                        Box::new(AstNode::VariableDeclaration {
1886                            scope: decl,
1887                            variables: vec![*var],
1888                            initializer: None,
1889                        })
1890                    })
1891                } else {
1892                    variable
1893                };
1894
1895                Ok(Some(AstNode::ForeachStatement {
1896                    label,
1897                    variable: final_variable,
1898                    list: list.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1899                    block: block.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1900                }))
1901            }
1902            Rule::for_statement => {
1903                let inner = pair.into_inner();
1904                let mut label = None;
1905                let mut init = None;
1906                let mut condition = None;
1907                let mut update = None;
1908                let mut block = None;
1909                let mut variable = None;
1910                let mut list = None;
1911                let mut declarator = None;
1912
1913                // Determine if this is a C-style or foreach-style for loop
1914                let is_c_style = inner.clone().any(|p| p.as_rule() == Rule::for_init);
1915
1916                // Parse for loop components
1917                for p in inner {
1918                    match p.as_rule() {
1919                        Rule::label => {
1920                            label = Some(Arc::from(p.as_str().trim_end_matches(':')));
1921                        }
1922                        Rule::for_init => {
1923                            init = self.build_node(p)?.map(Box::new);
1924                        }
1925                        Rule::assignment_expression => {
1926                            // For C-style initialization without for_init wrapper
1927                            if init.is_none() && condition.is_none() {
1928                                init = self.build_node(p)?.map(Box::new);
1929                            }
1930                        }
1931                        Rule::expression => {
1932                            if is_c_style {
1933                                // C-style: condition and update
1934                                if condition.is_none() {
1935                                    condition = self.build_node(p)?.map(Box::new);
1936                                } else if update.is_none() {
1937                                    update = self.build_node(p)?.map(Box::new);
1938                                }
1939                            } else {
1940                                // foreach-style: list expression
1941                                list = Some(Box::new(
1942                                    self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1943                                ));
1944                            }
1945                        }
1946                        Rule::variable => {
1947                            variable = Some(Box::new(
1948                                self.build_node(p)?.unwrap_or(AstNode::EmptyExpression),
1949                            ));
1950                        }
1951                        Rule::loop_variable_declarator => {
1952                            declarator = Some(Arc::from(p.as_str()));
1953                        }
1954                        Rule::block => {
1955                            block = self.build_node(p)?.map(Box::new);
1956                        }
1957                        _ => {}
1958                    }
1959                }
1960
1961                if is_c_style || init.is_some() || condition.is_some() || update.is_some() {
1962                    // C-style for loop
1963                    Ok(Some(AstNode::ForStatement {
1964                        label,
1965                        init,
1966                        condition,
1967                        update,
1968                        block: block.unwrap_or_else(|| Box::new(AstNode::Block(vec![]))),
1969                    }))
1970                } else {
1971                    // foreach-style for loop - use ForeachStatement AST node
1972                    // If there's a declarator, wrap the variable in a declaration
1973                    let final_variable = if let Some(decl) = declarator {
1974                        variable.map(|var| {
1975                            Box::new(AstNode::VariableDeclaration {
1976                                scope: decl,
1977                                variables: vec![*var],
1978                                initializer: None,
1979                            })
1980                        })
1981                    } else {
1982                        variable
1983                    };
1984
1985                    Ok(Some(AstNode::ForeachStatement {
1986                        label,
1987                        variable: final_variable,
1988                        list: list.unwrap_or_else(|| Box::new(AstNode::EmptyExpression)),
1989                        block: block.unwrap_or_else(|| Box::new(AstNode::Block(vec![]))),
1990                    }))
1991                }
1992            }
1993            Rule::package_declaration => {
1994                let inner = pair.into_inner();
1995                let mut name = Arc::from("");
1996                let mut version = None;
1997                let mut block = None;
1998
1999                for p in inner {
2000                    match p.as_rule() {
2001                        Rule::qualified_name => name = Arc::from(p.as_str()),
2002                        Rule::version => version = Some(Arc::from(p.as_str())),
2003                        Rule::block => block = self.build_node(p)?.map(Box::new),
2004                        Rule::semicolon => {}
2005                        _ => {}
2006                    }
2007                }
2008                Ok(Some(AstNode::PackageDeclaration { name, version, block }))
2009            }
2010            Rule::use_statement => {
2011                let inner = pair.into_inner();
2012
2013                let mut module = Arc::from("");
2014                let mut version = None;
2015                let mut import_list = Vec::new();
2016
2017                for p in inner {
2018                    match p.as_rule() {
2019                        Rule::module_name => module = Arc::from(p.as_str()),
2020                        Rule::version => version = Some(Arc::from(p.as_str())),
2021                        Rule::import_list => {
2022                            for item in p.into_inner() {
2023                                if item.as_rule() == Rule::import_items {
2024                                    for import_item in item.into_inner() {
2025                                        if import_item.as_rule() == Rule::import_item {
2026                                            import_list.push(Arc::from(import_item.as_str()));
2027                                        }
2028                                    }
2029                                }
2030                            }
2031                        }
2032                        _ => {}
2033                    }
2034                }
2035
2036                Ok(Some(AstNode::UseStatement { module, version, import_list }))
2037            }
2038            Rule::require_statement => {
2039                let inner = pair.into_inner();
2040
2041                let mut module = Arc::from("");
2042
2043                for p in inner {
2044                    match p.as_rule() {
2045                        Rule::module_name => module = Arc::from(p.as_str()),
2046                        Rule::expression => {
2047                            // For require expressions, we'll use the expression as the module
2048                            if let Some(expr) = self.build_node(p)? {
2049                                module = Arc::from(Self::node_to_sexp(&expr));
2050                            }
2051                        }
2052                        _ => {}
2053                    }
2054                }
2055
2056                Ok(Some(AstNode::RequireStatement { module }))
2057            }
2058            Rule::interpolation => {
2059                // Handle interpolation within strings
2060                let inner = pair.into_inner().next().ok_or("Empty interpolation")?;
2061                self.build_node(inner)
2062            }
2063            Rule::complex_scalar_interpolation => {
2064                // ${expr} form
2065                let inner = pair.into_inner().next().ok_or("Empty complex scalar interpolation")?;
2066                self.build_node(inner)
2067            }
2068            Rule::complex_array_interpolation => {
2069                // @{[expr]} form
2070                let inner = pair.into_inner().next().ok_or("Empty complex array interpolation")?;
2071                self.build_node(inner)
2072            }
2073            Rule::reference => {
2074                // Handle variable references
2075                let inner = pair.into_inner().next().ok_or("Empty reference")?;
2076                self.build_node(inner)
2077            }
2078            Rule::dereference => {
2079                let inner = pair.into_inner().next().ok_or("Empty dereference")?;
2080                self.build_node(inner)
2081            }
2082            Rule::scalar_reference => {
2083                // Since these are atomic rules, use the whole pair's text
2084                Ok(Some(AstNode::ScalarReference(Arc::from(pair.as_str()))))
2085            }
2086            Rule::array_reference => {
2087                // Since these are atomic rules, use the whole pair's text
2088                Ok(Some(AstNode::ArrayReference(Arc::from(pair.as_str()))))
2089            }
2090            Rule::hash_reference => {
2091                // Since these are atomic rules, use the whole pair's text
2092                Ok(Some(AstNode::HashReference(Arc::from(pair.as_str()))))
2093            }
2094            Rule::subroutine_reference => {
2095                // Since these are atomic rules, use the whole pair's text
2096                Ok(Some(AstNode::SubroutineReference(Arc::from(pair.as_str()))))
2097            }
2098            Rule::glob_reference => {
2099                // Since these are atomic rules, use the whole pair's text
2100                Ok(Some(AstNode::GlobReference(Arc::from(pair.as_str()))))
2101            }
2102            Rule::scalar_dereference => self.build_dereference_node(pair, "$"),
2103            Rule::array_dereference => self.build_dereference_node(pair, "@"),
2104            Rule::hash_dereference => self.build_dereference_node(pair, "%"),
2105            Rule::code_dereference => self.build_dereference_node(pair, "&"),
2106            Rule::glob_dereference => self.build_dereference_node(pair, "*"),
2107            Rule::primary_expression => {
2108                // Handle primary expressions including parenthesized expressions
2109                let inner: Vec<_> = pair.into_inner().collect();
2110                if inner.is_empty() {
2111                    Ok(None)
2112                } else if inner.len() == 1 {
2113                    let first = inner.into_iter().next().ok_or("Expected exactly one element")?;
2114                    // Check if it's a parenthesized expression
2115                    match first.as_rule() {
2116                        Rule::expression => {
2117                            // It's a parenthesized expression, just unwrap it
2118                            self.build_node(first)
2119                        }
2120                        _ => self.build_node(first),
2121                    }
2122                } else {
2123                    // Handle multiple parts (shouldn't happen for primary_expression)
2124                    let mut result = None;
2125                    for p in inner {
2126                        if p.as_str() == "(" || p.as_str() == ")" {
2127                            // Skip parentheses tokens
2128                            continue;
2129                        }
2130                        if let Some(node) = self.build_node(p)? {
2131                            result = Some(node);
2132                        }
2133                    }
2134                    Ok(result)
2135                }
2136            }
2137            _ => {
2138                // For unhandled rules, try to process inner pairs
2139                let inner: Vec<_> = pair.into_inner().collect();
2140                if inner.is_empty() {
2141                    Ok(None)
2142                } else if inner.len() == 1 {
2143                    let first = inner.into_iter().next().ok_or("Expected exactly one element")?;
2144                    self.build_node(first)
2145                } else {
2146                    let mut nodes = Vec::new();
2147                    for p in inner {
2148                        if let Some(node) = self.build_node(p)? {
2149                            nodes.push(node);
2150                        }
2151                    }
2152                    if nodes.is_empty() {
2153                        Ok(None)
2154                    } else if nodes.len() == 1 {
2155                        Ok(nodes.into_iter().next())
2156                    } else {
2157                        Ok(Some(AstNode::List(nodes)))
2158                    }
2159                }
2160            }
2161        }
2162    }
2163
2164    fn build_expression(
2165        &mut self,
2166        pair: Pair<Rule>,
2167    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
2168        let inner = pair.into_inner().next().ok_or("Empty expression")?;
2169        match inner.as_rule() {
2170            Rule::assignment_expression => self.build_node(inner),
2171            Rule::ternary_expression => self.build_ternary_expression(inner),
2172            _ => self.build_node(inner),
2173        }
2174    }
2175
2176    #[inline]
2177    fn build_ternary_expression(
2178        &mut self,
2179        pair: Pair<Rule>,
2180    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
2181        let inner: Vec<_> = pair.into_inner().collect();
2182        if inner.len() == 1 {
2183            // No ternary, just pass through
2184            let first = inner.into_iter().next().ok_or("Expected exactly one element")?;
2185            self.build_node(first)
2186        } else if inner.len() == 3 {
2187            let condition = Box::new(
2188                self.build_node(inner[0].clone())?.ok_or("Failed to build ternary condition")?,
2189            );
2190            let then_expr = Box::new(
2191                self.build_node(inner[1].clone())?
2192                    .ok_or("Failed to build ternary then expression")?,
2193            );
2194            let else_expr = Box::new(
2195                self.build_node(inner[2].clone())?
2196                    .ok_or("Failed to build ternary else expression")?,
2197            );
2198            Ok(Some(AstNode::TernaryOp { condition, true_expr: then_expr, false_expr: else_expr }))
2199        } else {
2200            let first = inner.into_iter().next().ok_or("Expected exactly one element")?;
2201            self.build_node(first)
2202        }
2203    }
2204
2205    #[inline]
2206    fn build_binary_expression(
2207        &mut self,
2208        pair: Pair<Rule>,
2209        _op_rule: Rule,
2210    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
2211        let inner: Vec<_> = pair.into_inner().collect();
2212        if inner.len() == 1 {
2213            let first = inner.into_iter().next().ok_or("Expected exactly one element")?;
2214            self.build_node(first)
2215        } else if inner.len() >= 3 {
2216            // Build with proper precedence
2217            self.build_binary_expr_with_precedence(inner)
2218        } else {
2219            let first = inner.into_iter().next().ok_or("Expected exactly one element")?;
2220            self.build_node(first)
2221        }
2222    }
2223
2224    fn build_binary_expr_with_precedence(
2225        &mut self,
2226        pairs: Vec<Pair<Rule>>,
2227    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
2228        if pairs.is_empty() {
2229            return Ok(None);
2230        }
2231
2232        // Build left-associative binary operations
2233        let mut result = self.build_node(pairs[0].clone())?.unwrap_or(AstNode::EmptyExpression);
2234        let mut i = 1;
2235
2236        while i < pairs.len() - 1 {
2237            // The operator is at position i
2238            let op_str = pairs[i].as_str();
2239            let op = Arc::from(if op_str == "_DIV_" { "/" } else { op_str });
2240            // The right operand is at position i + 1
2241            let right = self.build_node(pairs[i + 1].clone())?.unwrap_or(AstNode::EmptyExpression);
2242
2243            result = AstNode::BinaryOp { op, left: Box::new(result), right: Box::new(right) };
2244
2245            i += 2;
2246        }
2247
2248        Ok(Some(result))
2249    }
2250
2251    fn _apply_precedence(&self, left: AstNode, op: Arc<str>, right: AstNode, _prec: u8) -> AstNode {
2252        // For now, simple left-associative. Full Pratt parser implementation would go here
2253        AstNode::BinaryOp { op, left: Box::new(left), right: Box::new(right) }
2254    }
2255
2256    fn parse_arg_list(
2257        &mut self,
2258        pair: Pair<Rule>,
2259    ) -> Result<Vec<AstNode>, Box<dyn std::error::Error>> {
2260        let mut args = Vec::new();
2261        for arg in pair.into_inner() {
2262            if let Some(node) = self.build_node(arg)? {
2263                args.push(node);
2264            }
2265        }
2266        Ok(args)
2267    }
2268
2269    fn build_dereference_node(
2270        &mut self,
2271        pair: Pair<Rule>,
2272        deref_type: &'static str,
2273    ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
2274        let mut inner = pair.into_inner();
2275        let expr = if let Some(inner_pair) = inner.next() {
2276            match inner_pair.as_rule() {
2277                Rule::expression => {
2278                    Box::new(self.build_node(inner_pair)?.unwrap_or(AstNode::EmptyExpression))
2279                }
2280                Rule::variable_name => {
2281                    let variable = Arc::<str>::from(format!("${}", inner_pair.as_str()));
2282                    Box::new(AstNode::ScalarVariable(variable))
2283                }
2284                _ => Box::new(self.build_node(inner_pair)?.unwrap_or(AstNode::EmptyExpression)),
2285            }
2286        } else {
2287            Box::new(AstNode::EmptyExpression)
2288        };
2289
2290        Ok(Some(AstNode::Dereference { expr, deref_type: Arc::from(deref_type) }))
2291    }
2292
2293    pub fn to_sexp(&self, node: &AstNode) -> String {
2294        Self::node_to_sexp(node)
2295    }
2296
2297    pub fn node_to_sexp(node: &AstNode) -> String {
2298        match node {
2299            AstNode::Program(children) => {
2300                // Remove nested source_file in S-expression output
2301                let mut flat_children = vec![];
2302                for c in children {
2303                    let sexp = Self::node_to_sexp(c);
2304                    if sexp.starts_with("(source_file ") {
2305                        let inner = sexp.trim_start_matches("(source_file ").trim_end_matches(")");
2306                        flat_children.push(inner.to_string());
2307                    } else {
2308                        flat_children.push(sexp);
2309                    }
2310                }
2311                if flat_children.is_empty() {
2312                    "(source_file)".to_string()
2313                } else {
2314                    format!("(source_file {})", flat_children.join(" "))
2315                }
2316            }
2317            AstNode::Statement(expr) => Self::node_to_sexp(expr),
2318            AstNode::Block(statements) => {
2319                let stmt_sexps: Vec<String> = statements.iter().map(Self::node_to_sexp).collect();
2320                format!("(block {})", stmt_sexps.join(" "))
2321            }
2322            AstNode::VariableDeclaration { scope, variables, initializer } => {
2323                let var_sexps: Vec<String> = variables.iter().map(Self::node_to_sexp).collect();
2324                if let Some(init) = initializer {
2325                    format!(
2326                        "(variable_declaration {} {} = {})",
2327                        scope,
2328                        var_sexps.join(" "),
2329                        Self::node_to_sexp(init)
2330                    )
2331                } else {
2332                    format!("(variable_declaration {} {})", scope, var_sexps.join(" "))
2333                }
2334            }
2335            AstNode::SubDeclaration { name, prototype, body, .. } => {
2336                let mut parts = vec![format!("(identifier {})", name)];
2337                if let Some(proto) = prototype {
2338                    parts.push(format!("(signature {})", proto));
2339                }
2340                parts.push(Self::node_to_sexp(body));
2341                format!("(subroutine {})", parts.join(" "))
2342            }
2343            AstNode::AnonymousSub { body, .. } => {
2344                format!("(anonymous_subroutine {})", Self::node_to_sexp(body))
2345            }
2346            AstNode::FormatDeclaration { name, format_lines } => {
2347                let lines_sexp = format_lines
2348                    .iter()
2349                    .map(|line| format!("(format_line \"{}\")", line.replace("\"", "\\\"")))
2350                    .collect::<Vec<_>>()
2351                    .join(" ");
2352                if name.is_empty() {
2353                    format!("(format_declaration {})", lines_sexp)
2354                } else {
2355                    format!("(format_declaration (identifier {}) {})", name, lines_sexp)
2356                }
2357            }
2358            AstNode::IfStatement { condition, then_block, .. } => {
2359                format!(
2360                    "(if_statement {} {})",
2361                    Self::node_to_sexp(condition),
2362                    Self::node_to_sexp(then_block)
2363                )
2364            }
2365            AstNode::GivenStatement { expression, when_clauses, default_block } => {
2366                let mut result = format!("(given_statement {}", Self::node_to_sexp(expression));
2367                for (cond, block) in when_clauses {
2368                    result.push_str(&format!(
2369                        " (when_clause {} {})",
2370                        Self::node_to_sexp(cond),
2371                        Self::node_to_sexp(block)
2372                    ));
2373                }
2374                if let Some(default) = default_block {
2375                    result.push_str(&format!(" (default_clause {})", Self::node_to_sexp(default)));
2376                }
2377                result.push(')');
2378                result
2379            }
2380            AstNode::TieStatement { variable, class, args } => {
2381                let args_str = args.iter().map(Self::node_to_sexp).collect::<Vec<_>>().join(" ");
2382                format!(
2383                    "(tie_statement {} {} {})",
2384                    Self::node_to_sexp(variable),
2385                    Self::node_to_sexp(class),
2386                    args_str
2387                )
2388            }
2389            AstNode::UntieStatement { variable } => {
2390                format!("(untie_statement {})", Self::node_to_sexp(variable))
2391            }
2392            AstNode::TiedExpression { variable } => {
2393                format!("(tied_expression {})", Self::node_to_sexp(variable))
2394            }
2395            AstNode::PostfixDereference { expr, deref_type } => {
2396                format!("(postfix_deref {} {})", Self::node_to_sexp(expr), deref_type)
2397            }
2398            AstNode::Dereference { expr, deref_type } => {
2399                format!("(dereference {} {})", Self::node_to_sexp(expr), deref_type)
2400            }
2401            AstNode::TypeglobSlotAccess { typeglob, slot } => {
2402                format!("(typeglob_slot_access {} {})", Self::node_to_sexp(typeglob), slot)
2403            }
2404            AstNode::ArrayAccess { array, index } => {
2405                format!(
2406                    "(array_access {} {})",
2407                    Self::node_to_sexp(array),
2408                    Self::node_to_sexp(index)
2409                )
2410            }
2411            AstNode::HashAccess { hash, key } => {
2412                format!("(hash_access {} {})", Self::node_to_sexp(hash), Self::node_to_sexp(key))
2413            }
2414            AstNode::MethodCall { object, method, args } => {
2415                let args_str = if args.is_empty() {
2416                    "( )".to_string()
2417                } else {
2418                    format!(
2419                        "( {} )",
2420                        args.iter().map(Self::node_to_sexp).collect::<Vec<_>>().join(" ")
2421                    )
2422                };
2423                format!(
2424                    "(method_call_expression {} -> (method {}) {})",
2425                    Self::node_to_sexp(object),
2426                    method,
2427                    args_str
2428                )
2429            }
2430            AstNode::Assignment { target, op, value } => {
2431                format!(
2432                    "(assignment {} ({}) {})",
2433                    Self::node_to_sexp(target),
2434                    op,
2435                    Self::node_to_sexp(value)
2436                )
2437            }
2438            AstNode::FunctionCall { function, args } => {
2439                let args_str = if args.is_empty() {
2440                    "".to_string()
2441                } else {
2442                    format!(
2443                        " {}",
2444                        args.iter().map(Self::node_to_sexp).collect::<Vec<_>>().join(" ")
2445                    )
2446                };
2447                format!("(function_call {}{})", Self::node_to_sexp(function), args_str)
2448            }
2449            AstNode::BuiltinListOp { name, args } => {
2450                let args_str = if args.is_empty() {
2451                    "".to_string()
2452                } else {
2453                    format!(
2454                        " {}",
2455                        args.iter().map(Self::node_to_sexp).collect::<Vec<_>>().join(" ")
2456                    )
2457                };
2458                format!("(function_call (identifier {}){})", name, args_str)
2459            }
2460            AstNode::BinaryOp { op, left, right } => {
2461                format!(
2462                    "(binary_expression {} ({}) {})",
2463                    Self::node_to_sexp(left),
2464                    op,
2465                    Self::node_to_sexp(right)
2466                )
2467            }
2468            AstNode::ScalarVariable(name) => {
2469                format!("(scalar_variable {})", name)
2470            }
2471            AstNode::ArrayVariable(name) => {
2472                format!("(array_variable {})", name)
2473            }
2474            AstNode::HashVariable(name) => {
2475                format!("(hash_variable {})", name)
2476            }
2477            AstNode::TypeglobVariable(name) => {
2478                format!("(typeglob_variable {})", name)
2479            }
2480            AstNode::ScalarReference(name) => {
2481                format!("(scalar_reference {})", name)
2482            }
2483            AstNode::ArrayReference(name) => {
2484                format!("(array_reference {})", name)
2485            }
2486            AstNode::HashReference(name) => {
2487                format!("(hash_reference {})", name)
2488            }
2489            AstNode::SubroutineReference(name) => {
2490                format!("(subroutine_reference {})", name)
2491            }
2492            AstNode::GlobReference(name) => {
2493                format!("(glob_reference {})", name)
2494            }
2495            AstNode::Number(value) => {
2496                format!("(number {})", value)
2497            }
2498            AstNode::String(value) => {
2499                format!("(string_literal {})", value)
2500            }
2501            AstNode::Bareword(value) => {
2502                format!("(bareword {})", value)
2503            }
2504            AstNode::Regex { pattern, flags, .. } => {
2505                if flags.is_empty() {
2506                    format!("(regex /{}/ )", pattern)
2507                } else {
2508                    format!("(regex /{}/{} )", pattern, flags)
2509                }
2510            }
2511            AstNode::InterpolatedString(parts) => {
2512                let parts_str = parts.iter().map(Self::node_to_sexp).collect::<Vec<_>>().join(" ");
2513                format!("(interpolated_string {})", parts_str)
2514            }
2515            AstNode::Identifier(name) => {
2516                format!("(identifier {})", name)
2517            }
2518            AstNode::SpecialLiteral(name) => {
2519                format!("(special_literal {})", name)
2520            }
2521            AstNode::EmptyExpression => "(empty_expression)".to_string(),
2522            AstNode::Comment(content) => {
2523                format!("(comment {})", content)
2524            }
2525            AstNode::List(items) => {
2526                let item_sexps: Vec<String> = items.iter().map(Self::node_to_sexp).collect();
2527                item_sexps.join(" ")
2528            }
2529            AstNode::ArrayRef(items) => {
2530                let item_sexps: Vec<String> = items.iter().map(Self::node_to_sexp).collect();
2531                format!("(array_ref {})", item_sexps.join(" "))
2532            }
2533            AstNode::HashRef(items) => {
2534                let item_sexps: Vec<String> = items.iter().map(Self::node_to_sexp).collect();
2535                format!("(hash_ref {})", item_sexps.join(" "))
2536            }
2537            AstNode::WhileStatement { label, condition, block } => {
2538                let label_str =
2539                    if let Some(l) = label { format!(" (label {})", l) } else { String::new() };
2540                format!(
2541                    "(while_statement{} {} {})",
2542                    label_str,
2543                    Self::node_to_sexp(condition),
2544                    Self::node_to_sexp(block)
2545                )
2546            }
2547            AstNode::UntilStatement { label, condition, block } => {
2548                let label_str =
2549                    if let Some(l) = label { format!(" (label {})", l) } else { String::new() };
2550                format!(
2551                    "(until_statement{} {} {})",
2552                    label_str,
2553                    Self::node_to_sexp(condition),
2554                    Self::node_to_sexp(block)
2555                )
2556            }
2557            AstNode::UnlessStatement { condition, block, else_block } => {
2558                let else_str = if let Some(e) = else_block {
2559                    format!(" (else {})", Self::node_to_sexp(e))
2560                } else {
2561                    String::new()
2562                };
2563                format!(
2564                    "(unless_statement {} {}{}",
2565                    Self::node_to_sexp(condition),
2566                    Self::node_to_sexp(block),
2567                    else_str
2568                )
2569            }
2570            AstNode::ForStatement { init, condition, update, block, .. } => {
2571                let mut parts = vec![];
2572                if let Some(i) = init {
2573                    parts.push(format!("(init {})", Self::node_to_sexp(i)));
2574                }
2575                if let Some(c) = condition {
2576                    parts.push(format!("(condition {})", Self::node_to_sexp(c)));
2577                }
2578                if let Some(u) = update {
2579                    parts.push(format!("(update {})", Self::node_to_sexp(u)));
2580                }
2581                parts.push(format!("(body {})", Self::node_to_sexp(block)));
2582                format!("(for_statement {})", parts.join(" "))
2583            }
2584            AstNode::ForeachStatement { label, variable, list, block } => {
2585                let label_str =
2586                    if let Some(l) = label { format!(" (label {})", l) } else { String::new() };
2587                let var_str = if let Some(v) = variable {
2588                    format!(" (variable {})", Self::node_to_sexp(v))
2589                } else {
2590                    String::new()
2591                };
2592                format!(
2593                    "(foreach_statement{}{} {} {})",
2594                    label_str,
2595                    var_str,
2596                    Self::node_to_sexp(list),
2597                    Self::node_to_sexp(block)
2598                )
2599            }
2600            AstNode::PackageDeclaration { name, version, block } => {
2601                let mut parts = vec![format!("(name {})", name)];
2602                if let Some(v) = version {
2603                    parts.push(format!("(version {})", v));
2604                }
2605                if let Some(b) = block {
2606                    parts.push(format!("(body {})", Self::node_to_sexp(b)));
2607                }
2608                format!("(package_declaration {})", parts.join(" "))
2609            }
2610            AstNode::UseStatement { module, version, import_list } => {
2611                let mut parts = vec![format!("use (package {})", module)];
2612                if let Some(v) = version {
2613                    parts.push(format!("(version {})", v));
2614                }
2615                if !import_list.is_empty() {
2616                    parts.push(format!("(import_list {})", import_list.join(" ")));
2617                }
2618                parts.push(";".to_string());
2619                format!("(use_statement {})", parts.join(" "))
2620            }
2621            AstNode::RequireStatement { module } => {
2622                format!("(require_statement require (package {}) ;)", module)
2623            }
2624            AstNode::Substitution { pattern, replacement, flags } => {
2625                if flags.is_empty() {
2626                    format!("(substitution s/{}/{}/ )", pattern, replacement)
2627                } else {
2628                    format!("(substitution s/{}/{}/{} )", pattern, replacement, flags)
2629                }
2630            }
2631            AstNode::Transliteration { search_list, replace_list, flags } => {
2632                if flags.is_empty() {
2633                    format!("(transliteration tr/{}/{}/ )", search_list, replace_list)
2634                } else {
2635                    format!("(transliteration tr/{}/{}/{} )", search_list, replace_list, flags)
2636                }
2637            }
2638            AstNode::BeginBlock(block) => {
2639                format!("(begin_block {})", Self::node_to_sexp(block))
2640            }
2641            AstNode::EndBlock(block) => {
2642                format!("(end_block {})", Self::node_to_sexp(block))
2643            }
2644            AstNode::CheckBlock(block) => {
2645                format!("(check_block {})", Self::node_to_sexp(block))
2646            }
2647            AstNode::InitBlock(block) => {
2648                format!("(init_block {})", Self::node_to_sexp(block))
2649            }
2650            AstNode::UnitcheckBlock(block) => {
2651                format!("(unitcheck_block {})", Self::node_to_sexp(block))
2652            }
2653            AstNode::QwList(words) => {
2654                let word_list =
2655                    words.iter().map(|w| format!("(word {})", w)).collect::<Vec<_>>().join(" ");
2656                format!("(qw_list {})", word_list)
2657            }
2658            AstNode::DoBlock(expr) => {
2659                format!("(do_block {})", Self::node_to_sexp(expr))
2660            }
2661            AstNode::EvalBlock(block) => {
2662                format!("(eval_block {})", Self::node_to_sexp(block))
2663            }
2664            AstNode::EvalString(expr) => {
2665                format!("(eval_string {})", Self::node_to_sexp(expr))
2666            }
2667            AstNode::GotoStatement { target } => {
2668                format!("(goto_statement {})", target)
2669            }
2670            AstNode::ReturnStatement { value } => {
2671                if let Some(v) = value {
2672                    format!("(return_statement {})", Self::node_to_sexp(v))
2673                } else {
2674                    "(return_statement)".to_string()
2675                }
2676            }
2677            AstNode::LabeledBlock { label, block } => {
2678                format!("(labeled_block {} {})", label, Self::node_to_sexp(block))
2679            }
2680            AstNode::Heredoc { marker, indented, quoted, content } => {
2681                let flags = format!(
2682                    "{}{}",
2683                    if *indented { "~" } else { "" },
2684                    if *quoted { "'" } else { "" }
2685                );
2686                format!("(heredoc {} {} \"{}\")", marker, flags, content.escape_default())
2687            }
2688            AstNode::Pod(content) => {
2689                format!("(pod {})", content)
2690            }
2691            AstNode::DataSection(content) => {
2692                format!("(data_section {})", content)
2693            }
2694            AstNode::EndSection(content) => {
2695                format!("(end_section {})", content)
2696            }
2697            AstNode::Glob(pattern) => {
2698                format!("(glob <{}>)", pattern)
2699            }
2700            AstNode::QqString(content) => {
2701                format!("(string_literal {})", content)
2702            }
2703            AstNode::QxString(content) => {
2704                format!("(command_substitution {})", content)
2705            }
2706            AstNode::Readline { filehandle } => {
2707                if let Some(fh) = filehandle {
2708                    format!("(readline <{}>)", fh)
2709                } else {
2710                    "(readline <>)".to_string()
2711                }
2712            }
2713            AstNode::TryCatch { try_block, catch_clauses, finally_block } => {
2714                let mut result = format!("(try_catch_statement {}", Self::node_to_sexp(try_block));
2715                for (param, block) in catch_clauses {
2716                    if let Some(p) = param {
2717                        result.push_str(&format!(" (catch ({}) {})", p, Self::node_to_sexp(block)));
2718                    } else {
2719                        result.push_str(&format!(" (catch {})", Self::node_to_sexp(block)));
2720                    }
2721                }
2722                if let Some(finally) = finally_block {
2723                    result.push_str(&format!(" (finally {})", Self::node_to_sexp(finally)));
2724                }
2725                result.push(')');
2726                result
2727            }
2728            AstNode::DeferStatement(block) => {
2729                format!("(defer_statement {})", Self::node_to_sexp(block))
2730            }
2731            AstNode::ClassDeclaration { name, version, superclass, body } => {
2732                let mut result = format!("(class_declaration {}", name);
2733                if let Some(v) = version {
2734                    result.push_str(&format!(" (version {})", v));
2735                }
2736                if let Some(s) = superclass {
2737                    result.push_str(&format!(" (superclass {})", s));
2738                }
2739                for member in body {
2740                    result.push_str(&format!(" {}", Self::node_to_sexp(member)));
2741                }
2742                result.push(')');
2743                result
2744            }
2745            AstNode::MethodDeclaration { name, signature, attributes, body } => {
2746                let mut result = format!("(method_declaration {}", name);
2747                if let Some(sig) = signature {
2748                    result.push_str(&format!(" (signature {})", sig));
2749                }
2750                if !attributes.is_empty() {
2751                    result.push_str(&format!(" (attributes {})", attributes.join(" ")));
2752                }
2753                result.push_str(&format!(" {}", Self::node_to_sexp(body)));
2754                result.push(')');
2755                result
2756            }
2757            AstNode::FieldDeclaration { name, attributes, default } => {
2758                let mut result = format!("(field_declaration {}", name);
2759                if !attributes.is_empty() {
2760                    result.push_str(&format!(" (attributes {})", attributes.join(" ")));
2761                }
2762                if let Some(d) = default {
2763                    result.push_str(&format!(" (default {})", Self::node_to_sexp(d)));
2764                }
2765                result.push(')');
2766                result
2767            }
2768            AstNode::RoleDeclaration { name, body } => {
2769                format!("(role_declaration {} {})", name, Self::node_to_sexp(body))
2770            }
2771            _ => format!("(unhandled_node {:?})", node),
2772        }
2773    }
2774}
2775
2776impl Default for PureRustPerlParser {
2777    fn default() -> Self {
2778        Self::new()
2779    }
2780}
2781
2782#[cfg(test)]
2783mod tests {
2784    use super::*;
2785    use perl_tdd_support::must;
2786
2787    #[test]
2788    fn test_basic_parsing() {
2789        let mut parser = PureRustPerlParser::new();
2790        let source = "$var";
2791        let ast = must(parser.parse(source));
2792        let sexp = parser.to_sexp(&ast);
2793
2794        assert!(sexp.contains("(scalar_variable $var)"), "expected scalar variable; got: {sexp}");
2795    }
2796
2797    #[test]
2798    fn test_variable_parsing() {
2799        let mut parser = PureRustPerlParser::new();
2800        let source = "$scalar @array %hash";
2801        let ast = must(parser.parse(source));
2802        let sexp = parser.to_sexp(&ast);
2803
2804        assert!(sexp.contains("$scalar"), "expected scalar variable; got: {sexp}");
2805        assert!(sexp.contains("@array"), "expected array variable; got: {sexp}");
2806        assert!(
2807            sexp.contains("(%)") && sexp.contains("(identifier hash)"),
2808            "expected hash token shape; got: {sexp}"
2809        );
2810    }
2811
2812    #[test]
2813    fn test_assignment_parsing() {
2814        let mut parser = PureRustPerlParser::new();
2815        let source = "my $var = 42;";
2816        let ast = must(parser.parse(source));
2817        let sexp = parser.to_sexp(&ast);
2818
2819        assert!(sexp.contains("(variable_declaration"), "expected declaration; got: {sexp}");
2820        assert!(sexp.contains("(number 42)"), "expected numeric initializer; got: {sexp}");
2821    }
2822
2823    #[test]
2824    fn test_function_declaration() {
2825        let mut parser = PureRustPerlParser::new();
2826        let source = "sub hello { print 'Hello'; }";
2827        let ast = must(parser.parse(source));
2828        let sexp = parser.to_sexp(&ast);
2829
2830        assert!(
2831            sexp.contains("(subroutine (identifier hello)"),
2832            "expected subroutine declaration; got: {sexp}"
2833        );
2834    }
2835
2836    #[test]
2837    fn test_if_statement() {
2838        let mut parser = PureRustPerlParser::new();
2839        let source = "if ($x > 0) { print 'positive'; }";
2840        let ast = must(parser.parse(source));
2841        let sexp = parser.to_sexp(&ast);
2842
2843        assert!(sexp.contains("(if_statement"), "expected if statement; got: {sexp}");
2844    }
2845
2846    #[test]
2847    fn test_regression_percent_string_in_if_assignment() {
2848        let mut parser = PureRustPerlParser::new();
2849        let source = r#"if ($a > 0) { $a = "%"; }"#;
2850        let result = parser.parse(source);
2851        assert!(result.is_ok(), "Failed to parse regression input: {source}");
2852    }
2853
2854    #[test]
2855    fn test_array_assignment() {
2856        let mut parser = PureRustPerlParser::new();
2857        let source = "@array = (1, 2, 3);";
2858        let ast = must(parser.parse(source));
2859        let sexp = parser.to_sexp(&ast);
2860
2861        assert!(
2862            sexp.contains("(assignment (array_variable @array)"),
2863            "expected array assignment; got: {sexp}"
2864        );
2865    }
2866
2867    #[test]
2868    fn test_hash_assignment() {
2869        let mut parser = PureRustPerlParser::new();
2870        let source = "%hash = (a => 1, b => 2);";
2871        let ast = must(parser.parse(source));
2872        let sexp = parser.to_sexp(&ast);
2873
2874        assert!(
2875            sexp.contains("(assignment (hash_variable %hash)"),
2876            "expected hash assignment; got: {sexp}"
2877        );
2878    }
2879}