ezno_parser/types/
enum_declaration.rs

1use crate::{derive_ASTNode, TSXKeyword, TSXToken};
2use iterator_endiate::EndiateIteratorExt;
3use source_map::Span;
4use tokenizer_lib::{sized_tokens::TokenReaderWithTokenEnds, Token};
5use visitable_derive::Visitable;
6
7use crate::{errors::parse_lexing_error, tokens::token_as_identifier, ASTNode, Expression};
8
9#[derive(Debug, Clone, PartialEq, Visitable)]
10#[apply(derive_ASTNode)]
11pub struct EnumDeclaration {
12	pub is_constant: bool,
13	pub name: String,
14	pub members: Vec<EnumMember>,
15	pub position: Span,
16}
17
18impl ASTNode for EnumDeclaration {
19	fn get_position(&self) -> Span {
20		self.position
21	}
22
23	fn from_reader(
24		reader: &mut impl tokenizer_lib::TokenReader<crate::TSXToken, crate::TokenStart>,
25		state: &mut crate::ParsingState,
26		options: &crate::ParseOptions,
27	) -> Result<Self, crate::ParseError> {
28		let const_pos = reader
29			.conditional_next(|tok| matches!(tok, TSXToken::Keyword(TSXKeyword::Const)))
30			.map(|Token(_, pos)| pos);
31
32		let is_constant = const_pos.is_some();
33		let enum_pos = state.expect_keyword(reader, TSXKeyword::Enum)?;
34		let (name, _) =
35			token_as_identifier(reader.next().ok_or_else(parse_lexing_error)?, "Enum name")?;
36		reader.expect_next(TSXToken::OpenBrace)?;
37		let mut members = Vec::new();
38		loop {
39			if let Some(Token(TSXToken::CloseBrace, _)) = reader.peek() {
40				break;
41			}
42			members.push(EnumMember::from_reader(reader, state, options)?);
43			// Commas are optional
44			if let Some(Token(TSXToken::Comma, _)) = reader.peek() {
45				reader.next();
46			}
47		}
48		let end = reader.expect_next_get_end(TSXToken::CloseBrace)?;
49		Ok(EnumDeclaration {
50			is_constant,
51			position: const_pos.unwrap_or(enum_pos).union(end),
52			name,
53			members,
54		})
55	}
56
57	fn to_string_from_buffer<T: source_map::ToString>(
58		&self,
59		buf: &mut T,
60		options: &crate::ToStringOptions,
61		local: crate::LocalToStringInformation,
62	) {
63		if options.include_type_annotations {
64			if self.is_constant {
65				buf.push_str("const ");
66			}
67			buf.push_str("enum ");
68			buf.push_str(&self.name);
69			options.push_gap_optionally(buf);
70			buf.push_str("{");
71			for (at_end, member) in self.members.iter().endiate() {
72				if options.pretty {
73					buf.push_new_line();
74					options.add_indent(local.depth + 1, buf);
75				}
76				member.to_string_from_buffer(buf, options, local);
77				if !options.pretty && !at_end {
78					buf.push(',');
79				}
80			}
81			if options.pretty && !self.members.is_empty() {
82				buf.push_new_line();
83			}
84			buf.push('}');
85		}
86	}
87}
88
89#[derive(Debug, Clone, PartialEq, Visitable)]
90#[apply(derive_ASTNode)]
91pub enum EnumMember {
92	Variant { name: String, value: Option<Expression>, position: Span },
93}
94
95impl ASTNode for EnumMember {
96	fn get_position(&self) -> Span {
97		match self {
98			EnumMember::Variant { position, .. } => *position,
99		}
100	}
101
102	fn from_reader(
103		reader: &mut impl tokenizer_lib::TokenReader<crate::TSXToken, crate::TokenStart>,
104		state: &mut crate::ParsingState,
105		options: &crate::ParseOptions,
106	) -> Result<Self, crate::ParseError> {
107		let (name, start_pos) =
108			token_as_identifier(reader.next().ok_or_else(parse_lexing_error)?, "Enum variant")?;
109		match reader.peek() {
110			Some(Token(TSXToken::Assign, _)) => {
111				reader.next();
112				let expression = Expression::from_reader(reader, state, options)?;
113				Ok(EnumMember::Variant {
114					name,
115					position: start_pos.union(expression.get_position()),
116					value: Some(expression),
117				})
118			}
119			_ => Ok(EnumMember::Variant { name, value: None, position: start_pos }),
120		}
121	}
122
123	fn to_string_from_buffer<T: source_map::ToString>(
124		&self,
125		buf: &mut T,
126		options: &crate::ToStringOptions,
127		local: crate::LocalToStringInformation,
128	) {
129		match self {
130			EnumMember::Variant { name, value, .. } => {
131				buf.push_str(name);
132				if let Some(value) = value {
133					buf.push_str(if options.pretty { " = " } else { "=" });
134					value.to_string_from_buffer(buf, options, local);
135				}
136			}
137		}
138	}
139}