Skip to content

Commit

Permalink
Fix unary operations on this (#2507)
Browse files Browse the repository at this point in the history
<!---
Thank you for contributing to Boa! Please fill out the template below, and remove or add any
information as you feel necessary.
--->

This Pull Request fixes/closes #2416.

Previously, prefix increment and decrement operations on `this` caused a panic. This PR makes the parser issue a syntax error when the operand UnaryExpression is not simple (as mentioned in https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors).
  • Loading branch information
veera-sivarajan committed Dec 30, 2022
1 parent 81680ff commit f216a6d
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 35 deletions.
17 changes: 17 additions & 0 deletions boa_engine/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2836,3 +2836,20 @@ fn spread_with_call() {
"#;
assert_eq!(&exec(scenario), r#""message""#);
}

#[test]
fn unary_operations_on_this() {
// https://tc39.es/ecma262/#sec-assignment-operators-static-semantics-early-errors
let mut context = Context::default();
let test_cases = [
("++this", "1:1"),
("--this", "1:1"),
("this++", "1:5"),
("this--", "1:5"),
];
for (case, pos) in &test_cases {
let string = forward(&mut context, case);
assert!(string.starts_with("Uncaught SyntaxError: "));
assert!(string.contains(pos));
}
}
66 changes: 31 additions & 35 deletions boa_parser/src/parser/expression/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use boa_ast::{
operator::{unary::UnaryOp, Unary},
Identifier,
},
Expression, Punctuator,
Expression, Position, Punctuator,
};
use boa_interner::{Interner, Sym};
use boa_interner::Interner;
use boa_profiler::Profiler;
use std::io::Read;

Expand Down Expand Up @@ -56,6 +56,21 @@ impl UpdateExpression {
}
}

/// <https://tc39.es/ecma262/multipage/syntax-directed-operations.html#sec-static-semantics-assignmenttargettype>
/// This function checks if the target type is simple
fn is_simple(expr: &Expression, position: Position, strict: bool) -> ParseResult<bool> {
match expr {
Expression::Identifier(ident) => {
if strict {
check_strict_arguments_or_eval(*ident, position)?;
}
Ok(true)
}
Expression::PropertyAccess(_) => Ok(true),
_ => Ok(false),
}
}

impl<R> TokenParser<R> for UpdateExpression
where
R: Read,
Expand All @@ -75,11 +90,12 @@ where

let target = UnaryExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;

if cursor.strict_mode() {
if let Expression::Identifier(ident) = target {
check_strict_arguments_or_eval(ident, position)?;
}
// https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors
if !is_simple(&target, position, cursor.strict_mode())? {
return Err(Error::lex(LexError::Syntax(
"Invalid left-hand side in assignment".into(),
position,
)));
}

return Ok(Unary::new(UnaryOp::IncrementPre, target).into());
Expand All @@ -91,11 +107,12 @@ where

let target = UnaryExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;

if cursor.strict_mode() {
if let Expression::Identifier(ident) = target {
check_strict_arguments_or_eval(ident, position)?;
}
// https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors
if !is_simple(&target, position, cursor.strict_mode())? {
return Err(Error::lex(LexError::Syntax(
"Invalid left-hand side in assignment".into(),
position,
)));
}

return Ok(Unary::new(UnaryOp::DecrementPre, target).into());
Expand All @@ -106,7 +123,6 @@ where
let lhs = LeftHandSideExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;

let strict = cursor.strict_mode();
if let Some(tok) = cursor.peek(0, interner)? {
let token_start = tok.span().start();
match tok.kind() {
Expand All @@ -115,17 +131,7 @@ where
.next(interner)?
.expect("Punctuator::Inc token disappeared");
// https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors
let ok = match &lhs {
Expression::Identifier(_) if !strict => true,
Expression::Identifier(ident)
if ![Sym::EVAL, Sym::ARGUMENTS].contains(&ident.sym()) =>
{
true
}
Expression::PropertyAccess(_) => true,
_ => false,
};
if !ok {
if !is_simple(&lhs, token_start, cursor.strict_mode())? {
return Err(Error::lex(LexError::Syntax(
"Invalid left-hand side in assignment".into(),
token_start,
Expand All @@ -139,17 +145,7 @@ where
.next(interner)?
.expect("Punctuator::Dec token disappeared");
// https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors
let ok = match &lhs {
Expression::Identifier(_) if !strict => true,
Expression::Identifier(ident)
if ![Sym::EVAL, Sym::ARGUMENTS].contains(&ident.sym()) =>
{
true
}
Expression::PropertyAccess(_) => true,
_ => false,
};
if !ok {
if !is_simple(&lhs, token_start, cursor.strict_mode())? {
return Err(Error::lex(LexError::Syntax(
"Invalid left-hand side in assignment".into(),
token_start,
Expand Down

0 comments on commit f216a6d

Please sign in to comment.