Skip to main content

shape_ast/parser/expressions/
functions.rs

1//! Function expression parsing
2//!
3//! This module handles parsing of function-related expressions:
4//! - Function expressions (anonymous functions)
5//! - Arrow functions
6//! - Function calls
7//! - Method calls
8//! - Argument lists
9//! - Type annotations
10
11use super::super::pair_span;
12use crate::ast::{Expr, FunctionParameter, Span, Statement, TypeAnnotation};
13use crate::error::Result;
14use crate::parser::Rule;
15use pest::iterators::Pair;
16
17/// Parse function expression (anonymous function)
18pub fn parse_function_expr(pair: Pair<Rule>) -> Result<Expr> {
19    match pair.as_rule() {
20        Rule::function_expr => {
21            // Check if it's a pipe lambda or regular function
22            let inner_pairs: Vec<_> = pair.clone().into_inner().collect();
23            if !inner_pairs.is_empty() && inner_pairs[0].as_rule() == Rule::pipe_lambda {
24                parse_pipe_lambda(inner_pairs.into_iter().next().unwrap())
25            } else {
26                // For regular function, pass the entire pair with all its parts
27                parse_regular_function_expr(pair)
28            }
29        }
30        Rule::pipe_lambda => parse_pipe_lambda(pair),
31        _ => parse_regular_function_expr(pair),
32    }
33}
34
35/// Parse pipe lambda: |x| expr, |x, y| x + y, || 42, |x| { ... }
36/// Reuses the same AST node as arrow functions (Expr::FunctionExpr).
37pub fn parse_pipe_lambda(pair: Pair<Rule>) -> Result<Expr> {
38    let span = pair_span(&pair);
39    let inner = pair.into_inner();
40    let mut params = vec![];
41    let mut body_expr = None;
42    let mut body_stmts = vec![];
43
44    for part in inner {
45        match part.as_rule() {
46            Rule::function_params => {
47                for param_pair in part.into_inner() {
48                    if param_pair.as_rule() == Rule::function_param {
49                        params.push(crate::parser::functions::parse_function_param(param_pair)?);
50                    }
51                }
52            }
53            Rule::expression => {
54                body_expr = Some(super::parse_expression(part)?);
55            }
56            Rule::function_body => {
57                body_stmts = crate::parser::statements::parse_statements(part.into_inner())?;
58            }
59            _ => {}
60        }
61    }
62
63    let body = if let Some(expr) = body_expr {
64        vec![Statement::Return(Some(expr), Span::DUMMY)]
65    } else {
66        body_stmts
67    };
68
69    Ok(Expr::FunctionExpr {
70        params,
71        return_type: None,
72        body,
73        span,
74    })
75}
76
77/// Parse arrow function
78pub fn parse_arrow_function(pair: Pair<Rule>) -> Result<Expr> {
79    let span = pair_span(&pair);
80    let inner = pair.into_inner();
81    let mut params = vec![];
82    let mut return_type: Option<TypeAnnotation> = None;
83    let mut body_expr = None;
84    let mut body_stmts = vec![];
85
86    for part in inner {
87        match part.as_rule() {
88            Rule::ident => {
89                // Single parameter without parentheses: x => x + 1
90                let pattern = crate::ast::DestructurePattern::Identifier(
91                    part.as_str().to_string(),
92                    pair_span(&part),
93                );
94                params.push(FunctionParameter {
95                    pattern,
96                    is_const: false,
97                    is_reference: false,
98                    is_mut_reference: false,
99                    is_out: false,
100                    type_annotation: None,
101                    default_value: None,
102                });
103            }
104            Rule::function_params => {
105                // Multiple parameters in parentheses: (x, y) => x + y
106                for param_pair in part.into_inner() {
107                    if param_pair.as_rule() == Rule::function_param {
108                        params.push(crate::parser::functions::parse_function_param(param_pair)?);
109                    }
110                }
111            }
112            Rule::function_param => {
113                // Parenthesized single parameter may be emitted directly.
114                params.push(crate::parser::functions::parse_function_param(part)?);
115            }
116            Rule::return_type => {
117                return_type = Some(crate::parser::parse_type_annotation(
118                    part.into_inner().next().unwrap(),
119                )?);
120            }
121            Rule::expression => {
122                // Arrow function with expression body
123                body_expr = Some(super::parse_expression(part)?);
124            }
125            Rule::function_body => {
126                // Arrow function with block body
127                body_stmts = crate::parser::statements::parse_statements(part.into_inner())?;
128            }
129            _ => {}
130        }
131    }
132
133    // If we have an expression body, convert it to a return statement
134    let body = if let Some(expr) = body_expr {
135        vec![Statement::Return(Some(expr), Span::DUMMY)]
136    } else {
137        body_stmts
138    };
139
140    Ok(Expr::FunctionExpr {
141        params,
142        return_type,
143        body,
144        span,
145    })
146}
147
148/// Parse regular function expression
149pub fn parse_regular_function_expr(pair: Pair<Rule>) -> Result<Expr> {
150    let span = pair_span(&pair);
151    let inner_pairs: Vec<_> = if pair.as_rule() == Rule::function_expr {
152        pair.into_inner().collect()
153    } else {
154        vec![pair]
155    };
156    let mut params = vec![];
157    let mut return_type: Option<TypeAnnotation> = None;
158    let mut body = vec![];
159
160    // Skip "function" keyword
161
162    // Parse parameters
163    for part in inner_pairs {
164        match part.as_rule() {
165            Rule::function_params => {
166                // Parse function parameters
167                for param_pair in part.into_inner() {
168                    if param_pair.as_rule() == Rule::function_param {
169                        params.push(crate::parser::functions::parse_function_param(param_pair)?);
170                    }
171                }
172            }
173            Rule::return_type => {
174                return_type = Some(crate::parser::parse_type_annotation(
175                    part.into_inner().next().unwrap(),
176                )?);
177            }
178            Rule::function_body => {
179                // Parse statements in the function body
180                for stmt_pair in part.into_inner() {
181                    if stmt_pair.as_rule() == Rule::statement {
182                        body.push(crate::parser::statements::parse_statement(stmt_pair)?);
183                    }
184                }
185            }
186            _ => {}
187        }
188    }
189
190    Ok(Expr::FunctionExpr {
191        params,
192        return_type,
193        body,
194        span,
195    })
196}
197
198/// Parse argument list with support for named arguments
199/// Returns (positional_args, named_args)
200pub fn parse_arg_list(pair: Pair<Rule>) -> Result<(Vec<Expr>, Vec<(String, Expr)>)> {
201    let mut positional_args = Vec::new();
202    let mut named_args = Vec::new();
203
204    if let Some(arg_list) = pair.into_inner().next() {
205        for argument in arg_list.into_inner() {
206            match argument.as_rule() {
207                Rule::argument => {
208                    // Unwrap the argument to get named_arg or expression
209                    let inner = argument.into_inner().next().unwrap();
210                    match inner.as_rule() {
211                        Rule::named_arg => {
212                            let mut parts = inner.into_inner();
213                            let name = parts.next().unwrap().as_str().to_string();
214                            let value = super::parse_expression(parts.next().unwrap())?;
215                            named_args.push((name, value));
216                        }
217                        _ => {
218                            // It's an expression (positional argument)
219                            positional_args.push(super::parse_expression(inner)?);
220                        }
221                    }
222                }
223                Rule::named_arg => {
224                    let mut parts = argument.into_inner();
225                    let name = parts.next().unwrap().as_str().to_string();
226                    let value = super::parse_expression(parts.next().unwrap())?;
227                    named_args.push((name, value));
228                }
229                _ => {
230                    // Direct expression (for backward compatibility)
231                    positional_args.push(super::parse_expression(argument)?);
232                }
233            }
234        }
235    }
236
237    Ok((positional_args, named_args))
238}