1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:57:36 +00:00

LibSQL: Add Parser::parse_comma_separated_list helper

A quite common semantic emerged for parsing comma-separated expressions:

    consume(TokenType::ParenOpen);

    do {
        // do something

        if (!match(TokenType::Comma))
            break;

        consume(TokenType::Comma);
    } while (!match(TokenType::Eof));

    consume(TokenType::ParenClose);

Add a helper to do the bulk of the while loop.
This commit is contained in:
Timothy Flynn 2021-04-23 12:33:32 -04:00 committed by Andreas Kling
parent 6a69b8efa7
commit 418884ab64
2 changed files with 39 additions and 95 deletions

View file

@ -86,19 +86,10 @@ NonnullRefPtr<CreateTable> Parser::parse_create_table_statement()
// FIXME: Parse "AS select-stmt". // FIXME: Parse "AS select-stmt".
NonnullRefPtrVector<ColumnDefinition> column_definitions; NonnullRefPtrVector<ColumnDefinition> column_definitions;
consume(TokenType::ParenOpen); parse_comma_separated_list(true, [&]() { column_definitions.append(parse_column_definition()); });
do {
column_definitions.append(parse_column_definition());
if (match(TokenType::ParenClose))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
// FIXME: Parse "table-constraint". // FIXME: Parse "table-constraint".
consume(TokenType::ParenClose);
consume(TokenType::SemiColon); consume(TokenType::SemiColon);
return create_ast_node<CreateTable>(move(schema_name), move(table_name), move(column_definitions), is_temporary, is_error_if_table_exists); return create_ast_node<CreateTable>(move(schema_name), move(table_name), move(column_definitions), is_temporary, is_error_if_table_exists);
@ -161,23 +152,12 @@ NonnullRefPtr<Select> Parser::parse_select_statement(RefPtr<CommonTableExpressio
consume_if(TokenType::All); // ALL is the default, so ignore it if specified. consume_if(TokenType::All); // ALL is the default, so ignore it if specified.
NonnullRefPtrVector<ResultColumn> result_column_list; NonnullRefPtrVector<ResultColumn> result_column_list;
do { parse_comma_separated_list(false, [&]() { result_column_list.append(parse_result_column()); });
result_column_list.append(parse_result_column());
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
NonnullRefPtrVector<TableOrSubquery> table_or_subquery_list; NonnullRefPtrVector<TableOrSubquery> table_or_subquery_list;
if (consume_if(TokenType::From)) { if (consume_if(TokenType::From)) {
// FIXME: Parse join-clause. // FIXME: Parse join-clause.
parse_comma_separated_list(false, [&]() { table_or_subquery_list.append(parse_table_or_subquery()); });
do {
table_or_subquery_list.append(parse_table_or_subquery());
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
} }
RefPtr<Expression> where_clause; RefPtr<Expression> where_clause;
@ -189,18 +169,15 @@ NonnullRefPtr<Select> Parser::parse_select_statement(RefPtr<CommonTableExpressio
consume(TokenType::By); consume(TokenType::By);
NonnullRefPtrVector<Expression> group_by_list; NonnullRefPtrVector<Expression> group_by_list;
do { parse_comma_separated_list(false, [&]() { group_by_list.append(parse_expression()); });
group_by_list.append(parse_expression());
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
RefPtr<Expression> having_clause; if (!group_by_list.is_empty()) {
if (consume_if(TokenType::Having)) RefPtr<Expression> having_clause;
having_clause = parse_expression(); if (consume_if(TokenType::Having))
having_clause = parse_expression();
group_by_clause = create_ast_node<GroupByClause>(move(group_by_list), move(having_clause)); group_by_clause = create_ast_node<GroupByClause>(move(group_by_list), move(having_clause));
}
} }
// FIXME: Parse 'WINDOW window-name AS window-defn'. // FIXME: Parse 'WINDOW window-name AS window-defn'.
@ -209,13 +186,7 @@ NonnullRefPtr<Select> Parser::parse_select_statement(RefPtr<CommonTableExpressio
NonnullRefPtrVector<OrderingTerm> ordering_term_list; NonnullRefPtrVector<OrderingTerm> ordering_term_list;
if (consume_if(TokenType::Order)) { if (consume_if(TokenType::Order)) {
consume(TokenType::By); consume(TokenType::By);
parse_comma_separated_list(false, [&]() { ordering_term_list.append(parse_ordering_term()); });
do {
ordering_term_list.append(parse_ordering_term());
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
} }
RefPtr<LimitClause> limit_clause; RefPtr<LimitClause> limit_clause;
@ -246,13 +217,7 @@ NonnullRefPtr<CommonTableExpressionList> Parser::parse_common_table_expression_l
bool recursive = consume_if(TokenType::Recursive); bool recursive = consume_if(TokenType::Recursive);
NonnullRefPtrVector<CommonTableExpression> common_table_expression; NonnullRefPtrVector<CommonTableExpression> common_table_expression;
do { parse_comma_separated_list(false, [&]() { common_table_expression.append(parse_common_table_expression()); });
common_table_expression.append(parse_common_table_expression());
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
return create_ast_node<CommonTableExpressionList>(recursive, move(common_table_expression)); return create_ast_node<CommonTableExpressionList>(recursive, move(common_table_expression));
} }
@ -504,17 +469,7 @@ Optional<NonnullRefPtr<Expression>> Parser::parse_chained_expression()
return {}; return {};
NonnullRefPtrVector<Expression> expressions; NonnullRefPtrVector<Expression> expressions;
consume(TokenType::ParenOpen); parse_comma_separated_list(true, [&]() { expressions.append(parse_expression()); });
do {
expressions.append(parse_expression());
if (match(TokenType::ParenClose))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
consume(TokenType::ParenClose);
return create_ast_node<ChainedExpression>(move(expressions)); return create_ast_node<ChainedExpression>(move(expressions));
} }
@ -669,16 +624,8 @@ Optional<NonnullRefPtr<Expression>> Parser::parse_in_expression(NonnullRefPtr<Ex
// FIXME: Consolidate this with parse_chained_expression(). That method consumes the opening paren as // FIXME: Consolidate this with parse_chained_expression(). That method consumes the opening paren as
// well, and also requires at least one expression (whereas this allows for an empty chain). // well, and also requires at least one expression (whereas this allows for an empty chain).
NonnullRefPtrVector<Expression> expressions; NonnullRefPtrVector<Expression> expressions;
if (!match(TokenType::ParenClose))
if (!match(TokenType::ParenClose)) { parse_comma_separated_list(false, [&]() { expressions.append(parse_expression()); });
do {
expressions.append(parse_expression());
if (match(TokenType::ParenClose))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
}
consume(TokenType::ParenClose); consume(TokenType::ParenClose);
@ -763,17 +710,8 @@ NonnullRefPtr<CommonTableExpression> Parser::parse_common_table_expression()
auto table_name = consume(TokenType::Identifier).value(); auto table_name = consume(TokenType::Identifier).value();
Vector<String> column_names; Vector<String> column_names;
if (consume_if(TokenType::ParenOpen)) { if (match(TokenType::ParenOpen))
do { parse_comma_separated_list(true, [&]() { column_names.append(consume(TokenType::Identifier).value()); });
column_names.append(consume(TokenType::Identifier).value());
if (match(TokenType::ParenClose))
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
consume(TokenType::ParenClose);
}
consume(TokenType::As); consume(TokenType::As);
consume(TokenType::ParenOpen); consume(TokenType::ParenOpen);
@ -818,8 +756,7 @@ NonnullRefPtr<ReturningClause> Parser::parse_returning_clause()
return create_ast_node<ReturningClause>(); return create_ast_node<ReturningClause>();
Vector<ReturningClause::ColumnClause> columns; Vector<ReturningClause::ColumnClause> columns;
parse_comma_separated_list(false, [&]() {
do {
auto expression = parse_expression(); auto expression = parse_expression();
String column_alias; String column_alias;
@ -827,11 +764,7 @@ NonnullRefPtr<ReturningClause> Parser::parse_returning_clause()
column_alias = consume(TokenType::Identifier).value(); column_alias = consume(TokenType::Identifier).value();
columns.append({ move(expression), move(column_alias) }); columns.append({ move(expression), move(column_alias) });
if (!match(TokenType::Comma)) });
break;
consume(TokenType::Comma);
} while (!match(TokenType::Eof));
return create_ast_node<ReturningClause>(move(columns)); return create_ast_node<ReturningClause>(move(columns));
} }
@ -888,18 +821,10 @@ NonnullRefPtr<TableOrSubquery> Parser::parse_table_or_subquery()
return create_ast_node<TableOrSubquery>(move(schema_name), move(table_name), move(table_alias)); return create_ast_node<TableOrSubquery>(move(schema_name), move(table_name), move(table_alias));
} }
consume(TokenType::ParenOpen);
// FIXME: Parse join-clause. // FIXME: Parse join-clause.
NonnullRefPtrVector<TableOrSubquery> subqueries; NonnullRefPtrVector<TableOrSubquery> subqueries;
while (!has_errors() && !match(TokenType::Eof)) { parse_comma_separated_list(true, [&]() { subqueries.append(parse_table_or_subquery()); });
subqueries.append(parse_table_or_subquery());
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
}
consume(TokenType::ParenClose);
return create_ast_node<TableOrSubquery>(move(subqueries)); return create_ast_node<TableOrSubquery>(move(subqueries));
} }

View file

@ -85,6 +85,25 @@ private:
NonnullRefPtr<TableOrSubquery> parse_table_or_subquery(); NonnullRefPtr<TableOrSubquery> parse_table_or_subquery();
NonnullRefPtr<OrderingTerm> parse_ordering_term(); NonnullRefPtr<OrderingTerm> parse_ordering_term();
template<typename ParseCallback>
void parse_comma_separated_list(bool surrounded_by_parentheses, ParseCallback&& parse_callback)
{
if (surrounded_by_parentheses)
consume(TokenType::ParenOpen);
while (!has_errors() && !match(TokenType::Eof)) {
parse_callback();
if (!match(TokenType::Comma))
break;
consume(TokenType::Comma);
};
if (surrounded_by_parentheses)
consume(TokenType::ParenClose);
}
Token consume(); Token consume();
Token consume(TokenType type); Token consume(TokenType type);
bool consume_if(TokenType type); bool consume_if(TokenType type);