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

[Merged by Bors] - Fix unary operations on this #2507

Closed
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> {
Razican marked this conversation as resolved.
Show resolved Hide resolved
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