ezno_parser/declarations/classes/
mod.rs

1mod 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}