ezno_parser/types/
enum_declaration.rs1use 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 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}