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}