1 use indexmap::set::IndexSet;
2 
3 /// Index into SourceAtomSet.atoms.
4 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5 pub struct SourceAtomSetIndex {
6     index: usize,
7 }
8 impl SourceAtomSetIndex {
new(index: usize) -> Self9     fn new(index: usize) -> Self {
10         Self { index }
11     }
12 }
13 
14 impl From<SourceAtomSetIndex> for usize {
from(index: SourceAtomSetIndex) -> usize15     fn from(index: SourceAtomSetIndex) -> usize {
16         index.index
17     }
18 }
19 
20 // Call $handler macro with the list of common atoms.
21 //
22 // Basic Usage:
23 //
24 // ```
25 // for_all_common_atoms!(test);
26 // ```
27 //
28 // is expanded to
29 //
30 // ```
31 // test!(
32 //   ("arguments", arguments, Arguments),
33 //   ("async", async_, Async),
34 //   ...
35 // );
36 // ```
37 //
38 // Extra Parameters:
39 //
40 // ```
41 // for_all_common_atoms!(test, foo, bar);
42 // ```
43 //
44 // is expanded to
45 //
46 // ```
47 // test!(
48 //   foo, bar,
49 //   ("arguments", arguments, Arguments),
50 //   ("async", async_, Async),
51 //   ...
52 // );
53 // ```
54 macro_rules! for_all_common_atoms {
55     ($handler:ident $(, $($params:tt)*)?) => {
56         // string representation, method name, enum variant
57         $handler!(
58             $($($params)*,)?
59             ("arguments", arguments, Arguments),
60             ("as", as_, As),
61             ("async", async_, Async),
62             ("await", await_, Await),
63             ("break", break_, Break),
64             ("case", case, Case),
65             ("catch", catch, Catch),
66             ("class", class, Class),
67             ("const", const_, Const),
68             ("continue", continue_, Continue),
69             ("debugger", debugger, Debugger),
70             ("default", default, Default),
71             ("delete", delete, Delete),
72             ("do", do_, Do),
73             ("else", else_, Else),
74             ("enum", enum_, Enum),
75             ("eval", eval, Eval),
76             ("export", export, Export),
77             ("extends", extends, Extends),
78             ("false", false_, False),
79             ("finally", finally, Finally),
80             ("for", for_, For),
81             ("from", from, From),
82             ("function", function, Function),
83             ("get", get, Get),
84             ("if", if_, If),
85             ("implements", implements, Implements),
86             ("import", import, Import),
87             ("in", in_, In),
88             ("instanceof", instanceof, Instanceof),
89             ("interface", interface, Interface),
90             ("let", let_, Let),
91             ("new", new_, New),
92             ("null", null, Null),
93             ("of", of, Of),
94             ("package", package, Package),
95             ("private", private, Private),
96             ("protected", protected, Protected),
97             ("public", public, Public),
98             ("return", return_, Return),
99             ("set", set, Set),
100             ("static", static_, Static),
101             ("super", super_, Super),
102             ("switch", switch, Switch),
103             ("target", target, Target),
104             ("this", this, This),
105             ("throw", throw, Throw),
106             ("true", true_, True),
107             ("try", try_, Try),
108             ("typeof", typeof_, Typeof),
109             ("var", var, Var),
110             ("void", void, Void),
111             ("while", while_, While),
112             ("with", with, With),
113             ("yield", yield_, Yield),
114             ("use strict", use_strict, UseStrict),
115             ("__proto__", __proto__, Proto),
116         );
117     }
118 }
119 
120 // Define CommonAtoms enum, with
121 //
122 // enum CommonAtoms {
123 //   Arguments = 0,
124 //   Async,
125 //   ...
126 // }
127 macro_rules! define_enum {
128     (($s0:tt, $method0:ident, $variant0:ident),
129      $(($s:tt, $method:ident, $variant:ident),)*) => {
130         enum CommonAtoms {
131             $variant0 = 0,
132             $($variant,)*
133         }
134     };
135 }
136 for_all_common_atoms!(define_enum);
137 
138 // Define CommonSourceAtomSetIndices struct.
139 //
140 // impl CommonSourceAtomSetIndices {
141 //   pub fn arguments() -> SourceAtomSetIndex { ... }
142 //   pub fn async_() -> SourceAtomSetIndex { ... }
143 //   ...
144 // }
145 macro_rules! define_struct {
146     ($(($s:tt, $method:ident, $variant:ident),)*) => {
147         #[derive(Debug)]
148         pub struct CommonSourceAtomSetIndices {}
149 
150         impl CommonSourceAtomSetIndices {
151             $(
152                 pub fn $method() -> SourceAtomSetIndex {
153                     SourceAtomSetIndex::new(CommonAtoms::$variant as usize)
154                 }
155             )*
156         }
157     };
158 }
159 for_all_common_atoms!(define_struct);
160 
161 /// Set of atoms, including the following:
162 ///
163 ///   * atoms referred from bytecode
164 ///   * variable names referred from scope data
165 ///
166 /// WARNING: This set itself does *NOT* map to JSScript::atoms().
167 #[derive(Debug)]
168 pub struct SourceAtomSet<'alloc> {
169     atoms: IndexSet<&'alloc str>,
170 }
171 
172 impl<'alloc> SourceAtomSet<'alloc> {
173     // Create a set, with all common atoms inserted.
new() -> Self174     pub fn new() -> Self {
175         let mut result = Self {
176             atoms: IndexSet::new(),
177         };
178         result.insert_common_atoms();
179         result
180     }
181 
182     // Insert all common atoms.
insert_common_atoms(&mut self)183     fn insert_common_atoms(&mut self) {
184         macro_rules! insert_atom {
185             ($self: ident,
186              $(($s:tt, $method:ident, $variant:ident),)*) => {
187                 $(
188                     $self.atoms.insert($s);
189                 )*
190             };
191         }
192         for_all_common_atoms!(insert_atom, self);
193     }
194 
195     // Create a set, without any common atoms.
196     //
197     // This is for moving `SourceAtomSet` out of `Rc<RefCell>`, by replacing
198     // it with the result of this method.
new_uninitialized() -> Self199     pub fn new_uninitialized() -> Self {
200         Self {
201             // 256 is a number which should cover 75% of scripts without
202             // reallocation.
203             atoms: IndexSet::with_capacity(256),
204         }
205     }
206 
insert(&mut self, s: &'alloc str) -> SourceAtomSetIndex207     pub fn insert(&mut self, s: &'alloc str) -> SourceAtomSetIndex {
208         let (index, _) = self.atoms.insert_full(s);
209         SourceAtomSetIndex::new(index)
210     }
211 
get(&self, index: SourceAtomSetIndex) -> &'alloc str212     pub fn get(&self, index: SourceAtomSetIndex) -> &'alloc str {
213         self.atoms.get_index(usize::from(index)).unwrap()
214     }
215 }
216 
217 impl<'alloc> From<SourceAtomSet<'alloc>> for Vec<&'alloc str> {
from(set: SourceAtomSet<'alloc>) -> Vec<&'alloc str>218     fn from(set: SourceAtomSet<'alloc>) -> Vec<&'alloc str> {
219         set.atoms.into_iter().collect()
220     }
221 }
222