Skip to content

Commit

Permalink
feat(es/ast): Support import phase (#8279)
Browse files Browse the repository at this point in the history
  • Loading branch information
magic-akari authored and kdy1 committed Jan 21, 2024
1 parent bc38ac9 commit 72048ae
Show file tree
Hide file tree
Showing 371 changed files with 2,436 additions and 718 deletions.
2 changes: 2 additions & 0 deletions crates/swc_bundler/src/bundler/import/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ where
src: Box::new(src.clone()),
type_only: false,
with: None,
phase: Default::default(),
};

if self.top_level {
Expand Down Expand Up @@ -645,6 +646,7 @@ where
src: Box::new(src),
type_only: false,
with: None,
phase: Default::default(),
};

// if self.top_level {
Expand Down
1 change: 1 addition & 0 deletions crates/swc_bundler/src/bundler/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ where
src: Box::new(src),
type_only: false,
with: None,
phase: Default::default(),
},
true,
false,
Expand Down
8 changes: 6 additions & 2 deletions crates/swc_ecma_ast/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
TsAsExpr, TsConstAssertion, TsInstantiation, TsNonNullExpr, TsSatisfiesExpr, TsTypeAnn,
TsTypeAssertion, TsTypeParamDecl, TsTypeParamInstantiation,
},
ComputedPropName, Id, Invalid, KeyValueProp, PropName, Str,
ComputedPropName, Id, ImportPhase, Invalid, KeyValueProp, PropName, Str,
};

