Browse Source

Correctly initialize functions inside modules (#2993)

pull/2995/head
José Julián Espina 1 year ago committed by GitHub
parent
commit
2fa9c65e97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 64
      boa_ast/src/operations.rs
  2. 2
      boa_engine/src/bytecompiler/declarations.rs
  3. 15
      boa_engine/src/module/source.rs

64
boa_ast/src/operations.rs

@ -1358,37 +1358,37 @@ where
} }
/// The type of a lexically scoped declaration. /// The type of a lexically scoped declaration.
#[derive(Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum LexicallyScopedDeclaration { pub enum LexicallyScopedDeclaration<'a> {
/// See [`LexicalDeclaration`] /// See [`LexicalDeclaration`]
LexicalDeclaration(LexicalDeclaration), LexicalDeclaration(&'a LexicalDeclaration),
/// See [`Function`] /// See [`Function`]
Function(Function), Function(&'a Function),
/// See [`Generator`] /// See [`Generator`]
Generator(Generator), Generator(&'a Generator),
/// See [`AsyncFunction`] /// See [`AsyncFunction`]
AsyncFunction(AsyncFunction), AsyncFunction(&'a AsyncFunction),
/// See [`AsyncGenerator`] /// See [`AsyncGenerator`]
AsyncGenerator(AsyncGenerator), AsyncGenerator(&'a AsyncGenerator),
/// See [`Class`] /// See [`Class`]
Class(Class), Class(&'a Class),
/// A default assignment expression as an export declaration. /// A default assignment expression as an export declaration.
/// ///
/// Only valid inside module exports. /// Only valid inside module exports.
AssignmentExpression(Expression), AssignmentExpression(&'a Expression),
} }
impl LexicallyScopedDeclaration { impl LexicallyScopedDeclaration<'_> {
/// Return the bound names of the declaration. /// Return the bound names of the declaration.
#[must_use] #[must_use]
pub fn bound_names(&self) -> Vec<Identifier> { pub fn bound_names(&self) -> Vec<Identifier> {
match self { match *self {
Self::LexicalDeclaration(v) => bound_names(v), Self::LexicalDeclaration(v) => bound_names(v),
Self::Function(f) => bound_names(f), Self::Function(f) => bound_names(f),
Self::Generator(g) => bound_names(g), Self::Generator(g) => bound_names(g),
@ -1400,8 +1400,8 @@ impl LexicallyScopedDeclaration {
} }
} }
impl From<Declaration> for LexicallyScopedDeclaration { impl<'ast> From<&'ast Declaration> for LexicallyScopedDeclaration<'ast> {
fn from(value: Declaration) -> Self { fn from(value: &'ast Declaration) -> LexicallyScopedDeclaration<'ast> {
match value { match value {
Declaration::Function(f) => Self::Function(f), Declaration::Function(f) => Self::Function(f),
Declaration::Generator(g) => Self::Generator(g), Declaration::Generator(g) => Self::Generator(g),
@ -1419,7 +1419,7 @@ impl From<Declaration> for LexicallyScopedDeclaration {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallyscopeddeclarations /// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallyscopeddeclarations
#[must_use] #[must_use]
pub fn lexically_scoped_declarations<'a, N>(node: &'a N) -> Vec<LexicallyScopedDeclaration> pub fn lexically_scoped_declarations<'a, N>(node: &'a N) -> Vec<LexicallyScopedDeclaration<'a>>
where where
&'a N: Into<NodeRef<'a>>, &'a N: Into<NodeRef<'a>>,
{ {
@ -1430,9 +1430,9 @@ where
/// The [`Visitor`] used to obtain the lexically scoped declarations of a node. /// The [`Visitor`] used to obtain the lexically scoped declarations of a node.
#[derive(Debug)] #[derive(Debug)]
struct LexicallyScopedDeclarationsVisitor<'a>(&'a mut Vec<LexicallyScopedDeclaration>); struct LexicallyScopedDeclarationsVisitor<'a, 'ast>(&'a mut Vec<LexicallyScopedDeclaration<'ast>>);
impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_> { impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_, 'ast> {
type BreakTy = Infallible; type BreakTy = Infallible;
// ScriptBody : StatementList // ScriptBody : StatementList
@ -1460,34 +1460,30 @@ impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_> {
// ExportDeclaration : export Declaration // ExportDeclaration : export Declaration
ExportDeclaration::Declaration(decl) => { ExportDeclaration::Declaration(decl) => {
// 1. Return a List whose sole element is DeclarationPart of Declaration. // 1. Return a List whose sole element is DeclarationPart of Declaration.
decl.clone().into() decl.into()
} }
// ExportDeclaration : export default HoistableDeclaration // ExportDeclaration : export default HoistableDeclaration
// 1. Return a List whose sole element is DeclarationPart of HoistableDeclaration. // 1. Return a List whose sole element is DeclarationPart of HoistableDeclaration.
ExportDeclaration::DefaultFunction(f) => { ExportDeclaration::DefaultFunction(f) => LexicallyScopedDeclaration::Function(f),
LexicallyScopedDeclaration::Function(f.clone()) ExportDeclaration::DefaultGenerator(g) => LexicallyScopedDeclaration::Generator(g),
}
ExportDeclaration::DefaultGenerator(g) => {
LexicallyScopedDeclaration::Generator(g.clone())
}
ExportDeclaration::DefaultAsyncFunction(af) => { ExportDeclaration::DefaultAsyncFunction(af) => {
LexicallyScopedDeclaration::AsyncFunction(af.clone()) LexicallyScopedDeclaration::AsyncFunction(af)
} }
ExportDeclaration::DefaultAsyncGenerator(ag) => { ExportDeclaration::DefaultAsyncGenerator(ag) => {
LexicallyScopedDeclaration::AsyncGenerator(ag.clone()) LexicallyScopedDeclaration::AsyncGenerator(ag)
} }
// ExportDeclaration : export default ClassDeclaration // ExportDeclaration : export default ClassDeclaration
ExportDeclaration::DefaultClassDeclaration(c) => { ExportDeclaration::DefaultClassDeclaration(c) => {
// 1. Return a List whose sole element is ClassDeclaration. // 1. Return a List whose sole element is ClassDeclaration.
LexicallyScopedDeclaration::Class(c.clone()) LexicallyScopedDeclaration::Class(c)
} }
// ExportDeclaration : export default AssignmentExpression ; // ExportDeclaration : export default AssignmentExpression ;
ExportDeclaration::DefaultAssignmentExpression(expr) => { ExportDeclaration::DefaultAssignmentExpression(expr) => {
// 1. Return a List whose sole element is this ExportDeclaration. // 1. Return a List whose sole element is this ExportDeclaration.
LexicallyScopedDeclaration::AssignmentExpression(expr.clone()) LexicallyScopedDeclaration::AssignmentExpression(expr)
} }
}; };
@ -1514,7 +1510,7 @@ impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_> {
// StatementListItem : Declaration // StatementListItem : Declaration
StatementListItem::Declaration(declaration) => { StatementListItem::Declaration(declaration) => {
// 1. Return a List whose sole element is DeclarationPart of Declaration. // 1. Return a List whose sole element is DeclarationPart of Declaration.
self.0.push(declaration.clone().into()); self.0.push(declaration.into());
ControlFlow::Continue(()) ControlFlow::Continue(())
} }
} }
@ -1525,7 +1521,7 @@ impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_> {
// LabelledItem : FunctionDeclaration // LabelledItem : FunctionDeclaration
LabelledItem::Function(f) => { LabelledItem::Function(f) => {
// 1. Return « FunctionDeclaration ». // 1. Return « FunctionDeclaration ».
self.0.push(LexicallyScopedDeclaration::Function(f.clone())); self.0.push(LexicallyScopedDeclaration::Function(f));
} }
// LabelledItem : Statement // LabelledItem : Statement
@ -1555,9 +1551,11 @@ impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_> {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallyscopeddeclarations /// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallyscopeddeclarations
#[derive(Debug)] #[derive(Debug)]
struct TopLevelLexicallyScopedDeclarationsVisitor<'a>(&'a mut Vec<LexicallyScopedDeclaration>); struct TopLevelLexicallyScopedDeclarationsVisitor<'a, 'ast>(
&'a mut Vec<LexicallyScopedDeclaration<'ast>>,
);
impl<'ast> Visitor<'ast> for TopLevelLexicallyScopedDeclarationsVisitor<'_> { impl<'ast> Visitor<'ast> for TopLevelLexicallyScopedDeclarationsVisitor<'_, 'ast> {
type BreakTy = Infallible; type BreakTy = Infallible;
fn visit_statement_list_item( fn visit_statement_list_item(
@ -1577,11 +1575,11 @@ impl<'ast> Visitor<'ast> for TopLevelLexicallyScopedDeclarationsVisitor<'_> {
// 2. Return « Declaration ». // 2. Return « Declaration ».
Declaration::Class(cl) => { Declaration::Class(cl) => {
self.0.push(LexicallyScopedDeclaration::Class(cl.clone())); self.0.push(LexicallyScopedDeclaration::Class(cl));
} }
Declaration::Lexical(lex) => { Declaration::Lexical(lex) => {
self.0 self.0
.push(LexicallyScopedDeclaration::LexicalDeclaration(lex.clone())); .push(LexicallyScopedDeclaration::LexicalDeclaration(lex));
} }
}, },

2
boa_engine/src/bytecompiler/declarations.rs

@ -351,7 +351,7 @@ impl ByteCompiler<'_, '_> {
// ii. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv. // ii. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
// iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6. // iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6.
// TODO: Support B.3.2.6. // TODO: Support B.3.2.6.
for d in &declarations { for d in declarations {
match d { match d {
LexicallyScopedDeclaration::Function(function) => { LexicallyScopedDeclaration::Function(function) => {
self.function_with_binding(function.into(), NodeKind::Declaration, false); self.function_with_binding(function.into(), NodeKind::Declaration, false);

15
boa_engine/src/module/source.rs

@ -1505,7 +1505,7 @@ impl SourceTextModule {
let lex_declarations = lexically_scoped_declarations(&self.inner.code.source); let lex_declarations = lexically_scoped_declarations(&self.inner.code.source);
let mut functions = Vec::new(); let mut functions = Vec::new();
// 24. For each element d of lexDeclarations, do // 24. For each element d of lexDeclarations, do
for declaration in &lex_declarations { for declaration in lex_declarations {
// ii. Else, // ii. Else,
// a. For each element dn of the BoundNames of d, do // a. For each element dn of the BoundNames of d, do
// 1. Perform ! env.CreateMutableBinding(dn, false). // 1. Perform ! env.CreateMutableBinding(dn, false).
@ -1576,10 +1576,19 @@ impl SourceTextModule {
} }
}; };
functions.push((spec, locator));
}
// Should compile after initializing bindings first to ensure inner calls
// are correctly resolved to the outer functions instead of as global bindings.
let functions = functions
.into_iter()
.map(|(spec, locator)| {
let kind = spec.kind; let kind = spec.kind;
functions.push((compiler.function(spec), locator, kind)); (compiler.function(spec), locator, kind)
} })
.collect::<Vec<_>>();
compiler.compile_module_item_list(self.inner.code.source.items()); compiler.compile_module_item_list(self.inner.code.source.items());

Loading…
Cancel
Save