Skip to main content

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}