1use 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#[derive(Debug, Clone, PartialEq)]
26pub enum AstNode {
27 Program(Vec<AstNode>),
29 Statement(Box<AstNode>),
30 Block(Vec<AstNode>),
31
32 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 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 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 ScalarVariable(Arc<str>),
159 ArrayVariable(Arc<str>),
160 HashVariable(Arc<str>),
161 TypeglobVariable(Arc<str>),
162
163 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 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 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 BeginBlock(Box<AstNode>),
238 EndBlock(Box<AstNode>),
239 CheckBlock(Box<AstNode>),
240 InitBlock(Box<AstNode>),
241 UnitcheckBlock(Box<AstNode>),
242
243 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 Heredoc {
256 marker: Arc<str>,
257 indented: bool,
258 quoted: bool,
259 content: Arc<str>,
260 },
261
262 Glob(Arc<str>),
264 Readline {
265 filehandle: Option<Arc<str>>,
266 },
267
268 DoBlock(Box<AstNode>),
270 EvalBlock(Box<AstNode>),
271 EvalString(Box<AstNode>),
272 GotoStatement {
273 target: Arc<str>,
274 },
275
276 DataSection(Arc<str>),
278 EndSection(Arc<str>),
279
280 Pod(Arc<str>),
282
283 TryCatch {
285 try_block: Box<AstNode>,
286 catch_clauses: Vec<(Option<Arc<str>>, AstNode)>, finally_block: Option<Box<AstNode>>,
288 },
289 DeferStatement(Box<AstNode>),
290
291 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
319pub 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 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 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: ®ex::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: ®ex::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 {
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 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 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 current_block.clear();
438 in_single_quote = false;
439 in_double_quote = false;
440 }
441 } else if trimmed.starts_with('#') {
442 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 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 #[inline]
499 pub fn build_node(
500 &mut self,
501 pair: Pair<Rule>,
502 ) -> Result<Option<AstNode>, Box<dyn std::error::Error>> {
503 const STACK_RED_ZONE: usize = 512 * 1024; const STACK_SIZE: usize = 8 * 1024 * 1024; stacker::maybe_grow(STACK_RED_ZONE, STACK_SIZE, || self.build_node_impl(pair))
507 }
508
509 #[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 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 let text = pair.as_str();
532 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 let method_name = method_part.split('(').next().unwrap_or("").trim();
540
541 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 let text = pair.as_str();
560 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 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 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 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")?; 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 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 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 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 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 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 match first.as_rule() {
1016 Rule::postfix_expression | Rule::reference => {
1017 self.build_node(first)
1019 }
1020 Rule::file_test_operator => {
1021 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 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 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 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 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 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 let mut parts = Vec::new();
1262
1263 if let Some(content_pair) = pair.into_inner().next() {
1264 for part in content_pair.into_inner() {
1266 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 Ok(Some(AstNode::String(Arc::from(""))))
1292 }
1293 }
1294 Rule::q_string => {
1295 let content = pair.as_str();
1298 if content.contains("__HEREDOC__") {
1299 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 let content = pair.as_str();
1313 if content.contains("__HEREDOC__") {
1314 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 Ok(Some(AstNode::QxString(Arc::from(pair.as_str()))))
1327 }
1328 Rule::backtick_string => {
1329 Ok(Some(AstNode::QxString(Arc::from(pair.as_str()))))
1331 }
1332 Rule::heredoc_placeholder => {
1333 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 Ok(Some(AstNode::Heredoc {
1382 marker,
1383 indented,
1384 quoted,
1385 content: Arc::from(""), }))
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")?; 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")?; 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")?; 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")?; 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")?; 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 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 if let Some(expr) = self.build_node(inner)? {
1490 Arc::from(format!("{:?}", expr)) } 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 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 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 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 let is_c_style = inner.clone().any(|p| p.as_rule() == Rule::for_init);
1915
1916 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 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 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 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 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 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 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 let inner = pair.into_inner().next().ok_or("Empty interpolation")?;
2061 self.build_node(inner)
2062 }
2063 Rule::complex_scalar_interpolation => {
2064 let inner = pair.into_inner().next().ok_or("Empty complex scalar interpolation")?;
2066 self.build_node(inner)
2067 }
2068 Rule::complex_array_interpolation => {
2069 let inner = pair.into_inner().next().ok_or("Empty complex array interpolation")?;
2071 self.build_node(inner)
2072 }
2073 Rule::reference => {
2074 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 Ok(Some(AstNode::ScalarReference(Arc::from(pair.as_str()))))
2085 }
2086 Rule::array_reference => {
2087 Ok(Some(AstNode::ArrayReference(Arc::from(pair.as_str()))))
2089 }
2090 Rule::hash_reference => {
2091 Ok(Some(AstNode::HashReference(Arc::from(pair.as_str()))))
2093 }
2094 Rule::subroutine_reference => {
2095 Ok(Some(AstNode::SubroutineReference(Arc::from(pair.as_str()))))
2097 }
2098 Rule::glob_reference => {
2099 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 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 match first.as_rule() {
2116 Rule::expression => {
2117 self.build_node(first)
2119 }
2120 _ => self.build_node(first),
2121 }
2122 } else {
2123 let mut result = None;
2125 for p in inner {
2126 if p.as_str() == "(" || p.as_str() == ")" {
2127 continue;
2129 }
2130 if let Some(node) = self.build_node(p)? {
2131 result = Some(node);
2132 }
2133 }
2134 Ok(result)
2135 }
2136 }
2137 _ => {
2138 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 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 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 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 let op_str = pairs[i].as_str();
2239 let op = Arc::from(if op_str == "_DIV_" { "/" } else { op_str });
2240 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 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 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}