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};
#[derive(Debug, Clone, PartialEq)]
pub struct ParserState {
pub allow_object_expr: bool,
pub include_in: bool,
pub continue_allowed: bool,
pub break_allowed: bool,
pub labels: HashMap<String, Range<usize>>,
pub in_generator: bool,
pub in_function: bool,
pub potential_arrow_start: bool,
pub in_async: bool,
pub strict: Option<StrictMode>,
pub is_module: bool,
pub default_item: Option<Range<usize>>,
pub expr_recovery_set: TokenSet,
pub should_record_names: bool,
pub name_map: HashMap<String, Range<usize>>,
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 {
pub fn check_default(
&mut self,
p: &mut Parser,
mut marker: CompletedMarker,
) -> CompletedMarker {
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
}
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);
}
}