LibJS: Memoize failed calls of try_parse_arrow_function_expression()

This commit is contained in:
Stephan Unverwerth 2021-04-11 22:41:51 +02:00 committed by Andreas Kling
parent 435bd841ee
commit 8c80eb8870
2 changed files with 46 additions and 4 deletions

View file

@ -627,11 +627,14 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
switch (m_parser_state.m_current_token.type()) {
case TokenType::ParenOpen: {
auto paren_position = position();
consume(TokenType::ParenOpen);
if (match(TokenType::ParenClose) || match(TokenType::Identifier) || match(TokenType::TripleDot)) {
if ((match(TokenType::ParenClose) || match(TokenType::Identifier) || match(TokenType::TripleDot)) && !try_parse_arrow_function_expression_failed_at_position(paren_position)) {
auto arrow_function_result = try_parse_arrow_function_expression(true);
if (!arrow_function_result.is_null())
return arrow_function_result.release_nonnull();
set_try_parse_arrow_function_expression_failed_at_position(paren_position, true);
}
auto expression = parse_expression(0);
consume(TokenType::ParenClose);
@ -651,9 +654,13 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
syntax_error("'super' keyword unexpected here");
return create_ast_node<SuperExpression>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() });
case TokenType::Identifier: {
auto arrow_function_result = try_parse_arrow_function_expression(false);
if (!arrow_function_result.is_null())
return arrow_function_result.release_nonnull();
if (!try_parse_arrow_function_expression_failed_at_position(position())) {
auto arrow_function_result = try_parse_arrow_function_expression(false);
if (!arrow_function_result.is_null())
return arrow_function_result.release_nonnull();
set_try_parse_arrow_function_expression_failed_at_position(position(), true);
}
return create_ast_node<Identifier>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, consume().value());
}
case TokenType::NumericLiteral:
@ -2039,6 +2046,20 @@ Position Parser::position() const
};
}
bool Parser::try_parse_arrow_function_expression_failed_at_position(const Position& position) const
{
auto it = m_token_memoizations.find(position);
if (it == m_token_memoizations.end())
return false;
return (*it).value.try_parse_arrow_function_expression_failed;
}
void Parser::set_try_parse_arrow_function_expression_failed_at_position(const Position& position, bool failed)
{
m_token_memoizations.set(position, { failed });
}
void Parser::syntax_error(const String& message, Optional<Position> position)
{
if (!position.has_value())

View file

@ -147,6 +147,10 @@ public:
}
}
struct TokenMemoization {
bool try_parse_arrow_function_expression_failed;
};
private:
friend class ScopePusher;
@ -172,6 +176,9 @@ private:
void discard_saved_state();
Position position() const;
bool try_parse_arrow_function_expression_failed_at_position(const Position&) const;
void set_try_parse_arrow_function_expression_failed_at_position(const Position&, bool);
struct RulePosition {
AK_MAKE_NONCOPYABLE(RulePosition);
AK_MAKE_NONMOVABLE(RulePosition);
@ -220,9 +227,23 @@ private:
explicit ParserState(Lexer);
};
class PositionKeyTraits {
public:
static int hash(const Position& position)
{
return int_hash(position.line) ^ int_hash(position.column);
}
static bool equals(const Position& a, const Position& b)
{
return a.column == b.column && a.line == b.line;
}
};
Vector<Position> m_rule_starts;
ParserState m_parser_state;
FlyString m_filename;
Vector<ParserState> m_saved_state;
HashMap<Position, TokenMemoization, PositionKeyTraits> m_token_memoizations;
};
}