mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:57:44 +00:00
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
4 changed files with 50 additions and 1 deletions
|
@ -130,7 +130,27 @@ protected:
|
||||||
void dump_tree(StringBuilder& builder) override;
|
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 error_tree = make_ref_counted<ErrorNode>();
|
||||||
|
inline Tree const zero_argument_function_call = make_ref_counted<WellKnownNode>(WellKnownNode::ZeroArgumentFunctionCall);
|
||||||
|
|
||||||
class ControlFlowFunctionReturn : public ControlFlowOperator {
|
class ControlFlowFunctionReturn : public ControlFlowOperator {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -35,6 +35,14 @@ void ErrorNode::dump_tree(StringBuilder& builder)
|
||||||
dump_node(builder, "Error \"{}\"", m_error);
|
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)
|
void ControlFlowFunctionReturn::dump_tree(StringBuilder& builder)
|
||||||
{
|
{
|
||||||
dump_node(builder, "ControlFlowFunctionReturn");
|
dump_node(builder, "ControlFlowFunctionReturn");
|
||||||
|
|
|
@ -25,6 +25,11 @@ RecursionDecision FunctionCallCanonicalizationPass::on_entry(Tree tree)
|
||||||
}
|
}
|
||||||
arguments.append(current_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)));
|
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)
|
if (last_element_type == ExpressionType)
|
||||||
stack.append(Token { TokenType::FunctionCall, ""sv, m_node });
|
stack.append(Token { TokenType::FunctionCall, ""sv, m_node });
|
||||||
stack.append(token);
|
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()) {
|
} else if (token.is_pre_merged_binary_operator()) {
|
||||||
THROW_PARSE_ERROR_IF(last_element_type != ExpressionType);
|
THROW_PARSE_ERROR_IF(last_element_type != ExpressionType);
|
||||||
stack.append(token);
|
stack.append(token);
|
||||||
|
@ -492,7 +501,14 @@ ParseErrorOr<ClauseHeader> TextParser::parse_clause_header()
|
||||||
|
|
||||||
TRY(consume_token_with_type(TokenType::ParenOpen));
|
TRY(consume_token_with_type(TokenType::ParenOpen));
|
||||||
while (true) {
|
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 }));
|
auto next_token = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Comma }));
|
||||||
if (next_token->type == TokenType::ParenClose)
|
if (next_token->type == TokenType::ParenClose)
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue