Skip to main content

rl_lang/parser/statements/
tag_declaration.rs

1//! Tag (enum) declaration parser (`tag`).
2//!
3//! Handles simple unit-variant enum declarations:
4//!
5//! ```text
6//! tag Name {
7//!     VariantA,
8//!     VariantB,
9//! }
10//! ```
11//!
12//! A trailing comma after the last field is allowed.
13
14use crate::{
15    ast::statements::{Statement, StatementKind},
16    lexer::tokentypes::TokenType,
17    parser::parser_logic::Parser,
18    utils::{errors::Error, span::Span},
19};
20
21impl Parser {
22    /// Parses a `tag` declaration.
23    ///
24    /// Called after `tag` has been consumed. Reads the tag name, then a
25    /// `{`-delimited, comma-separated list of variant names.
26    ///
27    /// Produces [`StatementKind::TagDeclaration`].
28    ///
29    /// # Errors
30    /// Returns an error if the tag name, a variant name, or the closing
31    /// `}` are missing or malformed.
32    pub fn parse_tag_declaration(&mut self, start: Span) -> Result<Statement, Error> {
33        while self.match_type(&[TokenType::Newline]) {}
34
35        let name = match self.peek() {
36            TokenType::Identifier(n) => {
37                self.advance();
38                n
39            }
40            _ => return Err(self.err("expected tag name", self.peek_span())),
41        };
42
43        self.tag_names.insert(name.clone());
44
45        while self.match_type(&[TokenType::Newline]) {}
46        if !self.match_type(&[TokenType::LeftBrace]) {
47            return Err(self.err("expected `{` after tag name", self.peek_span()));
48        }
49
50        let mut variants = Vec::new();
51        loop {
52            while self.match_type(&[TokenType::Newline]) {}
53            if self.peek() == TokenType::RightBrace {
54                break;
55            }
56            let variant_name = match self.peek() {
57                TokenType::Identifier(n) => {
58                    self.advance();
59                    n
60                }
61                _ => return Err(self.err("expected variant name", self.peek_span())),
62            };
63            variants.push(variant_name);
64
65            while self.match_type(&[TokenType::Newline]) {}
66            if !self.match_type(&[TokenType::Comma]) {
67                break;
68            }
69        }
70
71        while self.match_type(&[TokenType::Newline]) {}
72        if !self.match_type(&[TokenType::RightBrace]) {
73            return Err(self.err("expected `}` after tag variants", self.peek_span()));
74        }
75
76        let span = start.join(self.previous_span());
77        Ok(Statement::new(
78            StatementKind::TagDeclaration { name, variants },
79            span,
80        ))
81    }
82}