Skip to main content

shape_ast/parser/
extensions.rs

1//! AST parser for language extensions
2
3use crate::ast::{
4    AnnotationDef, AnnotationHandler, AnnotationHandlerParam, AnnotationHandlerType,
5    FunctionParameter,
6};
7use crate::error::{Result, ShapeError};
8use crate::parser::Rule;
9use crate::parser::expressions::control_flow::parse_block_expr;
10use crate::parser::pair_span;
11use crate::parser::types::parse_type_annotation;
12use pest::iterators::Pair;
13
14/// Parse an annotation definition with lifecycle handlers
15///
16/// Grammar:
17/// ```pest
18/// annotation_def = {
19///     "annotation" ~ ident ~ "(" ~ annotation_def_params? ~ ")" ~ "{" ~ annotation_body ~ "}"
20/// }
21/// annotation_body = { annotation_handler* }
22/// annotation_handler = {
23///     annotation_handler_name ~ "(" ~ annotation_handler_params? ~ ")" ~ return_type? ~ block_expr
24/// }
25/// ```
26pub fn parse_annotation_def(pair: Pair<Rule>) -> Result<AnnotationDef> {
27    let span = pair_span(&pair);
28    let mut inner = pair.into_inner();
29
30    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
31        message: "Missing annotation name".to_string(),
32        location: None,
33    })?;
34    let name = name_pair.as_str().to_string();
35    let name_span = pair_span(&name_pair);
36
37    let mut params: Vec<FunctionParameter> = Vec::new();
38    let mut handlers = Vec::new();
39    let mut allowed_targets: Option<Vec<crate::ast::AnnotationTargetKind>> = None;
40
41    for part in inner {
42        match part.as_rule() {
43            Rule::annotation_def_params => {
44                for param_pair in part.into_inner() {
45                    if param_pair.as_rule() == Rule::ident {
46                        let pattern = crate::ast::DestructurePattern::Identifier(
47                            param_pair.as_str().to_string(),
48                            pair_span(&param_pair),
49                        );
50                        params.push(FunctionParameter {
51                            pattern,
52                            is_const: false,
53                            is_reference: false,
54                            is_mut_reference: false,
55                            is_out: false,
56                            type_annotation: None,
57                            default_value: None,
58                        });
59                    }
60                }
61            }
62            Rule::annotation_body => {
63                for body_item in part.into_inner() {
64                    let item = if body_item.as_rule() == Rule::annotation_body_item {
65                        body_item
66                            .into_inner()
67                            .next()
68                            .ok_or_else(|| ShapeError::ParseError {
69                                message: "empty annotation body item".to_string(),
70                                location: None,
71                            })?
72                    } else {
73                        body_item
74                    };
75
76                    match item.as_rule() {
77                        Rule::annotation_handler => {
78                            handlers.push(parse_annotation_handler(item)?);
79                        }
80                        Rule::annotation_targets_decl => {
81                            let mut targets = Vec::new();
82                            for target_pair in item.into_inner() {
83                                if target_pair.as_rule() != Rule::annotation_target_kind {
84                                    continue;
85                                }
86                                let kind = match target_pair.as_str() {
87                                    "function" => crate::ast::AnnotationTargetKind::Function,
88                                    "type" => crate::ast::AnnotationTargetKind::Type,
89                                    "module" => crate::ast::AnnotationTargetKind::Module,
90                                    "expression" => crate::ast::AnnotationTargetKind::Expression,
91                                    "block" => crate::ast::AnnotationTargetKind::Block,
92                                    "await_expr" => crate::ast::AnnotationTargetKind::AwaitExpr,
93                                    "binding" => crate::ast::AnnotationTargetKind::Binding,
94                                    other => {
95                                        return Err(ShapeError::ParseError {
96                                            message: format!(
97                                                "unknown annotation target kind '{}'",
98                                                other
99                                            ),
100                                            location: None,
101                                        });
102                                    }
103                                };
104                                targets.push(kind);
105                            }
106                            allowed_targets = Some(targets);
107                        }
108                        _ => {}
109                    }
110                }
111            }
112            _ => {}
113        }
114    }
115
116    Ok(AnnotationDef {
117        name,
118        name_span,
119        doc_comment: None,
120        params,
121        allowed_targets,
122        handlers,
123        span,
124    })
125}
126
127/// Parse a single annotation lifecycle handler
128fn parse_annotation_handler(pair: Pair<Rule>) -> Result<AnnotationHandler> {
129    let span = pair_span(&pair);
130    let mut inner = pair.into_inner();
131
132    // Parse handler type (on_define, before, after, metadata, comptime pre/post)
133    let handler_name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
134        message: "Missing annotation handler name".to_string(),
135        location: None,
136    })?;
137
138    let handler_kind = handler_name_pair
139        .as_str()
140        .split_whitespace()
141        .collect::<Vec<_>>()
142        .join(" ");
143
144    let handler_type = match handler_kind.as_str() {
145        "on_define" => AnnotationHandlerType::OnDefine,
146        "before" => AnnotationHandlerType::Before,
147        "after" => AnnotationHandlerType::After,
148        "metadata" => AnnotationHandlerType::Metadata,
149        "comptime pre" => AnnotationHandlerType::ComptimePre,
150        "comptime post" => AnnotationHandlerType::ComptimePost,
151        other => {
152            return Err(ShapeError::ParseError {
153                message: format!(
154                    "unknown annotation handler type '{}'. Expected `on_define`, `before`, `after`, `metadata`, `comptime pre`, or `comptime post`",
155                    other
156                ),
157                location: None,
158            });
159        }
160    };
161
162    // Parse handler parameters
163    let mut params = Vec::new();
164    let mut return_type = None;
165    let mut body = None;
166
167    for part in inner {
168        match part.as_rule() {
169            Rule::annotation_handler_params => {
170                for param_pair in part.into_inner() {
171                    if param_pair.as_rule() == Rule::annotation_handler_param {
172                        let raw = param_pair.as_str().trim();
173                        let (name, is_variadic) = if let Some(rest) = raw.strip_prefix("...") {
174                            (rest.trim().to_string(), true)
175                        } else {
176                            (raw.to_string(), false)
177                        };
178                        if !name.is_empty() {
179                            params.push(AnnotationHandlerParam { name, is_variadic });
180                        }
181                    }
182                }
183            }
184            Rule::return_type => {
185                // return_type = "->" ~ type_annotation
186                if let Some(type_pair) = part.into_inner().next() {
187                    return_type = Some(parse_type_annotation(type_pair)?);
188                }
189            }
190            Rule::block_expr => {
191                body = Some(parse_block_expr(part)?);
192            }
193            _ => {}
194        }
195    }
196
197    let body = body.ok_or_else(|| ShapeError::ParseError {
198        message: "Missing annotation handler body".to_string(),
199        location: None,
200    })?;
201
202    Ok(AnnotationHandler {
203        handler_type,
204        params,
205        return_type,
206        body,
207        span,
208    })
209}
210
211pub fn parse_extend_statement(pair: Pair<Rule>) -> Result<crate::ast::ExtendStatement> {
212    use crate::ast::types::TypeName;
213
214    let mut inner = pair.into_inner();
215
216    // Parse type_name: ident ~ ("<" ~ type_annotation ~ ">")?
217    let type_name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
218        message: "Missing type name in extend statement".to_string(),
219        location: None,
220    })?;
221
222    let type_name = {
223        let mut tn_inner = type_name_pair.into_inner();
224        let name_pair = tn_inner.next().ok_or_else(|| ShapeError::ParseError {
225            message: "Missing type name identifier".to_string(),
226            location: None,
227        })?;
228        let name = name_pair.as_str().to_string();
229        let type_args: Vec<_> = tn_inner
230            .map(|p| parse_type_annotation(p))
231            .collect::<Result<Vec<_>>>()?;
232        if type_args.is_empty() {
233            TypeName::Simple(name.into())
234        } else {
235            TypeName::Generic { name: name.into(), type_args }
236        }
237    };
238
239    // Parse documented_method_def*
240    let mut methods = Vec::new();
241    for method_pair in inner {
242        if matches!(
243            method_pair.as_rule(),
244            Rule::documented_method_def | Rule::method_def
245        ) {
246            methods.push(super::types::parse_documented_method_def_shared(
247                method_pair,
248            )?);
249        }
250    }
251
252    Ok(crate::ast::ExtendStatement { type_name, methods })
253}
254
255/// Parse an impl block: `impl TraitName for TypeName [as ImplName] { method_def* }`
256///
257/// Reuses the same method_def parsing as extend blocks.
258pub fn parse_impl_block(pair: Pair<Rule>) -> Result<crate::ast::ImplBlock> {
259    let mut inner = pair.into_inner();
260
261    // First type_name is the trait being implemented
262    let trait_name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
263        message: "Missing trait name in impl block".to_string(),
264        location: None,
265    })?;
266    let trait_name = parse_type_name(trait_name_pair)?;
267
268    // Second type_name is the target type
269    let target_type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
270        message: "Missing target type in impl block".to_string(),
271        location: None,
272    })?;
273    let target_type = parse_type_name(target_type_pair)?;
274
275    // Parse optional impl_name, where_clause and impl_member*
276    let mut impl_name = None;
277    let mut methods = Vec::new();
278    let mut associated_type_bindings = Vec::new();
279    let mut where_clause = None;
280    for member_pair in inner {
281        if member_pair.as_rule() == Rule::impl_name {
282            let name_pair =
283                member_pair
284                    .into_inner()
285                    .next()
286                    .ok_or_else(|| ShapeError::ParseError {
287                        message: "Missing impl name after 'as'".to_string(),
288                        location: None,
289                    })?;
290            impl_name = Some(name_pair.as_str().to_string());
291            continue;
292        }
293        if member_pair.as_rule() == Rule::where_clause {
294            where_clause = Some(super::functions::parse_where_clause(member_pair)?);
295            continue;
296        }
297        if member_pair.as_rule() != Rule::impl_member {
298            continue;
299        }
300        for child in member_pair.into_inner() {
301            match child.as_rule() {
302                Rule::associated_type_binding => {
303                    let binding = parse_associated_type_binding(child)?;
304                    associated_type_bindings.push(binding);
305                }
306                Rule::documented_method_def | Rule::method_def => {
307                    methods.push(super::types::parse_documented_method_def_shared(child)?);
308                }
309                _ => {}
310            }
311        }
312    }
313
314    Ok(crate::ast::ImplBlock {
315        trait_name,
316        target_type,
317        impl_name,
318        methods,
319        associated_type_bindings,
320        where_clause,
321    })
322}
323
324/// Parse `type Item = number;`
325fn parse_associated_type_binding(
326    pair: Pair<Rule>,
327) -> Result<crate::ast::types::AssociatedTypeBinding> {
328    let mut inner = pair.into_inner();
329
330    let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
331        message: "expected associated type name in binding".to_string(),
332        location: None,
333    })?;
334    let name = name_pair.as_str().to_string();
335
336    let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
337        message: format!("expected type annotation for associated type '{}'", name),
338        location: None,
339    })?;
340    let concrete_type = super::types::parse_type_annotation(type_pair)?;
341
342    Ok(crate::ast::types::AssociatedTypeBinding {
343        name,
344        concrete_type,
345    })
346}
347
348/// Parse a type_name from the grammar (ident with optional generic args)
349fn parse_type_name(pair: Pair<Rule>) -> Result<crate::ast::types::TypeName> {
350    use crate::ast::types::TypeName;
351
352    let mut tn_inner = pair.into_inner();
353    let name_pair = tn_inner.next().ok_or_else(|| ShapeError::ParseError {
354        message: "Missing type name identifier".to_string(),
355        location: None,
356    })?;
357    let name = name_pair.as_str().to_string();
358    let type_args: Vec<_> = tn_inner
359        .map(|p| super::types::parse_type_annotation(p))
360        .collect::<Result<Vec<_>>>()?;
361    if type_args.is_empty() {
362        Ok(TypeName::Simple(name.into()))
363    } else {
364        Ok(TypeName::Generic { name: name.into(), type_args })
365    }
366}
367
368pub fn parse_optimize_statement(_pair: Pair<Rule>) -> Result<crate::ast::OptimizeStatement> {
369    Err(ShapeError::ParseError {
370        message: "parse_optimize_statement not yet implemented".to_string(),
371        location: None,
372    })
373}