use super::*;
#[parser]
impl<'a, I: Input> Parser<'a, I> {
fn parse_import(&mut self) -> PResult<'a, ModuleDecl> {
let start = cur_pos!();
assert_and_bump!("import");
let str_start = cur_pos!();
match *cur!(false)? {
Token::Str { .. } => match bump!() {
Token::Str { value, has_escape } => {
expect!(';');
return Ok(ModuleDecl::Import(ImportDecl {
span: span!(start),
src: Str {
span: span!(str_start),
value,
has_escape,
},
specifiers: vec![],
}));
}
_ => unreachable!(),
},
_ => {}
}
let mut specifiers = vec![];
if is!(BindingIdent) {
let local = self.parse_imported_default_binding()?;
if !is!("from") {
expect!(',');
}
specifiers.push(ImportSpecifier::Default(ImportDefault {
span: local.span,
local,
}));
}
{
let import_spec_start = cur_pos!();
if eat!('*') {
expect!("as");
let local = self.parse_imported_binding()?;
specifiers.push(ImportSpecifier::Namespace(ImportStarAs {
span: span!(import_spec_start),
local,
}));
} else if eat!('{') {
let mut first = true;
while !eof!() && !is!('}') {
if first {
first = false;
} else {
if eat!(',') {
if is!('}') {
break;
}
}
}
specifiers.push(self.parse_import_specifier()?);
}
expect!('}');
}
}
let src = self.parse_from_clause_and_semi()?;
Ok(ModuleDecl::Import(ImportDecl {
span: span!(start),
specifiers,
src,
}))
}
fn parse_import_specifier(&mut self) -> PResult<'a, ImportSpecifier> {
let start = cur_pos!();
match *cur!(false)? {
Word(..) => {
let orig_name = self.parse_ident_name()?;
if eat!("as") {
let local = self.parse_binding_ident()?;
return Ok(ImportSpecifier::Specific(ImportSpecific {
span: Span::new(start, local.span.hi(), Default::default()),
local,
imported: Some(orig_name),
}));
}
if self.ctx().is_reserved_word(&orig_name.sym) {
syntax_error!(orig_name.span, SyntaxError::Unexpected)
}
let local = orig_name;
return Ok(ImportSpecifier::Specific(ImportSpecific {
span: span!(start),
local,
imported: None,
}));
}
_ => unexpected!(),
}
}
fn parse_imported_default_binding(&mut self) -> PResult<'a, Ident> {
self.parse_imported_binding()
}
fn parse_imported_binding(&mut self) -> PResult<'a, Ident> {
let ctx = Context {
in_async: false,
in_generator: false,
..self.ctx()
};
self.with_ctx(ctx).parse_binding_ident()
}
fn parse_export(&mut self) -> PResult<'a, ModuleDecl> {
let start = cur_pos!();
assert_and_bump!("export");
if eat!('*') {
let src = self.parse_from_clause_and_semi()?;
return Ok(ModuleDecl::ExportAll(ExportAll {
span: span!(start),
src,
}));
}
if eat!("default") {
let decl = if is!("class") {
self.parse_default_class()?
} else if is!("async")
&& peeked_is!("function")
&& !self.input.has_linebreak_between_cur_and_peeked()
{
self.parse_default_async_fn()?
} else if is!("function") {
self.parse_default_fn()?
} else {
let expr = self.include_in_expr(true).parse_assignment_expr()?;
expect!(';');
return Ok(ModuleDecl::ExportDefaultExpr(expr));
};
return Ok(ModuleDecl::ExportDefaultDecl(decl));
}
let decl = if is!("class") {
self.parse_class_decl()?
} else if is!("async")
&& peeked_is!("function")
&& !self.input.has_linebreak_between_cur_and_peeked()
{
self.parse_async_fn_decl()?
} else if is!("function") {
self.parse_fn_decl()?
} else if is!("var")
|| is!("const")
|| (is!("let")
&& peek!()
.map(|t| {
t.follows_keyword_let(true)
})
.unwrap_or(false))
{
self.parse_var_stmt(false).map(Decl::Var)?
} else {
expect!('{');
let mut specifiers = vec![];
let mut first = true;
while is_one_of!(',', IdentName) {
if first {
first = false;
} else {
if eat!(',') {
if is!('}') {
break;
}
}
}
specifiers.push(self.parse_export_specifier()?);
}
expect!('}');
let src = if is!("from") {
Some(self.parse_from_clause_and_semi()?)
} else {
None
};
return Ok(ModuleDecl::ExportNamed(NamedExport {
span: span!(start),
specifiers,
src,
}));
};
return Ok(ModuleDecl::ExportDecl(decl));
}
fn parse_export_specifier(&mut self) -> PResult<'a, ExportSpecifier> {
let start = cur_pos!();
let orig = self.parse_ident_name()?;
let exported = if eat!("as") {
Some(self.parse_ident_name()?)
} else {
None
};
Ok(ExportSpecifier {
span: span!(start),
orig,
exported,
})
}
fn parse_from_clause_and_semi(&mut self) -> PResult<'a, Str> {
expect!("from");
let start = cur_pos!();
match *cur!(true)? {
Token::Str { .. } => match bump!() {
Token::Str { value, has_escape } => {
expect!(';');
Ok(Str {
value,
has_escape,
span: span!(start),
})
}
_ => unreachable!(),
},
_ => unexpected!(),
}
}
}
impl IsDirective for ModuleItem {
fn as_ref(&self) -> Option<&Stmt> {
match *self {
ModuleItem::Stmt(ref s) => Some(s),
_ => None,
}
}
}
#[parser]
impl<'a, I: Input> StmtLikeParser<'a, ModuleItem> for Parser<'a, I> {
fn handle_import_export(&mut self, top_level: bool) -> PResult<'a, ModuleItem> {
if !top_level {
syntax_error!(SyntaxError::NonTopLevelImportExport);
}
let start = cur_pos!();
let decl = if is!("import") {
self.parse_import()?
} else if is!("export") {
self.parse_export()?
} else {
unreachable!(
"handle_import_export should not be called if current token isn't import nor \
export"
)
};
Ok(ModuleItem::ModuleDecl(decl))
}
}