1pub 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
17pub 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 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 let item_inner = item_pair.into_inner().next().unwrap();
109 match item_inner.as_rule() {
110 Rule::use_stmt => {
111 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 output = Some(parse_output_field(item_inner)?);
121 }
122 Rule::agent_field => {
123 let field = parse_agent_field(item_inner)?;
124 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
155fn parse_output_field(pair: pest::iterators::Pair<Rule>) -> GentResult<OutputType> {
157 let output_type_pair = pair.into_inner().next().unwrap();
160 parse_output_type(output_type_pair)
161}
162
163fn 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
179fn 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 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 for sub in inner.into_inner() {
255 match sub.as_rule() {
256 Rule::multiline_chars => {
257 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 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 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 let body_pair = inner.next().unwrap();
337 let body = if body_pair.as_rule() == Rule::lambda_body {
338 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 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
418fn 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 pairs.len() == 1 {
434 return parse_expression(pairs[0].clone());
435 }
436
437 let mut left = parse_expression(pairs[0].clone())?;
439 let mut last_end = pairs[0].as_span().end() - base_pos;
440
441 for right_pair in pairs.iter().skip(1) {
443 let right_start = right_pair.as_span().start() - base_pos;
444
445 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 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
490fn 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 let full_text = source.trim();
498 if full_text.starts_with('-') && full_text.len() > 1 {
499 let rest = full_text[1..].trim();
500 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 pairs.len() == 1 {
513 return parse_expression(pairs[0].clone());
514 }
515
516 let mut ops = Vec::new();
518
519 let operand_pair = &pairs[pairs.len() - 1];
521 let operand_start = operand_pair.as_span().start() - base_pos;
522
523 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 for op in ops.into_iter().rev() {
537 expr = Expression::Unary(op, Box::new(expr), span.clone());
538 }
539
540 Ok(expr)
541}
542
543fn 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
573fn 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
588fn 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
600fn 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 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 (Some(first.as_str().to_string()), second.as_str().to_string())
1110 } else {
1111 (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 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 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}