Skip to main content

shape_ast/parser/expressions/control_flow/
mod.rs

1//! Control flow expression parsing
2//!
3//! This module handles parsing of control flow expressions:
4//! - If/else expressions (conditionals)
5//! - While loops (loops)
6//! - For loops (loops)
7//! - Infinite loops (loops)
8//! - Let expressions (loops)
9//! - Match expressions (pattern_matching)
10//! - Try/catch expressions (conditionals)
11//! - Break/continue/return (loops)
12//! - Block expressions (loops)
13//! - Pattern matching (pattern_matching)
14//! - LINQ-style query expressions (this module)
15
16use crate::ast::{Expr, FromQueryExpr, OrderBySpec, QueryClause};
17use crate::error::{Result, ShapeError};
18use crate::parser::{Rule, pair_location};
19use pest::iterators::Pair;
20
21use super::super::pair_span;
22
23mod conditionals;
24mod loops;
25mod pattern_matching;
26
27// Re-export all public functions
28pub use conditionals::parse_if_expr;
29pub use loops::{
30    parse_async_let_expr, parse_async_scope_expr, parse_block_expr, parse_break_expr,
31    parse_for_expr, parse_let_expr, parse_loop_expr, parse_return_expr, parse_while_expr,
32};
33pub use pattern_matching::{parse_match_expr, parse_pattern};
34
35/// Parse LINQ-style from query expression
36/// Syntax: from var in source [clauses...] select expr
37pub fn parse_from_query_expr(pair: Pair<Rule>) -> Result<Expr> {
38    let span = pair_span(&pair);
39    let pair_loc = pair_location(&pair);
40    let mut inner = pair.into_inner();
41
42    // Parse: from variable in source
43    let variable_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
44        message: "expected variable name in from clause".to_string(),
45        location: Some(pair_loc.clone()),
46    })?;
47    let variable = variable_pair.as_str().to_string();
48
49    let source_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
50        message: "expected source expression in from clause".to_string(),
51        location: Some(pair_loc.clone()),
52    })?;
53    let source = Box::new(parse_query_source_expr(source_pair)?);
54
55    // Parse clauses
56    let mut clauses = Vec::new();
57    let mut select = None;
58
59    for part in inner {
60        match part.as_rule() {
61            Rule::query_clause => {
62                let clause_inner =
63                    part.into_inner()
64                        .next()
65                        .ok_or_else(|| ShapeError::ParseError {
66                            message: "expected query clause content".to_string(),
67                            location: Some(pair_loc.clone()),
68                        })?;
69                let clause = parse_query_clause(clause_inner)?;
70                clauses.push(clause);
71            }
72            Rule::where_query_clause => {
73                clauses.push(parse_where_query_clause(part)?);
74            }
75            Rule::order_by_query_clause => {
76                clauses.push(parse_order_by_query_clause(part)?);
77            }
78            Rule::group_by_query_clause => {
79                clauses.push(parse_group_by_query_clause(part)?);
80            }
81            Rule::join_query_clause => {
82                clauses.push(parse_join_query_clause(part)?);
83            }
84            Rule::let_query_clause => {
85                clauses.push(parse_let_query_clause(part)?);
86            }
87            Rule::select_query_clause => {
88                let select_inner =
89                    part.into_inner()
90                        .next()
91                        .ok_or_else(|| ShapeError::ParseError {
92                            message: "expected expression after select".to_string(),
93                            location: Some(pair_loc.clone()),
94                        })?;
95                select = Some(Box::new(parse_query_expr_inner(select_inner)?));
96            }
97            _ => {}
98        }
99    }
100
101    let select = select.ok_or_else(|| ShapeError::ParseError {
102        message: "from query requires a select clause".to_string(),
103        location: Some(pair_loc),
104    })?;
105
106    Ok(Expr::FromQuery(
107        Box::new(FromQueryExpr {
108            variable,
109            source,
110            clauses,
111            select,
112        }),
113        span,
114    ))
115}
116
117/// Parse a query source expression (postfix_expr)
118fn parse_query_source_expr(pair: Pair<Rule>) -> Result<Expr> {
119    match pair.as_rule() {
120        Rule::query_source_expr => {
121            let inner = pair
122                .into_inner()
123                .next()
124                .ok_or_else(|| ShapeError::ParseError {
125                    message: "expected source expression".to_string(),
126                    location: None,
127                })?;
128            super::parse_postfix_expr(inner)
129        }
130        _ => super::parse_postfix_expr(pair),
131    }
132}
133
134/// Parse a query inner expression (comparison_expr)
135fn parse_query_expr_inner(pair: Pair<Rule>) -> Result<Expr> {
136    match pair.as_rule() {
137        Rule::query_expr_inner => {
138            let inner = pair
139                .into_inner()
140                .next()
141                .ok_or_else(|| ShapeError::ParseError {
142                    message: "expected expression".to_string(),
143                    location: None,
144                })?;
145            super::binary_ops::parse_comparison_expr(inner)
146        }
147        _ => super::binary_ops::parse_comparison_expr(pair),
148    }
149}
150
151fn parse_query_clause(pair: Pair<Rule>) -> Result<QueryClause> {
152    match pair.as_rule() {
153        Rule::where_query_clause => parse_where_query_clause(pair),
154        Rule::order_by_query_clause => parse_order_by_query_clause(pair),
155        Rule::group_by_query_clause => parse_group_by_query_clause(pair),
156        Rule::join_query_clause => parse_join_query_clause(pair),
157        Rule::let_query_clause => parse_let_query_clause(pair),
158        _ => Err(ShapeError::ParseError {
159            message: format!("unexpected query clause: {:?}", pair.as_rule()),
160            location: Some(pair_location(&pair)),
161        }),
162    }
163}
164
165fn parse_where_query_clause(pair: Pair<Rule>) -> Result<QueryClause> {
166    let pair_loc = pair_location(&pair);
167    let condition_pair = pair
168        .into_inner()
169        .next()
170        .ok_or_else(|| ShapeError::ParseError {
171            message: "expected condition expression in where clause".to_string(),
172            location: Some(pair_loc),
173        })?;
174    let condition = parse_query_expr_inner(condition_pair)?;
175    Ok(QueryClause::Where(Box::new(condition)))
176}
177
178fn parse_order_by_query_clause(pair: Pair<Rule>) -> Result<QueryClause> {
179    let mut specs = Vec::new();
180    for inner in pair.into_inner() {
181        if inner.as_rule() == Rule::order_by_spec {
182            specs.push(parse_order_by_spec(inner)?);
183        }
184    }
185    Ok(QueryClause::OrderBy(specs))
186}
187
188fn parse_order_by_spec(pair: Pair<Rule>) -> Result<OrderBySpec> {
189    let pair_loc = pair_location(&pair);
190    let mut inner = pair.into_inner();
191    let key_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
192        message: "expected key expression in order by".to_string(),
193        location: Some(pair_loc),
194    })?;
195    let key = Box::new(super::parse_postfix_expr(key_pair)?);
196    let descending = inner
197        .next()
198        .map(|dir| dir.as_str() == "desc")
199        .unwrap_or(false);
200    Ok(OrderBySpec { key, descending })
201}
202
203fn parse_group_by_query_clause(pair: Pair<Rule>) -> Result<QueryClause> {
204    let pair_loc = pair_location(&pair);
205    let mut inner = pair.into_inner();
206
207    let element_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
208        message: "expected element expression in group by".to_string(),
209        location: Some(pair_loc.clone()),
210    })?;
211    let element = Box::new(super::parse_postfix_expr(element_pair)?);
212
213    let key_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
214        message: "expected key expression in group by".to_string(),
215        location: Some(pair_loc),
216    })?;
217    let key = Box::new(super::parse_postfix_expr(key_pair)?);
218
219    let into_var = inner.next().map(|p| p.as_str().to_string());
220
221    Ok(QueryClause::GroupBy {
222        element,
223        key,
224        into_var,
225    })
226}
227
228fn parse_join_query_clause(pair: Pair<Rule>) -> Result<QueryClause> {
229    let pair_loc = pair_location(&pair);
230    let mut inner = pair.into_inner();
231
232    let variable = inner
233        .next()
234        .ok_or_else(|| ShapeError::ParseError {
235            message: "expected variable name in join".to_string(),
236            location: Some(pair_loc.clone()),
237        })?
238        .as_str()
239        .to_string();
240
241    let source_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
242        message: "expected source expression in join".to_string(),
243        location: Some(pair_loc.clone()),
244    })?;
245    let source = Box::new(super::parse_postfix_expr(source_pair)?);
246
247    let left_key_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
248        message: "expected left key expression in join".to_string(),
249        location: Some(pair_loc.clone()),
250    })?;
251    let left_key = Box::new(super::parse_postfix_expr(left_key_pair)?);
252
253    let right_key_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
254        message: "expected right key expression in join".to_string(),
255        location: Some(pair_loc),
256    })?;
257    let right_key = Box::new(super::parse_postfix_expr(right_key_pair)?);
258
259    let into_var = inner.next().map(|p| p.as_str().to_string());
260
261    Ok(QueryClause::Join {
262        variable,
263        source,
264        left_key,
265        right_key,
266        into_var,
267    })
268}
269
270fn parse_let_query_clause(pair: Pair<Rule>) -> Result<QueryClause> {
271    let pair_loc = pair_location(&pair);
272    let mut inner = pair.into_inner();
273
274    let variable = inner
275        .next()
276        .ok_or_else(|| ShapeError::ParseError {
277            message: "expected variable name in let clause".to_string(),
278            location: Some(pair_loc.clone()),
279        })?
280        .as_str()
281        .to_string();
282
283    let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
284        message: "expected value expression in let clause".to_string(),
285        location: Some(pair_loc),
286    })?;
287    let value = Box::new(parse_query_expr_inner(value_pair)?);
288
289    Ok(QueryClause::Let { variable, value })
290}