boa/syntax/ast/keyword.rs
1//! This module implements the `Keyword` structure, which represents reserved words of the JavaScript language.
2//!
3//! More information:
4//! - [ECMAScript reference][spec]
5//! - [MDN documentation][mdn]
6//!
7//! [spec]: https://www.ecma-international.org/ecma-262/#sec-keywords
8//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords
9
10use crate::syntax::ast::op::{BinOp, CompOp};
11use std::{convert::TryInto, error, fmt, str::FromStr};
12
13#[cfg(feature = "deser")]
14use serde::{Deserialize, Serialize};
15
16/// Keywords are tokens that have special meaning in JavaScript.
17///
18/// In JavaScript you cannot use these reserved words as variables, labels, or function names.
19///
20/// More information:
21/// - [ECMAScript reference][spec]
22/// - [MDN documentation][mdn]
23///
24/// [spec]: https://www.ecma-international.org/ecma-262/#sec-keywords
25/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords
26#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
27#[derive(Clone, Copy, PartialEq, Debug)]
28pub enum Keyword {
29 /// The `await` keyword.
30 ///
31 /// More information:
32 /// - [ECMAScript reference][spec]
33 /// - [MDN documentation][mdn]
34 ///
35 /// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression
36 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
37 Await,
38
39 /// The `async` keyword.
40 ///
41 /// More information:
42 /// - [ECMAScript reference][spec]
43 /// - [MDN documentation][mdn]
44 ///
45 /// [spec]: https://tc39.es/ecma262/#prod-AsyncMethod
46 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
47 Async,
48
49 /// The `break` keyword.
50 ///
51 /// More information:
52 /// - [break `Node` documentation][node]
53 /// - [ECMAScript reference][spec]
54 /// - [MDN documentation][mdn]
55 ///
56 /// [spec]: https://tc39.es/ecma262/#prod-BreakStatement
57 /// [node]: ../node/enum.Node.html#variant.Break
58 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break
59 Break,
60
61 /// The `case` keyword.
62 ///
63 /// More information:
64 /// - [switch `Node` documentation][node]
65 /// - [ECMAScript reference][spec]
66 /// - [MDN documentation][mdn]
67 ///
68 /// [spec]: https://tc39.es/ecma262/#prod-CaseClause
69 /// [node]: ../node/enum.Node.html#variant.Switch
70 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
71 Case,
72
73 /// The `catch` keyword.
74 ///
75 /// More information:
76 /// - [try `Node` documentation][node]
77 /// - [ECMAScript reference][spec]
78 /// - [MDN documentation][mdn]
79 ///
80 /// [spec]: https://tc39.es/ecma262/#prod-Catch
81 /// [node]: ../node/enum.Node.html#variant.Try
82 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
83 Catch,
84
85 /// The `class` keyword.
86 ///
87 /// More information:
88 /// - [ECMAScript reference][spec]
89 /// - [MDN documentation][mdn]
90 ///
91 /// [spec]: https://tc39.es/ecma262/#prod-ClassDeclaration
92 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class
93 Class,
94
95 /// The `continue` keyword.
96 ///
97 /// More information:
98 /// - [continue `Node` documentation][node]
99 /// - [ECMAScript reference][spec]
100 /// - [MDN documentation][mdn]
101 ///
102 /// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement
103 /// [node]: ../node/enum.Node.html#variant.Continue
104 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue
105 Continue,
106
107 /// The `const` keyword.
108 ///
109 /// More information:
110 /// - [const `Node` documentation][node]
111 /// - [ECMAScript reference][spec]
112 /// - [MDN documentation][mdn]
113 ///
114 /// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
115 /// [node]: ../node/enum.Node.html#variant.ConstDecl
116 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
117 Const,
118
119 /// The `debugger` keyword.
120 ///
121 /// More information:
122 /// - [ECMAScript reference][spec]
123 /// - [MDN documentation][mdn]
124 ///
125 /// [spec]: https://tc39.es/ecma262/#sec-debugger-statement
126 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger
127 Debugger,
128
129 /// The `default` keyword.
130 ///
131 /// More information:
132 /// - [switch `Node` documentation][node]
133 /// - [ECMAScript reference default clause][spec-clause]
134 /// - [ECMAScript reference default export][spec-export]
135 /// - [MDN documentation][mdn]
136 ///
137 /// [node]: ../node/enum.Node.html#variant.Switch
138 /// [spec-clause]: https://tc39.es/ecma262/#prod-DefaultClause
139 /// [spec-export]: https://tc39.es/ecma262/#prod-ImportedDefaultBinding
140 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/default
141 Default,
142
143 /// The `delete` keyword.
144 ///
145 /// More information:
146 /// - [delete `UnaryOp` documentation][unary]
147 /// - [ECMAScript reference][spec]
148 /// - [MDN documentation][mdn]
149 ///
150 /// [spec]: https://tc39.es/ecma262/#sec-delete-operator
151 /// [unary]: ../op/enum.UnaryOp.html#variant.Delete
152 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
153 Delete,
154
155 /// The `do` keyword.
156 ///
157 /// More information:
158 /// - [ECMAScript reference][spec]
159 /// - [MDN documentation][mdn]
160 ///
161 /// [spec]: https://tc39.es/ecma262/#sec-do-while-statement
162 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while
163 Do,
164
165 /// The `else` keyword.
166 ///
167 /// More information:
168 /// - [if `Node` documentation][node]
169 /// - [ECMAScript reference][spec]
170 /// - [MDN documentation][mdn]
171 ///
172 /// [node]: ../node/enum.Node.html#variant.If
173 /// [spec]: https://tc39.es/ecma262/#prod-IfStatement
174 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
175 Else,
176
177 /// The `enum` keyword.
178 ///
179 /// Future reserved keyword.
180 Enum,
181
182 /// The `export` keyword.
183 ///
184 /// More information:
185 /// - [ECMAScript reference][spec]
186 /// - [MDN documentation][mdn]
187 ///
188 /// [spec]: https://tc39.es/ecma262/#sec-exports
189 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
190 Export,
191
192 /// The `extends` keyword.
193 ///
194 /// More information:
195 /// - [ECMAScript reference][spec]
196 /// - [MDN documentation][mdn]
197 ///
198 /// [spec]: https://tc39.es/ecma262/#prod-ClassHeritage
199 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends
200 Extends,
201
202 /// The `false` keyword.
203 ///
204 /// More information:
205 /// - [ECMAScript reference][spec]
206 /// - [MDN documentation][mdn]
207 ///
208 /// [spec]: https://tc39.es/ecma262/#prod-BooleanLiteral
209 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
210 False,
211
212 /// The `finally` keyword.
213 ///
214 /// More information:
215 /// - [try `Node` documentation][node]
216 /// - [ECMAScript reference][spec]
217 /// - [MDN documentation][mdn]
218 ///
219 /// [node]: ../node/enum.Node.html#variant.Try
220 /// [spec]: https://tc39.es/ecma262/#prod-Finally
221 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
222 Finally,
223
224 /// The `for` keyword.
225 ///
226 /// More information:
227 /// - [for loop `Node` documentation][node]
228 /// - [ECMAScript reference][spec]
229 /// - [MDN documentation][mdn]
230 ///
231 /// [node]: ../node/enum.Node.html#variant.ForLoop
232 /// [spec]: https://tc39.es/ecma262/#prod-ForDeclaration
233 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
234 For,
235
236 /// The `function` keyword.
237 ///
238 /// More information:
239 /// - [function `Node` documentation][node]
240 /// - [ECMAScript reference][spec]
241 /// - [MDN documentation][mdn]
242 ///
243 /// [node]: ../node/enum.Node.html#variant.FunctionDecl
244 /// [spec]: https://tc39.es/ecma262/#sec-terms-and-definitions-function
245 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function
246 Function,
247
248 /// The `if` keyword.
249 ///
250 /// More information:
251 /// - [if `Node` documentation][node]
252 /// - [ECMAScript reference][spec]
253 /// - [MDN documentation][mdn]
254 ///
255 /// [node]: ../node/enum.Node.html#variant.If
256 /// [spec]: https://tc39.es/ecma262/#prod-IfStatement
257 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
258 If,
259
260 /// The `in` keyword.
261 ///
262 /// More information:
263 /// - [ECMAScript reference][spec]
264 /// - [MDN documentation][mdn]
265 ///
266 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
267 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
268 In,
269
270 /// The `instanceof` keyword.
271 ///
272 /// More information:
273 /// - [ECMAScript reference][spec]
274 /// - [MDN documentation][mdn]
275 ///
276 /// [spec]: https://tc39.es/ecma262/#sec-instanceofoperator
277 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
278 InstanceOf,
279
280 /// The `import` keyword.
281 ///
282 /// More information:
283 /// - [ECMAScript reference][spec]
284 /// - [MDN documentation][mdn]
285 ///
286 /// [spec]: https://tc39.es/ecma262/#sec-imports
287 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
288 Import,
289
290 /// The `let` keyword.
291 ///
292 /// More information:
293 /// - [let `Node` documentation][node]
294 /// - [ECMAScript reference][spec]
295 /// - [MDN documentation][mdn]
296 ///
297 /// [node]: ../node/enum.Node.html#variant.LetDecl
298 /// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
299 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
300 Let,
301
302 /// The `new` keyword.
303 ///
304 /// More information:
305 /// - [new `Node` documentation][node]
306 /// - [ECMAScript reference][spec]
307 /// - [MDN documentation][mdn]
308 ///
309 /// [node]: ../node/enum.Node.html#variant.New
310 /// [spec]: https://tc39.es/ecma262/#prod-NewExpression
311 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
312 New,
313
314 /// The `null` keyword.
315 ///
316 /// More information:
317 /// - [ECMAScript reference][spec]
318 /// - [MDN documentation][mdn]
319 ///
320 /// [spec]: https://tc39.es/ecma262/#prod-NullLiteral
321 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null
322 Null,
323
324 /// The `of` keyword.
325 ///
326 /// More information:
327 /// - [ECMAScript reference][spec]
328 /// - [MDN documentation][mdn]
329 ///
330 /// [spec]: https://tc39.es/ecma262/#sec-for-in-and-for-of-statements
331 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
332 Of,
333
334 /// The `return` keyword
335 ///
336 /// More information:
337 /// - [return `Node` documentation][node]
338 /// - [ECMAScript reference][spec]
339 /// - [MDN documentation][mdn]
340 ///
341 /// [node]: ../node/enum.Node.html#variant.Return
342 /// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement
343 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return
344 Return,
345
346 /// The `super` keyword
347 ///
348 /// More information:
349 /// - [ECMAScript reference][spec]
350 /// - [MDN documentation][mdn]
351 ///
352 /// [spec]: https://tc39.es/ecma262/#sec-super-keyword
353 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
354 Super,
355
356 /// The `switch` keyword.
357 ///
358 /// More information:
359 /// - [switch `Node` documentation][node]
360 /// - [ECMAScript reference][spec]
361 /// - [MDN documentation][mdn]
362 ///
363 /// [node]: ../node/enum.Node.html#variant.Switch
364 /// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement
365 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
366 Switch,
367
368 /// The `this` keyword.
369 ///
370 /// More information:
371 /// - [this `Node` documentation][node]
372 /// - [ECMAScript reference][spec]
373 /// - [MDN documentation][mdn]
374 ///
375 /// [node]: ../node/enum.Node.html#variant.This
376 /// [spec]: https://tc39.es/ecma262/#sec-this-keyword
377 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
378 This,
379
380 /// The `throw` keyword.
381 ///
382 /// More information:
383 /// - [throw `Node` documentation][node]
384 /// - [ECMAScript reference][spec]
385 /// - [MDN documentation][mdn]
386 ///
387 /// [node]: ../node/enum.Node.html#variant.Throw
388 /// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction
389 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
390 Throw,
391
392 /// The `true` keyword
393 ///
394 /// More information:
395 /// - [ECMAScript reference][spec]
396 /// - [MDN documentation][mdn]
397 ///
398 /// [spec]: https://tc39.es/ecma262/#prod-BooleanLiteral
399 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
400 True,
401
402 /// The `try` keyword.
403 ///
404 /// More information:
405 /// - [try `Node` documentation][node]
406 /// - [ECMAScript reference][spec]
407 /// - [MDN documentation][mdn]
408 ///
409 /// [node]: ../node/enum.Node.html#variant.Try
410 /// [spec]: https://tc39.es/ecma262/#prod-TryStatement
411 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
412 Try,
413
414 /// The `typeof` keyword.
415 ///
416 /// More information:
417 /// - [typeof `UnaryOp` documentation][unary]
418 /// - [ECMAScript reference][spec]
419 /// - [MDN documentation][mdn]
420 ///
421 /// [unary]: ../op/enum.UnaryOp.html#variant.TypeOf
422 /// [spec]: https://tc39.es/ecma262/#sec-typeof-operator
423 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
424 TypeOf,
425
426 /// The `var` keyword.
427 ///
428 /// More information:
429 /// - [var `Node` documentation][node]
430 /// - [ECMAScript reference][spec]
431 /// - [MDN documentation][mdn]
432 ///
433 /// [node]: ../node/enum.Node.html#variant.VarDecl
434 /// [spec]: https://tc39.es/ecma262/#prod-VariableStatement
435 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
436 Var,
437
438 /// The `void` keyword.
439 ///
440 /// More information:
441 /// - [void `UnaryOp` documentation][unary]
442 /// - [ECMAScript reference][spec]
443 /// - [MDN documentation][mdn]
444 ///
445 /// [unary]: ../op/enum.UnaryOp.html#variant.Void
446 /// [spec]: https://tc39.es/ecma262/#sec-void-operator
447 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
448 Void,
449
450 /// The `while` keyword.
451 ///
452 /// More information:
453 /// - [while `Node` documentation][node]
454 /// - [ECMAScript reference][spec]
455 /// - [MDN documentation][mdn]
456 ///
457 /// [node]: ../node/enum.Node.html#variant.While
458 /// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement
459 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while
460 While,
461
462 /// The `with` keyword.
463 ///
464 /// More information:
465 /// - [ECMAScript reference][spec]
466 /// - [MDN documentation][mdn]
467 ///
468 /// [spec]: https://tc39.es/ecma262/#prod-WithStatement
469 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
470 With,
471
472 /// The 'yield' keyword.
473 ///
474 /// More information:
475 /// - [ECMAScript reference][spec]
476 /// - [MDN documentation][mdn]
477 ///
478 /// [spec]: https://tc39.es/ecma262/#prod-YieldExpression
479 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
480 Yield,
481}
482
483impl Keyword {
484 /// Gets the keyword as a binary operation, if this keyword is the `in` keyword.
485 pub fn as_binop(self) -> Option<BinOp> {
486 match self {
487 Keyword::In => Some(BinOp::Comp(CompOp::In)),
488 Keyword::InstanceOf => Some(BinOp::Comp(CompOp::InstanceOf)),
489 _ => None,
490 }
491 }
492
493 /// Gets the keyword as a string.
494 pub fn as_str(self) -> &'static str {
495 match self {
496 Self::Await => "await",
497 Self::Async => "async",
498 Self::Break => "break",
499 Self::Case => "case",
500 Self::Catch => "catch",
501 Self::Class => "class",
502 Self::Continue => "continue",
503 Self::Const => "const",
504 Self::Debugger => "debugger",
505 Self::Default => "default",
506 Self::Delete => "delete",
507 Self::Do => "do",
508 Self::Else => "else",
509 Self::Enum => "enum",
510 Self::Extends => "extends",
511 Self::Export => "export",
512 Self::False => "false",
513 Self::Finally => "finally",
514 Self::For => "for",
515 Self::Function => "function",
516 Self::If => "if",
517 Self::In => "in",
518 Self::InstanceOf => "instanceof",
519 Self::Import => "import",
520 Self::Let => "let",
521 Self::New => "new",
522 Self::Null => "null",
523 Self::Of => "of",
524 Self::Return => "return",
525 Self::Super => "super",
526 Self::Switch => "switch",
527 Self::This => "this",
528 Self::Throw => "throw",
529 Self::True => "true",
530 Self::Try => "try",
531 Self::TypeOf => "typeof",
532 Self::Var => "var",
533 Self::Void => "void",
534 Self::While => "while",
535 Self::With => "with",
536 Self::Yield => "yield",
537 }
538 }
539}
540
541impl TryInto<BinOp> for Keyword {
542 type Error = String;
543 fn try_into(self) -> Result<BinOp, Self::Error> {
544 self.as_binop()
545 .ok_or_else(|| format!("No binary operation for {}", self))
546 }
547}
548
549#[derive(Debug, Clone, Copy)]
550pub struct KeywordError;
551impl fmt::Display for KeywordError {
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 write!(f, "invalid token")
554 }
555}
556
557// This is important for other errors to wrap this one.
558impl error::Error for KeywordError {
559 fn description(&self) -> &str {
560 "invalid token"
561 }
562
563 fn cause(&self) -> Option<&dyn error::Error> {
564 // Generic error, underlying cause isn't tracked.
565 None
566 }
567}
568impl FromStr for Keyword {
569 type Err = KeywordError;
570 fn from_str(s: &str) -> Result<Self, Self::Err> {
571 match s {
572 "await" => Ok(Self::Await),
573 "async" => Ok(Self::Async),
574 "break" => Ok(Self::Break),
575 "case" => Ok(Self::Case),
576 "catch" => Ok(Self::Catch),
577 "class" => Ok(Self::Class),
578 "continue" => Ok(Self::Continue),
579 "const" => Ok(Self::Const),
580 "debugger" => Ok(Self::Debugger),
581 "default" => Ok(Self::Default),
582 "delete" => Ok(Self::Delete),
583 "do" => Ok(Self::Do),
584 "else" => Ok(Self::Else),
585 "enum" => Ok(Self::Enum),
586 "extends" => Ok(Self::Extends),
587 "export" => Ok(Self::Export),
588 "false" => Ok(Self::False),
589 "finally" => Ok(Self::Finally),
590 "for" => Ok(Self::For),
591 "function" => Ok(Self::Function),
592 "if" => Ok(Self::If),
593 "in" => Ok(Self::In),
594 "instanceof" => Ok(Self::InstanceOf),
595 "import" => Ok(Self::Import),
596 "let" => Ok(Self::Let),
597 "new" => Ok(Self::New),
598 "null" => Ok(Self::Null),
599 "of" => Ok(Self::Of),
600 "return" => Ok(Self::Return),
601 "super" => Ok(Self::Super),
602 "switch" => Ok(Self::Switch),
603 "this" => Ok(Self::This),
604 "throw" => Ok(Self::Throw),
605 "true" => Ok(Self::True),
606 "try" => Ok(Self::Try),
607 "typeof" => Ok(Self::TypeOf),
608 "var" => Ok(Self::Var),
609 "void" => Ok(Self::Void),
610 "while" => Ok(Self::While),
611 "with" => Ok(Self::With),
612 "yield" => Ok(Self::Yield),
613 _ => Err(KeywordError),
614 }
615 }
616}
617
618impl fmt::Display for Keyword {
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 fmt::Display::fmt(self.as_str(), f)
621 }
622}