Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement dynamic imports #2932

Merged
merged 12 commits into from
May 22, 2023
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)
}
}