Skip to main content

rl_lang/parser/statements/
record_declaration.rs

1//! Record (struct) declaration parser (`record`).
2//!
3//! Handles record type declarations in the form:
4//!
5//! ```text
6//! record Name {
7//!     int field_a,
8//!     string field_b,
9//! }
10//! ```
11//!
12//! Field types are parsed via [`Parser::parse_param_type`], so any type
13//! usable in a function parameter (including other record names) may be
14//! used as a field type. A trailing comma after the last field is allowed.
15
16use crate::{
17    ast::statements::{Statement, StatementKind},
18    lexer::tokentypes::TokenType,
19    parser::parser_logic::Parser,
20    utils::{errors::Error, span::Span},
21};
22
23impl Parser {
24    /// Parses a `record` declaration.
25    ///
26    /// Called after `record` has been consumed. Reads the record name,
27    /// then a `{`-delimited, comma-separated list of `T name` field pairs.
28    ///
29    /// Produces [`StatementKind::RecordDeclaration`].
30    ///
31    /// # Errors
32    /// Returns an error if the record name, a field type/name, or the
33    /// closing `}` are missing or malformed.
34    pub fn parse_record_declaration(&mut self, start: Span) -> Result<Statement, Error> {
35        while self.match_type(&[TokenType::Newline]) {}
36
37        let name = match self.peek() {
38            TokenType::Identifier(n) => {
39                self.advance();
40                n
41            }
42            _ => return Err(self.err("expected record name", self.peek_span())),
43        };
44
45        self.record_names.insert(name.clone());
46
47        while self.match_type(&[TokenType::Newline]) {}
48        if !self.match_type(&[TokenType::LeftBrace]) {
49            return Err(self.err("expected `{` after record name", self.peek_span()));
50        }
51
52        let mut fields = Vec::new();
53        loop {
54            while self.match_type(&[TokenType::Newline]) {}
55            if self.peek() == TokenType::RightBrace {
56                break;
57            }
58            let field_type = self.parse_param_type()?;
59            while self.match_type(&[TokenType::Newline]) {}
60            let field_name = match self.peek() {
61                TokenType::Identifier(n) => {
62                    self.advance();
63                    n
64                }
65                _ => return Err(self.err("expected field name", self.peek_span())),
66            };
67            fields.push((field_name, field_type));
68
69            while self.match_type(&[TokenType::Newline]) {}
70            if !self.match_type(&[TokenType::Comma]) {
71                break;
72            }
73        }
74
75        while self.match_type(&[TokenType::Newline]) {}
76        if !self.match_type(&[TokenType::RightBrace]) {
77            return Err(self.err("expected `}` after record fields", self.peek_span()));
78        }
79
80        let span = start.join(self.previous_span());
81        Ok(Statement::new(
82            StatementKind::RecordDeclaration { name, fields },
83            span,
84        ))
85    }
86}