ezno_parser/expressions/
arrow_function.rs

1use crate::{derive_ASTNode, functions::HeadingAndPosition, VariableIdentifier};
2use tokenizer_lib::sized_tokens::TokenStart;
3use visitable_derive::Visitable;
4
5use crate::{
6	errors::parse_lexing_error,
7	functions::{FunctionBased, FunctionParameters, Parameter},
8	tokens::token_as_identifier,
9	ASTNode, Block, Expression, FunctionBase, ParseOptions, ParseResult, Span, TSXToken, Token,
10	TokenReader, TypeAnnotation, VariableField,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct ArrowFunctionBase;
15
16pub type ArrowFunction = FunctionBase<ArrowFunctionBase>;
17#[cfg_attr(target_family = "wasm", tsify::declare)]
18pub type IsAsync = bool;
19
20#[cfg_attr(target_family = "wasm", wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section))]
21#[allow(dead_code)]
22const TYPES: &str = r"
23	export interface ArrowFunction extends FunctionBase {
24		header: IsAsync,
25		body: ExpressionOrBlock
26	}
27";
28
29impl FunctionBased for ArrowFunctionBase {
30	type Name = ();
31	type Header = IsAsync;
32	type Body = ExpressionOrBlock;
33	type LeadingParameter = ();
34	type ParameterVisibility = ();
35
36	// fn get_chain_variable(this: &FunctionBase<Self>) -> ChainVariable {
37	// 	ChainVariable::UnderArrowFunction(this.body.get_block_id())
38	// }
39
40	fn header_and_name_from_reader(
41		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
42		state: &mut crate::ParsingState,
43		_options: &ParseOptions,
44	) -> ParseResult<(HeadingAndPosition<Self>, Self::Name)> {
45		let async_pos = state.optionally_expect_keyword(reader, crate::TSXKeyword::Async);
46		Ok(((async_pos.map(|s| s.get_start()), async_pos.is_some()), ()))
47	}
48
49	fn header_and_name_to_string_from_buffer<T: source_map::ToString>(
50		buf: &mut T,
51		is_async: &Self::Header,
52		_name: &Self::Name,
53		_options: &crate::ToStringOptions,
54		_local: crate::LocalToStringInformation,
55	) {
56		if *is_async {
57			buf.push_str("async ");
58		}
59	}
60
61	fn parameters_from_reader<T: source_map::ToString>(
62		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
63		state: &mut crate::ParsingState,
64		options: &ParseOptions,
65	) -> ParseResult<FunctionParameters<(), ()>> {
66		match reader.next().ok_or_else(parse_lexing_error)? {
67			Token(TSXToken::OpenParentheses, open_paren) => {
68				FunctionParameters::from_reader_sub_open_parenthesis(
69					reader, state, options, open_paren,
70				)
71			}
72			// `x` => ...
73			token => {
74				let (name, position) = token_as_identifier(token, "arrow function parameter")?;
75				let parameters = vec![Parameter {
76					visibility: (),
77					name: VariableField::Name(VariableIdentifier::Standard(name, position)).into(),
78					type_annotation: None,
79					additionally: None,
80					position,
81				}];
82				Ok(FunctionParameters { leading: (), parameters, rest_parameter: None, position })
83			}
84		}
85	}
86
87	fn parameters_to_string_from_buffer<T: source_map::ToString>(
88		buf: &mut T,
89		parameters: &FunctionParameters<(), ()>,
90		options: &crate::ToStringOptions,
91		local: crate::LocalToStringInformation,
92	) {
93		// Use shorthand if one parameter with no declared type
94		if let ([Parameter { name, type_annotation, .. }], None) =
95			(parameters.parameters.as_slice(), &parameters.rest_parameter)
96		{
97			let is_printing_type_annotation =
98				options.include_type_annotations && type_annotation.is_some();
99			if !is_printing_type_annotation {
100				if let VariableField::Name(name, ..) = name.get_ast_ref() {
101					name.to_string_from_buffer(buf, options, local);
102					return;
103				}
104			}
105		}
106		parameters.to_string_from_buffer(buf, options, local);
107	}
108
109	fn parameter_body_boundary_token_to_string_from_buffer<T: source_map::ToString>(
110		buf: &mut T,
111		options: &crate::ToStringOptions,
112	) {
113		buf.push_str(if options.pretty { " => " } else { "=>" });
114	}
115
116	fn visit_name<TData>(
117		(): &Self::Name,
118		_: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
119		_: &mut TData,
120		_: &crate::visiting::VisitOptions,
121		_: &mut temporary_annex::Annex<crate::Chain>,
122	) {
123	}
124
125	fn visit_name_mut<TData>(
126		(): &mut Self::Name,
127		_: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
128		_: &mut TData,
129		_: &crate::visiting::VisitOptions,
130		_: &mut temporary_annex::Annex<crate::Chain>,
131	) {
132	}
133
134	fn get_name((): &Self::Name) -> Option<&str> {
135		None
136	}
137}
138
139impl ArrowFunction {
140	pub(crate) fn from_reader_with_first_parameter(
141		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
142		state: &mut crate::ParsingState,
143		options: &ParseOptions,
144		first_parameter: (String, Span),
145		is_async: IsAsync,
146	) -> ParseResult<Self> {
147		let (first_parameter_name, first_parameter_position) = first_parameter;
148		let name = VariableField::Name(VariableIdentifier::Standard(
149			first_parameter_name,
150			first_parameter_position,
151		));
152		let parameters = vec![Parameter {
153			visibility: (),
154			name: name.into(),
155			type_annotation: None,
156			additionally: None,
157			position: first_parameter.1,
158		}];
159		reader.expect_next(TSXToken::Arrow)?;
160		let body = ExpressionOrBlock::from_reader(reader, state, options)?;
161		let arrow_function = FunctionBase {
162			header: is_async,
163			position: first_parameter.1.union(body.get_position()),
164			name: (),
165			parameters: FunctionParameters {
166				parameters,
167				rest_parameter: None,
168				position: first_parameter.1,
169				leading: (),
170			},
171			return_type: None,
172			type_parameters: None,
173			body,
174		};
175		Ok(arrow_function)
176	}
177
178	pub(crate) fn from_reader_sub_open_paren(
179		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
180		state: &mut crate::ParsingState,
181		options: &ParseOptions,
182		is_async: IsAsync,
183		start: TokenStart,
184	) -> ParseResult<Self> {
185		let parameters =
186			FunctionParameters::from_reader_sub_open_parenthesis(reader, state, options, start)?;
187
188		let return_type = if reader
189			.conditional_next(|token| options.type_annotations && matches!(token, TSXToken::Colon))
190			.is_some()
191		{
192			Some(TypeAnnotation::from_reader(reader, state, options)?)
193		} else {
194			None
195		};
196		reader.expect_next(TSXToken::Arrow)?;
197		let body = ExpressionOrBlock::from_reader(reader, state, options)?;
198		Ok(FunctionBase {
199			header: is_async,
200			name: (),
201			parameters,
202			return_type,
203			type_parameters: None,
204			position: start.union(body.get_position()),
205			body,
206		})
207	}
208}
209
210/// For [`ArrowFunction`] and [`crate::MatchArm`] bodies
211#[derive(Debug, Clone, PartialEq, Visitable)]
212#[apply(derive_ASTNode)]
213pub enum ExpressionOrBlock {
214	Expression(Box<Expression>),
215	Block(Block),
216}
217
218impl ASTNode for ExpressionOrBlock {
219	fn get_position(&self) -> Span {
220		match self {
221			ExpressionOrBlock::Expression(expression) => expression.get_position(),
222			ExpressionOrBlock::Block(block) => block.get_position(),
223		}
224	}
225
226	fn from_reader(
227		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
228		state: &mut crate::ParsingState,
229		options: &ParseOptions,
230	) -> ParseResult<Self> {
231		if let Some(Token(TSXToken::OpenBrace, _)) = reader.peek() {
232			Ok(Self::Block(Block::from_reader(reader, state, options)?))
233		} else {
234			let expression = Expression::from_reader(reader, state, options)?;
235			Ok(Self::Expression(Box::new(expression)))
236		}
237	}
238
239	fn to_string_from_buffer<T: source_map::ToString>(
240		&self,
241		buf: &mut T,
242		options: &crate::ToStringOptions,
243		local: crate::LocalToStringInformation,
244	) {
245		match self {
246			ExpressionOrBlock::Expression(expr) => expr.to_string_from_buffer(buf, options, local),
247			ExpressionOrBlock::Block(block) => block.to_string_from_buffer(buf, options, local),
248		}
249	}
250}