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.into_inner();
157 let value = if let Some(expr) = inner.next() {
158 Some(Box::new(super::super::parse_expression(expr)?))
159 } else {
160 None
161 };
162 Ok(Expr::Break(value, span))
163}
164
165pub fn parse_return_expr(pair: Pair<Rule>) -> Result<Expr> {
167 let span = pair_span(&pair);
168 let mut inner = pair.into_inner();
169 let value = if let Some(expr) = inner.next() {
170 Some(Box::new(super::super::parse_expression(expr)?))
171 } else {
172 None
173 };
174 Ok(Expr::Return(value, span))
175}
176
177pub fn parse_block_expr(pair: Pair<Rule>) -> Result<Expr> {
179 let span = pair_span(&pair);
180 let mut items = Vec::new();
181
182 if let Some(block_items) = pair.into_inner().next() {
183 let inner_pairs: Vec<_> = block_items.into_inner().collect();
185
186 for item_pair in inner_pairs {
188 match item_pair.as_rule() {
189 Rule::block_statement => {
190 let inner = item_pair.into_inner().next().unwrap();
192 let block_item = parse_block_entry(inner)?;
193 items.push(block_item);
194 }
195 Rule::block_item => {
196 let inner = item_pair.into_inner().next().unwrap();
198 let block_item = parse_block_entry(inner)?;
199 let block_item = if_stmt_to_tail_expr(block_item);
202 items.push(block_item);
203 }
204 _ => {} }
206 }
207 }
208
209 if items.is_empty() {
211 return Ok(Expr::Unit(span));
212 }
213
214 if let Some(last) = items.pop() {
222 items.push(if_stmt_to_tail_expr(last));
223 }
224
225 Ok(Expr::Block(BlockExpr { items }, span))
226}
227
228fn if_stmt_to_tail_expr(item: BlockItem) -> BlockItem {
234 match item {
235 BlockItem::Statement(Statement::If(if_stmt, span)) => {
236 BlockItem::Expression(if_stmt_to_conditional(if_stmt, span))
237 }
238 other => other,
239 }
240}
241
242fn if_stmt_to_conditional(if_stmt: IfStatement, span: Span) -> Expr {
246 let then_expr = stmts_to_block_expr(if_stmt.then_body, span);
247
248 let else_expr = if_stmt.else_body.map(|stmts| {
249 if stmts.len() == 1 {
251 if matches!(stmts.first(), Some(Statement::If(..))) {
252 let stmt = stmts.into_iter().next().unwrap();
253 if let Statement::If(nested_if, nested_span) = stmt {
254 return Box::new(if_stmt_to_conditional(nested_if, nested_span));
255 }
256 unreachable!();
257 }
258 }
259 Box::new(stmts_to_block_expr(stmts, span))
260 });
261
262 Expr::Conditional {
263 condition: Box::new(if_stmt.condition),
264 then_expr: Box::new(then_expr),
265 else_expr,
266 span,
267 }
268}
269
270fn stmts_to_block_expr(stmts: Vec<Statement>, span: Span) -> Expr {
274 if stmts.is_empty() {
275 return Expr::Unit(span);
276 }
277 let len = stmts.len();
278 let mut items: Vec<BlockItem> = Vec::with_capacity(len);
279 for (i, s) in stmts.into_iter().enumerate() {
280 let is_last = i == len - 1;
281 if is_last {
282 match s {
283 Statement::Expression(expr, _) => {
285 items.push(BlockItem::Expression(expr));
286 }
287 Statement::If(nested_if, nested_span) => {
289 items.push(BlockItem::Expression(if_stmt_to_conditional(
290 nested_if,
291 nested_span,
292 )));
293 }
294 other => {
295 items.push(BlockItem::Statement(other));
296 }
297 }
298 } else {
299 items.push(BlockItem::Statement(s));
300 }
301 }
302 Expr::Block(BlockExpr { items }, span)
303}
304
305fn parse_block_entry(inner: Pair<Rule>) -> Result<BlockItem> {
306 match inner.as_rule() {
307 Rule::return_stmt => {
308 let return_span = pair_span(&inner);
309 let value = inner
310 .into_inner()
311 .filter(|p| p.as_rule() != Rule::return_keyword)
312 .next()
313 .map(|expr_pair| super::super::parse_expression(expr_pair))
314 .transpose()?
315 .map(Box::new);
316 Ok(BlockItem::Expression(Expr::Return(value, return_span)))
317 }
318 Rule::variable_decl => {
319 let decl = crate::parser::parse_variable_decl(inner)?;
320 Ok(BlockItem::VariableDecl(decl))
321 }
322 Rule::assignment => {
323 let mut inner = inner.into_inner();
324 let pattern = crate::parser::parse_pattern(inner.next().unwrap())?;
325 let value = super::super::parse_expression(inner.next().unwrap())?;
326 Ok(BlockItem::Assignment(Assignment { pattern, value }))
327 }
328 Rule::expression => {
329 let expr = super::super::parse_expression(inner)?;
330 Ok(BlockItem::Expression(expr))
331 }
332 Rule::if_stmt => {
333 let stmt = crate::parser::statements::parse_if_stmt(inner)?;
334 Ok(BlockItem::Statement(stmt))
335 }
336 Rule::for_loop => {
337 let stmt = crate::parser::statements::parse_for_loop(inner)?;
338 Ok(BlockItem::Statement(stmt))
339 }
340 Rule::while_loop => {
341 let stmt = crate::parser::statements::parse_while_loop(inner)?;
342 Ok(BlockItem::Statement(stmt))
343 }
344 Rule::extend_statement => {
345 let span = pair_span(&inner);
346 let ext = crate::parser::extensions::parse_extend_statement(inner)?;
347 Ok(BlockItem::Statement(crate::ast::Statement::Extend(
348 ext, span,
349 )))
350 }
351 Rule::remove_target_stmt => Ok(BlockItem::Statement(crate::ast::Statement::RemoveTarget(
352 pair_span(&inner),
353 ))),
354 Rule::set_param_value_stmt => {
355 let span = pair_span(&inner);
356 let mut parts = inner.into_inner();
357 let param_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
358 message: "expected parameter name in `set param` value directive".to_string(),
359 location: None,
360 })?;
361 let expr_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
362 message: "expected expression in `set param` value directive".to_string(),
363 location: None,
364 })?;
365 let expression = super::super::parse_expression(expr_pair)?;
366 Ok(BlockItem::Statement(crate::ast::Statement::SetParamValue {
367 param_name: param_pair.as_str().to_string(),
368 expression,
369 span,
370 }))
371 }
372 Rule::set_param_type_stmt => {
373 let span = pair_span(&inner);
374 let mut parts = inner.into_inner();
375 let param_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
376 message: "expected parameter name in `set param` directive".to_string(),
377 location: None,
378 })?;
379 let type_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
380 message: "expected type annotation in `set param` directive".to_string(),
381 location: None,
382 })?;
383 let type_annotation = crate::parser::types::parse_type_annotation(type_pair)?;
384 Ok(BlockItem::Statement(crate::ast::Statement::SetParamType {
385 param_name: param_pair.as_str().to_string(),
386 type_annotation,
387 span,
388 }))
389 }
390 Rule::set_return_stmt => {
391 let span = pair_span(&inner);
392 let mut parts = inner.into_inner();
393 let payload_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
394 message: "expected type annotation or expression in `set return` directive"
395 .to_string(),
396 location: None,
397 })?;
398 match payload_pair.as_rule() {
399 Rule::type_annotation => {
400 let type_annotation =
401 crate::parser::types::parse_type_annotation(payload_pair)?;
402 Ok(BlockItem::Statement(crate::ast::Statement::SetReturnType {
403 type_annotation,
404 span,
405 }))
406 }
407 Rule::set_return_expr_payload => {
408 let expr_pair =
409 payload_pair
410 .into_inner()
411 .next()
412 .ok_or_else(|| ShapeError::ParseError {
413 message:
414 "expected expression in parenthesized `set return` directive"
415 .to_string(),
416 location: None,
417 })?;
418 let expression = super::super::parse_expression(expr_pair)?;
419 Ok(BlockItem::Statement(crate::ast::Statement::SetReturnExpr {
420 expression,
421 span,
422 }))
423 }
424 _ => Err(ShapeError::ParseError {
425 message: "expected type annotation or expression in `set return` directive"
426 .to_string(),
427 location: None,
428 }),
429 }
430 }
431 Rule::replace_body_stmt => {
432 let span = pair_span(&inner);
433 let mut parts = inner.into_inner();
434 let Some(payload) = parts.next() else {
435 return Ok(BlockItem::Statement(crate::ast::Statement::ReplaceBody {
436 body: Vec::new(),
437 span,
438 }));
439 };
440 match payload.as_rule() {
441 Rule::replace_body_expr_payload => {
442 let expr_pair =
443 payload
444 .into_inner()
445 .next()
446 .ok_or_else(|| ShapeError::ParseError {
447 message:
448 "expected expression in parenthesized `replace body` directive"
449 .to_string(),
450 location: None,
451 })?;
452 let expression = super::super::parse_expression(expr_pair)?;
453 Ok(BlockItem::Statement(
454 crate::ast::Statement::ReplaceBodyExpr { expression, span },
455 ))
456 }
457 Rule::statement => {
458 let mut body = Vec::new();
459 body.push(crate::parser::statements::parse_statement(payload)?);
460 body.extend(crate::parser::statements::parse_statements(parts)?);
461 Ok(BlockItem::Statement(crate::ast::Statement::ReplaceBody {
462 body,
463 span,
464 }))
465 }
466 _ => Err(ShapeError::ParseError {
467 message: "expected body block or expression in `replace body` directive"
468 .to_string(),
469 location: None,
470 }),
471 }
472 }
473 Rule::replace_module_stmt => {
474 let span = pair_span(&inner);
475 let mut parts = inner.into_inner();
476 let payload = parts.next().ok_or_else(|| ShapeError::ParseError {
477 message: "expected expression payload in `replace module` directive".to_string(),
478 location: None,
479 })?;
480 if payload.as_rule() != Rule::replace_module_expr_payload {
481 return Err(ShapeError::ParseError {
482 message: "expected parenthesized expression in `replace module` directive"
483 .to_string(),
484 location: None,
485 });
486 }
487 let expr_pair = payload
488 .into_inner()
489 .next()
490 .ok_or_else(|| ShapeError::ParseError {
491 message: "expected expression in parenthesized `replace module` directive"
492 .to_string(),
493 location: None,
494 })?;
495 let expression = super::super::parse_expression(expr_pair)?;
496 Ok(BlockItem::Statement(
497 crate::ast::Statement::ReplaceModuleExpr { expression, span },
498 ))
499 }
500 Rule::function_def => {
503 let span = pair_span(&inner);
504 let func_def = crate::parser::functions::parse_function_def(inner)?;
505 let func_expr = Expr::FunctionExpr {
506 params: func_def.params,
507 return_type: func_def.return_type,
508 body: func_def.body,
509 span,
510 };
511 Ok(BlockItem::VariableDecl(crate::ast::VariableDecl {
512 kind: crate::ast::VarKind::Let,
513 is_mut: false,
514 pattern: crate::ast::DestructurePattern::Identifier(func_def.name, span),
515 type_annotation: None,
516 value: Some(func_expr),
517 ownership: Default::default(),
518 }))
519 }
520 _ => Err(ShapeError::ParseError {
521 message: format!("Unexpected block entry: {:?}", inner.as_rule()),
522 location: None,
523 }),
524 }
525}
526
527pub fn parse_async_let_expr(pair: Pair<Rule>) -> Result<Expr> {
530 let span = pair_span(&pair);
531 let pair_loc = pair_location(&pair);
532 let mut inner = pair.into_inner();
533
534 let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
535 message: "expected variable name in async let".to_string(),
536 location: Some(pair_loc.clone()),
537 })?;
538 let name = name_pair.as_str().to_string();
539
540 let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
541 message: "expected expression in async let".to_string(),
542 location: Some(pair_loc),
543 })?;
544 let expr = super::super::parse_expression(expr_pair)?;
545
546 Ok(Expr::AsyncLet(
547 Box::new(AsyncLetExpr {
548 name,
549 expr: Box::new(expr),
550 span,
551 }),
552 span,
553 ))
554}
555
556pub fn parse_async_scope_expr(pair: Pair<Rule>) -> Result<Expr> {
559 let span = pair_span(&pair);
560 let pair_loc = pair_location(&pair);
561 let mut inner = pair.into_inner();
562
563 let body_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
564 message: "expected body in async scope".to_string(),
565 location: Some(pair_loc),
566 })?;
567 let body = parse_block_expr(body_pair)?;
568
569 Ok(Expr::AsyncScope(Box::new(body), span))
570}