1use crate::expression::operator::{
9 assign::AssignOp,
10 binary::{ArithmeticOp, BinaryOp, BitwiseOp, LogicalOp, RelationalOp},
11};
12use std::fmt::{Display, Error, Formatter};
13
14#[cfg(test)]
15mod tests;
16
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[derive(PartialEq, Eq, Clone, Copy, Debug, strum::EnumIter)]
25pub enum Punctuator {
26 Add,
28 And,
30 Arrow,
32 Assign,
34 AssignAdd,
36 AssignAnd,
38 AssignBoolAnd,
40 AssignBoolOr,
42 AssignCoalesce,
44 AssignDiv,
46 AssignLeftSh,
48 AssignMod,
50 AssignMul,
52 AssignOr,
54 AssignPow,
56 AssignRightSh,
58 AssignSub,
60 AssignURightSh,
62 AssignXor,
64 BoolAnd,
66 BoolOr,
68 CloseBlock,
70 CloseBracket,
72 CloseParen,
74 Coalesce,
76 Colon,
78 Comma,
80 Dec,
82 Div,
84 Dot,
86 Eq,
88 GreaterThan,
90 GreaterThanOrEq,
92 Inc,
94 LeftSh,
96 LessThan,
98 LessThanOrEq,
100 Mod,
102 Mul,
104 Neg,
106 Not,
108 NotEq,
110 OpenBlock,
112 OpenBracket,
114 OpenParen,
116 Optional,
118 Or,
120 Exp,
122 Question,
124 RightSh,
126 Semicolon,
128 Spread,
130 StrictEq,
132 StrictNotEq,
134 Sub,
136 URightSh,
138 Xor,
140}
141
142impl Punctuator {
143 #[must_use]
147 pub const fn as_assign_op(self) -> Option<AssignOp> {
148 match self {
149 Self::Assign => Some(AssignOp::Assign),
150 Self::AssignAdd => Some(AssignOp::Add),
151 Self::AssignAnd => Some(AssignOp::And),
152 Self::AssignBoolAnd => Some(AssignOp::BoolAnd),
153 Self::AssignBoolOr => Some(AssignOp::BoolOr),
154 Self::AssignCoalesce => Some(AssignOp::Coalesce),
155 Self::AssignDiv => Some(AssignOp::Div),
156 Self::AssignLeftSh => Some(AssignOp::Shl),
157 Self::AssignMod => Some(AssignOp::Mod),
158 Self::AssignMul => Some(AssignOp::Mul),
159 Self::AssignOr => Some(AssignOp::Or),
160 Self::AssignPow => Some(AssignOp::Exp),
161 Self::AssignRightSh => Some(AssignOp::Shr),
162 Self::AssignSub => Some(AssignOp::Sub),
163 Self::AssignURightSh => Some(AssignOp::Ushr),
164 Self::AssignXor => Some(AssignOp::Xor),
165 _ => None,
166 }
167 }
168
169 #[must_use]
173 pub const fn as_binary_op(self) -> Option<BinaryOp> {
174 match self {
175 Self::Add => Some(BinaryOp::Arithmetic(ArithmeticOp::Add)),
176 Self::Sub => Some(BinaryOp::Arithmetic(ArithmeticOp::Sub)),
177 Self::Mul => Some(BinaryOp::Arithmetic(ArithmeticOp::Mul)),
178 Self::Div => Some(BinaryOp::Arithmetic(ArithmeticOp::Div)),
179 Self::Mod => Some(BinaryOp::Arithmetic(ArithmeticOp::Mod)),
180 Self::Exp => Some(BinaryOp::Arithmetic(ArithmeticOp::Exp)),
181 Self::And => Some(BinaryOp::Bitwise(BitwiseOp::And)),
182 Self::Or => Some(BinaryOp::Bitwise(BitwiseOp::Or)),
183 Self::Xor => Some(BinaryOp::Bitwise(BitwiseOp::Xor)),
184 Self::BoolAnd => Some(BinaryOp::Logical(LogicalOp::And)),
185 Self::BoolOr => Some(BinaryOp::Logical(LogicalOp::Or)),
186 Self::Coalesce => Some(BinaryOp::Logical(LogicalOp::Coalesce)),
187 Self::Eq => Some(BinaryOp::Relational(RelationalOp::Equal)),
188 Self::NotEq => Some(BinaryOp::Relational(RelationalOp::NotEqual)),
189 Self::StrictEq => Some(BinaryOp::Relational(RelationalOp::StrictEqual)),
190 Self::StrictNotEq => Some(BinaryOp::Relational(RelationalOp::StrictNotEqual)),
191 Self::LessThan => Some(BinaryOp::Relational(RelationalOp::LessThan)),
192 Self::GreaterThan => Some(BinaryOp::Relational(RelationalOp::GreaterThan)),
193 Self::GreaterThanOrEq => Some(BinaryOp::Relational(RelationalOp::GreaterThanOrEqual)),
194 Self::LessThanOrEq => Some(BinaryOp::Relational(RelationalOp::LessThanOrEqual)),
195 Self::LeftSh => Some(BinaryOp::Bitwise(BitwiseOp::Shl)),
196 Self::RightSh => Some(BinaryOp::Bitwise(BitwiseOp::Shr)),
197 Self::URightSh => Some(BinaryOp::Bitwise(BitwiseOp::UShr)),
198 Self::Comma => Some(BinaryOp::Comma),
199 _ => None,
200 }
201 }
202
203 #[must_use]
205 pub const fn as_str(self) -> &'static str {
206 match self {
207 Self::Add => "+",
208 Self::And => "&",
209 Self::Arrow => "=>",
210 Self::Assign => "=",
211 Self::AssignAdd => "+=",
212 Self::AssignAnd => "&=",
213 Self::AssignBoolAnd => "&&=",
214 Self::AssignBoolOr => "||=",
215 Self::AssignCoalesce => "??=",
216 Self::AssignDiv => "/=",
217 Self::AssignLeftSh => "<<=",
218 Self::AssignMod => "%=",
219 Self::AssignMul => "*=",
220 Self::AssignOr => "|=",
221 Self::AssignPow => "**=",
222 Self::AssignRightSh => ">>=",
223 Self::AssignSub => "-=",
224 Self::AssignURightSh => ">>>=",
225 Self::AssignXor => "^=",
226 Self::BoolAnd => "&&",
227 Self::BoolOr => "||",
228 Self::Coalesce => "??",
229 Self::CloseBlock => "}",
230 Self::CloseBracket => "]",
231 Self::CloseParen => ")",
232 Self::Colon => ":",
233 Self::Comma => ",",
234 Self::Dec => "--",
235 Self::Div => "/",
236 Self::Dot => ".",
237 Self::Eq => "==",
238 Self::GreaterThan => ">",
239 Self::GreaterThanOrEq => ">=",
240 Self::Inc => "++",
241 Self::LeftSh => "<<",
242 Self::LessThan => "<",
243 Self::LessThanOrEq => "<=",
244 Self::Mod => "%",
245 Self::Mul => "*",
246 Self::Neg => "~",
247 Self::Not => "!",
248 Self::NotEq => "!=",
249 Self::OpenBlock => "{",
250 Self::OpenBracket => "[",
251 Self::OpenParen => "(",
252 Self::Optional => "?.",
253 Self::Or => "|",
254 Self::Exp => "**",
255 Self::Question => "?",
256 Self::RightSh => ">>",
257 Self::Semicolon => ";",
258 Self::Spread => "...",
259 Self::StrictEq => "===",
260 Self::StrictNotEq => "!==",
261 Self::Sub => "-",
262 Self::URightSh => ">>>",
263 Self::Xor => "^",
264 }
265 }
266}
267
268impl TryFrom<Punctuator> for AssignOp {
269 type Error = String;
271
272 fn try_from(punct: Punctuator) -> Result<Self, Self::Error> {
273 punct
274 .as_assign_op()
275 .ok_or_else(|| format!("No assignment operator for {punct}"))
276 }
277}
278
279impl TryFrom<Punctuator> for BinaryOp {
280 type Error = String;
282
283 fn try_from(punct: Punctuator) -> Result<Self, Self::Error> {
284 punct
285 .as_binary_op()
286 .ok_or_else(|| format!("No binary operator for {punct}"))
287 }
288}
289
290impl Display for Punctuator {
291 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
292 f.write_str(self.as_str())
293 }
294}
295
296impl From<Punctuator> for Box<str> {
297 fn from(p: Punctuator) -> Self {
298 p.as_str().into()
299 }
300}