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 scope analysis and local variables #3988

Merged
merged 7 commits into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,9 @@ where
let mut parser = boa_parser::Parser::new(Source::from_bytes(src));
let dump =
if args.module {
let scope = context.realm().scope().clone();
let module = parser
.parse_module(context.interner_mut())
.parse_module(&scope, context.interner_mut())
.map_err(|e| format!("Uncaught SyntaxError: {e}"))?;

match arg {
Expand All @@ -202,8 +203,9 @@ where
DumpFormat::Debug => format!("{module:#?}"),
}
} else {
let scope = context.realm().scope().clone();
let mut script = parser
.parse_script(context.interner_mut())
.parse_script(&scope, context.interner_mut())
.map_err(|e| format!("Uncaught SyntaxError: {e}"))?;

if args.optimize {
Expand Down
2 changes: 2 additions & 0 deletions core/ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ repository.workspace = true
rust-version.workspace = true

[features]
annex-b = []
serde = ["dep:serde", "boa_interner/serde", "bitflags/serde", "num-bigint/serde"]
arbitrary = ["dep:arbitrary", "boa_interner/arbitrary", "num-bigint/arbitrary"]

[dependencies]
boa_interner.workspace = true
boa_macros.workspace = true
boa_string.workspace = true
rustc-hash = { workspace = true, features = ["std"] }
bitflags.workspace = true
num-bigint.workspace = true
Expand Down
31 changes: 24 additions & 7 deletions core/ast/src/expression/literal/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use crate::{
},
function::{FormalParameterList, FunctionBody},
join_nodes,
operations::{contains, ContainsSymbol},
pattern::{ObjectPattern, ObjectPatternElement},
property::{MethodDefinitionKind, PropertyName},
scope::FunctionScopes,
try_break,
visitor::{VisitWith, Visitor, VisitorMut},
};
Expand Down Expand Up @@ -401,27 +403,35 @@ impl VisitWith for PropertyDefinition {
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)]
pub struct ObjectMethodDefinition {
name: PropertyName,
parameters: FormalParameterList,
body: FunctionBody,
pub(crate) name: PropertyName,
pub(crate) parameters: FormalParameterList,
pub(crate) body: FunctionBody,
pub(crate) contains_direct_eval: bool,
kind: MethodDefinitionKind,

#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) scopes: FunctionScopes,
}

