Skip to content

Commit

Permalink
Give the arrow function its proper name (#1832)
Browse files Browse the repository at this point in the history
With this change an arrow function name is correctly set to the name of the variable:

```javascript
const myFunction = () => {};
console.log(myFunction.name); // Prints "myFunction"
```

_Note:_ I'm still getting familiar with the codebase and am pretty new to Rust so I won't be offended if this isn't merged. I am actually surprised I had to make so many changes to give the right code the name it needed. Maybe there is a better way? I'm all ears :)
  • Loading branch information
rumpl committed Feb 14, 2022
1 parent 53ef07b commit 7e77276
Show file tree
Hide file tree
Showing 29 changed files with 186 additions and 82 deletions.
2 changes: 1 addition & 1 deletion boa/src/bytecompiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1423,7 +1423,7 @@ impl<'b> ByteCompiler<'b> {
),
Node::ArrowFunctionDecl(function) => (
FunctionKind::Arrow,
None,
function.name(),
function.params(),
function.body(),
),
Expand Down
17 changes: 15 additions & 2 deletions boa/src/syntax/ast/node/declaration/arrow_function_decl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
gc::{Finalize, Trace},
syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList},
};
use boa_interner::{Interner, ToInternedString};
use boa_interner::{Interner, Sym, ToInternedString};

#[cfg(feature = "deser")]
use serde::{Deserialize, Serialize};
Expand All @@ -23,23 +23,36 @@ use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
pub struct ArrowFunctionDecl {
name: Option<Sym>,
params: Box<[FormalParameter]>,
body: StatementList,
}

impl ArrowFunctionDecl {
/// Creates a new `ArrowFunctionDecl` AST node.
pub(in crate::syntax) fn new<P, B>(params: P, body: B) -> Self
pub(in crate::syntax) fn new<N, P, B>(name: N, params: P, body: B) -> Self
where
N: Into<Option<Sym>>,
P: Into<Box<[FormalParameter]>>,
B: Into<StatementList>,
{
Self {
name: name.into(),
params: params.into(),
body: body.into(),
}
}

/// Gets the name of the function declaration.
pub fn name(&self) -> Option<Sym> {
self.name
}

/// Sets the name of the function declaration.
pub fn set_name(&mut self, name: Option<Sym>) {
self.name = name;
}

/// Gets the list of parameters of the arrow function.
pub(crate) fn params(&self) -> &[FormalParameter] {
&self.params
Expand Down
13 changes: 10 additions & 3 deletions boa/src/syntax/parser/expression/assignment/arrow_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
//! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions

use boa_interner::Sym;

use super::AssignmentExpression;
use crate::{
syntax::{
Expand Down Expand Up @@ -40,24 +42,28 @@ use std::io::Read;
/// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction
#[derive(Debug, Clone, Copy)]
pub(in crate::syntax::parser) struct ArrowFunction {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}

impl ArrowFunction {
/// Creates a new `ArrowFunction` parser.
pub(in crate::syntax::parser) fn new<I, Y, A>(
pub(in crate::syntax::parser) fn new<N, I, Y, A>(
name: N,
allow_in: I,
allow_yield: Y,
allow_await: A,
) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
Expand Down Expand Up @@ -159,7 +165,7 @@ where
}
}

Ok(ArrowFunctionDecl::new(params.parameters, body))
Ok(ArrowFunctionDecl::new(self.name, params.parameters, body))
}
}

Expand Down Expand Up @@ -240,6 +246,7 @@ where
type Output = Node;

fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult {
AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor, interner)
AssignmentExpression::new(None, self.allow_in, false, self.allow_await)
.parse(cursor, interner)
}
}
20 changes: 14 additions & 6 deletions boa/src/syntax/parser/expression/assignment/conditional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,22 @@ where
if let Some(tok) = cursor.peek(0, interner)? {
if tok.kind() == &TokenKind::Punctuator(Punctuator::Question) {
cursor.next(interner)?.expect("? character vanished"); // Consume the token.
let then_clause =
AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
let then_clause = AssignmentExpression::new(
None,
self.allow_in,
self.allow_yield,
self.allow_await,
)
.parse(cursor, interner)?;
cursor.expect(Punctuator::Colon, "conditional expression", interner)?;

let else_clause =
AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
let else_clause = AssignmentExpression::new(
None,
self.allow_in,
self.allow_yield,
self.allow_await,
)
.parse(cursor, interner)?;
return Ok(ConditionalOp::new(lhs, then_clause, else_clause).into());
}
}
Expand Down
15 changes: 13 additions & 2 deletions boa/src/syntax/parser/expression/assignment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
},
BoaProfiler,
};
use boa_interner::Sym;
pub(super) use exponentiation::ExponentiationExpression;

use std::io::Read;
Expand All @@ -50,24 +51,28 @@ use std::io::Read;
/// [lhs]: ../lhs_expression/struct.LeftHandSideExpression.html
#[derive(Debug, Clone, Copy)]
pub(in crate::syntax::parser) struct AssignmentExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}

