Bug 1825052 [wpt PR 39246] - Update wpt metadata, a=testonly
[gecko.git] / third_party / rust / jsparagus-generated-parser / src / context_stack.rs
blob97138247f857803b4ddc9d4eff66e0982914be44
1 use ast::source_atom_set::SourceAtomSetIndex;
2 use std::iter::{Skip, Take};
3 use std::slice::Iter;
5 // The kind of BindingIdentifier found while parsing.
6 //
7 // Given we don't yet have the context stack, at the point of finding
8 // a BindingIdentifier, we don't know what kind of binding it is.
9 // So it's marked as `Unknown`.
11 // Once the parser reaches the end of a declaration, bindings found in the
12 // range are marked as corresponding kind.
14 // This is a separate enum than `DeclarationKind` for the following reason:
15 //   * `DeclarationKind` is determined only when the parser reaches the end of
16 //     the entire context (also because we don't have context stack), not each
17 //     declaration
18 //   * As long as `BindingKind` is known for each binding, we can map it to
19 //     `DeclarationKind`
20 //   * `DeclarationKind::CatchParameter` and some others don't to be marked
21 //     this way, because `AstBuilder` knows where they are in the `bindings`
22 //     vector.
23 #[derive(Debug, PartialEq, Clone, Copy)]
24 pub enum BindingKind {
25     // The initial state.
26     // BindingIdentifier is found, and haven't yet marked as any kind.
27     Unknown,
29     // BindingIdentifier is inside VariableDeclaration.
30     Var,
32     // BindingIdentifier is the name of FunctionDeclaration.
33     Function,
35     // BindingIdentifier is the name of GeneratorDeclaration,
36     // AsyncFunctionDeclaration, or AsyncGeneratorDeclaration.
37     AsyncOrGenerator,
39     // BindingIdentifier is inside LexicalDeclaration with let.
40     Let,
42     // BindingIdentifier is inside LexicalDeclaration with const.
43     Const,
45     // BindingIdentifier is the name of ClassDeclaration.
46     Class,
49 #[derive(Debug, PartialEq, Clone, Copy)]
50 pub struct BindingInfo {
51     pub name: SourceAtomSetIndex,
52     // The offset of the BindingIdentifier in the source.
53     pub offset: usize,
54     pub kind: BindingKind,
57 #[derive(Debug, PartialEq, Clone, Copy)]
58 pub struct BindingsIndex {
59     pub index: usize,
62 #[derive(Debug, PartialEq, Clone, Copy)]
63 pub enum ControlKind {
64     Continue,
65     Break,
68 #[derive(Debug, PartialEq, Clone, Copy)]
69 pub struct ControlInfo {
70     pub label: Option<SourceAtomSetIndex>,
71     // The offset of the nested control in the source.
72     pub offset: usize,
73     pub kind: ControlKind,
76 impl ControlInfo {
77     pub fn new_continue(offset: usize, label: Option<SourceAtomSetIndex>) -> Self {
78         Self {
79             label,
80             kind: ControlKind::Continue,
81             offset,
82         }
83     }
85     pub fn new_break(offset: usize, label: Option<SourceAtomSetIndex>) -> Self {
86         Self {
87             label,
88             kind: ControlKind::Break,
89             offset,
90         }
91     }
94 #[derive(Debug, PartialEq, Clone, Copy)]
95 pub struct BreakOrContinueIndex {
96     pub index: usize,
99 impl BreakOrContinueIndex {
100     pub fn new(index: usize) -> Self {
101         Self { index }
102     }
105 #[derive(Debug, PartialEq, Clone, Copy)]
106 pub enum LabelKind {
107     Other,
109     Function,
111     Loop,
113     LabelledLabel,
116 #[derive(Debug, PartialEq, Clone, Copy)]
117 pub struct LabelInfo {
118     pub name: SourceAtomSetIndex,
119     // The offset of the BindingIdentifier in the source.
120     pub offset: usize,
121     pub kind: LabelKind,
124 #[derive(Debug, PartialEq, Clone, Copy)]
125 pub struct LabelIndex {
126     pub index: usize,
129 #[derive(Debug, PartialEq, Clone)]
130 pub struct ContextMetadata {
131     // The stack of information about BindingIdentifier.
132     //
133     // When the parser found BindingIdentifier, the information (`name` and
134     // `offset`) are noted to this vector, and when the parser determined what
135     // kind of binding it is, `kind` is updated.
136     //
137     // The bindings are sorted by offset.
138     //
139     // When the parser reaches the end of a scope, all bindings declared within
140     // that scope (not including nested scopes) are fed to an
141     // EarlyErrorsContext to detect Early Errors.
142     //
143     // When leaving a context that is not one of script/module/function,
144     // lexical items (`kind != BindingKind::Var) in the corresponding range
145     // are removed, while non-lexical items (`kind == BindingKind::Var) are
146     // left there, so that VariableDeclarations and labels are propagated to the
147     // enclosing context.
148     //
149     // FIXME: Once the context stack gets implemented, this structure and
150     //        related methods should be removed and each declaration should be
151     //        fed directly to EarlyErrorsContext.
152     bindings: Vec<BindingInfo>,
154     // Track continues and breaks without the use of a context stack.
155     //
156     // FIXME: Once th context stack geets implmentd, this structure and
157     //        related metehods should be removed, and each break/continue should be
158     //        fed directly to EarlyErrorsContext.
159     breaks_and_continues: Vec<ControlInfo>,
161     labels: Vec<LabelInfo>,
164 impl ContextMetadata {
165     pub fn new() -> Self {
166         Self {
167             bindings: Vec::new(),
168             breaks_and_continues: Vec::new(),
169             labels: Vec::new(),
170         }
171     }
173     pub fn push_binding(&mut self, binding: BindingInfo) {
174         self.bindings.push(binding);
175     }
177     pub fn last_binding(&mut self) -> Option<&BindingInfo> {
178         self.bindings.last()
179     }
181     pub fn push_break_or_continue(&mut self, control: ControlInfo) {
182         self.breaks_and_continues.push(control);
183     }
185     pub fn push_label(&mut self, label: LabelInfo) {
186         self.labels.push(label);
187     }
189     // Update the binding kind of all names declared in a specific range of the
190     // source (and not in any nested scope). This is used e.g. when the parser
191     // reaches the end of a VariableStatement to mark all the variables as Var
192     // bindings.
193     //
194     // It's necessary because the current parser only calls AstBuilder methods
195     // at the end of each production, not at the beginning.
196     //
197     // Bindings inside `StatementList` must be marked using this method before
198     // we reach the end of its scope.
199     pub fn mark_binding_kind(&mut self, from: usize, to: Option<usize>, kind: BindingKind) {
200         for info in self.bindings.iter_mut().rev() {
201             if info.offset < from {
202                 break;
203             }
205             if to.is_none() || info.offset < to.unwrap() {
206                 info.kind = kind;
207             }
208         }
209     }
211     pub fn bindings_from(&self, index: BindingsIndex) -> Skip<Iter<'_, BindingInfo>> {
212         self.bindings.iter().skip(index.index)
213     }
215     pub fn bindings_from_to(
216         &self,
217         from: BindingsIndex,
218         to: BindingsIndex,
219     ) -> Take<Skip<Iter<'_, BindingInfo>>> {
220         self.bindings
221             .iter()
222             .skip(from.index)
223             .take(to.index - from.index)
224     }
226     // Returns the index of the first label at/after `offset` source position.
227     pub fn find_first_binding(&mut self, offset: usize) -> BindingsIndex {
228         let mut i = self.bindings.len();
229         for info in self.bindings.iter_mut().rev() {
230             if info.offset < offset {
231                 break;
232             }
233             i -= 1;
234         }
235         BindingsIndex { index: i }
236     }
238     // Remove all bindings after `index`-th item.
239     //
240     // This should be called when leaving function/script/module.
241     pub fn pop_bindings_from(&mut self, index: BindingsIndex) {
242         self.bindings.truncate(index.index)
243     }
245     pub fn labels_from(&self, index: LabelIndex) -> Skip<Iter<'_, LabelInfo>> {
246         self.labels.iter().skip(index.index)
247     }
249     // Update the label kind of a label declared in a specific range of the
250     // source (and not in any nested scope). There should never be more than one.
251     //
252     // It's necessary because the current parser only calls AstBuilder methods
253     // at the end of each production, not at the beginning.
254     //
255     // Labels inside `StatementList` must be marked using this method before
256     // we reach the end of its scope.
257     pub fn mark_label_kind_at_offset(&mut self, from: usize, kind: LabelKind) {
258         let maybe_label = self.find_label_at_offset(from);
259         if let Some(info) = maybe_label {
260             info.kind = kind
261         } else {
262             panic!("Tried to mark a non-existant label");
263         }
264     }
266     // Remove lexical bindings after `index`-th item,
267     // while keeping var bindings.
268     //
269     // This should be called when leaving block.
270     pub fn pop_lexical_bindings_from(&mut self, index: BindingsIndex) {
271         let len = self.bindings.len();
272         let mut i = index.index;
274         while i < len && self.bindings[i].kind == BindingKind::Var {
275             i += 1;
276         }
278         let mut j = i;
279         while j < len {
280             if self.bindings[j].kind == BindingKind::Var {
281                 self.bindings[i] = self.bindings[j];
282                 i += 1;
283             }
284             j += 1;
285         }
287         self.bindings.truncate(i)
288     }
290     // Returns the index of the first binding at/after `offset` source position.
291     pub fn find_first_label(&mut self, offset: usize) -> LabelIndex {
292         let mut i = self.labels.len();
293         for info in self.labels.iter_mut().rev() {
294             if info.offset < offset {
295                 break;
296             }
297             i -= 1;
298         }
299         LabelIndex { index: i }
300     }
302     // Remove all bindings after `index`-th item.
303     //
304     // This should be called when leaving function/script/module.
305     pub fn pop_labels_from(&mut self, index: LabelIndex) {
306         self.labels.truncate(index.index)
307     }
309     pub fn breaks_and_continues_from(
310         &self,
311         index: BreakOrContinueIndex,
312     ) -> Skip<Iter<'_, ControlInfo>> {
313         self.breaks_and_continues.iter().skip(index.index)
314     }
316     // Returns the index of the first break or continue at/after `offset` source position.
317     pub fn find_first_break_or_continue(&mut self, offset: usize) -> BreakOrContinueIndex {
318         let mut i = self.breaks_and_continues.len();
319         for info in self.breaks_and_continues.iter_mut().rev() {
320             if info.offset < offset {
321                 break;
322             }
323             i -= 1;
324         }
325         BreakOrContinueIndex::new(i)
326     }
328     pub fn pop_labelled_breaks_and_continues_from_index(
329         &mut self,
330         index: BreakOrContinueIndex,
331         name: SourceAtomSetIndex,
332     ) {
333         let len = self.breaks_and_continues.len();
334         let mut i = index.index;
336         let mut j = i;
337         while j < len {
338             let label = self.breaks_and_continues[j].label;
339             if label.is_none() || label.unwrap() != name {
340                 self.breaks_and_continues[i] = self.breaks_and_continues[j];
341                 i += 1;
342             }
343             j += 1;
344         }
346         self.breaks_and_continues.truncate(i)
347     }
349     pub fn pop_unlabelled_breaks_and_continues_from(&mut self, offset: usize) {
350         let len = self.breaks_and_continues.len();
351         let index = self.find_first_break_or_continue(offset);
352         let mut i = index.index;
354         while i < len && self.breaks_and_continues[i].label.is_some() {
355             i += 1;
356         }
358         let mut j = i;
359         while j < len {
360             if self.breaks_and_continues[j].label.is_some() {
361                 self.breaks_and_continues[i] = self.breaks_and_continues[j];
362                 i += 1;
363             }
364             j += 1;
365         }
367         self.breaks_and_continues.truncate(i)
368     }
370     pub fn pop_unlabelled_breaks_from(&mut self, offset: usize) {
371         let len = self.breaks_and_continues.len();
372         let index = self.find_first_break_or_continue(offset);
373         let mut i = index.index;
375         while i < len && self.breaks_and_continues[i].label.is_some() {
376             i += 1;
377         }
379         let mut j = i;
380         while j < len {
381             if self.breaks_and_continues[j].label.is_some()
382                 || self.breaks_and_continues[j].kind == ControlKind::Continue
383             {
384                 self.breaks_and_continues[i] = self.breaks_and_continues[j];
385                 i += 1;
386             }
387             j += 1;
388         }
390         self.breaks_and_continues.truncate(i)
391     }
393     pub fn find_break_or_continue_at(&self, index: BreakOrContinueIndex) -> Option<&ControlInfo> {
394         self.breaks_and_continues.get(index.index)
395     }
397     pub fn find_label_index_at_offset(&self, offset: usize) -> Option<LabelIndex> {
398         let index = self.labels.iter().position(|info| info.offset == offset);
399         index.map(|index| LabelIndex { index })
400     }
402     pub fn find_label_at_offset(&mut self, offset: usize) -> Option<&mut LabelInfo> {
403         self.labels.iter_mut().find(|info| info.offset == offset)
404     }