Skip to content

Commit

Permalink
Implement dynamic imports (#2932)
Browse files Browse the repository at this point in the history
* WIP: 76d7eceed6 Implement dynamic imports

* Expand `ActiveRunnable` to missing places

* Fix memory leak

* Fix docs

* Parse `import` as call expression

* Fix regressions

* Fix copypasted doc

* clippy fix

* Adjust ignored features

* Migrate away from `top_level_*` operations

* Fix more module tests

* Fix doc link
  • Loading branch information
jedel1043 committed May 22, 2023
1 parent 43d4324 commit 09658b0
Show file tree
Hide file tree
Showing 89 changed files with 2,192 additions and 982 deletions.
11 changes: 8 additions & 3 deletions boa_ast/src/declaration/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use crate::{
use boa_interner::Sym;

/// The kind of re-export in an [`ExportDeclaration`].
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReExportKind {
/// Namespaced Re-export (`export * as name from "module-name"`).
Namespaced {
Expand Down Expand Up @@ -76,7 +78,8 @@ impl VisitWith for ReExportKind {
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-ExportDeclaration
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum ExportDeclaration {
/// Re-export.
ReExport {
Expand Down Expand Up @@ -165,7 +168,9 @@ impl VisitWith for ExportDeclaration {
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-ExportSpecifier
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
pub struct ExportSpecifier {
alias: Sym,
private_name: Sym,
Expand Down
11 changes: 8 additions & 3 deletions boa_ast/src/declaration/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ use boa_interner::Sym;
use super::ModuleSpecifier;

/// The kind of import in an [`ImportDeclaration`].
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ImportKind {
/// Default (`import defaultName from "module-name"`) or unnamed (`import "module-name").
DefaultOrUnnamed,
Expand Down Expand Up @@ -77,7 +79,8 @@ impl VisitWith for ImportKind {
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-ImportDeclaration
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ImportDeclaration {
/// Binding for the default export of `specifier`.
default: Option<Identifier>,
Expand Down Expand Up @@ -155,7 +158,9 @@ impl VisitWith for ImportDeclaration {
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-ImportSpecifier
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ImportSpecifier {
binding: Identifier,
export_name: Sym,
Expand Down
4 changes: 3 additions & 1 deletion boa_ast/src/declaration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ impl VisitWith for Declaration {
/// This is equivalent to the [`ModuleSpecifier`] production.
///
/// [`FromClause`]: https://tc39.es/ecma262/#prod-ModuleSpecifier
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
pub struct ModuleSpecifier {
module: Sym,
}
Expand Down
65 changes: 65 additions & 0 deletions boa_ast/src/expression/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,68 @@ impl VisitWith for SuperCall {
ControlFlow::Continue(())
}
}

/// The import() syntax, commonly called dynamic import, is a function-like expression that allows
/// loading an ECMAScript module asynchronously and dynamically into a potentially non-module
/// environment.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#prod-ImportCall
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub struct ImportCall {
arg: Box<Expression>,
}

impl ImportCall {
/// Creates a new `ImportCall` AST node.
pub fn new<A>(arg: A) -> Self
where
A: Into<Expression>,
{
Self {
arg: Box::new(arg.into()),
}
}

/// Retrieves the single argument of the import call.
#[must_use]
pub const fn argument(&self) -> &Expression {
&self.arg
}
}

impl ToInternedString for ImportCall {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
format!("import({})", self.arg.to_interned_string(interner))
}
}

impl From<ImportCall> for Expression {
#[inline]
fn from(call: ImportCall) -> Self {
Self::ImportCall(call)
}
}

impl VisitWith for ImportCall {
fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: Visitor<'a>,
{
visitor.visit_expression(&self.arg)
}

fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
where
V: VisitorMut<'a>,
{
visitor.visit_expression_mut(&mut self.arg)
}
}
24 changes: 20 additions & 4 deletions boa_ast/src/expression/literal/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,16 +256,32 @@ impl ToIndentedString for ObjectLiteral {
MethodDefinition::Get(expression)
| MethodDefinition::Set(expression)
| MethodDefinition::Ordinary(expression) => {
block_to_string(expression.body(), interner, indent_n + 1)
block_to_string(
expression.body().statements(),
interner,
indent_n + 1,
)
}
MethodDefinition::Generator(expression) => {
block_to_string(expression.body(), interner, indent_n + 1)
block_to_string(
expression.body().statements(),
interner,
indent_n + 1,
)
}
MethodDefinition::AsyncGenerator(expression) => {
block_to_string(expression.body(), interner, indent_n + 1)
block_to_string(
expression.body().statements(),
interner,
indent_n + 1,
)
}
MethodDefinition::Async(expression) => {
block_to_string(expression.body(), interner, indent_n + 1)
block_to_string(
expression.body().statements(),
interner,
indent_n + 1,
)
}
},
)
Expand Down
9 changes: 7 additions & 2 deletions boa_ast/src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ mod tagged_template;
mod r#yield;

use crate::visitor::{VisitWith, Visitor, VisitorMut};
pub use call::{Call, SuperCall};
pub use call::{Call, ImportCall, SuperCall};
pub use identifier::{Identifier, RESERVED_IDENTIFIERS_STRICT};
pub use new::New;
pub use optional::{Optional, OptionalOperation, OptionalOperationKind};
Expand Down Expand Up @@ -121,10 +121,12 @@ pub enum Expression {
/// See [`SuperCall`].
SuperCall(SuperCall),

/// See [`ImportCall`].
ImportCall(ImportCall),

/// See [`Optional`].
Optional(Optional),

// TODO: Import calls
/// See [`TaggedTemplate`].
TaggedTemplate(TaggedTemplate),

Expand Down Expand Up @@ -192,6 +194,7 @@ impl Expression {
Self::New(new) => new.to_interned_string(interner),
Self::Call(call) => call.to_interned_string(interner),
Self::SuperCall(supc) => supc.to_interned_string(interner),
Self::ImportCall(impc) => impc.to_interned_string(interner),
Self::Optional(opt) => opt.to_interned_string(interner),
Self::NewTarget => "new.target".to_owned(),
Self::TaggedTemplate(tag) => tag.to_interned_string(interner),
Expand Down Expand Up @@ -300,6 +303,7 @@ impl VisitWith for Expression {
Self::New(n) => visitor.visit_new(n),
Self::Call(c) => visitor.visit_call(c),
Self::SuperCall(sc) => visitor.visit_super_call(sc),
Self::ImportCall(ic) => visitor.visit_import_call(ic),
Self::Optional(opt) => visitor.visit_optional(opt),
Self::TaggedTemplate(tt) => visitor.visit_tagged_template(tt),
Self::Assign(a) => visitor.visit_assign(a),
Expand Down Expand Up @@ -341,6 +345,7 @@ impl VisitWith for Expression {
Self::New(n) => visitor.visit_new_mut(n),
Self::Call(c) => visitor.visit_call_mut(c),
Self::SuperCall(sc) => visitor.visit_super_call_mut(sc),
Self::ImportCall(ic) => visitor.visit_import_call_mut(ic),
Self::Optional(opt) => visitor.visit_optional_mut(opt),
Self::TaggedTemplate(tt) => visitor.visit_tagged_template_mut(tt),
Self::Assign(a) => visitor.visit_assign_mut(a),
Expand Down
14 changes: 7 additions & 7 deletions boa_ast/src/function/arrow_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use crate::try_break;
use crate::visitor::{VisitWith, Visitor, VisitorMut};
use crate::{
expression::{Expression, Identifier},
join_nodes, StatementList,
join_nodes,
};
use boa_interner::{Interner, ToIndentedString};
use core::ops::ControlFlow;

use super::FormalParameterList;
use super::{FormalParameterList, FunctionBody};

/// An arrow function expression, as defined by the [spec].
///
Expand All @@ -24,7 +24,7 @@ use super::FormalParameterList;
pub struct ArrowFunction {
name: Option<Identifier>,
parameters: FormalParameterList,
body: StatementList,
body: FunctionBody,
}

impl ArrowFunction {
Expand All @@ -34,7 +34,7 @@ impl ArrowFunction {
pub const fn new(
name: Option<Identifier>,
params: FormalParameterList,
body: StatementList,
body: FunctionBody,
) -> Self {
Self {
name,
Expand Down Expand Up @@ -66,7 +66,7 @@ impl ArrowFunction {
/// Gets the body of the arrow function.
#[inline]
#[must_use]
pub const fn body(&self) -> &StatementList {
pub const fn body(&self) -> &FunctionBody {
&self.body
}
}
Expand Down Expand Up @@ -102,7 +102,7 @@ impl VisitWith for ArrowFunction {
try_break!(visitor.visit_identifier(ident));
}
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
visitor.visit_statement_list(&self.body)
visitor.visit_script(&self.body)
}

fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
Expand All @@ -113,6 +113,6 @@ impl VisitWith for ArrowFunction {
try_break!(visitor.visit_identifier_mut(ident));
}
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
visitor.visit_statement_list_mut(&mut self.body)
visitor.visit_script_mut(&mut self.body)
}
}
14 changes: 7 additions & 7 deletions boa_ast/src/function/async_arrow_function.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::ops::ControlFlow;

use super::FormalParameterList;
use super::{FormalParameterList, FunctionBody};
use crate::try_break;
use crate::visitor::{VisitWith, Visitor, VisitorMut};
use crate::{
expression::{Expression, Identifier},
join_nodes, StatementList,
join_nodes,
};
use boa_interner::{Interner, ToIndentedString};

Expand All @@ -24,7 +24,7 @@ use boa_interner::{Interner, ToIndentedString};
pub struct AsyncArrowFunction {
name: Option<Identifier>,
parameters: FormalParameterList,
body: StatementList,
body: FunctionBody,
}

impl AsyncArrowFunction {
Expand All @@ -34,7 +34,7 @@ impl AsyncArrowFunction {
pub const fn new(
name: Option<Identifier>,
parameters: FormalParameterList,
body: StatementList,
body: FunctionBody,
) -> Self {
Self {
name,
Expand Down Expand Up @@ -66,7 +66,7 @@ impl AsyncArrowFunction {
/// Gets the body of the arrow function.
#[inline]
#[must_use]
pub const fn body(&self) -> &StatementList {
pub const fn body(&self) -> &FunctionBody {
&self.body
}
}
Expand Down Expand Up @@ -102,7 +102,7 @@ impl VisitWith for AsyncArrowFunction {
try_break!(visitor.visit_identifier(ident));
}
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
visitor.visit_statement_list(&self.body)
visitor.visit_script(&self.body)
}

fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
Expand All @@ -113,6 +113,6 @@ impl VisitWith for AsyncArrowFunction {
try_break!(visitor.visit_identifier_mut(ident));
}
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
visitor.visit_statement_list_mut(&mut self.body)
visitor.visit_script_mut(&mut self.body)
}
}

0 comments on commit 09658b0

Please sign in to comment.