JSSpecCompiler: Properly parse function calls with zero arguments
We cannot handle them normally since we need text between parenthesis to be a valid expression. As a workaround, we now push an artificial value to stack to act as an argument (it'll be later removed during function call canonicalization).
This commit is contained in:
parent
14ee25b8ba
commit
33b36476d9
Notes:
sideshowbarker
2024-07-17 22:09:47 +09:00
Author: https://github.com/DanShaders Commit: https://github.com/SerenityOS/serenity/commit/33b36476d9 Pull-request: https://github.com/SerenityOS/serenity/pull/22794 Reviewed-by: https://github.com/ADKaster ✅
4 changed files with 50 additions and 1 deletions
Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler
|
@ -130,7 +130,27 @@ protected:
|
|||
void dump_tree(StringBuilder& builder) override;
|
||||
};
|
||||
|
||||
class WellKnownNode : public Expression {
|
||||
public:
|
||||
enum Type {
|
||||
ZeroArgumentFunctionCall,
|
||||
// Update WellKnownNode::dump_tree after adding an entry here
|
||||
};
|
||||
|
||||
WellKnownNode(Type type)
|
||||
: m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void dump_tree(StringBuilder& builder) override;
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
};
|
||||
|
||||
inline Tree const error_tree = make_ref_counted<ErrorNode>();
|
||||
inline Tree const zero_argument_function_call = make_ref_counted<WellKnownNode>(WellKnownNode::ZeroArgumentFunctionCall);
|
||||
|
||||
class ControlFlowFunctionReturn : public ControlFlowOperator {
|
||||
public:
|
||||
|
|
|
@ -35,6 +35,14 @@ void ErrorNode::dump_tree(StringBuilder& builder)
|
|||
dump_node(builder, "Error \"{}\"", m_error);
|
||||
}
|
||||
|
||||
void WellKnownNode::dump_tree(StringBuilder& builder)
|
||||
{
|
||||
static constexpr StringView type_to_name[] = {
|
||||
"ZeroArgumentFunctionCall"sv,
|
||||
};
|
||||
dump_node(builder, "WellKnownNode {}", type_to_name[m_type]);
|
||||
}
|
||||
|
||||
void ControlFlowFunctionReturn::dump_tree(StringBuilder& builder)
|
||||
{
|
||||
dump_node(builder, "ControlFlowFunctionReturn");
|
||||
|
|
|
@ -25,6 +25,11 @@ RecursionDecision FunctionCallCanonicalizationPass::on_entry(Tree tree)
|
|||
}
|
||||
arguments.append(current_tree);
|
||||
|
||||
if (arguments[0] == zero_argument_function_call) {
|
||||
VERIFY(arguments.size() == 1);
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
replace_current_node_with(make_ref_counted<FunctionCall>(binary_operation->m_left, move(arguments)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,6 +228,15 @@ ParseErrorOr<Tree> TextParser::parse_expression()
|
|||
if (last_element_type == ExpressionType)
|
||||
stack.append(Token { TokenType::FunctionCall, ""sv, m_node });
|
||||
stack.append(token);
|
||||
|
||||
if (m_next_token_index + 1 < m_tokens.size()
|
||||
&& m_tokens[m_next_token_index + 1].type == TokenType::ParenClose) {
|
||||
// This is a call to function which does not take parameters. We cannot handle it
|
||||
// normally since we need text between parenthesis to be a valid expression. As a
|
||||
// workaround, we push an artificial tree to stack to act as an argument (it'll be
|
||||
// removed later during function call canonicalization).
|
||||
stack.append(zero_argument_function_call);
|
||||
}
|
||||
} else if (token.is_pre_merged_binary_operator()) {
|
||||
THROW_PARSE_ERROR_IF(last_element_type != ExpressionType);
|
||||
stack.append(token);
|
||||
|
@ -492,7 +501,14 @@ ParseErrorOr<ClauseHeader> TextParser::parse_clause_header()
|
|||
|
||||
TRY(consume_token_with_type(TokenType::ParenOpen));
|
||||
while (true) {
|
||||
function_definition.arguments.append({ TRY(consume_token_with_type(TokenType::Identifier))->data });
|
||||
if (function_definition.arguments.is_empty()) {
|
||||
auto argument = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Identifier }));
|
||||
if (argument->type == TokenType::ParenClose)
|
||||
break;
|
||||
function_definition.arguments.append({ argument->data });
|
||||
} else {
|
||||
function_definition.arguments.append({ TRY(consume_token_with_type(TokenType::Identifier))->data });
|
||||
}
|
||||
auto next_token = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Comma }));
|
||||
if (next_token->type == TokenType::ParenClose)
|
||||
break;
|
||||
|
|
Loading…
Add table
Reference in a new issue