impl AssignmentExpression {
/// Creates a new `AssignmentExpression` parser.
pub(in crate::syntax::parser) fn new<I, Y, A>(
pub(in crate::syntax::parser) fn new<N, I, Y, A>(
name: N,
allow_in: I,
allow_yield: Y,
allow_await: A,
) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
Expand Down Expand Up @@ -102,6 +107,7 @@ where
{
if tok.kind() == &TokenKind::Punctuator(Punctuator::Arrow) {
return ArrowFunction::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
Expand All @@ -121,6 +127,7 @@ where
if let Some(t) = cursor.peek(2, interner)? {
if t.kind() == &TokenKind::Punctuator(Punctuator::Arrow) {
return ArrowFunction::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
Expand All @@ -132,6 +139,7 @@ where
}
TokenKind::Punctuator(Punctuator::Spread) => {
return ArrowFunction::new(
None,
self.allow_in,
self.allow_yield,
self.allow_await,
Expand All @@ -145,6 +153,7 @@ where
TokenKind::Punctuator(Punctuator::Comma) => {
// This must be an argument list and therefore (a, b) => {}
return ArrowFunction::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
Expand All @@ -160,6 +169,7 @@ where
if t.kind() == &TokenKind::Punctuator(Punctuator::Arrow)
{
return ArrowFunction::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
Expand Down Expand Up @@ -193,7 +203,8 @@ where
TokenKind::Punctuator(Punctuator::Assign) => {
cursor.next(interner)?.expect("= token vanished"); // Consume the token.
if is_assignable(&lhs) {
lhs = Assign::new(lhs, self.parse(cursor, interner)?).into();
let expr = self.parse(cursor, interner)?;
lhs = Assign::new(lhs, expr).into();
} else {
return Err(ParseError::lex(LexError::Syntax(
"Invalid left-hand side in assignment".into(),
Expand Down
2 changes: 1 addition & 1 deletion boa/src/syntax/parser/expression/assignment/yield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ where
delegate = true;
}
expr = Some(
AssignmentExpression::new(self.allow_in, true, self.allow_await)
AssignmentExpression::new(None, self.allow_in, true, self.allow_await)
.parse(cursor, interner)?,
);
}
Expand Down
4 changes: 2 additions & 2 deletions boa/src/syntax/parser/expression/left_hand_side/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ where
if cursor.next_if(Punctuator::Spread, interner)?.is_some() {
args.push(
Spread::new(
AssignmentExpression::new(true, self.allow_yield, self.allow_await)
AssignmentExpression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
)
.into(),
);
} else {
cursor.set_goal(InputElement::RegExp);
args.push(
AssignmentExpression::new(true, self.allow_yield, self.allow_await)
AssignmentExpression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
);
}
Expand Down
2 changes: 1 addition & 1 deletion boa/src/syntax/parser/expression/left_hand_side/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ where
}
TokenKind::Punctuator(Punctuator::OpenBracket) => {
let _next = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?; // We move the parser.
let idx = Expression::new(true, self.allow_yield, self.allow_await)
let idx = Expression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
cursor.expect(Punctuator::CloseBracket, "call expression", interner)?;
lhs = GetField::new(lhs, idx).into();
Expand Down
2 changes: 1 addition & 1 deletion boa/src/syntax/parser/expression/left_hand_side/member.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ where
cursor
.next(interner)?
.expect("open bracket punctuator token disappeared"); // We move the parser forward.
let idx = Expression::new(true, self.allow_yield, self.allow_await)
let idx = Expression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
cursor.expect(Punctuator::CloseBracket, "member expression", interner)?;
lhs = GetField::new(lhs, idx).into();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ where
raws.push(template_string.as_raw());
cookeds.push(template_string.to_owned_cooked(interner).ok());
exprs.push(
Expression::new(true, self.allow_yield, self.allow_await)
Expression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
);
cursor.expect(
Expand Down
9 changes: 7 additions & 2 deletions boa/src/syntax/parser/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ mod update;

pub(in crate::syntax::parser) mod await_expr;

use boa_interner::Sym;

use self::assignment::ExponentiationExpression;
pub(super) use self::{assignment::AssignmentExpression, primary::Initializer};
use super::{AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser};
Expand Down Expand Up @@ -121,20 +123,23 @@ macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $lo
/// [spec]: https://tc39.es/ecma262/#prod-Expression
#[derive(Debug, Clone, Copy)]
pub(super) struct Expression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}

impl Expression {
/// Creates a new `Expression` parser.
pub(super) fn new<I, Y, A>(allow_in: I, allow_yield: Y, allow_await: A) -> Self
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
Expand All @@ -146,7 +151,7 @@ expression!(
Expression,
AssignmentExpression,
[Punctuator::Comma],
[allow_in, allow_yield, allow_await],
[name, allow_in, allow_yield, allow_await],
None::<InputElement>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ where
let _next = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd); // Check that there are more tokens to read.

if cursor.next_if(Punctuator::Spread, interner)?.is_some() {
let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
let node =
AssignmentExpression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
elements.push(Spread::new(node).into());
} else {
elements.push(
AssignmentExpression::new(true, self.allow_yield, self.allow_await)
AssignmentExpression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
);
}
Expand Down
2 changes: 1 addition & 1 deletion boa/src/syntax/parser/expression/primary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ where
}
TokenKind::Punctuator(Punctuator::OpenParen) => {
cursor.set_goal(InputElement::RegExp);
let expr = Expression::new(true, self.allow_yield, self.allow_await)
let expr = Expression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
cursor.expect(Punctuator::CloseParen, "primary expression", interner)?;
Ok(expr)
Expand Down
Loading

0 comments on commit 7e77276

Please sign in to comment.