Skip to main content

shape_ast/parser/
statements.rs

1//! Statement parsing for Shape
2
3use crate::error::{Result, ShapeError};
4use crate::parser::pair_location;
5use pest::iterators::Pair;
6
7use crate::ast::{Assignment, ForInit, ForLoop, IfStatement, Span, Statement, WhileLoop};
8use crate::parser::extensions::parse_extend_statement;
9use crate::parser::{Rule, expressions, pair_span, parse_variable_decl};
10
11/// Parse a statement
12pub fn parse_statement(pair: Pair<Rule>) -> Result<Statement> {
13    let pair_loc = pair_location(&pair);
14    let span = pair_span(&pair);
15    let inner = pair
16        .into_inner()
17        .next()
18        .ok_or_else(|| ShapeError::ParseError {
19            message: "expected statement content".to_string(),
20            location: Some(pair_loc.clone()),
21        })?;
22
23    match inner.as_rule() {
24        Rule::return_stmt => parse_return_stmt(inner),
25        Rule::break_stmt => Ok(Statement::Break(pair_span(&inner))),
26        Rule::continue_stmt => Ok(Statement::Continue(pair_span(&inner))),
27        Rule::variable_decl => {
28            let decl = parse_variable_decl(inner)?;
29            Ok(Statement::VariableDecl(decl, span))
30        }
31        Rule::assignment => {
32            let inner_loc = pair_location(&inner);
33            let inner_span = pair_span(&inner);
34            let mut inner = inner.into_inner();
35            let pattern_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
36                message: "expected pattern in assignment".to_string(),
37                location: Some(inner_loc.clone()),
38            })?;
39            let pattern = crate::parser::parse_pattern(pattern_pair)?;
40            let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
41                message: "expected value in assignment".to_string(),
42                location: Some(inner_loc),
43            })?;
44            let value = expressions::parse_expression(value_pair)?;
45            Ok(Statement::Assignment(
46                Assignment { pattern, value },
47                inner_span,
48            ))
49        }
50        Rule::expression_stmt => {
51            let inner_loc = pair_location(&inner);
52            let inner_span = pair_span(&inner);
53            let expr_pair = inner
54                .into_inner()
55                .next()
56                .ok_or_else(|| ShapeError::ParseError {
57                    message: "expected expression in statement".to_string(),
58                    location: Some(inner_loc),
59                })?;
60            let expr = expressions::parse_expression(expr_pair)?;
61            Ok(Statement::Expression(expr, inner_span))
62        }
63        Rule::for_loop => parse_for_loop(inner),
64        Rule::while_loop => parse_while_loop(inner),
65        Rule::if_stmt => parse_if_stmt(inner),
66        Rule::extend_statement => {
67            let ext = parse_extend_statement(inner)?;
68            Ok(Statement::Extend(ext, span))
69        }
70        Rule::function_def => {
71            // Desugar nested `fn name(params) { body }` to
72            // `let name = fn(params) { body }` (a VariableDecl statement).
73            let func_def = crate::parser::functions::parse_function_def(inner)?;
74            let func_expr = crate::ast::Expr::FunctionExpr {
75                params: func_def.params,
76                return_type: func_def.return_type,
77                body: func_def.body,
78                span,
79            };
80            Ok(Statement::VariableDecl(
81                crate::ast::VariableDecl {
82                    kind: crate::ast::VarKind::Let,
83                    is_mut: false,
84                    pattern: crate::ast::DestructurePattern::Identifier(func_def.name, span),
85                    type_annotation: None,
86                    value: Some(func_expr),
87                    ownership: Default::default(),
88                },
89                span,
90            ))
91        }
92        Rule::remove_target_stmt => Ok(Statement::RemoveTarget(pair_span(&inner))),
93        Rule::set_param_type_stmt => {
94            let inner_span = pair_span(&inner);
95            let mut inner_parts = inner.into_inner();
96            let param_pair = inner_parts.next().ok_or_else(|| ShapeError::ParseError {
97                message: "expected parameter name in `set param` directive".to_string(),
98                location: Some(pair_loc.clone()),
99            })?;
100            let type_pair = inner_parts.next().ok_or_else(|| ShapeError::ParseError {
101                message: "expected type annotation in `set param` directive".to_string(),
102                location: Some(pair_loc.clone()),
103            })?;
104            let type_annotation = crate::parser::types::parse_type_annotation(type_pair)?;
105            Ok(Statement::SetParamType {
106                param_name: param_pair.as_str().to_string(),
107                type_annotation,
108                span: inner_span,
109            })
110        }
111        Rule::set_return_stmt => {
112            let inner_span = pair_span(&inner);
113            let mut inner_parts = inner.into_inner();
114            let payload_pair = inner_parts.next().ok_or_else(|| ShapeError::ParseError {
115                message: "expected type annotation or expression in `set return` directive"
116                    .to_string(),
117                location: Some(pair_loc.clone()),
118            })?;
119            match payload_pair.as_rule() {
120                Rule::type_annotation => {
121                    let type_annotation =
122                        crate::parser::types::parse_type_annotation(payload_pair)?;
123                    Ok(Statement::SetReturnType {
124                        type_annotation,
125                        span: inner_span,
126                    })
127                }
128                Rule::set_return_expr_payload => {
129                    let expr_pair =
130                        payload_pair
131                            .into_inner()
132                            .next()
133                            .ok_or_else(|| ShapeError::ParseError {
134                                message:
135                                    "expected expression in parenthesized `set return` directive"
136                                        .to_string(),
137                                location: Some(pair_loc.clone()),
138                            })?;
139                    let expression = expressions::parse_expression(expr_pair)?;
140                    Ok(Statement::SetReturnExpr {
141                        expression,
142                        span: inner_span,
143                    })
144                }
145                _ => Err(ShapeError::ParseError {
146                    message: "expected type annotation or expression in `set return` directive"
147                        .to_string(),
148                    location: Some(pair_loc),
149                }),
150            }
151        }
152        Rule::replace_body_stmt => {
153            let inner_span = pair_span(&inner);
154            let mut parts = inner.into_inner();
155            let Some(payload) = parts.next() else {
156                return Ok(Statement::ReplaceBody {
157                    body: Vec::new(),
158                    span: inner_span,
159                });
160            };
161            match payload.as_rule() {
162                Rule::replace_body_expr_payload => {
163                    let expr_pair =
164                        payload
165                            .into_inner()
166                            .next()
167                            .ok_or_else(|| ShapeError::ParseError {
168                                message:
169                                    "expected expression in parenthesized `replace body` directive"
170                                        .to_string(),
171                                location: Some(pair_loc.clone()),
172                            })?;
173                    let expression = expressions::parse_expression(expr_pair)?;
174                    Ok(Statement::ReplaceBodyExpr {
175                        expression,
176                        span: inner_span,
177                    })
178                }
179                Rule::statement => {
180                    let mut body = Vec::new();
181                    body.push(parse_statement(payload)?);
182                    body.extend(parse_statements(parts)?);
183                    Ok(Statement::ReplaceBody {
184                        body,
185                        span: inner_span,
186                    })
187                }
188                _ => Err(ShapeError::ParseError {
189                    message: "expected body block or expression in `replace body` directive"
190                        .to_string(),
191                    location: Some(pair_loc),
192                }),
193            }
194        }
195        Rule::replace_module_stmt => {
196            let inner_span = pair_span(&inner);
197            let mut parts = inner.into_inner();
198            let payload = parts.next().ok_or_else(|| ShapeError::ParseError {
199                message: "expected expression payload in `replace module` directive".to_string(),
200                location: Some(pair_loc.clone()),
201            })?;
202            if payload.as_rule() != Rule::replace_module_expr_payload {
203                return Err(ShapeError::ParseError {
204                    message: "expected parenthesized expression in `replace module` directive"
205                        .to_string(),
206                    location: Some(pair_loc),
207                });
208            }
209            let expr_pair = payload
210                .into_inner()
211                .next()
212                .ok_or_else(|| ShapeError::ParseError {
213                    message: "expected expression in parenthesized `replace module` directive"
214                        .to_string(),
215                    location: Some(pair_loc),
216                })?;
217            let expression = expressions::parse_expression(expr_pair)?;
218            Ok(Statement::ReplaceModuleExpr {
219                expression,
220                span: inner_span,
221            })
222        }
223        _ => Err(ShapeError::ParseError {
224            message: format!("Unexpected statement type: {:?}", inner.as_rule()),
225            location: None,
226        }),
227    }
228}
229
230/// Parse a return statement
231fn parse_return_stmt(pair: Pair<Rule>) -> Result<Statement> {
232    let span = pair_span(&pair);
233    let mut inner = pair.into_inner();
234
235    // Skip the return_keyword atomic token
236    let first = inner.next();
237    if let Some(ref p) = first {
238        if p.as_rule() == Rule::return_keyword {
239            // Keyword consumed, check for expression
240            if let Some(expr_pair) = inner.next() {
241                let expr = expressions::parse_expression(expr_pair)?;
242                return Ok(Statement::Return(Some(expr), span));
243            } else {
244                return Ok(Statement::Return(None, span));
245            }
246        }
247    }
248
249    if let Some(expr_pair) = first {
250        // Return with expression
251        let expr = expressions::parse_expression(expr_pair)?;
252        Ok(Statement::Return(Some(expr), span))
253    } else {
254        // Return without expression
255        Ok(Statement::Return(None, span))
256    }
257}
258
259/// Parse a for loop
260pub fn parse_for_loop(pair: Pair<Rule>) -> Result<Statement> {
261    let pair_loc = pair_location(&pair);
262    let span = pair_span(&pair);
263    let mut inner = pair.into_inner();
264
265    // Parse for clause
266    let for_clause = inner.next().ok_or_else(|| ShapeError::ParseError {
267        message: "expected for clause".to_string(),
268        location: Some(pair_loc),
269    })?;
270    let init = parse_for_clause(for_clause)?;
271
272    // Parse body
273    let mut body = vec![];
274    for stmt_pair in inner {
275        if stmt_pair.as_rule() == Rule::statement {
276            body.push(parse_statement(stmt_pair)?);
277        }
278    }
279
280    Ok(Statement::For(
281        ForLoop {
282            init,
283            body,
284            is_async: false,
285        },
286        span,
287    ))
288}
289
290/// Parse a for clause (for x in expr or for init; cond; update)
291fn parse_for_clause(pair: Pair<Rule>) -> Result<ForInit> {
292    let pair_loc = pair_location(&pair);
293    let inner_str = pair.as_str();
294    let mut inner = pair.into_inner();
295
296    // Check if it's a for-in loop by looking for "in" keyword
297    if inner_str.contains(" in ") {
298        // for x in expr (or for {x, y} in expr with destructuring)
299        let pattern_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
300            message: "expected pattern in for-in loop".to_string(),
301            location: Some(pair_loc.clone()),
302        })?;
303        let pattern = super::items::parse_pattern(pattern_pair)?;
304        let iter_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
305            message: "expected iterable expression in for-in loop".to_string(),
306            location: Some(pair_loc),
307        })?;
308        let iter_expr = expressions::parse_expression(iter_pair)?;
309        Ok(ForInit::ForIn {
310            pattern,
311            iter: iter_expr,
312        })
313    } else {
314        // for (init; condition; update)
315        let init_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
316            message: "expected initialization in for loop".to_string(),
317            location: Some(pair_loc.clone()),
318        })?;
319        let init_decl = parse_variable_decl(init_pair)?;
320        let condition_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
321            message: "expected condition in for loop".to_string(),
322            location: Some(pair_loc.clone()),
323        })?;
324        let condition = expressions::parse_expression(condition_pair)?;
325        let update_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
326            message: "expected update expression in for loop".to_string(),
327            location: Some(pair_loc),
328        })?;
329        let update = expressions::parse_expression(update_pair)?;
330
331        Ok(ForInit::ForC {
332            init: Box::new(Statement::VariableDecl(init_decl, Span::DUMMY)),
333            condition,
334            update,
335        })
336    }
337}
338
339/// Parse a while loop
340pub fn parse_while_loop(pair: Pair<Rule>) -> Result<Statement> {
341    let pair_loc = pair_location(&pair);
342    let span = pair_span(&pair);
343    let mut inner = pair.into_inner();
344
345    // Parse condition
346    let condition_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
347        message: "expected condition in while loop".to_string(),
348        location: Some(pair_loc),
349    })?;
350    let condition = expressions::parse_expression(condition_pair)?;
351
352    // Parse body
353    let mut body = vec![];
354    for stmt_pair in inner {
355        if stmt_pair.as_rule() == Rule::statement {
356            body.push(parse_statement(stmt_pair)?);
357        }
358    }
359
360    Ok(Statement::While(WhileLoop { condition, body }, span))
361}
362
363/// Parse an if statement
364pub fn parse_if_stmt(pair: Pair<Rule>) -> Result<Statement> {
365    let pair_loc = pair_location(&pair);
366    let span = pair_span(&pair);
367    let mut inner = pair.into_inner();
368
369    // Parse condition
370    let condition_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
371        message: "expected condition in if statement".to_string(),
372        location: Some(pair_loc),
373    })?;
374    let condition = expressions::parse_expression(condition_pair)?;
375
376    // Parse then body
377    let mut then_body = vec![];
378    let mut else_body = None;
379
380    for part in inner {
381        match part.as_rule() {
382            Rule::statement => {
383                then_body.push(parse_statement(part)?);
384            }
385            Rule::else_clause => {
386                else_body = Some(parse_else_clause(part)?);
387            }
388            _ => {}
389        }
390    }
391
392    Ok(Statement::If(
393        IfStatement {
394            condition,
395            then_body,
396            else_body,
397        },
398        span,
399    ))
400}
401
402/// Parse an else clause (can be else {...} or else if (...) {...})
403fn parse_else_clause(pair: Pair<Rule>) -> Result<Vec<Statement>> {
404    let span = pair_span(&pair);
405    let mut inner = pair.into_inner();
406    let mut statements = vec![];
407
408    // Check if this is an else if
409    let first = inner.next();
410    if let Some(first_pair) = first {
411        match first_pair.as_rule() {
412            Rule::expression => {
413                // This is an else if - parse condition
414                let condition = expressions::parse_expression(first_pair)?;
415                let mut then_body = vec![];
416                let mut else_body = None;
417
418                // Parse the body and potential else clause
419                for part in inner {
420                    match part.as_rule() {
421                        Rule::statement => {
422                            then_body.push(parse_statement(part)?);
423                        }
424                        Rule::else_clause => {
425                            else_body = Some(parse_else_clause(part)?);
426                        }
427                        _ => {}
428                    }
429                }
430
431                // Create an if statement for the else if
432                statements.push(Statement::If(
433                    IfStatement {
434                        condition,
435                        then_body,
436                        else_body,
437                    },
438                    span,
439                ));
440            }
441            Rule::statement => {
442                // This is a regular else block - just parse statements
443                statements.push(parse_statement(first_pair)?);
444                for stmt_pair in inner {
445                    if stmt_pair.as_rule() == Rule::statement {
446                        statements.push(parse_statement(stmt_pair)?);
447                    }
448                }
449            }
450            _ => {}
451        }
452    }
453
454    Ok(statements)
455}
456
457/// Parse multiple statements (for function bodies)
458pub fn parse_statements(pairs: pest::iterators::Pairs<Rule>) -> Result<Vec<Statement>> {
459    let mut statements = vec![];
460
461    for pair in pairs {
462        if pair.as_rule() == Rule::statement {
463            statements.push(parse_statement(pair)?);
464        } else if pair.as_rule() == Rule::stmt_recovery {
465            let span = pair.as_span();
466            let text = pair.as_str().trim();
467            let preview = if text.len() > 40 {
468                format!("{}...", &text[..40])
469            } else {
470                text.to_string()
471            };
472            return Err(ShapeError::ParseError {
473                message: format!("Syntax error near: {}", preview),
474                location: Some(pair_location(&pair).with_length(span.end() - span.start())),
475            });
476        }
477    }
478
479    Ok(statements)
480}