impl ObjectMethodDefinition {
/// Creates a new object method definition.
#[inline]
#[must_use]
pub const fn new(
pub fn new(
name: PropertyName,
parameters: FormalParameterList,
body: FunctionBody,
kind: MethodDefinitionKind,
) -> Self {
let contains_direct_eval = contains(&parameters, ContainsSymbol::DirectEval)
|| contains(&body, ContainsSymbol::DirectEval);
Self {
name,
parameters,
body,
contains_direct_eval,
kind,
scopes: FunctionScopes::default(),
}
}

Expand Down Expand Up @@ -452,6 +462,13 @@ impl ObjectMethodDefinition {
pub const fn kind(&self) -> MethodDefinitionKind {
self.kind
}

/// Gets the scopes of the object method definition.
#[inline]
#[must_use]
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
}

impl ToIndentedString for ObjectMethodDefinition {
Expand All @@ -467,7 +484,7 @@ impl ToIndentedString for ObjectMethodDefinition {
};
let name = self.name.to_interned_string(interner);
let parameters = join_nodes(interner, self.parameters.as_ref());
let body = block_to_string(self.body.statements(), interner, indent_n + 1);
let body = block_to_string(&self.body.statements, interner, indent_n + 1);
format!("{indentation}{prefix}{name}({parameters}) {body},\n")
}
}
Expand All @@ -479,7 +496,7 @@ impl VisitWith for ObjectMethodDefinition {
{
try_break!(visitor.visit_property_name(&self.name));
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
visitor.visit_script(&self.body)
visitor.visit_function_body(&self.body)
}

fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
Expand All @@ -488,6 +505,6 @@ impl VisitWith for ObjectMethodDefinition {
{
try_break!(visitor.visit_property_name_mut(&mut self.name));
try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters));
visitor.visit_script_mut(&mut self.body)
visitor.visit_function_body_mut(&mut self.body)
}
}
35 changes: 26 additions & 9 deletions core/ast/src/function/arrow_function.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::operations::{contains, ContainsSymbol};
use crate::scope::FunctionScopes;
use crate::try_break;
use crate::visitor::{VisitWith, Visitor, VisitorMut};
use crate::{
Expand All @@ -23,34 +25,42 @@ use super::{FormalParameterList, FunctionBody};
#[derive(Clone, Debug, PartialEq)]
pub struct ArrowFunction {
pub(crate) name: Option<Identifier>,
parameters: FormalParameterList,
body: FunctionBody,
pub(crate) parameters: FormalParameterList,
pub(crate) body: FunctionBody,
pub(crate) contains_direct_eval: bool,

#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) scopes: FunctionScopes,
}

impl ArrowFunction {
/// Creates a new `ArrowFunctionDecl` AST Expression.
#[inline]
#[must_use]
pub const fn new(
pub fn new(
name: Option<Identifier>,
params: FormalParameterList,
parameters: FormalParameterList,
body: FunctionBody,
) -> Self {
let contains_direct_eval = contains(&parameters, ContainsSymbol::DirectEval)
|| contains(&body, ContainsSymbol::DirectEval);
Self {
name,
parameters: params,
parameters,
body,
contains_direct_eval,
scopes: FunctionScopes::default(),
}
}

/// Gets the name of the function declaration.
/// Gets the name of the arrow function.
#[inline]
#[must_use]
pub const fn name(&self) -> Option<Identifier> {
self.name
}

/// Sets the name of the function declaration.
/// Sets the name of the arrow function.
#[inline]
pub fn set_name(&mut self, name: Option<Identifier>) {
self.name = name;
Expand All @@ -69,6 +79,13 @@ impl ArrowFunction {
pub const fn body(&self) -> &FunctionBody {
&self.body
}

/// Returns the scopes of the arrow function.
#[inline]
#[must_use]
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
}

impl ToIndentedString for ArrowFunction {
Expand Down Expand Up @@ -102,7 +119,7 @@ impl VisitWith for ArrowFunction {
try_break!(visitor.visit_identifier(ident));
}
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
visitor.visit_script(&self.body)
visitor.visit_function_body(&self.body)
}

fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
Expand All @@ -113,6 +130,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_script_mut(&mut self.body)
visitor.visit_function_body_mut(&mut self.body)
}
}
35 changes: 26 additions & 9 deletions core/ast/src/function/async_arrow_function.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::ops::ControlFlow;

use super::{FormalParameterList, FunctionBody};
use crate::operations::{contains, ContainsSymbol};
use crate::scope::FunctionScopes;
use crate::try_break;
use crate::visitor::{VisitWith, Visitor, VisitorMut};
use crate::{
Expand All @@ -23,52 +25,67 @@ use boa_interner::{Interner, ToIndentedString};
#[derive(Clone, Debug, PartialEq)]
pub struct AsyncArrowFunction {
pub(crate) name: Option<Identifier>,
parameters: FormalParameterList,
body: FunctionBody,
pub(crate) parameters: FormalParameterList,
pub(crate) body: FunctionBody,
pub(crate) contains_direct_eval: bool,

#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) scopes: FunctionScopes,
}

impl AsyncArrowFunction {
/// Creates a new `AsyncArrowFunction` AST Expression.
#[inline]
#[must_use]
pub const fn new(
pub fn new(
name: Option<Identifier>,
parameters: FormalParameterList,
body: FunctionBody,
) -> Self {
let contains_direct_eval = contains(&parameters, ContainsSymbol::DirectEval)
|| contains(&body, ContainsSymbol::DirectEval);
Self {
name,
parameters,
body,
contains_direct_eval,
scopes: FunctionScopes::default(),
}
}

/// Gets the name of the function declaration.
/// Gets the name of the async arrow function.
#[inline]
#[must_use]
pub const fn name(&self) -> Option<Identifier> {
self.name
}

/// Sets the name of the function declaration.
/// Sets the name of the async arrow function.
#[inline]
pub fn set_name(&mut self, name: Option<Identifier>) {
self.name = name;
}

/// Gets the list of parameters of the arrow function.
/// Gets the list of parameters of the async arrow function.
#[inline]
#[must_use]
pub const fn parameters(&self) -> &FormalParameterList {
&self.parameters
}

/// Gets the body of the arrow function.
/// Gets the body of the async arrow function.
#[inline]
#[must_use]
pub const fn body(&self) -> &FunctionBody {
&self.body
}

/// Returns the scopes of the async arrow function.
#[inline]
#[must_use]
pub const fn scopes(&self) -> &FunctionScopes {
&self.scopes
}
}

impl ToIndentedString for AsyncArrowFunction {
Expand Down Expand Up @@ -102,7 +119,7 @@ impl VisitWith for AsyncArrowFunction {
try_break!(visitor.visit_identifier(ident));
}
try_break!(visitor.visit_formal_parameter_list(&self.parameters));
visitor.visit_script(&self.body)
visitor.visit_function_body(&self.body)
}

fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
Expand All @@ -113,6 +130,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_script_mut(&mut self.body)
visitor.visit_function_body_mut(&mut self.body)
}
}
Loading
Loading