ezno_parser/declarations/classes/
mod.rs1mod class_member;
2
3use std::fmt::Debug;
4
5use crate::{
6 derive_ASTNode, throw_unexpected_token_with_token, to_string_bracketed, Expression,
7 ParseErrors, VariableIdentifier,
8};
9pub use class_member::*;
10use iterator_endiate::EndiateIteratorExt;
11
12use crate::{
13 extensions::decorators::Decorated, visiting::Visitable, ASTNode, ExpressionOrStatementPosition,
14 ParseOptions, ParseResult, Span, TSXKeyword, TSXToken, TypeAnnotation, TypeParameter,
15 VisitOptions,
16};
17use tokenizer_lib::{
18 sized_tokens::{TokenReaderWithTokenEnds, TokenStart},
19 Token, TokenReader,
20};
21
22#[apply(derive_ASTNode)]
23#[derive(Debug, Clone, PartialEq, get_field_by_type::GetFieldByType)]
24#[get_field_by_type_target(Span)]
25pub struct ClassDeclaration<T: ExpressionOrStatementPosition> {
26 pub name: T,
27 pub type_parameters: Option<Vec<TypeParameter>>,
28 pub extends: Option<Box<Expression>>,
29 pub implements: Option<Vec<TypeAnnotation>>,
30 pub members: Vec<Decorated<ClassMember>>,
31 pub position: Span,
32}
33
34impl<U: ExpressionOrStatementPosition + Debug + PartialEq + Clone + 'static> ASTNode
35 for ClassDeclaration<U>
36{
37 fn from_reader(
38 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
39 state: &mut crate::ParsingState,
40 options: &ParseOptions,
41 ) -> ParseResult<Self> {
42 let start = state.expect_keyword(reader, TSXKeyword::Class)?;
43 Self::from_reader_sub_class_keyword(reader, state, options, start)
44 }
45
46 fn to_string_from_buffer<T: source_map::ToString>(
47 &self,
48 buf: &mut T,
49 options: &crate::ToStringOptions,
50 local: crate::LocalToStringInformation,
51 ) {
52 self.to_string_from_buffer(buf, options, local);
53 }
54
55 fn get_position(&self) -> Span {
56 self.position
57 }
58}
59
60impl<U: ExpressionOrStatementPosition> ClassDeclaration<U> {
61 pub(crate) fn from_reader_sub_class_keyword(
62 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
63 state: &mut crate::ParsingState,
64 options: &ParseOptions,
65 start: TokenStart,
66 ) -> ParseResult<Self> {
67 let name = U::from_reader(reader, state, options)?;
68
69 if let Some(VariableIdentifier::Standard(name, pos)) = name.as_option_variable_identifier()
70 {
71 if let "extends" = name.as_str() {
72 return Err(crate::ParseError::new(ParseErrors::ExpectedIdentifier, *pos));
73 }
74 }
75
76 let type_parameters = reader
77 .conditional_next(|token| *token == TSXToken::OpenChevron)
78 .is_some()
79 .then(|| {
80 crate::parse_bracketed(reader, state, options, None, TSXToken::CloseChevron)
81 .map(|(params, _, _)| params)
82 })
83 .transpose()?;
84
85 let extends = if reader
86 .conditional_next(|t| matches!(t, TSXToken::Keyword(TSXKeyword::Extends)))
87 .is_some()
88 {
89 Some(Expression::from_reader(reader, state, options)?.into())
90 } else {
91 None
92 };
93
94 let implements = if reader
95 .conditional_next(|t| matches!(t, TSXToken::Keyword(TSXKeyword::Implements)))
96 .is_some()
97 {
98 let type_annotation = TypeAnnotation::from_reader(reader, state, options)?;
99 let mut implements = vec![type_annotation];
100 if reader.conditional_next(|t| matches!(t, TSXToken::Comma)).is_some() {
101 loop {
102 implements.push(TypeAnnotation::from_reader(reader, state, options)?);
103 match reader.peek() {
104 Some(Token(TSXToken::Comma, _)) => {
105 reader.next();
106 }
107 Some(Token(TSXToken::OpenBrace, _)) | None => break,
108 _ => {
109 return throw_unexpected_token_with_token(
110 reader.next().unwrap(),
111 &[TSXToken::Comma, TSXToken::OpenBrace],
112 )
113 }
114 }
115 }
116 }
117 Some(implements)
118 } else {
119 None
120 };
121
122 reader.expect_next(TSXToken::OpenBrace)?;
123 let mut members: Vec<Decorated<ClassMember>> = Vec::new();
124 loop {
125 if let Some(Token(TSXToken::CloseBrace, _)) = reader.peek() {
126 break;
127 }
128 let value = Decorated::<ClassMember>::from_reader(reader, state, options)?;
129 members.push(value);
130
131 if let Some(Token(TSXToken::SemiColon, _)) = reader.peek() {
132 reader.next();
133 }
134 }
135 let position = start.union(reader.expect_next_get_end(TSXToken::CloseBrace)?);
136
137 Ok(ClassDeclaration { name, type_parameters, extends, implements, members, position })
138 }
139
140 pub(crate) fn to_string_from_buffer<T: source_map::ToString>(
141 &self,
142 buf: &mut T,
143 options: &crate::ToStringOptions,
144 local: crate::LocalToStringInformation,
145 ) {
146 buf.push_str("class ");
147 if let Some(name) = self.name.as_option_str() {
148 buf.push_str(name);
149 }
150 if let Some(type_parameters) = &self.type_parameters {
151 to_string_bracketed(type_parameters, ('<', '>'), buf, options, local);
152 }
153 if let Some(extends) = &self.extends {
154 buf.push_str(" extends ");
155 extends.to_string_from_buffer(buf, options, local);
156 }
157 options.push_gap_optionally(buf);
158 buf.push('{');
159 for (at_end, member) in self.members.iter().endiate() {
160 if options.pretty {
161 buf.push_new_line();
162 options.add_indent(local.depth + 1, buf);
163 }
164 member.to_string_from_buffer(buf, options, local);
165 if !options.pretty && !at_end {
166 buf.push(';');
167 }
168 }
169 if options.pretty && !self.members.is_empty() {
170 buf.push_new_line();
171 }
172 buf.push('}');
173 }
174}
175
176impl<T: ExpressionOrStatementPosition> Visitable for ClassDeclaration<T> {
177 fn visit<TData>(
178 &self,
179 visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
180 data: &mut TData,
181 options: &VisitOptions,
182 chain: &mut temporary_annex::Annex<crate::Chain>,
183 ) {
184 visitors.visit_variable(
185 &crate::visiting::ImmutableVariableOrProperty::ClassName(
186 self.name.as_option_variable_identifier(),
187 ),
188 data,
189 chain,
190 );
191 self.extends.visit(visitors, data, options, chain);
192 self.members.visit(visitors, data, options, chain);
193 }
194
195 fn visit_mut<TData>(
196 &mut self,
197 visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
198 data: &mut TData,
199 options: &VisitOptions,
200 chain: &mut temporary_annex::Annex<crate::Chain>,
201 ) {
202 visitors.visit_variable_mut(
203 &mut crate::visiting::MutableVariableOrProperty::ClassName(
204 self.name.as_option_variable_identifier_mut(),
205 ),
206 data,
207 chain,
208 );
209 self.extends.visit_mut(visitors, data, options, chain);
210 self.members.visit_mut(visitors, data, options, chain);
211 }
212}