shape_ast/parser/expressions/control_flow/
loops.rs1use crate::ast::{
13 Assignment, AsyncLetExpr, BlockExpr, BlockItem, Expr, ForExpr, IfStatement, LetExpr, LoopExpr,
14 Span, Statement, WhileExpr,
15};
16use crate::error::{Result, ShapeError};
17use crate::parser::Rule;
18use pest::iterators::Pair;
19
20use super::super::super::pair_span;
21use super::pattern_matching::parse_pattern;
22use crate::parser::pair_location;
23
24pub fn parse_while_expr(pair: Pair<Rule>) -> Result<Expr> {
26 let span = pair_span(&pair);
27 let pair_loc = pair_location(&pair);
28 let mut inner = pair.into_inner();
29
30 let condition_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
31 message: "expected condition in while expression".to_string(),
32 location: Some(pair_loc.clone()),
33 })?;
34 let condition = super::super::parse_expression(condition_pair)?;
35 let body_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
36 message: "expected body in while expression".to_string(),
37 location: Some(pair_loc),
38 })?;
39 let body = parse_block_expr(body_pair)?;
40
41 Ok(Expr::While(
42 Box::new(WhileExpr {
43 condition: Box::new(condition),
44 body: Box::new(body),
45 }),
46 span,
47 ))
48}
49
50pub fn parse_for_expr(pair: Pair<Rule>) -> Result<Expr> {
52 let span = pair_span(&pair);
53 let pair_loc = pair_location(&pair);
54 let is_async = pair.as_str().trim_start().starts_with("for") && pair.as_str().contains("await");
56 let mut inner = pair.into_inner();
57
58 let for_clause = inner.next().ok_or_else(|| ShapeError::ParseError {
59 message: "expected for clause".to_string(),
60 location: Some(pair_loc.clone()),
61 })?;
62 let clause_loc = pair_location(&for_clause);
63 let mut clause_inner = for_clause.into_inner();
64 let pattern_pair = clause_inner.next().ok_or_else(|| ShapeError::ParseError {
65 message: "expected pattern in for loop".to_string(),
66 location: Some(clause_loc.clone()),
67 })?;
68 let pattern = parse_pattern(pattern_pair)?;
69 let iterable_pair = clause_inner.next().ok_or_else(|| ShapeError::ParseError {
70 message: "expected iterable expression in for loop".to_string(),
71 location: Some(clause_loc),
72 })?;
73 let iterable = super::super::parse_expression(iterable_pair)?;
74
75 let body_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
76 message: "expected body in for expression".to_string(),
77 location: Some(pair_loc),
78 })?;
79 let body = parse_block_expr(body_pair)?;
80
81 Ok(Expr::For(
82 Box::new(ForExpr {
83 pattern,
84 iterable: Box::new(iterable),
85 body: Box::new(body),
86 is_async,
87 }),
88 span,
89 ))
90}
91
92pub fn parse_loop_expr(pair: Pair<Rule>) -> Result<Expr> {
94 let span = pair_span(&pair);
95 let pair_loc = pair_location(&pair);
96 let mut inner = pair.into_inner();
97 let body_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
98 message: "expected body in loop expression".to_string(),
99 location: Some(pair_loc),
100 })?;
101 let body = parse_block_expr(body_pair)?;
102
103 Ok(Expr::Loop(
104 Box::new(LoopExpr {
105 body: Box::new(body),
106 }),
107 span,
108 ))
109}
110
111pub fn parse_let_expr(pair: Pair<Rule>) -> Result<Expr> {
113 let span = pair_span(&pair);
114 let pair_loc = pair_location(&pair);
115 let mut inner = pair.into_inner();
116
117 let pattern_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
118 message: "expected pattern in let expression".to_string(),
119 location: Some(pair_loc.clone()),
120 })?;
121 let pattern = parse_pattern(pattern_pair)?;
122
123 let mut value = None;
125 let mut body_expr = None;
126
127 for next_pair in inner {
128 if next_pair.as_rule() == Rule::expression {
129 if value.is_none() {
130 value = Some(Box::new(super::super::parse_expression(next_pair)?));
131 } else {
132 body_expr = Some(super::super::parse_expression(next_pair)?);
133 }
134 }
135 }
136
137 let body = body_expr.ok_or_else(|| ShapeError::ParseError {
138 message: "let expression missing body".to_string(),
139 location: Some(pair_loc),
140 })?;
141
142 Ok(Expr::Let(
143 Box::new(LetExpr {
144 pattern,
145 type_annotation: None, value,
147 body: Box::new(body),
148 }),
149 span,
150 ))
151}
152
153pub fn parse_break_expr(pair: Pair<Rule>) -> Result<Expr> {
155 let span = pair_span(&pair);
156 let mut inner = pair
158 .into_inner()
159 .filter(|p| p.as_rule() != Rule::break_keyword);
160 let value = if let Some(expr) = inner.next() {
161 Some(Box::new(super::super::parse_expression(expr)?))
162 } else {
163 None
164 };
165 Ok(Expr::Break(value, span))
166}
167
168pub fn parse_return_expr(pair: Pair<Rule>) -> Result<Expr> {
170 let span = pair_span(&pair);
171 let keyword_line = pair.as_span().start_pos().line_col().0;
173 let mut inner = pair
175 .into_inner()
176 .filter(|p| p.as_rule() != Rule::return_keyword);
177 let value = if let Some(expr) = inner.next() {
178 let expr_line = expr.as_span().start_pos().line_col().0;
183 if expr_line > keyword_line {
184 None
185 } else {
186 Some(Box::new(super::super::parse_expression(expr)?))
187 }
188 } else {
189 None
190 };
191 Ok(Expr::Return(value, span))
192}
193
194pub fn parse_block_expr(pair: Pair<Rule>) -> Result<Expr> {
202 let span = pair_span(&pair);
203 let mut items = Vec::new();
204 let mut had_semi = Vec::new();
205
206 if let Some(block_items) = pair.into_inner().next() {
207 let source = block_items.as_str();
208 let block_start = block_items.as_span().start();
209 let inner_pairs: Vec<_> = block_items.into_inner().collect();
211
212 for item_pair in inner_pairs {
214 match item_pair.as_rule() {
215 Rule::block_statement => {
216 let stmt_end = item_pair.as_span().end();
218 let offset = stmt_end - block_start;
219 let has_semicolon = source[offset..].starts_with(';')
220 || source[offset..].trim_start().starts_with(';');
221
222 let inner = item_pair.into_inner().next().unwrap();
223 let inner_span = pair_span(&inner);
224 let block_item = parse_block_entry(inner)?;
225 let block_item = if has_semicolon {
228 expr_to_statement(block_item, inner_span)
229 } else {
230 block_item
231 };
232 had_semi.push(has_semicolon);
233 items.push(block_item);
234 }
235 Rule::block_item => {
236 let inner = item_pair.into_inner().next().unwrap();
238 let block_item = parse_block_entry(inner)?;
239 let block_item = if_stmt_to_tail_expr(block_item);
242 had_semi.push(false);
243 items.push(block_item);
244 }
245 _ => {} }
247 }
248 }
249
250 if items.is_empty() {
252 return Ok(Expr::Unit(span));
253 }
254
255 if let Some(&last_had_semi) = had_semi.last() {
260 if !last_had_semi {
261 if let Some(last) = items.pop() {
262 items.push(if_stmt_to_tail_expr(last));
263 }
264 }
265 }
266
267 Ok(Expr::Block(BlockExpr { items }, span))
268}
269
270fn expr_to_statement(item: BlockItem, span: Span) -> BlockItem {
274 match item {
275 BlockItem::Expression(expr) => BlockItem::Statement(Statement::Expression(expr, span)),
276 other => other,
277 }
278}
279
280fn if_stmt_to_tail_expr(item: BlockItem) -> BlockItem {
286 match item {
287 BlockItem::Statement(Statement::If(if_stmt, span)) => {
288 BlockItem::Expression(if_stmt_to_conditional(if_stmt, span))
289 }
290 other => other,
291 }
292}
293
294fn if_stmt_to_conditional(if_stmt: IfStatement, span: Span) -> Expr {
298 let then_expr = stmts_to_block_expr(if_stmt.then_body, span);
299
300 let else_expr = if_stmt.else_body.map(|stmts| {
301 if stmts.len() == 1 && matches!(stmts.first(), Some(Statement::If(..))) {
303 let mut iter = stmts.into_iter();
304 if let Some(Statement::If(nested_if, nested_span)) = iter.next() {
305 return Box::new(if_stmt_to_conditional(nested_if, nested_span));
306 }
307 return Box::new(stmts_to_block_expr(Vec::new(), span));
311 }
312 Box::new(stmts_to_block_expr(stmts, span))
313 });
314
315 Expr::Conditional {
316 condition: Box::new(if_stmt.condition),
317 then_expr: Box::new(then_expr),
318 else_expr,
319 span,
320 }
321}
322
323fn stmts_to_block_expr(stmts: Vec<Statement>, span: Span) -> Expr {
327 if stmts.is_empty() {
328 return Expr::Unit(span);
329 }
330 let len = stmts.len();
331 let mut items: Vec<BlockItem> = Vec::with_capacity(len);
332 for (i, s) in stmts.into_iter().enumerate() {
333 let is_last = i == len - 1;
334 if is_last {
335 match s {
336 Statement::Expression(expr, _) => {
338 items.push(BlockItem::Expression(expr));
339 }
340 Statement::If(nested_if, nested_span) => {
342 items.push(BlockItem::Expression(if_stmt_to_conditional(
343 nested_if,
344 nested_span,
345 )));
346 }
347 other => {
348 items.push(BlockItem::Statement(other));
349 }
350 }
351 } else {
352 items.push(BlockItem::Statement(s));
353 }
354 }
355 Expr::Block(BlockExpr { items }, span)
356}
357
358fn parse_block_entry(inner: Pair<Rule>) -> Result<BlockItem> {
359 match inner.as_rule() {
360 Rule::return_stmt => {
361 let return_span = pair_span(&inner);
362 let value = inner
363 .into_inner()
364 .filter(|p| p.as_rule() != Rule::return_keyword)
365 .next()
366 .map(|expr_pair| super::super::parse_expression(expr_pair))
367 .transpose()?
368 .map(Box::new);
369 Ok(BlockItem::Expression(Expr::Return(value, return_span)))
370 }
371 Rule::variable_decl => {
372 let decl = crate::parser::parse_variable_decl(inner)?;
373 Ok(BlockItem::VariableDecl(decl))
374 }
375 Rule::assignment => {
376 let mut inner = inner.into_inner();
377 let pattern = crate::parser::parse_pattern(inner.next().unwrap())?;
378 let value = super::super::parse_expression(inner.next().unwrap())?;
379 Ok(BlockItem::Assignment(Assignment { pattern, value }))
380 }
381 Rule::expression => {
382 let expr = super::super::parse_expression(inner)?;
383 Ok(BlockItem::Expression(expr))
384 }
385 Rule::if_stmt => {
386 let stmt = crate::parser::statements::parse_if_stmt(inner)?;
387 Ok(BlockItem::Statement(stmt))
388 }
389 Rule::for_loop => {
390 let stmt = crate::parser::statements::parse_for_loop(inner)?;
391 Ok(BlockItem::Statement(stmt))
392 }
393 Rule::while_loop => {
394 let stmt = crate::parser::statements::parse_while_loop(inner)?;
395 Ok(BlockItem::Statement(stmt))
396 }
397 Rule::extend_statement => {
398 let span = pair_span(&inner);
399 let ext = crate::parser::extensions::parse_extend_statement(inner)?;
400 Ok(BlockItem::Statement(crate::ast::Statement::Extend(
401 ext, span,
402 )))
403 }
404 Rule::remove_target_stmt => Ok(BlockItem::Statement(crate::ast::Statement::RemoveTarget(
405 pair_span(&inner),
406 ))),
407 Rule::set_param_value_stmt => {
408 let span = pair_span(&inner);
409 let mut parts = inner.into_inner();
410 let param_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
411 message: "expected parameter name in `set param` value directive".to_string(),
412 location: None,
413 })?;
414 let expr_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
415 message: "expected expression in `set param` value directive".to_string(),
416 location: None,
417 })?;
418 let expression = super::super::parse_expression(expr_pair)?;
419 Ok(BlockItem::Statement(crate::ast::Statement::SetParamValue {
420 param_name: param_pair.as_str().to_string(),
421 expression,
422 span,
423 }))
424 }
425 Rule::set_param_type_stmt => {
426 let span = pair_span(&inner);
427 let mut parts = inner.into_inner();
428 let param_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
429 message: "expected parameter name in `set param` directive".to_string(),
430 location: None,
431 })?;
432 let type_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
433 message: "expected type annotation in `set param` directive".to_string(),
434 location: None,
435 })?;
436 let type_annotation = crate::parser::types::parse_type_annotation(type_pair)?;
437 Ok(BlockItem::Statement(crate::ast::Statement::SetParamType {
438 param_name: param_pair.as_str().to_string(),
439 type_annotation,
440 span,
441 }))
442 }
443 Rule::set_return_stmt => {
444 let span = pair_span(&inner);
445 let mut parts = inner.into_inner();
446 let payload_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
447 message: "expected type annotation or expression in `set return` directive"
448 .to_string(),
449 location: None,
450 })?;
451 match payload_pair.as_rule() {
452 Rule::type_annotation => {
453 let type_annotation =
454 crate::parser::types::parse_type_annotation(payload_pair)?;
455 Ok(BlockItem::Statement(crate::ast::Statement::SetReturnType {
456 type_annotation,
457 span,
458 }))
459 }
460 Rule::set_return_expr_payload => {
461 let expr_pair =
462 payload_pair
463 .into_inner()
464 .next()
465 .ok_or_else(|| ShapeError::ParseError {
466 message:
467 "expected expression in parenthesized `set return` directive"
468 .to_string(),
469 location: None,
470 })?;
471 let expression = super::super::parse_expression(expr_pair)?;
472 Ok(BlockItem::Statement(crate::ast::Statement::SetReturnExpr {
473 expression,
474 span,
475 }))
476 }
477 _ => Err(ShapeError::ParseError {
478 message: "expected type annotation or expression in `set return` directive"
479 .to_string(),
480 location: None,
481 }),
482 }
483 }
484 Rule::replace_body_stmt => {
485 let span = pair_span(&inner);
486 let mut parts = inner.into_inner();
487 let Some(payload) = parts.next() else {
488 return Ok(BlockItem::Statement(crate::ast::Statement::ReplaceBody {
489 body: Vec::new(),
490 span,
491 }));
492 };
493 match payload.as_rule() {
494 Rule::replace_body_expr_payload => {
495 let expr_pair =
496 payload
497 .into_inner()
498 .next()
499 .ok_or_else(|| ShapeError::ParseError {
500 message:
501 "expected expression in parenthesized `replace body` directive"
502 .to_string(),
503 location: None,
504 })?;
505 let expression = super::super::parse_expression(expr_pair)?;
506 Ok(BlockItem::Statement(
507 crate::ast::Statement::ReplaceBodyExpr { expression, span },
508 ))
509 }
510 Rule::statement => {
511 let mut body = Vec::new();
512 body.push(crate::parser::statements::parse_statement(payload)?);
513 body.extend(crate::parser::statements::parse_statements(parts)?);
514 Ok(BlockItem::Statement(crate::ast::Statement::ReplaceBody {
515 body,
516 span,
517 }))
518 }
519 _ => Err(ShapeError::ParseError {
520 message: "expected body block or expression in `replace body` directive"
521 .to_string(),
522 location: None,
523 }),
524 }
525 }
526 Rule::replace_module_stmt => {
527 let span = pair_span(&inner);
528 let mut parts = inner.into_inner();
529 let payload = parts.next().ok_or_else(|| ShapeError::ParseError {
530 message: "expected expression payload in `replace module` directive".to_string(),
531 location: None,
532 })?;
533 if payload.as_rule() != Rule::replace_module_expr_payload {
534 return Err(ShapeError::ParseError {
535 message: "expected parenthesized expression in `replace module` directive"
536 .to_string(),
537 location: None,
538 });
539 }
540 let expr_pair = payload
541 .into_inner()
542 .next()
543 .ok_or_else(|| ShapeError::ParseError {
544 message: "expected expression in parenthesized `replace module` directive"
545 .to_string(),
546 location: None,
547 })?;
548 let expression = super::super::parse_expression(expr_pair)?;
549 Ok(BlockItem::Statement(
550 crate::ast::Statement::ReplaceModuleExpr { expression, span },
551 ))
552 }
553 Rule::function_def => {
556 let span = pair_span(&inner);
557 let func_def = crate::parser::functions::parse_function_def(inner)?;
558 let func_expr = Expr::FunctionExpr {
559 params: func_def.params,
560 return_type: func_def.return_type,
561 body: func_def.body,
562 span,
563 };
564 Ok(BlockItem::VariableDecl(crate::ast::VariableDecl {
565 kind: crate::ast::VarKind::Let,
566 is_mut: false,
567 pattern: crate::ast::DestructurePattern::Identifier(func_def.name, span),
568 type_annotation: None,
569 value: Some(func_expr),
570 ownership: Default::default(),
571 }))
572 }
573 _ => Err(ShapeError::ParseError {
574 message: format!("Unexpected block entry: {:?}", inner.as_rule()),
575 location: None,
576 }),
577 }
578}
579
580pub fn parse_async_let_expr(pair: Pair<Rule>) -> Result<Expr> {
583 let span = pair_span(&pair);
584 let pair_loc = pair_location(&pair);
585 let mut inner = pair.into_inner();
586
587 let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
588 message: "expected variable name in async let".to_string(),
589 location: Some(pair_loc.clone()),
590 })?;
591 let name = name_pair.as_str().to_string();
592
593 let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
594 message: "expected expression in async let".to_string(),
595 location: Some(pair_loc),
596 })?;
597 let expr = super::super::parse_expression(expr_pair)?;
598
599 Ok(Expr::AsyncLet(
600 Box::new(AsyncLetExpr {
601 name,
602 expr: Box::new(expr),
603 span,
604 }),
605 span,
606 ))
607}
608
609pub fn parse_async_scope_expr(pair: Pair<Rule>) -> Result<Expr> {
612 let span = pair_span(&pair);
613 let pair_loc = pair_location(&pair);
614 let mut inner = pair.into_inner();
615
616 let body_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
617 message: "expected body in async scope".to_string(),
618 location: Some(pair_loc),
619 })?;
620 let body = parse_block_expr(body_pair)?;
621
622 Ok(Expr::AsyncScope(Box::new(body), span))
623}