ezno_parser/expressions/
operators.rs

1//! Contains the definitions for expressions
2
3//! Operators marked in spec but implemented as a variant of [`crate::Expression`] rather than a *operator*:
4//! `OptionalChain`, `OptionalCall`, `OptionalIndex`, Index, Group, Initialize, Call,
5
6use std::convert::TryFrom;
7
8use crate::{derive_ASTNode, TSXKeyword, TSXToken};
9
10/// Comma operator is on [`crate::MultipleExpression`]
11/// 
12/// `InstanceOf`, In are special operators
13#[rustfmt::skip]
14#[derive(Debug, PartialEq, Eq, Clone, Copy)]
15#[apply(derive_ASTNode!)]
16pub enum BinaryOperator {
17	Add, Subtract, Multiply, Divide, Modulo, Exponent,
18
19    BitwiseShiftLeft, BitwiseShiftRight, BitwiseShiftRightUnsigned,
20    BitwiseAnd, BitwiseXOr, BitwiseOr,
21
22    StrictEqual, StrictNotEqual, Equal, NotEqual,
23    GreaterThan, LessThan, LessThanEqual, GreaterThanEqual,
24
25    LogicalAnd, LogicalOr,
26    NullCoalescing, 
27
28    /// Non standard
29    Pipe,
30    Compose
31}
32
33impl BinaryOperator {
34	#[must_use]
35	pub fn is_non_standard(&self) -> bool {
36		matches!(self, BinaryOperator::Pipe | BinaryOperator::Compose)
37	}
38}
39
40/// Straight assignment is not here because LHS can be destructuring
41#[rustfmt::skip]
42#[derive(Debug, PartialEq, Eq, Clone, Copy)]
43#[apply(derive_ASTNode!)]
44pub enum BinaryAssignmentOperator {
45    LogicalNullishAssignment,
46    
47    AddAssign, SubtractAssign, MultiplyAssign, DivideAssign, ModuloAssign, ExponentAssign,
48    LogicalAndAssign, LogicalOrAssign,
49    BitwiseShiftLeftAssign, BitwiseShiftRightAssign, BitwiseShiftRightUnsigned, 
50    BitwiseAndAssign, BitwiseXOrAssign, BitwiseOrAssign,
51}
52
53#[rustfmt::skip]
54#[derive(Debug, PartialEq, Eq, Clone, Copy)]
55#[apply(derive_ASTNode!)]
56pub enum UnaryOperator {
57    Plus, Negation,
58    BitwiseNot, LogicalNot,
59    Await, TypeOf, Void, Delete,
60	Yield, DelegatedYield,
61}
62
63#[derive(Debug, PartialEq, Eq, Clone, Copy)]
64#[apply(derive_ASTNode!)]
65pub enum IncrementOrDecrement {
66	Increment,
67	Decrement,
68}
69
70#[derive(Debug, PartialEq, Eq, Clone, Copy)]
71#[apply(derive_ASTNode!)]
72pub enum UnaryPrefixAssignmentOperator {
73	Invert,
74	IncrementOrDecrement(IncrementOrDecrement),
75}
76
77#[derive(Debug, PartialEq, Eq, Clone, Copy)]
78#[apply(derive_ASTNode!)]
79pub struct UnaryPostfixAssignmentOperator(pub IncrementOrDecrement);
80
81#[derive(Debug, PartialEq, Eq, Clone, Copy)]
82pub enum AssociativityDirection {
83	NA,
84	LeftToRight,
85	RightToLeft,
86}
87
88impl AssociativityDirection {
89	pub(crate) fn should_return(self, parent_precedence: u8, upcoming_precedence: u8) -> bool {
90		match self {
91			AssociativityDirection::RightToLeft => parent_precedence > upcoming_precedence,
92			AssociativityDirection::NA | AssociativityDirection::LeftToRight => {
93				parent_precedence >= upcoming_precedence
94			}
95		}
96	}
97}
98
99pub trait Operator: for<'a> TryFrom<&'a TSXToken> {
100	/// String representation of operator
101	fn to_str(&self) -> &'static str;
102
103	/// Taken from: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table>
104	fn precedence(&self) -> u8;
105
106	/// Returns the associativity of the operator. Taken from: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table>
107	fn associativity_direction(&self) -> AssociativityDirection;
108
109	/// Is associative with self <https://en.wikipedia.org/wiki/Associative_property>
110	fn is_associative(&self) -> bool;
111
112	fn precedence_and_associativity_direction(&self) -> (u8, AssociativityDirection) {
113		(self.precedence(), self.associativity_direction())
114	}
115}
116
117impl Operator for BinaryOperator {
118	fn to_str(&self) -> &'static str {
119		match self {
120			BinaryOperator::Add => "+",
121			BinaryOperator::Subtract => "-",
122			BinaryOperator::Multiply => "*",
123			BinaryOperator::Divide => "/",
124			BinaryOperator::Exponent => "**",
125			BinaryOperator::LessThan => "<",
126			BinaryOperator::GreaterThan => ">",
127			BinaryOperator::LessThanEqual => "<=",
128			BinaryOperator::GreaterThanEqual => ">=",
129			BinaryOperator::Equal => "==",
130			BinaryOperator::StrictEqual => "===",
131			BinaryOperator::NotEqual => "!=",
132			BinaryOperator::StrictNotEqual => "!==",
133			BinaryOperator::Modulo => "%",
134			BinaryOperator::NullCoalescing => "??",
135			BinaryOperator::LogicalAnd => "&&",
136			BinaryOperator::LogicalOr => "||",
137			BinaryOperator::BitwiseShiftLeft => "<<",
138			BinaryOperator::BitwiseShiftRight => ">>",
139			BinaryOperator::BitwiseShiftRightUnsigned => ">>>",
140			BinaryOperator::BitwiseAnd => "&",
141			BinaryOperator::BitwiseOr => "|",
142			BinaryOperator::BitwiseXOr => "^",
143			BinaryOperator::Compose => "<@>", // ∘
144			BinaryOperator::Pipe => "|>",
145		}
146	}
147
148	fn precedence(&self) -> u8 {
149		match self {
150			BinaryOperator::Pipe | BinaryOperator::Compose => 15,
151			BinaryOperator::Exponent => 14,
152			BinaryOperator::Multiply | BinaryOperator::Divide | BinaryOperator::Modulo => 13,
153			BinaryOperator::Add | BinaryOperator::Subtract => 12,
154			BinaryOperator::BitwiseShiftLeft
155			| BinaryOperator::BitwiseShiftRightUnsigned
156			| BinaryOperator::BitwiseShiftRight => 11,
157			BinaryOperator::LessThan
158			| BinaryOperator::LessThanEqual
159			| BinaryOperator::GreaterThanEqual
160			| BinaryOperator::GreaterThan => 10,
161			BinaryOperator::Equal
162			| BinaryOperator::NotEqual
163			| BinaryOperator::StrictEqual
164			| BinaryOperator::StrictNotEqual => 9,
165			BinaryOperator::BitwiseAnd => 8,
166			BinaryOperator::BitwiseXOr => 7,
167			BinaryOperator::BitwiseOr => 6,
168			BinaryOperator::LogicalAnd => 5,
169			BinaryOperator::NullCoalescing | BinaryOperator::LogicalOr => 4,
170		}
171	}
172
173	fn associativity_direction(&self) -> AssociativityDirection {
174		if let BinaryOperator::Exponent = self {
175			AssociativityDirection::RightToLeft
176		} else {
177			AssociativityDirection::LeftToRight
178		}
179	}
180
181	fn is_associative(&self) -> bool {
182		!matches!(self, Self::Subtract | Self::Exponent | Self::Divide)
183	}
184}
185
186impl Operator for UnaryOperator {
187	fn to_str(&self) -> &'static str {
188		match self {
189			UnaryOperator::Plus => "+",
190			UnaryOperator::Negation => "-",
191			UnaryOperator::BitwiseNot => "~",
192			UnaryOperator::LogicalNot => "!",
193			UnaryOperator::Delete => "delete ",
194			UnaryOperator::Yield => "yield ",
195			UnaryOperator::DelegatedYield => "yield* ",
196			UnaryOperator::Await => "await ",
197			UnaryOperator::TypeOf => "typeof ",
198			UnaryOperator::Void => "void ",
199		}
200	}
201
202	fn precedence(&self) -> u8 {
203		match self {
204			UnaryOperator::TypeOf
205			| UnaryOperator::Await
206			| UnaryOperator::Delete
207			| UnaryOperator::Void
208			| UnaryOperator::BitwiseNot
209			| UnaryOperator::LogicalNot
210			| UnaryOperator::Plus
211			| UnaryOperator::Negation => 15,
212			UnaryOperator::Yield | UnaryOperator::DelegatedYield => 2,
213		}
214	}
215
216	fn associativity_direction(&self) -> AssociativityDirection {
217		AssociativityDirection::RightToLeft
218	}
219
220	fn is_associative(&self) -> bool {
221		true
222	}
223}
224
225impl Operator for BinaryAssignmentOperator {
226	fn to_str(&self) -> &'static str {
227		match self {
228			BinaryAssignmentOperator::LogicalNullishAssignment => "??=",
229			BinaryAssignmentOperator::AddAssign => "+=",
230			BinaryAssignmentOperator::SubtractAssign => "-=",
231			BinaryAssignmentOperator::MultiplyAssign => "*=",
232			BinaryAssignmentOperator::DivideAssign => "/=",
233			BinaryAssignmentOperator::ModuloAssign => "%=",
234			BinaryAssignmentOperator::ExponentAssign => "**=",
235			BinaryAssignmentOperator::BitwiseShiftLeftAssign => "<<=",
236			BinaryAssignmentOperator::BitwiseShiftRightAssign => ">>=",
237			BinaryAssignmentOperator::BitwiseShiftRightUnsigned => ">>>=",
238			BinaryAssignmentOperator::BitwiseAndAssign => "&=",
239			BinaryAssignmentOperator::BitwiseXOrAssign => "^=",
240			BinaryAssignmentOperator::BitwiseOrAssign => "|=",
241			BinaryAssignmentOperator::LogicalAndAssign => "&&=",
242			BinaryAssignmentOperator::LogicalOrAssign => "||=",
243		}
244	}
245
246	fn precedence(&self) -> u8 {
247		ASSIGNMENT_PRECEDENCE
248	}
249
250	fn associativity_direction(&self) -> AssociativityDirection {
251		AssociativityDirection::RightToLeft
252	}
253
254	fn is_associative(&self) -> bool {
255		// dbg!("TODO unsure");
256		true
257	}
258}
259
260impl Operator for UnaryPrefixAssignmentOperator {
261	fn precedence(&self) -> u8 {
262		15
263	}
264
265	fn associativity_direction(&self) -> AssociativityDirection {
266		AssociativityDirection::RightToLeft
267	}
268
269	fn to_str(&self) -> &'static str {
270		match self {
271			UnaryPrefixAssignmentOperator::Invert => ">!", // ¡
272			UnaryPrefixAssignmentOperator::IncrementOrDecrement(inc_or_dec) => inc_or_dec.to_str(),
273		}
274	}
275
276	fn is_associative(&self) -> bool {
277		true
278	}
279}
280
281impl Operator for UnaryPostfixAssignmentOperator {
282	fn precedence(&self) -> u8 {
283		16
284	}
285
286	fn associativity_direction(&self) -> AssociativityDirection {
287		AssociativityDirection::NA
288	}
289
290	fn to_str(&self) -> &'static str {
291		self.0.to_str()
292	}
293
294	fn is_associative(&self) -> bool {
295		true
296	}
297}
298
299impl IncrementOrDecrement {
300	fn to_str(self) -> &'static str {
301		match self {
302			IncrementOrDecrement::Increment => "++",
303			IncrementOrDecrement::Decrement => "--",
304		}
305	}
306}
307
308impl From<BinaryAssignmentOperator> for BinaryOperator {
309	fn from(val: BinaryAssignmentOperator) -> Self {
310		match val {
311			BinaryAssignmentOperator::LogicalNullishAssignment => BinaryOperator::NullCoalescing,
312			BinaryAssignmentOperator::AddAssign => BinaryOperator::Add,
313			BinaryAssignmentOperator::SubtractAssign => BinaryOperator::Subtract,
314			BinaryAssignmentOperator::MultiplyAssign => BinaryOperator::Multiply,
315			BinaryAssignmentOperator::DivideAssign => BinaryOperator::Divide,
316			BinaryAssignmentOperator::ModuloAssign => BinaryOperator::Modulo,
317			BinaryAssignmentOperator::ExponentAssign => BinaryOperator::Exponent,
318			BinaryAssignmentOperator::LogicalAndAssign => BinaryOperator::LogicalAnd,
319			BinaryAssignmentOperator::LogicalOrAssign => BinaryOperator::LogicalOr,
320			BinaryAssignmentOperator::BitwiseShiftLeftAssign => BinaryOperator::BitwiseShiftLeft,
321			BinaryAssignmentOperator::BitwiseShiftRightAssign => BinaryOperator::BitwiseShiftRight,
322			BinaryAssignmentOperator::BitwiseShiftRightUnsigned => {
323				BinaryOperator::BitwiseShiftRightUnsigned
324			}
325			BinaryAssignmentOperator::BitwiseAndAssign => BinaryOperator::BitwiseAnd,
326			BinaryAssignmentOperator::BitwiseXOrAssign => BinaryOperator::BitwiseXOr,
327			BinaryAssignmentOperator::BitwiseOrAssign => BinaryOperator::BitwiseOr,
328		}
329	}
330}
331
332impl TryFrom<&TSXToken> for BinaryAssignmentOperator {
333	type Error = ();
334
335	fn try_from(expression: &TSXToken) -> Result<Self, Self::Error> {
336		match expression {
337			TSXToken::AddAssign => Ok(BinaryAssignmentOperator::AddAssign),
338			TSXToken::SubtractAssign => Ok(BinaryAssignmentOperator::SubtractAssign),
339			TSXToken::MultiplyAssign => Ok(BinaryAssignmentOperator::MultiplyAssign),
340			TSXToken::DivideAssign => Ok(BinaryAssignmentOperator::DivideAssign),
341			TSXToken::ExponentAssign => Ok(BinaryAssignmentOperator::ExponentAssign),
342			TSXToken::LogicalAndAssign => Ok(BinaryAssignmentOperator::LogicalAndAssign),
343			TSXToken::LogicalOrAssign => Ok(BinaryAssignmentOperator::LogicalOrAssign),
344			TSXToken::BitwiseAndAssign => Ok(BinaryAssignmentOperator::BitwiseAndAssign),
345			TSXToken::BitwiseOrAssign => Ok(BinaryAssignmentOperator::BitwiseOrAssign),
346			TSXToken::BitwiseXorAssign => Ok(BinaryAssignmentOperator::BitwiseXOrAssign),
347			TSXToken::BitwiseShiftLeftAssign => {
348				Ok(BinaryAssignmentOperator::BitwiseShiftLeftAssign)
349			}
350			TSXToken::BitwiseShiftRightAssign => {
351				Ok(BinaryAssignmentOperator::BitwiseShiftRightAssign)
352			}
353			TSXToken::BitwiseShiftRightUnsignedAssign => {
354				Ok(BinaryAssignmentOperator::BitwiseShiftRightUnsigned)
355			}
356			TSXToken::NullishCoalescingAssign => {
357				Ok(BinaryAssignmentOperator::LogicalNullishAssignment)
358			}
359			_ => Err(()),
360		}
361	}
362}
363
364impl TryFrom<&TSXToken> for BinaryOperator {
365	type Error = ();
366
367	fn try_from(expression: &TSXToken) -> Result<Self, Self::Error> {
368		match expression {
369			TSXToken::Add => Ok(BinaryOperator::Add),
370			TSXToken::Subtract => Ok(BinaryOperator::Subtract),
371			TSXToken::Multiply => Ok(BinaryOperator::Multiply),
372			TSXToken::Divide => Ok(BinaryOperator::Divide),
373			TSXToken::Exponent => Ok(BinaryOperator::Exponent),
374			TSXToken::Modulo => Ok(BinaryOperator::Modulo),
375			TSXToken::Equal => Ok(BinaryOperator::Equal),
376			TSXToken::NotEqual => Ok(BinaryOperator::NotEqual),
377			TSXToken::StrictEqual => Ok(BinaryOperator::StrictEqual),
378			TSXToken::StrictNotEqual => Ok(BinaryOperator::StrictNotEqual),
379			TSXToken::LogicalOr => Ok(BinaryOperator::LogicalOr),
380			TSXToken::LogicalAnd => Ok(BinaryOperator::LogicalAnd),
381			TSXToken::OpenChevron => Ok(BinaryOperator::LessThan),
382			TSXToken::LessThanEqual => Ok(BinaryOperator::LessThanEqual),
383			TSXToken::CloseChevron => Ok(BinaryOperator::GreaterThan),
384			TSXToken::GreaterThanEqual => Ok(BinaryOperator::GreaterThanEqual),
385			TSXToken::BitwiseAnd => Ok(BinaryOperator::BitwiseAnd),
386			TSXToken::BitwiseOr => Ok(BinaryOperator::BitwiseOr),
387			TSXToken::BitwiseXOr => Ok(BinaryOperator::BitwiseXOr),
388			TSXToken::BitwiseShiftLeft => Ok(BinaryOperator::BitwiseShiftLeft),
389			TSXToken::BitwiseShiftRight => Ok(BinaryOperator::BitwiseShiftRight),
390			TSXToken::BitwiseShiftRightUnsigned => Ok(BinaryOperator::BitwiseShiftRightUnsigned),
391			TSXToken::NullishCoalescing => Ok(BinaryOperator::NullCoalescing),
392			#[cfg(feature = "extras")]
393			TSXToken::ComposeOperator => Ok(BinaryOperator::Compose),
394			#[cfg(feature = "extras")]
395			TSXToken::PipeOperator => Ok(BinaryOperator::Pipe),
396			_ => Err(()),
397		}
398	}
399}
400
401// Note `yield` and `yield *` handled differently
402impl TryFrom<&TSXToken> for UnaryOperator {
403	type Error = ();
404
405	fn try_from(expression: &TSXToken) -> Result<Self, Self::Error> {
406		match expression {
407			TSXToken::Keyword(TSXKeyword::TypeOf) => Ok(UnaryOperator::TypeOf),
408			TSXToken::Keyword(TSXKeyword::Await) => Ok(UnaryOperator::Await),
409			TSXToken::Keyword(TSXKeyword::Void) => Ok(UnaryOperator::Void),
410			TSXToken::Keyword(TSXKeyword::Delete) => Ok(UnaryOperator::Delete),
411			TSXToken::LogicalNot => Ok(UnaryOperator::LogicalNot),
412			TSXToken::BitwiseNot => Ok(UnaryOperator::BitwiseNot),
413			TSXToken::Subtract => Ok(UnaryOperator::Negation),
414			TSXToken::Add => Ok(UnaryOperator::Plus),
415			_ => Err(()),
416		}
417	}
418}
419
420impl TryFrom<&TSXToken> for IncrementOrDecrement {
421	type Error = ();
422
423	fn try_from(token: &TSXToken) -> Result<Self, Self::Error> {
424		match token {
425			TSXToken::Increment => Ok(Self::Increment),
426			TSXToken::Decrement => Ok(Self::Decrement),
427			_ => Err(()),
428		}
429	}
430}
431
432impl TryFrom<&TSXToken> for UnaryPostfixAssignmentOperator {
433	type Error = ();
434
435	fn try_from(token: &TSXToken) -> Result<Self, Self::Error> {
436		IncrementOrDecrement::try_from(token).map(Self)
437	}
438}
439
440impl TryFrom<&TSXToken> for UnaryPrefixAssignmentOperator {
441	type Error = ();
442
443	fn try_from(token: &TSXToken) -> Result<Self, Self::Error> {
444		#[cfg(feature = "extras")]
445		if *token == TSXToken::InvertAssign {
446			Ok(Self::Invert)
447		} else {
448			IncrementOrDecrement::try_from(token).map(Self::IncrementOrDecrement)
449		}
450		#[cfg(not(feature = "extras"))]
451		IncrementOrDecrement::try_from(token).map(Self::IncrementOrDecrement)
452	}
453}
454
455impl BinaryOperator {
456	/// Operators which return true may or may not evaluate RHS based on their own value
457	#[must_use]
458	pub fn is_rhs_conditional_evaluation(&self) -> bool {
459		matches!(
460			self,
461			BinaryOperator::LogicalAnd | BinaryOperator::LogicalOr | BinaryOperator::NullCoalescing
462		)
463	}
464}
465
466// Operator precedences that aren't registered under operator trait
467pub(crate) const COMMA_PRECEDENCE: u8 = 1;
468pub(crate) const MEMBER_ACCESS_PRECEDENCE: u8 = 18;
469pub(crate) const INDEX_PRECEDENCE: u8 = 18;
470pub(crate) const CONDITIONAL_TERNARY_PRECEDENCE: u8 = 2;
471pub(crate) const FUNCTION_CALL_PRECEDENCE: u8 = 18;
472pub(crate) const CONSTRUCTOR_PRECEDENCE: u8 = 18;
473pub(crate) const CONSTRUCTOR_WITHOUT_PARENTHESIS_PRECEDENCE: u8 = 17;
474pub(crate) const RELATION_PRECEDENCE: u8 = 10;
475pub(crate) const PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE: u8 = 19;
476pub(crate) const ARROW_FUNCTION_PRECEDENCE: u8 = 2;
477pub(crate) const ASSIGNMENT_PRECEDENCE: u8 = 2;