gent/parser/
mod.rs

1//! Parser module for GENT - transforms pest CST to AST
2
3pub mod ast;
4
5pub use ast::{
6    AgentDecl, AgentField, AssignmentStmt, BinaryOp, Block, BlockStmt, Duration, DurationUnit,
7    EnumDecl, EnumField, EnumVariant, Expression, FieldType, FnDecl, ForStmt, IfStmt, ImportStmt,
8    Lambda, LambdaBody, LetStmt, MatchArm, MatchBody, MatchExpr, MatchPattern, OutputType,
9    ParallelDecl, Param, Program, ReturnStmt, Statement, StringPart, StructDecl, StructField,
10    ToolDecl, TopLevelCall, TryStmt, TypeName, UnaryOp, WhileStmt,
11};
12
13use crate::errors::{GentError, GentResult, Span};
14use crate::lexer::{GentParser, Rule};
15use pest::Parser;
16
17/// Parse GENT source code into an AST
18pub fn parse(source: &str) -> GentResult<Program> {
19    let pairs = GentParser::parse(Rule::program, source).map_err(|e| GentError::SyntaxError {
20        message: e.to_string(),
21        span: Span::new(0, 0),
22    })?;
23
24    let mut statements = Vec::new();
25    let program_span = Span::new(0, source.len());
26
27    for pair in pairs {
28        if pair.as_rule() == Rule::program {
29            for inner in pair.into_inner() {
30                match inner.as_rule() {
31                    Rule::statement => {
32                        statements.push(parse_statement(inner)?);
33                    }
34                    Rule::EOI => {}
35                    _ => {}
36                }
37            }
38        }
39    }
40
41    Ok(Program {
42        statements,
43        span: program_span,
44    })
45}
46
47fn parse_statement(pair: pest::iterators::Pair<Rule>) -> GentResult<Statement> {
48    let inner = pair.into_inner().next().unwrap();
49    match inner.as_rule() {
50        Rule::import_stmt => Ok(Statement::Import(parse_import_stmt(inner)?)),
51        Rule::struct_decl => Ok(Statement::StructDecl(parse_struct_decl(inner)?)),
52        Rule::enum_decl => Ok(Statement::EnumDecl(parse_enum_decl(inner)?)),
53        Rule::agent_decl => Ok(Statement::AgentDecl(parse_agent_decl(inner)?)),
54        Rule::tool_decl => Ok(Statement::ToolDecl(parse_tool_decl(inner)?)),
55        Rule::fn_decl => Ok(Statement::FnDecl(parse_fn_decl(inner)?)),
56        Rule::parallel_decl => Ok(Statement::ParallelDecl(parse_parallel_decl(inner)?)),
57        Rule::top_level_let => Ok(Statement::LetStmt(parse_top_level_let(inner)?)),
58        Rule::top_level_call => Ok(Statement::TopLevelCall(parse_top_level_call(inner)?)),
59        _ => Err(GentError::SyntaxError {
60            message: format!("Unexpected rule: {:?}", inner.as_rule()),
61            span: Span::new(0, 0),
62        }),
63    }
64}
65
66fn parse_import_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<ImportStmt> {
67    let span = Span::new(pair.as_span().start(), pair.as_span().end());
68    let mut inner = pair.into_inner();
69
70    let import_list = inner.next().unwrap();
71    let mut names = Vec::new();
72    for ident in import_list.into_inner() {
73        if ident.as_rule() == Rule::identifier {
74            names.push(ident.as_str().to_string());
75        }
76    }
77
78    let path_pair = inner.next().unwrap();
79    let raw_path = path_pair.as_str();
80    // Remove the quotes from the string literal
81    let path = raw_path[1..raw_path.len() - 1].to_string();
82
83    Ok(ImportStmt { names, path, span })
84}
85
86fn parse_top_level_let(pair: pest::iterators::Pair<Rule>) -> GentResult<LetStmt> {
87    let span = Span::new(pair.as_span().start(), pair.as_span().end());
88    let mut inner = pair.into_inner();
89
90    let name = inner.next().unwrap().as_str().to_string();
91    let value = parse_expression(inner.next().unwrap())?;
92
93    Ok(LetStmt { name, value, span })
94}
95
96fn parse_agent_decl(pair: pest::iterators::Pair<Rule>) -> GentResult<AgentDecl> {
97    let span = Span::new(pair.as_span().start(), pair.as_span().end());
98    let mut inner = pair.into_inner();
99
100    let name = inner.next().unwrap().as_str().to_string();
101    let mut fields = Vec::new();
102    let mut tools = Vec::new();
103    let mut output = None;
104
105    if let Some(body) = inner.next() {
106        for item_pair in body.into_inner() {
107            // item_pair is agent_item which contains either use_stmt or agent_field
108            let item_inner = item_pair.into_inner().next().unwrap();
109            match item_inner.as_rule() {
110                Rule::use_stmt => {
111                    // Extract tool names from use statement
112                    for ident in item_inner.into_inner() {
113                        if ident.as_rule() == Rule::identifier {
114                            tools.push(ident.as_str().to_string());
115                        }
116                    }
117                }
118                Rule::output_field => {
119                    // Parse output field directly from grammar rule
120                    output = Some(parse_output_field(item_inner)?);
121                }
122                Rule::agent_field => {
123                    let field = parse_agent_field(item_inner)?;
124                    // Legacy support: Check if this is the output field (shouldn't happen with new grammar)
125                    if field.name == "output" {
126                        output = Some(parse_output_type_from_expr(&field.value)?);
127                    } else {
128                        fields.push(field);
129                    }
130                }
131                _ => {}
132            }
133        }
134    }
135
136    Ok(AgentDecl {
137        name,
138        fields,
139        tools,
140        output,
141        span,
142    })
143}
144
145fn parse_agent_field(pair: pest::iterators::Pair<Rule>) -> GentResult<AgentField> {
146    let span = Span::new(pair.as_span().start(), pair.as_span().end());
147    let mut inner = pair.into_inner();
148
149    let name = inner.next().unwrap().as_str().to_string();
150    let value = parse_expression(inner.next().unwrap())?;
151
152    Ok(AgentField { name, value, span })
153}
154
155/// Parse output field: "output" ~ ":" ~ output_type
156fn parse_output_field(pair: pest::iterators::Pair<Rule>) -> GentResult<OutputType> {
157    // output_field = { "output" ~ ":" ~ output_type }
158    // We only get the output_type part since "output" and ":" are consumed by grammar
159    let output_type_pair = pair.into_inner().next().unwrap();
160    parse_output_type(output_type_pair)
161}
162
163/// Parse output_type = { field_type_object | identifier }
164fn parse_output_type(pair: pest::iterators::Pair<Rule>) -> GentResult<OutputType> {
165    let inner = pair.into_inner().next().unwrap();
166    match inner.as_rule() {
167        Rule::field_type_object => {
168            let fields = parse_struct_body_from_object(inner)?;
169            Ok(OutputType::Inline(fields))
170        }
171        Rule::identifier => Ok(OutputType::Named(inner.as_str().to_string())),
172        _ => Err(GentError::SyntaxError {
173            message: format!("Expected output type, got {:?}", inner.as_rule()),
174            span: Span::new(inner.as_span().start(), inner.as_span().end()),
175        }),
176    }
177}
178
179/// Parse struct_body from field_type_object: "{" ~ struct_body ~ "}"
180fn parse_struct_body_from_object(
181    pair: pest::iterators::Pair<Rule>,
182) -> GentResult<Vec<StructField>> {
183    let mut fields = Vec::new();
184    for inner in pair.into_inner() {
185        if inner.as_rule() == Rule::struct_body {
186            for field_pair in inner.into_inner() {
187                if field_pair.as_rule() == Rule::struct_field {
188                    fields.push(parse_struct_field(field_pair)?);
189                }
190            }
191        }
192    }
193    Ok(fields)
194}
195
196fn parse_expression(pair: pest::iterators::Pair<Rule>) -> GentResult<Expression> {
197    let span = Span::new(pair.as_span().start(), pair.as_span().end());
198
199    match pair.as_rule() {
200        Rule::expression => {
201            let inner = pair.into_inner().next().unwrap();
202            parse_expression(inner)
203        }
204        Rule::logical_or => parse_binary_left(pair, &[BinaryOp::Or]),
205        Rule::logical_and => parse_binary_left(pair, &[BinaryOp::And]),
206        Rule::equality => parse_binary_left(pair, &[BinaryOp::Eq, BinaryOp::Ne]),
207        Rule::comparison => parse_binary_left(
208            pair,
209            &[BinaryOp::Lt, BinaryOp::Le, BinaryOp::Gt, BinaryOp::Ge],
210        ),
211        Rule::additive => parse_binary_left(pair, &[BinaryOp::Add, BinaryOp::Sub]),
212        Rule::multiplicative => {
213            parse_binary_left(pair, &[BinaryOp::Mul, BinaryOp::Div, BinaryOp::Mod])
214        }
215        Rule::unary => parse_unary(pair),
216        Rule::postfix => parse_postfix(pair),
217        Rule::primary => {
218            let inner = pair.into_inner().next().unwrap();
219            parse_expression(inner)
220        }
221        Rule::string_literal => {
222            let mut parts = Vec::new();
223
224            for inner in pair.into_inner() {
225                match inner.as_rule() {
226                    Rule::string_chars => {
227                        let text = unescape_string(inner.as_str());
228                        parts.push(StringPart::Literal(text));
229                    }
230                    Rule::interpolation => {
231                        let expr_pair = inner.into_inner().next().unwrap();
232                        let expr = parse_expression(expr_pair)?;
233                        parts.push(StringPart::Expr(Box::new(expr)));
234                    }
235                    Rule::string_part => {
236                        // Handle nested string_part if needed
237                        for sub in inner.into_inner() {
238                            match sub.as_rule() {
239                                Rule::string_chars => {
240                                    let text = unescape_string(sub.as_str());
241                                    parts.push(StringPart::Literal(text));
242                                }
243                                Rule::interpolation => {
244                                    let expr_pair = sub.into_inner().next().unwrap();
245                                    let expr = parse_expression(expr_pair)?;
246                                    parts.push(StringPart::Expr(Box::new(expr)));
247                                }
248                                _ => {}
249                            }
250                        }
251                    }
252                    Rule::multiline_string => {
253                        // Handle multiline string (triple quotes)
254                        for sub in inner.into_inner() {
255                            match sub.as_rule() {
256                                Rule::multiline_chars => {
257                                    // No unescape needed for multiline - preserve content as-is
258                                    parts.push(StringPart::Literal(sub.as_str().to_string()));
259                                }
260                                Rule::multiline_interpolation => {
261                                    let expr_pair = sub.into_inner().next().unwrap();
262                                    let expr = parse_expression(expr_pair)?;
263                                    parts.push(StringPart::Expr(Box::new(expr)));
264                                }
265                                Rule::multiline_part => {
266                                    for subsub in sub.into_inner() {
267                                        match subsub.as_rule() {
268                                            Rule::multiline_chars => {
269                                                parts.push(StringPart::Literal(subsub.as_str().to_string()));
270                                            }
271                                            Rule::multiline_interpolation => {
272                                                let expr_pair = subsub.into_inner().next().unwrap();
273                                                let expr = parse_expression(expr_pair)?;
274                                                parts.push(StringPart::Expr(Box::new(expr)));
275                                            }
276                                            _ => {}
277                                        }
278                                    }
279                                }
280                                _ => {}
281                            }
282                        }
283                    }
284                    _ => {}
285                }
286            }
287
288            // If no parts, it's an empty string
289            if parts.is_empty() {
290                parts.push(StringPart::Literal(String::new()));
291            }
292
293            Ok(Expression::String(parts, span))
294        }
295        Rule::number_literal => {
296            let num: f64 = pair.as_str().parse().map_err(|_| GentError::SyntaxError {
297                message: format!("Invalid number: {}", pair.as_str()),
298                span: span.clone(),
299            })?;
300            Ok(Expression::Number(num, span))
301        }
302        Rule::boolean_literal => {
303            let val = pair.as_str() == "true";
304            Ok(Expression::Boolean(val, span))
305        }
306        Rule::null_literal => Ok(Expression::Null(span)),
307        Rule::identifier => Ok(Expression::Identifier(pair.as_str().to_string(), span)),
308        Rule::array_literal => parse_array_literal(pair),
309        Rule::object_literal => parse_object_literal(pair),
310        Rule::range_expr => parse_range_expr(pair),
311        Rule::lambda => Ok(Expression::Lambda(parse_lambda(pair)?)),
312        Rule::match_expr => Ok(Expression::Match(parse_match_expr(pair)?)),
313        _ => Err(GentError::SyntaxError {
314            message: format!("Unexpected expression: {:?}", pair.as_rule()),
315            span,
316        }),
317    }
318}
319
320fn parse_lambda(pair: pest::iterators::Pair<Rule>) -> GentResult<Lambda> {
321    let span = Span::new(pair.as_span().start(), pair.as_span().end());
322    let mut inner = pair.into_inner();
323
324    // Parse parameters (optional)
325    let mut params = Vec::new();
326    if let Some(params_pair) = inner.peek() {
327        if params_pair.as_rule() == Rule::lambda_params {
328            let params_pair = inner.next().unwrap();
329            for param in params_pair.into_inner() {
330                params.push(param.as_str().to_string());
331            }
332        }
333    }
334
335    // Parse body (lambda_body wraps either block or expression)
336    let body_pair = inner.next().unwrap();
337    let body = if body_pair.as_rule() == Rule::lambda_body {
338        // Unwrap lambda_body to get the actual block or expression
339        let inner_body = body_pair.into_inner().next().unwrap();
340        match inner_body.as_rule() {
341            Rule::block => LambdaBody::Block(parse_block(inner_body)?),
342            _ => LambdaBody::Expression(Box::new(parse_expression(inner_body)?)),
343        }
344    } else {
345        // Direct handling (shouldn't happen but handle gracefully)
346        match body_pair.as_rule() {
347            Rule::block => LambdaBody::Block(parse_block(body_pair)?),
348            _ => LambdaBody::Expression(Box::new(parse_expression(body_pair)?)),
349        }
350    };
351
352    Ok(Lambda { params, body, span })
353}
354
355fn parse_match_expr(pair: pest::iterators::Pair<Rule>) -> GentResult<MatchExpr> {
356    let span = Span::new(pair.as_span().start(), pair.as_span().end());
357    let mut inner = pair.into_inner();
358
359    let subject = Box::new(parse_expression(inner.next().unwrap())?);
360    let mut arms = Vec::new();
361
362    for arm_pair in inner {
363        arms.push(parse_match_arm(arm_pair)?);
364    }
365
366    Ok(MatchExpr { subject, arms, span })
367}
368
369fn parse_match_arm(pair: pest::iterators::Pair<Rule>) -> GentResult<MatchArm> {
370    let span = Span::new(pair.as_span().start(), pair.as_span().end());
371    let mut inner = pair.into_inner();
372
373    let pattern_pair = inner.next().unwrap();
374    let pattern = parse_match_pattern(pattern_pair)?;
375
376    let body_pair = inner.next().unwrap();
377    let body = parse_match_body(body_pair)?;
378
379    Ok(MatchArm { pattern, body, span })
380}
381
382fn parse_match_pattern(pair: pest::iterators::Pair<Rule>) -> GentResult<MatchPattern> {
383    let inner = pair.into_inner().next().unwrap();
384
385    match inner.as_rule() {
386        Rule::wildcard_pattern => Ok(MatchPattern::Wildcard),
387        Rule::enum_pattern => {
388            let mut parts = inner.into_inner();
389            let enum_name = parts.next().unwrap().as_str().to_string();
390            let variant_name = parts.next().unwrap().as_str().to_string();
391
392            let mut bindings = Vec::new();
393            if let Some(bindings_pair) = parts.next() {
394                for binding in bindings_pair.into_inner() {
395                    bindings.push(binding.as_str().to_string());
396                }
397            }
398
399            Ok(MatchPattern::EnumVariant {
400                enum_name,
401                variant_name,
402                bindings,
403            })
404        }
405        _ => unreachable!(),
406    }
407}
408
409fn parse_match_body(pair: pest::iterators::Pair<Rule>) -> GentResult<MatchBody> {
410    let inner = pair.into_inner().next().unwrap();
411
412    match inner.as_rule() {
413        Rule::block => Ok(MatchBody::Block(parse_block(inner)?)),
414        _ => Ok(MatchBody::Expression(Box::new(parse_expression(inner)?))),
415    }
416}
417
418/// Parse binary left-associative operators
419/// The grammar is: level = { next_level ~ ((op1 | op2 | ...) ~ next_level)* }
420/// Pest gives us all children at next_level, so we need to extract operators from source positions
421fn parse_binary_left(
422    pair: pest::iterators::Pair<Rule>,
423    ops: &[BinaryOp],
424) -> GentResult<Expression> {
425    let span = Span::new(pair.as_span().start(), pair.as_span().end());
426    let source = pair.as_str();
427    let base_pos = pair.as_span().start();
428
429    let inner = pair.into_inner();
430    let pairs: Vec<_> = inner.collect();
431
432    // If there's only one element, it's not a binary operation
433    if pairs.len() == 1 {
434        return parse_expression(pairs[0].clone());
435    }
436
437    // Parse first operand
438    let mut left = parse_expression(pairs[0].clone())?;
439    let mut last_end = pairs[0].as_span().end() - base_pos;
440
441    // Process remaining operands
442    for right_pair in pairs.iter().skip(1) {
443        let right_start = right_pair.as_span().start() - base_pos;
444
445        // Extract operator from the text between last operand and next operand
446        let between = &source[last_end..right_start];
447        let op_str = between.trim();
448
449        let op = match op_str {
450            "||" => BinaryOp::Or,
451            "&&" => BinaryOp::And,
452            "==" => BinaryOp::Eq,
453            "!=" => BinaryOp::Ne,
454            "<" => BinaryOp::Lt,
455            "<=" => BinaryOp::Le,
456            ">" => BinaryOp::Gt,
457            ">=" => BinaryOp::Ge,
458            "+" => BinaryOp::Add,
459            "-" => BinaryOp::Sub,
460            "*" => BinaryOp::Mul,
461            "/" => BinaryOp::Div,
462            "%" => BinaryOp::Mod,
463            _ => {
464                return Err(GentError::SyntaxError {
465                    message: format!("Unknown operator: {}", op_str),
466                    span: span.clone(),
467                })
468            }
469        };
470
471        // Verify this operator is in the expected set
472        if !ops.contains(&op) {
473            return Err(GentError::SyntaxError {
474                message: format!(
475                    "Unexpected operator: {} (expected one of {:?})",
476                    op_str, ops
477                ),
478                span: span.clone(),
479            });
480        }
481
482        let right = parse_expression(right_pair.clone())?;
483        left = Expression::Binary(op, Box::new(left), Box::new(right), span.clone());
484        last_end = right_pair.as_span().end() - base_pos;
485    }
486
487    Ok(left)
488}
489
490/// Parse unary operators
491fn parse_unary(pair: pest::iterators::Pair<Rule>) -> GentResult<Expression> {
492    let span = Span::new(pair.as_span().start(), pair.as_span().end());
493    let source = pair.as_str();
494    let base_pos = pair.as_span().start();
495
496    // Special case: Check if this is a negative number literal
497    let full_text = source.trim();
498    if full_text.starts_with('-') && full_text.len() > 1 {
499        let rest = full_text[1..].trim();
500        // Check if it's purely a number (no operators, just digits and maybe a decimal point)
501        if rest.chars().all(|c| c.is_ascii_digit() || c == '.') {
502            if let Ok(num) = full_text.parse::<f64>() {
503                return Ok(Expression::Number(num, span));
504            }
505        }
506    }
507
508    let inner = pair.into_inner();
509    let pairs: Vec<_> = inner.collect();
510
511    // If there's only one child, no unary operators
512    if pairs.len() == 1 {
513        return parse_expression(pairs[0].clone());
514    }
515
516    // Collect unary operators from the source text
517    let mut ops = Vec::new();
518
519    // The last pair is the operand, everything before are unary operators
520    let operand_pair = &pairs[pairs.len() - 1];
521    let operand_start = operand_pair.as_span().start() - base_pos;
522
523    // Extract operators from the text before the operand
524    let op_text = &source[..operand_start].trim();
525    for ch in op_text.chars() {
526        match ch {
527            '!' => ops.push(UnaryOp::Not),
528            '-' => ops.push(UnaryOp::Neg),
529            _ => {}
530        }
531    }
532
533    let mut expr = parse_expression(operand_pair.clone())?;
534
535    // Apply operators right-to-left (from the innermost to outermost)
536    for op in ops.into_iter().rev() {
537        expr = Expression::Unary(op, Box::new(expr), span.clone());
538    }
539
540    Ok(expr)
541}
542
543/// Parse postfix expressions (call, member, index)
544fn parse_postfix(pair: pest::iterators::Pair<Rule>) -> GentResult<Expression> {
545    let span = Span::new(pair.as_span().start(), pair.as_span().end());
546    let mut inner = pair.into_inner();
547
548    let mut expr = parse_expression(inner.next().unwrap())?;
549
550    for postfix_pair in inner {
551        match postfix_pair.as_rule() {
552            Rule::call_expr => {
553                let args = parse_arg_list(postfix_pair)?;
554                expr = Expression::Call(Box::new(expr), args, span.clone());
555            }
556            Rule::member_expr => {
557                let member_inner = postfix_pair.into_inner().next().unwrap();
558                let member_name = member_inner.as_str().to_string();
559                expr = Expression::Member(Box::new(expr), member_name, span.clone());
560            }
561            Rule::index_expr => {
562                let index_inner = postfix_pair.into_inner().next().unwrap();
563                let index = parse_expression(index_inner)?;
564                expr = Expression::Index(Box::new(expr), Box::new(index), span.clone());
565            }
566            _ => {}
567        }
568    }
569
570    Ok(expr)
571}
572
573/// Parse argument list for function calls
574fn parse_arg_list(pair: pest::iterators::Pair<Rule>) -> GentResult<Vec<Expression>> {
575    let mut args = Vec::new();
576
577    for inner in pair.into_inner() {
578        if inner.as_rule() == Rule::arg_list {
579            for arg_pair in inner.into_inner() {
580                args.push(parse_expression(arg_pair)?);
581            }
582        }
583    }
584
585    Ok(args)
586}
587
588/// Parse array literal [1, 2, 3]
589fn parse_array_literal(pair: pest::iterators::Pair<Rule>) -> GentResult<Expression> {
590    let span = Span::new(pair.as_span().start(), pair.as_span().end());
591    let mut elements = Vec::new();
592
593    for inner in pair.into_inner() {
594        elements.push(parse_expression(inner)?);
595    }
596
597    Ok(Expression::Array(elements, span))
598}
599
600/// Parse object literal {key: value, ...}
601fn parse_object_literal(pair: pest::iterators::Pair<Rule>) -> GentResult<Expression> {
602    let span = Span::new(pair.as_span().start(), pair.as_span().end());
603    let mut fields = Vec::new();
604
605    for field_pair in pair.into_inner() {
606        if field_pair.as_rule() == Rule::object_field {
607            let mut field_inner = field_pair.into_inner();
608
609            let key_pair = field_inner.next().unwrap();
610            let key = match key_pair.as_rule() {
611                Rule::identifier => key_pair.as_str().to_string(),
612                Rule::string_literal => {
613                    let raw = key_pair.as_str();
614                    let content = &raw[1..raw.len() - 1];
615                    unescape_string(content)
616                }
617                _ => {
618                    return Err(GentError::SyntaxError {
619                        message: "Expected identifier or string for object key".to_string(),
620                        span: Span::new(key_pair.as_span().start(), key_pair.as_span().end()),
621                    })
622                }
623            };
624
625            let value = parse_expression(field_inner.next().unwrap())?;
626            fields.push((key, value));
627        }
628    }
629
630    Ok(Expression::Object(fields, span))
631}
632
633fn parse_tool_decl(pair: pest::iterators::Pair<Rule>) -> GentResult<ToolDecl> {
634    let span = Span::new(pair.as_span().start(), pair.as_span().end());
635    let mut inner = pair.into_inner();
636
637    let name = inner.next().unwrap().as_str().to_string();
638    let mut params = Vec::new();
639    let mut return_type = None;
640    let mut body = None;
641
642    for item in inner {
643        match item.as_rule() {
644            Rule::param_list => {
645                params = parse_param_list(item)?;
646            }
647            Rule::return_type => {
648                let type_pair = item.into_inner().next().unwrap();
649                return_type = Some(parse_type_name(type_pair)?);
650            }
651            Rule::block => {
652                body = Some(parse_block(item)?);
653            }
654            _ => {}
655        }
656    }
657
658    Ok(ToolDecl {
659        name,
660        params,
661        return_type,
662        body: body.unwrap_or_else(|| Block {
663            statements: vec![],
664            span: span.clone(),
665        }),
666        span,
667    })
668}
669
670fn parse_fn_decl(pair: pest::iterators::Pair<Rule>) -> GentResult<FnDecl> {
671    let span = Span::new(pair.as_span().start(), pair.as_span().end());
672    let mut inner = pair.into_inner();
673
674    let name = inner.next().unwrap().as_str().to_string();
675    let mut params = Vec::new();
676    let mut return_type = None;
677    let mut body = None;
678
679    for item in inner {
680        match item.as_rule() {
681            Rule::param_list => {
682                params = parse_param_list(item)?;
683            }
684            Rule::return_type => {
685                let type_pair = item.into_inner().next().unwrap();
686                return_type = Some(parse_type_name(type_pair)?);
687            }
688            Rule::block => {
689                body = Some(parse_block(item)?);
690            }
691            _ => {}
692        }
693    }
694
695    Ok(FnDecl {
696        name,
697        params,
698        return_type,
699        body: body.unwrap_or_else(|| Block {
700            statements: vec![],
701            span: span.clone(),
702        }),
703        span,
704    })
705}
706
707fn parse_top_level_call(pair: pest::iterators::Pair<Rule>) -> GentResult<TopLevelCall> {
708    let span = Span::new(pair.as_span().start(), pair.as_span().end());
709    let mut inner = pair.into_inner();
710
711    let name = inner.next().unwrap().as_str().to_string();
712
713    let mut args = Vec::new();
714    if let Some(arg_list) = inner.next() {
715        for arg_pair in arg_list.into_inner() {
716            args.push(parse_expression(arg_pair)?);
717        }
718    }
719
720    Ok(TopLevelCall { name, args, span })
721}
722
723fn parse_param_list(pair: pest::iterators::Pair<Rule>) -> GentResult<Vec<Param>> {
724    let mut params = Vec::new();
725    for param_pair in pair.into_inner() {
726        if param_pair.as_rule() == Rule::param {
727            params.push(parse_param(param_pair)?);
728        }
729    }
730    Ok(params)
731}
732
733fn parse_param(pair: pest::iterators::Pair<Rule>) -> GentResult<Param> {
734    let span = Span::new(pair.as_span().start(), pair.as_span().end());
735    let mut inner = pair.into_inner();
736
737    let name = inner.next().unwrap().as_str().to_string();
738    let type_pair = inner.next().unwrap();
739    let type_name = parse_type_name(type_pair)?;
740
741    Ok(Param {
742        name,
743        type_name,
744        span,
745    })
746}
747
748fn parse_type_name(pair: pest::iterators::Pair<Rule>) -> GentResult<TypeName> {
749    match pair.as_str() {
750        "string" => Ok(TypeName::String),
751        "number" => Ok(TypeName::Number),
752        "boolean" => Ok(TypeName::Boolean),
753        "object" => Ok(TypeName::Object),
754        "array" => Ok(TypeName::Array),
755        "any" => Ok(TypeName::Any),
756        other => Err(GentError::SyntaxError {
757            message: format!("Unknown type: {}", other),
758            span: Span::new(pair.as_span().start(), pair.as_span().end()),
759        }),
760    }
761}
762
763fn parse_block(pair: pest::iterators::Pair<Rule>) -> GentResult<Block> {
764    let span = Span::new(pair.as_span().start(), pair.as_span().end());
765    let mut statements = Vec::new();
766
767    for stmt_pair in pair.into_inner() {
768        if stmt_pair.as_rule() == Rule::block_stmt {
769            statements.push(parse_block_stmt(stmt_pair)?);
770        }
771    }
772
773    Ok(Block { statements, span })
774}
775
776fn parse_block_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<BlockStmt> {
777    let inner = pair.into_inner().next().unwrap();
778    match inner.as_rule() {
779        Rule::let_stmt => Ok(BlockStmt::Let(parse_let_stmt(inner)?)),
780        Rule::assignment_stmt => Ok(BlockStmt::Assignment(parse_assignment_stmt(inner)?)),
781        Rule::return_stmt => Ok(BlockStmt::Return(parse_return_stmt(inner)?)),
782        Rule::if_stmt => Ok(BlockStmt::If(parse_if_stmt(inner)?)),
783        Rule::for_stmt => Ok(BlockStmt::For(parse_for_stmt(inner)?)),
784        Rule::while_stmt => Ok(BlockStmt::While(parse_while_stmt(inner)?)),
785        Rule::try_stmt => Ok(BlockStmt::Try(parse_try_stmt(inner)?)),
786        Rule::break_stmt => {
787            let span = Span::new(inner.as_span().start(), inner.as_span().end());
788            Ok(BlockStmt::Break(span))
789        }
790        Rule::continue_stmt => {
791            let span = Span::new(inner.as_span().start(), inner.as_span().end());
792            Ok(BlockStmt::Continue(span))
793        }
794        Rule::expr_stmt => {
795            let expr_pair = inner.into_inner().next().unwrap();
796            Ok(BlockStmt::Expr(parse_expression(expr_pair)?))
797        }
798        _ => Err(GentError::SyntaxError {
799            message: format!("Unexpected block statement: {:?}", inner.as_rule()),
800            span: Span::new(0, 0),
801        }),
802    }
803}
804
805fn parse_let_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<LetStmt> {
806    let span = Span::new(pair.as_span().start(), pair.as_span().end());
807    let mut inner = pair.into_inner();
808
809    let name = inner.next().unwrap().as_str().to_string();
810    let value = parse_expression(inner.next().unwrap())?;
811
812    Ok(LetStmt { name, value, span })
813}
814
815fn parse_assignment_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<AssignmentStmt> {
816    let span = Span::new(pair.as_span().start(), pair.as_span().end());
817    let mut inner = pair.into_inner();
818
819    let name = inner.next().unwrap().as_str().to_string();
820    let value = parse_expression(inner.next().unwrap())?;
821
822    Ok(AssignmentStmt { name, value, span })
823}
824
825fn parse_return_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<ReturnStmt> {
826    let span = Span::new(pair.as_span().start(), pair.as_span().end());
827    let value = pair
828        .into_inner()
829        .next()
830        .map(|p| parse_expression(p))
831        .transpose()?;
832
833    Ok(ReturnStmt { value, span })
834}
835
836fn parse_if_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<IfStmt> {
837    let span = Span::new(pair.as_span().start(), pair.as_span().end());
838    let mut inner = pair.into_inner();
839
840    let condition = parse_expression(inner.next().unwrap())?;
841    let then_block = parse_block(inner.next().unwrap())?;
842    let else_block = inner.next().map(|p| parse_block(p)).transpose()?;
843
844    Ok(IfStmt {
845        condition,
846        then_block,
847        else_block,
848        span,
849    })
850}
851
852fn parse_for_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<ForStmt> {
853    let span = Span::new(pair.as_span().start(), pair.as_span().end());
854    let mut inner = pair.into_inner();
855
856    let variable = inner.next().unwrap().as_str().to_string();
857    let iterable = parse_expression(inner.next().unwrap())?;
858    let body = parse_block(inner.next().unwrap())?;
859
860    Ok(ForStmt {
861        variable,
862        iterable,
863        body,
864        span,
865    })
866}
867
868fn parse_while_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<WhileStmt> {
869    let span = Span::new(pair.as_span().start(), pair.as_span().end());
870    let mut inner = pair.into_inner();
871
872    let condition = parse_expression(inner.next().unwrap())?;
873    let body = parse_block(inner.next().unwrap())?;
874
875    Ok(WhileStmt {
876        condition,
877        body,
878        span,
879    })
880}
881
882fn parse_try_stmt(pair: pest::iterators::Pair<Rule>) -> GentResult<TryStmt> {
883    let span = Span::new(pair.as_span().start(), pair.as_span().end());
884    let mut inner = pair.into_inner();
885
886    let try_block = parse_block(inner.next().unwrap())?;
887    let error_var = inner.next().unwrap().as_str().to_string();
888    let catch_block = parse_block(inner.next().unwrap())?;
889
890    Ok(TryStmt {
891        try_block,
892        error_var,
893        catch_block,
894        span,
895    })
896}
897
898fn parse_range_expr(pair: pest::iterators::Pair<Rule>) -> GentResult<Expression> {
899    let span = Span::new(pair.as_span().start(), pair.as_span().end());
900    let mut inner = pair.into_inner();
901
902    let start = parse_expression(inner.next().unwrap())?;
903    let end = parse_expression(inner.next().unwrap())?;
904
905    Ok(Expression::Range(Box::new(start), Box::new(end), span))
906}
907
908fn parse_struct_decl(pair: pest::iterators::Pair<Rule>) -> GentResult<StructDecl> {
909    let span = Span::new(pair.as_span().start(), pair.as_span().end());
910    let mut inner = pair.into_inner();
911
912    let name = inner.next().unwrap().as_str().to_string();
913    let body = inner.next().unwrap();
914    let fields = parse_struct_body(body)?;
915
916    Ok(StructDecl { name, fields, span })
917}
918
919fn parse_struct_body(pair: pest::iterators::Pair<Rule>) -> GentResult<Vec<StructField>> {
920    let mut fields = Vec::new();
921    for field_pair in pair.into_inner() {
922        if field_pair.as_rule() == Rule::struct_field {
923            fields.push(parse_struct_field(field_pair)?);
924        }
925    }
926    Ok(fields)
927}
928
929fn parse_struct_field(pair: pest::iterators::Pair<Rule>) -> GentResult<StructField> {
930    let span = Span::new(pair.as_span().start(), pair.as_span().end());
931    let mut inner = pair.into_inner();
932
933    let name = inner.next().unwrap().as_str().to_string();
934    let field_type = parse_field_type(inner.next().unwrap())?;
935
936    Ok(StructField {
937        name,
938        field_type,
939        span,
940    })
941}
942
943fn parse_field_type(pair: pest::iterators::Pair<Rule>) -> GentResult<FieldType> {
944    let inner = pair.into_inner().next().unwrap();
945    match inner.as_rule() {
946        Rule::field_type_array => {
947            let base = inner.into_inner().next().unwrap();
948            let base_type = parse_field_type_base(base)?;
949            Ok(FieldType::Array(Box::new(base_type)))
950        }
951        Rule::field_type_object => {
952            let body = inner.into_inner().next().unwrap();
953            let fields = parse_struct_body(body)?;
954            Ok(FieldType::Object(fields))
955        }
956        Rule::field_type_named => {
957            let name = inner.into_inner().next().unwrap().as_str();
958            match name {
959                "string" => Ok(FieldType::String),
960                "number" => Ok(FieldType::Number),
961                "boolean" => Ok(FieldType::Boolean),
962                _ => Ok(FieldType::Named(name.to_string())),
963            }
964        }
965        _ => Err(GentError::SyntaxError {
966            message: format!("Unexpected field type rule: {:?}", inner.as_rule()),
967            span: Span::new(inner.as_span().start(), inner.as_span().end()),
968        }),
969    }
970}
971
972fn parse_field_type_base(pair: pest::iterators::Pair<Rule>) -> GentResult<FieldType> {
973    let name = pair.as_str();
974    match name {
975        "string" => Ok(FieldType::String),
976        "number" => Ok(FieldType::Number),
977        "boolean" => Ok(FieldType::Boolean),
978        _ => Ok(FieldType::Named(name.to_string())),
979    }
980}
981
982fn unescape_string(s: &str) -> String {
983    let mut result = String::new();
984    let mut chars = s.chars().peekable();
985    while let Some(c) = chars.next() {
986        if c == '\\' {
987            if let Some(&next) = chars.peek() {
988                match next {
989                    '"' => {
990                        result.push('"');
991                        chars.next();
992                    }
993                    '\\' => {
994                        result.push('\\');
995                        chars.next();
996                    }
997                    'n' => {
998                        result.push('\n');
999                        chars.next();
1000                    }
1001                    'r' => {
1002                        result.push('\r');
1003                        chars.next();
1004                    }
1005                    't' => {
1006                        result.push('\t');
1007                        chars.next();
1008                    }
1009                    '{' => {
1010                        result.push('{');
1011                        chars.next();
1012                    }
1013                    '}' => {
1014                        result.push('}');
1015                        chars.next();
1016                    }
1017                    _ => result.push(c),
1018                }
1019            } else {
1020                result.push(c);
1021            }
1022        } else {
1023            result.push(c);
1024        }
1025    }
1026    result
1027}
1028
1029fn parse_output_type_from_expr(expr: &Expression) -> GentResult<OutputType> {
1030    match expr {
1031        Expression::Identifier(name, _) => Ok(OutputType::Named(name.clone())),
1032        Expression::Object(fields, _) => {
1033            let struct_fields = fields
1034                .iter()
1035                .map(|(name, value)| {
1036                    let field_type = infer_field_type_from_expr(value)?;
1037                    Ok(StructField {
1038                        name: name.clone(),
1039                        field_type,
1040                        span: value.span().clone(),
1041                    })
1042                })
1043                .collect::<GentResult<Vec<_>>>()?;
1044            Ok(OutputType::Inline(struct_fields))
1045        }
1046        _ => Err(GentError::SyntaxError {
1047            message: "output must be an identifier or object type".to_string(),
1048            span: expr.span().clone(),
1049        }),
1050    }
1051}
1052
1053fn infer_field_type_from_expr(expr: &Expression) -> GentResult<FieldType> {
1054    match expr {
1055        Expression::Identifier(name, _) => match name.as_str() {
1056            "string" => Ok(FieldType::String),
1057            "number" => Ok(FieldType::Number),
1058            "boolean" => Ok(FieldType::Boolean),
1059            _ => Ok(FieldType::Named(name.clone())),
1060        },
1061        _ => Err(GentError::SyntaxError {
1062            message: "Invalid type expression".to_string(),
1063            span: expr.span().clone(),
1064        }),
1065    }
1066}
1067
1068fn parse_enum_decl(pair: pest::iterators::Pair<Rule>) -> GentResult<EnumDecl> {
1069    let span = Span::new(pair.as_span().start(), pair.as_span().end());
1070    let mut inner = pair.into_inner();
1071
1072    let name = inner.next().unwrap().as_str().to_string();
1073    let mut variants = Vec::new();
1074
1075    if let Some(body) = inner.next() {
1076        for variant_pair in body.into_inner() {
1077            variants.push(parse_enum_variant(variant_pair)?);
1078        }
1079    }
1080
1081    Ok(EnumDecl { name, variants, span })
1082}
1083
1084fn parse_enum_variant(pair: pest::iterators::Pair<Rule>) -> GentResult<EnumVariant> {
1085    let span = Span::new(pair.as_span().start(), pair.as_span().end());
1086    let mut inner = pair.into_inner();
1087
1088    let name = inner.next().unwrap().as_str().to_string();
1089    let mut fields = Vec::new();
1090
1091    // Check for variant data
1092    if let Some(data_pair) = inner.next() {
1093        let field_list = data_pair.into_inner().next().unwrap();
1094        for field_pair in field_list.into_inner() {
1095            fields.push(parse_enum_field(field_pair)?);
1096        }
1097    }
1098
1099    Ok(EnumVariant { name, fields, span })
1100}
1101
1102fn parse_enum_field(pair: pest::iterators::Pair<Rule>) -> GentResult<EnumField> {
1103    let span = Span::new(pair.as_span().start(), pair.as_span().end());
1104    let mut inner = pair.into_inner();
1105
1106    let first = inner.next().unwrap();
1107    let (name, type_name) = if let Some(second) = inner.next() {
1108        // Named field: name: type
1109        (Some(first.as_str().to_string()), second.as_str().to_string())
1110    } else {
1111        // Unnamed field: just type
1112        (None, first.as_str().to_string())
1113    };
1114
1115    Ok(EnumField { name, type_name, span })
1116}
1117
1118fn parse_parallel_decl(pair: pest::iterators::Pair<Rule>) -> GentResult<ParallelDecl> {
1119    let span = Span::new(pair.as_span().start(), pair.as_span().end());
1120    let mut inner = pair.into_inner();
1121
1122    let name = inner.next().unwrap().as_str().to_string();
1123
1124    let mut agents = Vec::new();
1125    let mut timeout = None;
1126
1127    // Parse parallel_body -> parallel_field*
1128    for field_pair in inner {
1129        match field_pair.as_rule() {
1130            Rule::parallel_body => {
1131                for item in field_pair.into_inner() {
1132                    match item.as_rule() {
1133                        Rule::parallel_field => {
1134                            let field_inner = item.into_inner().next().unwrap();
1135                            match field_inner.as_rule() {
1136                                Rule::agents_field => {
1137                                    for expr_pair in field_inner.into_inner() {
1138                                        agents.push(parse_expression(expr_pair)?);
1139                                    }
1140                                }
1141                                Rule::timeout_field => {
1142                                    let duration_pair = field_inner.into_inner().next().unwrap();
1143                                    timeout = Some(parse_duration(duration_pair)?);
1144                                }
1145                                _ => {}
1146                            }
1147                        }
1148                        _ => {}
1149                    }
1150                }
1151            }
1152            _ => {}
1153        }
1154    }
1155
1156    let timeout = timeout.ok_or_else(|| GentError::SyntaxError {
1157        message: "parallel block requires 'timeout' field".to_string(),
1158        span: span.clone(),
1159    })?;
1160
1161    if agents.is_empty() {
1162        return Err(GentError::SyntaxError {
1163            message: "parallel block requires at least one agent in 'agents' field".to_string(),
1164            span: span.clone(),
1165        });
1166    }
1167
1168    Ok(ParallelDecl {
1169        name,
1170        agents,
1171        timeout,
1172        span,
1173    })
1174}
1175
1176fn parse_duration(pair: pest::iterators::Pair<Rule>) -> GentResult<Duration> {
1177    let span = Span::new(pair.as_span().start(), pair.as_span().end());
1178    let text = pair.as_str();
1179
1180    // Parse "30s", "2m", "500ms"
1181    let (value_str, unit) = if text.ends_with("ms") {
1182        (&text[..text.len() - 2], DurationUnit::Milliseconds)
1183    } else if text.ends_with('s') {
1184        (&text[..text.len() - 1], DurationUnit::Seconds)
1185    } else if text.ends_with('m') {
1186        (&text[..text.len() - 1], DurationUnit::Minutes)
1187    } else {
1188        return Err(GentError::SyntaxError {
1189            message: format!("Invalid duration: {}", text),
1190            span,
1191        });
1192    };
1193
1194    let value = value_str.parse::<u64>().map_err(|_| GentError::SyntaxError {
1195        message: format!("Invalid duration value: {}", value_str),
1196        span: span.clone(),
1197    })?;
1198
1199    Ok(Duration { value, unit, span })
1200}