1 use ast::source_atom_set::SourceAtomSetIndex;
2 use std::iter::{Skip, Take};
5 // The kind of BindingIdentifier found while parsing.
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
18 // * As long as `BindingKind` is known for each binding, we can map it to
20 // * `DeclarationKind::CatchParameter` and some others don't to be marked
21 // this way, because `AstBuilder` knows where they are in the `bindings`
23 #[derive(Debug, PartialEq, Clone, Copy)]
24 pub enum BindingKind {
26 // BindingIdentifier is found, and haven't yet marked as any kind.
29 // BindingIdentifier is inside VariableDeclaration.
32 // BindingIdentifier is the name of FunctionDeclaration.
35 // BindingIdentifier is the name of GeneratorDeclaration,
36 // AsyncFunctionDeclaration, or AsyncGeneratorDeclaration.
39 // BindingIdentifier is inside LexicalDeclaration with let.
42 // BindingIdentifier is inside LexicalDeclaration with const.
45 // BindingIdentifier is the name of ClassDeclaration.
49 #[derive(Debug, PartialEq, Clone, Copy)]
50 pub struct BindingInfo {
51 pub name: SourceAtomSetIndex,
52 // The offset of the BindingIdentifier in the source.
54 pub kind: BindingKind,
57 #[derive(Debug, PartialEq, Clone, Copy)]
58 pub struct BindingsIndex {
62 #[derive(Debug, PartialEq, Clone, Copy)]
63 pub enum ControlKind {
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.
73 pub kind: ControlKind,
77 pub fn new_continue(offset: usize, label: Option<SourceAtomSetIndex>) -> Self {
80 kind: ControlKind::Continue,
85 pub fn new_break(offset: usize, label: Option<SourceAtomSetIndex>) -> Self {
88 kind: ControlKind::Break,
94 #[derive(Debug, PartialEq, Clone, Copy)]
95 pub struct BreakOrContinueIndex {
99 impl BreakOrContinueIndex {
100 pub fn new(index: usize) -> Self {
105 #[derive(Debug, PartialEq, Clone, Copy)]
116 #[derive(Debug, PartialEq, Clone, Copy)]
117 pub struct LabelInfo {
118 pub name: SourceAtomSetIndex,
119 // The offset of the BindingIdentifier in the source.
124 #[derive(Debug, PartialEq, Clone, Copy)]
125 pub struct LabelIndex {
129 #[derive(Debug, PartialEq, Clone)]
130 pub struct ContextMetadata {
131 // The stack of information about BindingIdentifier.
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.
137 // The bindings are sorted by offset.
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.
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.
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.
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 {
167 bindings: Vec::new(),
168 breaks_and_continues: Vec::new(),
173 pub fn push_binding(&mut self, binding: BindingInfo) {
174 self.bindings.push(binding);
177 pub fn last_binding(&mut self) -> Option<&BindingInfo> {
181 pub fn push_break_or_continue(&mut self, control: ControlInfo) {
182 self.breaks_and_continues.push(control);
185 pub fn push_label(&mut self, label: LabelInfo) {
186 self.labels.push(label);
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
194 // It's necessary because the current parser only calls AstBuilder methods
195 // at the end of each production, not at the beginning.
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 {
205 if to.is_none() || info.offset < to.unwrap() {
211 pub fn bindings_from(&self, index: BindingsIndex) -> Skip<Iter<'_, BindingInfo>> {
212 self.bindings.iter().skip(index.index)
215 pub fn bindings_from_to(
219 ) -> Take<Skip<Iter<'_, BindingInfo>>> {
223 .take(to.index - from.index)
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 {
235 BindingsIndex { index: i }
238 // Remove all bindings after `index`-th item.
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)
245 pub fn labels_from(&self, index: LabelIndex) -> Skip<Iter<'_, LabelInfo>> {
246 self.labels.iter().skip(index.index)
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.
252 // It's necessary because the current parser only calls AstBuilder methods
253 // at the end of each production, not at the beginning.
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 {
262 panic!("Tried to mark a non-existant label");
266 // Remove lexical bindings after `index`-th item,
267 // while keeping var bindings.
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 {
280 if self.bindings[j].kind == BindingKind::Var {
281 self.bindings[i] = self.bindings[j];
287 self.bindings.truncate(i)
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 {
299 LabelIndex { index: i }
302 // Remove all bindings after `index`-th item.
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)
309 pub fn breaks_and_continues_from(
311 index: BreakOrContinueIndex,
312 ) -> Skip<Iter<'_, ControlInfo>> {
313 self.breaks_and_continues.iter().skip(index.index)
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 {
325 BreakOrContinueIndex::new(i)
328 pub fn pop_labelled_breaks_and_continues_from_index(
330 index: BreakOrContinueIndex,
331 name: SourceAtomSetIndex,
333 let len = self.breaks_and_continues.len();
334 let mut i = index.index;
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];
346 self.breaks_and_continues.truncate(i)
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() {
360 if self.breaks_and_continues[j].label.is_some() {
361 self.breaks_and_continues[i] = self.breaks_and_continues[j];
367 self.breaks_and_continues.truncate(i)
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() {
381 if self.breaks_and_continues[j].label.is_some()
382 || self.breaks_and_continues[j].kind == ControlKind::Continue
384 self.breaks_and_continues[i] = self.breaks_and_continues[j];
390 self.breaks_and_continues.truncate(i)
393 pub fn find_break_or_continue_at(&self, index: BreakOrContinueIndex) -> Option<&ControlInfo> {
394 self.breaks_and_continues.get(index.index)
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 })
402 pub fn find_label_at_offset(&mut self, offset: usize) -> Option<&mut LabelInfo> {
403 self.labels.iter_mut().find(|info| info.offset == offset)