LibJS: Allow reserved words as keys in object expressions.

This commit is contained in:
Stephan Unverwerth 2020-04-18 20:31:27 +02:00 committed by Andreas Kling
parent 0345fdcb77
commit bf5b251684
Notes: sideshowbarker 2024-07-19 07:29:33 +09:00
5 changed files with 61 additions and 3 deletions

View file

@ -437,8 +437,8 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
while (!done() && !match(TokenType::CurlyClose)) {
FlyString property_name;
if (match(TokenType::Identifier)) {
property_name = consume(TokenType::Identifier).value();
if (match_identifier_name()) {
property_name = consume().value();
} else if (match(TokenType::StringLiteral)) {
property_name = consume(TokenType::StringLiteral).string_value();
} else if (match(TokenType::NumericLiteral)) {
@ -582,7 +582,9 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
return create_ast_node<AssignmentExpression>(AssignmentOp::Assignment, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::Period:
consume();
return create_ast_node<MemberExpression>(move(lhs), parse_expression(min_precedence, associativity));
if (!match_identifier_name())
expected("IdentifierName");
return create_ast_node<MemberExpression>(move(lhs), create_ast_node<Identifier>(consume().value()));
case TokenType::BracketOpen: {
consume(TokenType::BracketOpen);
auto expression = create_ast_node<MemberExpression>(move(lhs), parse_expression(0), true);
@ -1072,6 +1074,11 @@ bool Parser::match_statement() const
|| type == TokenType::Var;
}
bool Parser::match_identifier_name() const
{
return m_parser_state.m_current_token.is_identifier_name();
}
bool Parser::done() const
{
return match(TokenType::Eof);

View file

@ -84,6 +84,7 @@ private:
bool match_secondary_expression() const;
bool match_statement() const;
bool match_variable_declaration() const;
bool match_identifier_name() const;
bool match(TokenType type) const;
bool done() const;
void expected(const char* what);

View file

@ -23,6 +23,14 @@ try {
// Note : this test doesn't pass yet due to floating-point literals being coerced to i32 on access
// assert(math[3.14] === "pi");
// This is also allowed! Watch out for syntax errors.
var o2 = { return: 1, yield: 1, for: 1, catch: 1, break: 1 };
assert(o2.return === 1);
assert(o2.yield === 1);
assert(o2.for === 1);
assert(o2.catch === 1);
assert(o2.break === 1);
console.log("PASS");
} catch (e) {
console.log("FAIL: " + e);

View file

@ -129,4 +129,44 @@ bool Token::bool_value() const
return m_value == "true";
}
bool Token::is_identifier_name() const
{
// IdentifierNames are Identifiers + ReservedWords
// The standard defines this reversed: Identifiers are IdentifierNames except reserved words
// https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
return m_type == TokenType::Identifier
|| m_type == TokenType::Await
|| m_type == TokenType::BoolLiteral
|| m_type == TokenType::Break
|| m_type == TokenType::Case
|| m_type == TokenType::Catch
|| m_type == TokenType::Class
|| m_type == TokenType::Const
|| m_type == TokenType::Continue
|| m_type == TokenType::Default
|| m_type == TokenType::Delete
|| m_type == TokenType::Do
|| m_type == TokenType::Else
|| m_type == TokenType::Finally
|| m_type == TokenType::For
|| m_type == TokenType::Function
|| m_type == TokenType::If
|| m_type == TokenType::In
|| m_type == TokenType::Instanceof
|| m_type == TokenType::Interface
|| m_type == TokenType::Let
|| m_type == TokenType::New
|| m_type == TokenType::NullLiteral
|| m_type == TokenType::Return
|| m_type == TokenType::Switch
|| m_type == TokenType::This
|| m_type == TokenType::Throw
|| m_type == TokenType::Try
|| m_type == TokenType::Typeof
|| m_type == TokenType::Var
|| m_type == TokenType::Void
|| m_type == TokenType::While
|| m_type == TokenType::Yield;
}
}

View file

@ -153,6 +153,8 @@ public:
String string_value() const;
bool bool_value() const;
bool is_identifier_name() const;
private:
TokenType m_type;
StringView m_trivia;