rl_lang/parser/statements/function_declaration.rs
1//! Function declaration parser (`fn`).
2//!
3//! Handles named function declarations in the form:
4//!
5//! ```text
6//! fn name(T param, T param) -> ReturnType {
7//! body
8//! }
9//! ```
10//!
11//! Return type annotations are optional; omitting `-> T` defaults to
12//! [`TypeAnnotation::Null`]. The `is_entry` flag is set when the function is
13//! preceded by a `!#[entry]` attribute, marking it as the program entry point.
14
15use crate::{
16 ast::statements::{FunctionAttribute, Param, Statement, StatementKind, TypeAnnotation},
17 lexer::tokentypes::TokenType,
18 parser::parser_logic::Parser,
19 utils::{errors::Error, span::Span},
20};
21
22impl Parser {
23 /// Parses a named function declaration.
24 ///
25 /// Called after `fn` has been consumed (either by [`parse_statement_to_ast`]
26 /// or [`parse_entry_attribute`]). Reads:
27 ///
28 /// 1. The function name (identifier).
29 /// 2. A `(`-delimited, comma-separated parameter list of `T name` pairs.
30 /// 3. An optional `-> T` return type annotation (defaults to
31 /// [`TypeAnnotation::Null`] when absent).
32 /// 4. The function body via [`parse_block`].
33 ///
34 /// Produces [`StatementKind::FunctionDeclaration`].
35 ///
36 /// # Parameters
37 /// - `start` - the span of the `fn` token, used as the start of the overall span.
38 /// - `is_entry` - `true` when the function was marked with `!#[entry]`.
39 ///
40 /// # Errors
41 /// Returns an error if the function name, a parameter name, or the body
42 /// block are missing or malformed.
43 ///
44 /// [`parse_statement_to_ast`]: Parser::parse_statement_to_ast
45 /// [`parse_entry_attribute`]: Parser::parse_entry_attribute
46 /// [`parse_block`]: Parser::parse_block
47 pub fn parse_function(
48 &mut self,
49 start: Span,
50 attribute: Option<FunctionAttribute>,
51 ) -> Result<Statement, Error> {
52 let name = match self.peek() {
53 TokenType::Identifier(n) => {
54 self.advance();
55 n
56 }
57 _ => return Err(self.err("expected function name", self.peek_span())),
58 };
59
60 self.match_type(&[TokenType::LeftParen]);
61
62 let mut params: Vec<Param> = Vec::new();
63 while !self.match_type(&[TokenType::RightParen]) {
64 let param_type = self.parse_param_type()?;
65 match self.peek() {
66 TokenType::Identifier(p) => {
67 self.advance();
68 params.push(Param {
69 param_name: p,
70 param_type,
71 });
72 }
73 _ => return Err(self.err("expected parameter name", self.peek_span())),
74 }
75 if !self.match_type(&[TokenType::Comma]) {
76 break;
77 }
78 }
79 self.match_type(&[TokenType::RightParen]);
80
81 // optional return type annotation; defaults to Null when omitted
82 let return_type = if self.match_type(&[TokenType::Arrow]) {
83 match self.parse_param_type() {
84 Ok(a) => a,
85 Err(_) => TypeAnnotation::Null,
86 }
87 } else {
88 TypeAnnotation::Null
89 };
90
91 let body = self.parse_block()?;
92
93 let span = start.join(self.previous_span());
94 Ok(Statement::new(
95 StatementKind::FunctionDeclaration {
96 name,
97 params,
98 return_type,
99 body,
100 attribute,
101 },
102 span,
103 ))
104 }
105}