#[ast_node(no_clone)]
Expand Down Expand Up @@ -1207,11 +1207,15 @@ impl Take for Super {
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Import {
pub span: Span,
pub phase: ImportPhase,
}

impl Take for Import {
fn dummy() -> Self {
Import { span: DUMMY_SP }
Import {
span: DUMMY_SP,
phase: ImportPhase::default(),
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use self::{
module_decl::{
DefaultDecl, ExportAll, ExportDecl, ExportDefaultDecl, ExportDefaultExpr,
ExportDefaultSpecifier, ExportNamedSpecifier, ExportNamespaceSpecifier, ExportSpecifier,
ImportDecl, ImportDefaultSpecifier, ImportNamedSpecifier, ImportSpecifier,
ImportDecl, ImportDefaultSpecifier, ImportNamedSpecifier, ImportPhase, ImportSpecifier,
ImportStarAsSpecifier, ModuleDecl, ModuleExportName, NamedExport,
},
operators::{AssignOp, BinaryOp, UnaryOp, UpdateOp},
Expand Down
23 changes: 23 additions & 0 deletions crates/swc_ecma_ast/src/module_decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,28 @@ pub struct ImportDecl {

#[cfg_attr(feature = "serde-impl", serde(default))]
pub with: Option<Box<ObjectLit>>,

#[cfg_attr(feature = "serde-impl", serde(default))]
pub phase: ImportPhase,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
any(feature = "rkyv-impl"),
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(u32)))]
#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
pub enum ImportPhase {
#[default]
#[cfg_attr(feature = "serde-impl", serde(rename = "evaluation"))]
Evaluation,
#[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
Source,
#[cfg_attr(feature = "serde-impl", serde(rename = "defer"))]
Defer,
}

impl Take for ImportDecl {
Expand All @@ -95,6 +117,7 @@ impl Take for ImportDecl {
src: Take::dummy(),
type_only: Default::default(),
with: Take::dummy(),
phase: Default::default(),
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions crates/swc_ecma_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,18 @@ where
keyword!("type");
}

match n.phase {
ImportPhase::Evaluation => {}
ImportPhase::Source => {
space!();
keyword!("source");
}
ImportPhase::Defer => {
space!();
keyword!("defer");
}
}

let starts_with_ident = !n.specifiers.is_empty()
&& match &n.specifiers[0] {
ImportSpecifier::Default(_) => true,
Expand Down Expand Up @@ -820,6 +832,17 @@ where
#[emitter]
fn emit_import_callee(&mut self, node: &Import) -> Result {
keyword!(node.span, "import");
match node.phase {
ImportPhase::Source => {
punct!(".");
keyword!("source")
}
ImportPhase::Defer => {
punct!(".");
keyword!("defer")
}
_ => {}
}
}

#[emitter]
Expand Down
1 change: 1 addition & 0 deletions crates/swc_ecma_compat_es2020/src/export_namespace_from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ impl VisitMut for ExportNamespaceFrom {
src: src.clone(),
type_only: false,
with: with.clone(),
phase: Default::default(),
})));

stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
Expand Down
69 changes: 47 additions & 22 deletions crates/swc_ecma_parser/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,19 +259,17 @@ impl<I: Tokens> Parser<I> {

tok!("import") => {
let import = self.parse_ident_name()?;

if is!(self, '.') {
self.state.found_module_item = true;
if !self.ctx().can_be_module {
let span = span!(self, start);
self.emit_err(span, SyntaxError::ImportMetaInScript);
}
return self
.parse_import_meta_prop(Import { span: import.span })
.map(Expr::MetaProp)
.map(Box::new);
return self.parse_import_meta_prop(start, import.span);
}

return self.parse_dynamic_import(start, import.span);
return self.parse_dynamic_import(start, import.span, ImportPhase::Evaluation);
}

tok!("async") => {
Expand Down Expand Up @@ -541,19 +539,27 @@ impl<I: Tokens> Parser<I> {
}

/// `parseImportMetaProperty`
pub(super) fn parse_import_meta_prop(&mut self, import: Import) -> PResult<MetaPropExpr> {
pub(super) fn parse_import_meta_prop(
&mut self,
start: BytePos,
import_span: Span,
) -> PResult<Box<Expr>> {
expect!(self, '.');

let _ = if is!(self, "meta") {
self.parse_ident_name()?
} else {
unexpected!(self, "meta");
};
let ident = self.parse_ident_name()?;

Ok(MetaPropExpr {
span: span!(self, import.span.lo()),
kind: MetaPropKind::ImportMeta,
})
match &*ident.sym {
"meta" => Ok(MetaPropExpr {
span: span!(self, import_span.lo()),
kind: MetaPropKind::ImportMeta,
}
.into()),
"source" => self.parse_dynamic_import(start, import_span, ImportPhase::Source),
// TODO: The proposal doesn't mention import.defer yet because it was
// pending on a decision for import.source. Wait to enable it until it's
// included in the proposal.
_ => unexpected!(self, "meta"),
}
}

/// `is_new_expr`: true iff we are parsing production 'NewExpression'.
Expand Down Expand Up @@ -676,6 +682,7 @@ impl<I: Tokens> Parser<I> {
if eat!(self, "import") {
let base = Callee::Import(Import {
span: span!(self, start),
phase: Default::default(),
});
return self.parse_subscripts(base, true, false);
}
Expand Down Expand Up @@ -1446,16 +1453,28 @@ impl<I: Tokens> Parser<I> {

return Ok((
Box::new(match obj {
Callee::Import(_) => match prop {
MemberProp::Ident(Ident { sym: meta, .. }) if &*meta == "meta" => {
callee @ Callee::Import(_) => match prop {
MemberProp::Ident(Ident { sym, .. }) => {
if !self.ctx().can_be_module {
let span = span!(self, start);
self.emit_err(span, SyntaxError::ImportMetaInScript);
}
Expr::MetaProp(MetaPropExpr {
span,
kind: MetaPropKind::ImportMeta,
})
match &*sym {
"meta" => Expr::MetaProp(MetaPropExpr {
span,
kind: MetaPropKind::ImportMeta,
}),
_ => {
let args = self.parse_args(true)?;

Expr::Call(CallExpr {
span,
callee,
args,
type_args: None,
})
}
}
}
_ => {
unexpected!(self, "meta");
Expand Down Expand Up @@ -1606,6 +1625,7 @@ impl<I: Tokens> Parser<I> {
if eat!(self, "import") {
let obj = Callee::Import(Import {
span: span!(self, start),
phase: Default::default(),
});
return self.parse_subscripts(obj, false, false);
}
Expand Down Expand Up @@ -1650,6 +1670,7 @@ impl<I: Tokens> Parser<I> {
_ if callee.is_ident_ref_to("import") => (
Callee::Import(Import {
span: callee.span(),
phase: Default::default(),
}),
true,
),
Expand Down Expand Up @@ -2075,11 +2096,15 @@ impl<I: Tokens> Parser<I> {
&mut self,
start: BytePos,
import_span: Span,
phase: ImportPhase,
) -> PResult<Box<Expr>> {
let args = self.parse_args(true)?;
let import = Box::new(Expr::Call(CallExpr {
span: span!(self, start),
callee: Callee::Import(Import { span: import_span }),
callee: Callee::Import(Import {
span: import_span,
phase,
}),
args,
type_args: Default::default(),
}));
Expand Down
5 changes: 4 additions & 1 deletion crates/swc_ecma_parser/src/parser/expr/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,10 @@ fn issue_328() {
span,
expr: Box::new(Expr::Call(CallExpr {
span,
callee: Callee::Import(Import { span }),
callee: Callee::Import(Import {
span,
phase: Default::default()
}),
args: vec![ExprOrSpread {
spread: None,
expr: Box::new(Expr::Lit(Lit::Str(Str {
Expand Down
21 changes: 21 additions & 0 deletions crates/swc_ecma_parser/src/parser/stmt/module_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,12 @@ impl<I: Tokens> Parser<I> {
specifiers: vec![],
type_only: false,
with,
phase: Default::default(),
})));
}

let mut type_only = false;
let mut phase = ImportPhase::Evaluation;
let mut specifiers = vec![];

'import_maybe_ident: {
Expand Down Expand Up @@ -106,6 +108,24 @@ impl<I: Tokens> Parser<I> {
.map(ModuleItem::from);
}

if matches!(&*local.sym, "source" | "defer") {
let new_phase = match &*local.sym {
"source" => ImportPhase::Source,
"defer" => ImportPhase::Defer,
_ => unreachable!(),
};

if is_one_of!(self, '*', '{') {
phase = new_phase;
break 'import_maybe_ident;
}

if is!(self, BindingIdent) && !is!(self, "from") || peeked_is!(self, "from") {
phase = new_phase;
local = self.parse_imported_default_binding()?;
}
}

//TODO: Better error reporting
if !is!(self, "from") {
expect!(self, ',');
Expand Down Expand Up @@ -178,6 +198,7 @@ impl<I: Tokens> Parser<I> {
src,
type_only,
with,
phase,
})))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import.defer("x", { with: { attr: "val" } });
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import.defer("foo");
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import.defer("foo");
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import defer * as ns from "x" with { attr: "val" };
Loading

0 comments on commit 72048ae

Please sign in to comment.