mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
LibJS: Syntax error for a unary expression followed by exponentiation
This change makes LibJS correctly report a syntax error when a unary expression is followed by exponentiation, as the spec requires. Apparently this is due to that expression being ambiguous ordering. Strangely this check does not seem to apply in the same way for '++' and '--' for reasons that I don't fully understand. For example ``` let x = 5; ++x ** 2 ``` Since `--5` and `++5` on it's own results in a syntax error anyway, it seems we do not need to perform this exponentiation check in those places. Diff Tests: +6 ✅ -6 ❌
This commit is contained in:
parent
5e7a82a853
commit
2d8b2328fd
Notes:
sideshowbarker
2024-07-16 23:51:07 +09:00
Author: https://github.com/shannonbooth Commit: https://github.com/SerenityOS/serenity/commit/2d8b2328fd Pull-request: https://github.com/SerenityOS/serenity/pull/21120
3 changed files with 50 additions and 2 deletions
|
@ -1805,6 +1805,13 @@ NonnullRefPtr<Expression const> Parser::parse_unary_prefixed_expression()
|
|||
auto rule_start = push_start();
|
||||
auto precedence = g_operator_precedence.get_unary(m_state.current_token.type());
|
||||
auto associativity = operator_associativity(m_state.current_token.type());
|
||||
|
||||
auto verify_next_token_is_not_exponentiation = [this]() {
|
||||
auto lookahead_token = next_token();
|
||||
if (lookahead_token.type() == TokenType::DoubleAsterisk)
|
||||
syntax_error("Unary operator must not be used before exponentiation expression without brackets");
|
||||
};
|
||||
|
||||
switch (m_state.current_token.type()) {
|
||||
case TokenType::PlusPlus: {
|
||||
consume();
|
||||
|
@ -1838,27 +1845,34 @@ NonnullRefPtr<Expression const> Parser::parse_unary_prefixed_expression()
|
|||
}
|
||||
case TokenType::ExclamationMark:
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Not, parse_expression(precedence, associativity));
|
||||
case TokenType::Tilde:
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::BitwiseNot, parse_expression(precedence, associativity));
|
||||
case TokenType::Plus:
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Plus, parse_expression(precedence, associativity));
|
||||
case TokenType::Minus:
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Minus, parse_expression(precedence, associativity));
|
||||
case TokenType::Typeof:
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Typeof, parse_expression(precedence, associativity));
|
||||
case TokenType::Void:
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
// FIXME: This check is really hiding the fact that we don't deal with different expressions correctly.
|
||||
if (match(TokenType::Yield) && m_state.in_generator_function_context)
|
||||
syntax_error("'yield' is not an identifier in generator function context");
|
||||
return create_ast_node<UnaryExpression>({ m_source_code, rule_start.position(), position() }, UnaryOp::Void, parse_expression(precedence, associativity));
|
||||
case TokenType::Delete: {
|
||||
consume();
|
||||
verify_next_token_is_not_exponentiation();
|
||||
auto rhs_start = position();
|
||||
auto rhs = parse_expression(precedence, associativity);
|
||||
if (is<Identifier>(*rhs) && m_state.strict_mode) {
|
||||
|
|
|
@ -14,8 +14,26 @@ test("exponentiation with negatives", () => {
|
|||
expect(2 ** -3).toBe(0.125);
|
||||
expect((-2) ** 3).toBe(-8);
|
||||
|
||||
// FIXME: This should fail :)
|
||||
// expect("-2 ** 3").not.toEval();
|
||||
expect("-2 ** 3").not.toEval();
|
||||
});
|
||||
|
||||
test("exponentiation with PlusPlus and MinusMinus", () => {
|
||||
let value = 5;
|
||||
// prettier-ignore
|
||||
expect(++value ** 2).toBe(36);
|
||||
|
||||
value = 5;
|
||||
expect((++value) ** 2).toBe(36);
|
||||
|
||||
value = 5;
|
||||
// prettier-ignore
|
||||
expect(--value ** 2).toBe(16);
|
||||
|
||||
value = 5;
|
||||
expect((--value) ** 2).toBe(16);
|
||||
|
||||
expect("++5 ** 2").not.toEval();
|
||||
expect("--5 ** 2").not.toEval();
|
||||
});
|
||||
|
||||
test("exponentiation with non-numeric primitives", () => {
|
||||
|
@ -50,3 +68,10 @@ test("exponentiation with infinities", () => {
|
|||
expect((-Infinity) ** 0).toBe(1);
|
||||
expect((-Infinity) ** 1).toBe(-Infinity);
|
||||
});
|
||||
|
||||
test("unary expression before exponentiation with brackets", () => {
|
||||
expect((!1) ** 2).toBe(0);
|
||||
expect((~5) ** 2).toBe(36);
|
||||
expect((+5) ** 2).toBe(25);
|
||||
expect((-5) ** 2).toBe(25);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
test("syntax error for an unary expression before exponentiation", () => {
|
||||
expect(`!5 ** 2`).not.toEval();
|
||||
expect(`~5 ** 2`).not.toEval();
|
||||
expect(`+5 ** 2`).not.toEval();
|
||||
expect(`-5 ** 2`).not.toEval();
|
||||
expect(`typeof 5 ** 2`).not.toEval();
|
||||
expect(`void 5 ** 2`).not.toEval();
|
||||
expect(`delete 5 ** 2`).not.toEval();
|
||||
});
|
Loading…
Reference in a new issue