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_type_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` directive".to_string(),
359 location: None,
360 })?;
361 let type_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
362 message: "expected type annotation in `set param` directive".to_string(),
363 location: None,
364 })?;
365 let type_annotation = crate::parser::types::parse_type_annotation(type_pair)?;
366 Ok(BlockItem::Statement(crate::ast::Statement::SetParamType {
367 param_name: param_pair.as_str().to_string(),
368 type_annotation,
369 span,
370 }))
371 }
372 Rule::set_return_stmt => {
373 let span = pair_span(&inner);
374 let mut parts = inner.into_inner();
375 let payload_pair = parts.next().ok_or_else(|| ShapeError::ParseError {
376 message: "expected type annotation or expression in `set return` directive"
377 .to_string(),
378 location: None,
379 })?;
380 match payload_pair.as_rule() {
381 Rule::type_annotation => {
382 let type_annotation =
383 crate::parser::types::parse_type_annotation(payload_pair)?;
384 Ok(BlockItem::Statement(crate::ast::Statement::SetReturnType {
385 type_annotation,
386 span,
387 }))
388 }
389 Rule::set_return_expr_payload => {
390 let expr_pair =
391 payload_pair
392 .into_inner()
393 .next()
394 .ok_or_else(|| ShapeError::ParseError {
395 message:
396 "expected expression in parenthesized `set return` directive"
397 .to_string(),
398 location: None,
399 })?;
400 let expression = super::super::parse_expression(expr_pair)?;
401 Ok(BlockItem::Statement(crate::ast::Statement::SetReturnExpr {
402 expression,
403 span,
404 }))
405 }
406 _ => Err(ShapeError::ParseError {
407 message: "expected type annotation or expression in `set return` directive"
408 .to_string(),
409 location: None,
410 }),
411 }
412 }
413 Rule::replace_body_stmt => {
414 let span = pair_span(&inner);
415 let mut parts = inner.into_inner();
416 let Some(payload) = parts.next() else {
417 return Ok(BlockItem::Statement(crate::ast::Statement::ReplaceBody {
418 body: Vec::new(),
419 span,
420 }));
421 };
422 match payload.as_rule() {
423 Rule::replace_body_expr_payload => {
424 let expr_pair =
425 payload
426 .into_inner()
427 .next()
428 .ok_or_else(|| ShapeError::ParseError {
429 message:
430 "expected expression in parenthesized `replace body` directive"
431 .to_string(),
432 location: None,
433 })?;
434 let expression = super::super::parse_expression(expr_pair)?;
435 Ok(BlockItem::Statement(
436 crate::ast::Statement::ReplaceBodyExpr { expression, span },
437 ))
438 }
439 Rule::statement => {
440 let mut body = Vec::new();
441 body.push(crate::parser::statements::parse_statement(payload)?);
442 body.extend(crate::parser::statements::parse_statements(parts)?);
443 Ok(BlockItem::Statement(crate::ast::Statement::ReplaceBody {
444 body,
445 span,
446 }))
447 }
448 _ => Err(ShapeError::ParseError {
449 message: "expected body block or expression in `replace body` directive"
450 .to_string(),
451 location: None,
452 }),
453 }
454 }
455 Rule::replace_module_stmt => {
456 let span = pair_span(&inner);
457 let mut parts = inner.into_inner();
458 let payload = parts.next().ok_or_else(|| ShapeError::ParseError {
459 message: "expected expression payload in `replace module` directive".to_string(),
460 location: None,
461 })?;
462 if payload.as_rule() != Rule::replace_module_expr_payload {
463 return Err(ShapeError::ParseError {
464 message: "expected parenthesized expression in `replace module` directive"
465 .to_string(),
466 location: None,
467 });
468 }
469 let expr_pair = payload
470 .into_inner()
471 .next()
472 .ok_or_else(|| ShapeError::ParseError {
473 message: "expected expression in parenthesized `replace module` directive"
474 .to_string(),
475 location: None,
476 })?;
477 let expression = super::super::parse_expression(expr_pair)?;
478 Ok(BlockItem::Statement(
479 crate::ast::Statement::ReplaceModuleExpr { expression, span },
480 ))
481 }
482 Rule::function_def => {
485 let span = pair_span(&inner);
486 let func_def = crate::parser::functions::parse_function_def(inner)?;
487 let func_expr = Expr::FunctionExpr {
488 params: func_def.params,
489 return_type: func_def.return_type,
490 body: func_def.body,
491 span,
492 };
493 Ok(BlockItem::VariableDecl(crate::ast::VariableDecl {
494 kind: crate::ast::VarKind::Let,
495 is_mut: false,
496 pattern: crate::ast::DestructurePattern::Identifier(func_def.name, span),
497 type_annotation: None,
498 value: Some(func_expr),
499 ownership: Default::default(),
500 }))
501 }
502 _ => Err(ShapeError::ParseError {
503 message: format!("Unexpected block entry: {:?}", inner.as_rule()),
504 location: None,
505 }),
506 }
507}
508
509pub fn parse_async_let_expr(pair: Pair<Rule>) -> Result<Expr> {
512 let span = pair_span(&pair);
513 let pair_loc = pair_location(&pair);
514 let mut inner = pair.into_inner();
515
516 let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
517 message: "expected variable name in async let".to_string(),
518 location: Some(pair_loc.clone()),
519 })?;
520 let name = name_pair.as_str().to_string();
521
522 let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
523 message: "expected expression in async let".to_string(),
524 location: Some(pair_loc),
525 })?;
526 let expr = super::super::parse_expression(expr_pair)?;
527
528 Ok(Expr::AsyncLet(
529 Box::new(AsyncLetExpr {
530 name,
531 expr: Box::new(expr),
532 span,
533 }),
534 span,
535 ))
536}
537
538pub fn parse_async_scope_expr(pair: Pair<Rule>) -> Result<Expr> {
541 let span = pair_span(&pair);
542 let pair_loc = pair_location(&pair);
543 let mut inner = pair.into_inner();
544
545 let body_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
546 message: "expected body in async scope".to_string(),
547 location: Some(pair_loc),
548 })?;
549 let body = parse_block_expr(body_pair)?;
550
551 Ok(Expr::AsyncScope(Box::new(body), span))
552}