ezno_parser/
modules.rs

1use crate::{
2	block::{parse_statements_and_declarations, statements_and_declarations_to_string},
3	derive_ASTNode, BlockLike, BlockLikeMut, LocalToStringInformation, ParseOptions, ParseResult,
4	StatementOrDeclaration, VisitOptions,
5};
6
7use super::{ASTNode, Span, TSXToken, TokenReader};
8
9#[derive(Debug, Clone)]
10#[apply(derive_ASTNode)]
11pub struct Module {
12	pub hashbang_comment: Option<String>,
13	pub items: Vec<StatementOrDeclaration>,
14	pub span: Span,
15}
16
17impl PartialEq for Module {
18	fn eq(&self, other: &Self) -> bool {
19		self.items == other.items
20	}
21}
22
23impl ASTNode for Module {
24	fn to_string_from_buffer<T: source_map::ToString>(
25		&self,
26		buf: &mut T,
27		options: &crate::ToStringOptions,
28		local: crate::LocalToStringInformation,
29	) {
30		if let Some(ref hashbang_comment) = self.hashbang_comment {
31			buf.push_str("#!");
32			buf.push_str(hashbang_comment);
33			buf.push_new_line();
34		}
35		statements_and_declarations_to_string(&self.items, buf, options, local);
36	}
37
38	fn get_position(&self) -> Span {
39		self.span
40	}
41
42	fn from_reader(
43		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
44		state: &mut crate::ParsingState,
45		options: &ParseOptions,
46	) -> ParseResult<Self> {
47		let start = reader.peek().map(|t| t.1 .0).unwrap_or_default();
48		let span = Span { start, source: (), end: start + state.length_of_source };
49		let hashbang_comment = if let Some(crate::Token(TSXToken::HashBangComment(_), _)) =
50			reader.peek()
51		{
52			let Some(crate::Token(TSXToken::HashBangComment(hashbang_comment), _)) = reader.next()
53			else {
54				unreachable!()
55			};
56			Some(hashbang_comment)
57		} else {
58			None
59		};
60		parse_statements_and_declarations(reader, state, options).map(|items| Module {
61			hashbang_comment,
62			items,
63			span,
64		})
65	}
66}
67
68impl Module {
69	pub fn to_string_with_source_map(
70		&self,
71		options: &crate::ToStringOptions,
72		this: source_map::SourceId,
73		fs: &impl source_map::FileSystem,
74	) -> (String, Option<source_map::SourceMap>) {
75		let mut buf = source_map::StringWithOptionalSourceMap::new(true);
76		self.to_string_from_buffer(
77			&mut buf,
78			options,
79			LocalToStringInformation { depth: 0, under: this, should_try_pretty_print: true },
80		);
81		buf.build(fs)
82	}
83
84	// #[must_use]
85	// pub fn length(&self, options: &crate::ToStringOptions) -> usize {
86	// 	let mut buf = source_map::Counter::new();
87	// 	self.to_string_from_buffer(
88	// 		&mut buf,
89	// 		options,
90	// 		LocalToStringInformation { depth: 0, under: source_map::Nullable::NULL },
91	// 	);
92	// 	buf.get_count()
93	// }
94}
95
96impl Module {
97	pub fn visit<TData>(
98		&self,
99		visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
100		data: &mut TData,
101		options: &VisitOptions,
102		source: source_map::SourceId,
103	) {
104		use crate::visiting::Visitable;
105		let mut chain = crate::Chain::new_with_initial(crate::ChainVariable::Module(source));
106		let mut chain = temporary_annex::Annex::new(&mut chain);
107
108		{
109			visitors.visit_block(&crate::block::BlockLike { items: &self.items }, data, &chain);
110		}
111
112		let iter = self.items.iter();
113		if options.reverse_statements {
114			iter.for_each(|item| item.visit(visitors, data, options, &mut chain));
115		} else {
116			iter.rev().for_each(|item| item.visit(visitors, data, options, &mut chain));
117		}
118	}
119
120	pub fn visit_mut<TData>(
121		&mut self,
122		visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
123		data: &mut TData,
124		options: &VisitOptions,
125		source: source_map::SourceId,
126	) {
127		use crate::visiting::Visitable;
128		let mut chain = crate::Chain::new_with_initial(crate::ChainVariable::Module(source));
129		let mut chain = temporary_annex::Annex::new(&mut chain);
130
131		{
132			visitors.visit_block_mut(
133				&mut crate::block::BlockLikeMut { items: &mut self.items },
134				data,
135				&chain,
136			);
137		}
138
139		let iter_mut = self.items.iter_mut();
140		if options.reverse_statements {
141			iter_mut.for_each(|item| item.visit_mut(visitors, data, options, &mut chain));
142		} else {
143			iter_mut.rev().for_each(|item| item.visit_mut(visitors, data, options, &mut chain));
144		}
145	}
146}
147
148impl<'a> From<&'a Module> for BlockLike<'a> {
149	fn from(module: &'a Module) -> Self {
150		BlockLike { items: &module.items }
151	}
152}
153
154impl<'a> From<&'a mut Module> for BlockLikeMut<'a> {
155	fn from(module: &'a mut Module) -> Self {
156		BlockLikeMut { items: &mut module.items }
157	}
158}