1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use rslint_errors::Diagnostic;

use crate::syntax::expr::EXPR_RECOVERY_SET;
use crate::{CompletedMarker, Parser, SyntaxKind, TokenSet};
use std::collections::HashMap;
use std::ops::{Deref, DerefMut, Range};

/// State kept by the parser while parsing.
/// It is required for things such as strict mode or async functions
#[derive(Debug, Clone, PartialEq)]
pub struct ParserState {
    /// If false, object expressions are not allowed to be parsed
    /// inside an expression.
    ///
    /// Also applies for object patterns
    pub allow_object_expr: bool,
    /// Whether `in` should be counted in a binary expression
    /// this is for `for...in` statements to prevent ambiguity.
    pub include_in: bool,
    /// Whether the parser is in an iteration statement and `continue` is allowed.
    pub continue_allowed: bool,
    /// Whether the parser is in an iteration or switch statement and
    /// `break` is allowed.
    pub break_allowed: bool,
    /// A list of labels for labelled statements used to report undefined label errors
    /// for break and continue, as well as duplicate labels
    pub labels: HashMap<String, Range<usize>>,
    /// Whether the parser is in a generator function like `function* a() {}`
    pub in_generator: bool,
    /// Whether the parser is inside of a function
    pub in_function: bool,
    /// Whether we potentially are in a place to parse an arrow expression
    pub potential_arrow_start: bool,
    /// Whether we are in an async function
    pub in_async: bool,
    /// Whether we are in strict mode code
    pub strict: Option<StrictMode>,
    /// Whether the code we are parsing is a module
    pub is_module: bool,
    /// The exported default item, used for checking duplicate defaults
    pub default_item: Option<Range<usize>>,
    /// The recovery set primary_expr will use
    pub expr_recovery_set: TokenSet,
    pub should_record_names: bool,
    pub name_map: HashMap<String, Range<usize>>,
    /// Whether the parser is in a conditional expr (ternary expr)
    pub in_cond_expr: bool,
    pub in_case_cond: bool,
    pub(crate) no_recovery: bool,
    pub in_declare: bool,
    pub in_binding_list_for_signature: bool,
    pub decorators_were_valid: bool,
    pub in_default: bool,
    pub for_head_error: Option<Diagnostic>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StrictMode {
    Module,
    Explicit(Range<usize>),
    Class(Range<usize>),
}

impl Default for ParserState {
    fn default() -> Self {
        Self {
            allow_object_expr: true,
            include_in: true,
            continue_allowed: false,
            break_allowed: false,
            labels: HashMap::new(),
            in_generator: false,
            in_function: false,
            potential_arrow_start: false,
            in_async: false,
            strict: None,
            is_module: false,
            default_item: None,
            expr_recovery_set: EXPR_RECOVERY_SET,
            name_map: HashMap::with_capacity(3),
            should_record_names: false,
            in_cond_expr: false,
            in_case_cond: false,
            no_recovery: false,
            in_declare: false,
            in_binding_list_for_signature: false,
            decorators_were_valid: false,
            in_default: false,
            for_head_error: None,
        }
    }
}

impl ParserState {
    /// Check for duplicate defaults and update state
    pub fn check_default(
        &mut self,
        p: &mut Parser,
        mut marker: CompletedMarker,
    ) -> CompletedMarker {
        // A default export is already present
        if let Some(range) = self.default_item.as_ref().filter(|_| self.is_module) {
            let err = p
                .err_builder("Illegal duplicate default export declarations")
                .secondary(
                    range.to_owned(),
                    "the module's default export is first defined here",
                )
                .primary(marker.range(p), "multiple default exports are erroneous");

            p.error(err);
            marker.change_kind(p, SyntaxKind::ERROR);
        } else if self.is_module {
            self.default_item = Some(marker.range(p).into());
        }
        marker
    }

    /// Turn on strict mode and issue a warning for redundant strict mode declarations
    pub fn strict(&mut self, p: &mut Parser, range: Range<usize>) {
        if let Some(strict) = self.strict.to_owned() {
            let mut err = p.warning_builder("Redundant strict mode declaration");

            match strict {
                StrictMode::Explicit(prev_range) => {
                    err = err.secondary(prev_range, "strict mode is previous declared here");
                }
                StrictMode::Module => {
                    err = err.footer_note("modules are always strict mode");
                }
                StrictMode::Class(prev_range) => {
                    err = err.secondary(prev_range, "class bodies are always strict mode");
                }
            }

            err = err.primary(range, "this declaration is redundant");
            p.error(err);
        } else {
            self.strict = Some(StrictMode::Explicit(range));
        }
    }
}

impl<'t> Parser<'t> {
    pub fn with_state<'a>(&'a mut self, state: ParserState) -> StateGuard<'a, 't> {
        let original_state = self.state.clone();
        self.state = state;
        StateGuard {
            original_state,
            inner: self,
        }
    }
}

pub struct StateGuard<'p, 't> {
    inner: &'p mut Parser<'t>,
    original_state: ParserState,
}

impl<'p, 't> Deref for StateGuard<'p, 't> {
    type Target = Parser<'t>;

    fn deref(&self) -> &Parser<'t> {
        self.inner
    }
}

impl<'p, 't> DerefMut for StateGuard<'p, 't> {
    fn deref_mut(&mut self) -> &mut Parser<'t> {
        &mut self.inner
    }
}

impl<'p, 't> Drop for StateGuard<'p, 't> {
    fn drop(&mut self) {
        std::mem::swap(&mut self.inner.state, &mut self.original_state);
    }
}