Coverage Report

Created: 2026-10-28 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibSQL/AST/Parser.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
3
 * Copyright (c) 2021, Mahmoud Mandour <ma.mandourr@gmail.com>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#pragma once
9
10
#include <AK/ByteString.h>
11
#include <AK/StringView.h>
12
#include <LibSQL/AST/AST.h>
13
#include <LibSQL/AST/Lexer.h>
14
#include <LibSQL/AST/Token.h>
15
16
namespace SQL::AST {
17
18
namespace Limits {
19
// https://www.sqlite.org/limits.html
20
constexpr size_t maximum_expression_tree_depth = 1000;
21
constexpr size_t maximum_subquery_depth = 100;
22
constexpr size_t maximum_bound_parameters = 1000;
23
}
24
25
class Parser {
26
    struct Error {
27
        ByteString message;
28
        SourcePosition position;
29
30
        ByteString to_byte_string() const
31
0
        {
32
0
            return ByteString::formatted("{} (line: {}, column: {})", message, position.line, position.column);
33
0
        }
34
    };
35
36
public:
37
    explicit Parser(Lexer lexer);
38
39
    NonnullRefPtr<Statement> next_statement();
40
41
71.9M
    bool has_errors() const { return m_parser_state.m_errors.size(); }
42
0
    Vector<Error> const& errors() const { return m_parser_state.m_errors; }
43
44
protected:
45
    NonnullRefPtr<Expression> parse_expression(); // Protected for unit testing.
46
47
private:
48
    struct ParserState {
49
        explicit ParserState(Lexer);
50
51
        Lexer m_lexer;
52
        Token m_token;
53
        Vector<Error> m_errors;
54
        size_t m_current_expression_depth { 0 };
55
        size_t m_current_subquery_depth { 0 };
56
        size_t m_bound_parameters { 0 };
57
    };
58
59
    NonnullRefPtr<Statement> parse_statement();
60
    NonnullRefPtr<Statement> parse_statement_with_expression_list(RefPtr<CommonTableExpressionList>);
61
    NonnullRefPtr<CreateSchema> parse_create_schema_statement();
62
    NonnullRefPtr<CreateTable> parse_create_table_statement();
63
    NonnullRefPtr<AlterTable> parse_alter_table_statement();
64
    NonnullRefPtr<DropTable> parse_drop_table_statement();
65
    NonnullRefPtr<DescribeTable> parse_describe_table_statement();
66
    NonnullRefPtr<Insert> parse_insert_statement(RefPtr<CommonTableExpressionList>);
67
    NonnullRefPtr<Update> parse_update_statement(RefPtr<CommonTableExpressionList>);
68
    NonnullRefPtr<Delete> parse_delete_statement(RefPtr<CommonTableExpressionList>);
69
    NonnullRefPtr<Select> parse_select_statement(RefPtr<CommonTableExpressionList>);
70
    RefPtr<CommonTableExpressionList> parse_common_table_expression_list();
71
72
    NonnullRefPtr<Expression> parse_primary_expression();
73
    NonnullRefPtr<Expression> parse_secondary_expression(NonnullRefPtr<Expression> primary);
74
    bool match_secondary_expression() const;
75
    RefPtr<Expression> parse_literal_value_expression();
76
    RefPtr<Expression> parse_bind_parameter_expression();
77
    RefPtr<Expression> parse_column_name_expression(Optional<ByteString> with_parsed_identifier = {}, bool with_parsed_period = false);
78
    RefPtr<Expression> parse_unary_operator_expression();
79
    RefPtr<Expression> parse_binary_operator_expression(NonnullRefPtr<Expression> lhs);
80
    RefPtr<Expression> parse_chained_expression(bool surrounded_by_parentheses = true);
81
    RefPtr<Expression> parse_cast_expression();
82
    RefPtr<Expression> parse_case_expression();
83
    RefPtr<Expression> parse_exists_expression(bool invert_expression);
84
    RefPtr<Expression> parse_collate_expression(NonnullRefPtr<Expression> expression);
85
    RefPtr<Expression> parse_is_expression(NonnullRefPtr<Expression> expression);
86
    RefPtr<Expression> parse_match_expression(NonnullRefPtr<Expression> lhs, bool invert_expression);
87
    RefPtr<Expression> parse_null_expression(NonnullRefPtr<Expression> expression, bool invert_expression);
88
    RefPtr<Expression> parse_between_expression(NonnullRefPtr<Expression> expression, bool invert_expression);
89
    RefPtr<Expression> parse_in_expression(NonnullRefPtr<Expression> expression, bool invert_expression);
90
91
    NonnullRefPtr<ColumnDefinition> parse_column_definition();
92
    NonnullRefPtr<TypeName> parse_type_name();
93
    NonnullRefPtr<SignedNumber> parse_signed_number();
94
    NonnullRefPtr<CommonTableExpression> parse_common_table_expression();
95
    NonnullRefPtr<QualifiedTableName> parse_qualified_table_name();
96
    NonnullRefPtr<ReturningClause> parse_returning_clause();
97
    NonnullRefPtr<ResultColumn> parse_result_column();
98
    NonnullRefPtr<TableOrSubquery> parse_table_or_subquery();
99
    NonnullRefPtr<OrderingTerm> parse_ordering_term();
100
    void parse_schema_and_table_name(ByteString& schema_name, ByteString& table_name);
101
    ConflictResolution parse_conflict_resolution();
102
103
    template<typename ParseCallback>
104
    void parse_comma_separated_list(bool surrounded_by_parentheses, ParseCallback&& parse_callback)
105
998k
    {
106
998k
        if (surrounded_by_parentheses)
107
12.9k
            consume(TokenType::ParenOpen);
108
109
71.9M
        while (!has_errors() && !match(TokenType::Eof)) {
110
71.6M
            parse_callback();
111
112
71.6M
            if (!match(TokenType::Comma))
113
696k
                break;
114
115
70.9M
            consume(TokenType::Comma);
116
70.9M
        };
117
118
998k
        if (surrounded_by_parentheses)
119
12.9k
            consume(TokenType::ParenClose);
120
998k
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_create_table_statement()::$_0>(bool, SQL::AST::Parser::parse_create_table_statement()::$_0&&)
Line
Count
Source
105
267
    {
106
267
        if (surrounded_by_parentheses)
107
267
            consume(TokenType::ParenOpen);
108
109
6.96M
        while (!has_errors() && !match(TokenType::Eof)) {
110
6.96M
            parse_callback();
111
112
6.96M
            if (!match(TokenType::Comma))
113
156
                break;
114
115
6.96M
            consume(TokenType::Comma);
116
6.96M
        };
117
118
267
        if (surrounded_by_parentheses)
119
267
            consume(TokenType::ParenClose);
120
267
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_insert_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0>(bool, SQL::AST::Parser::parse_insert_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0&&)
Line
Count
Source
105
223
    {
106
223
        if (surrounded_by_parentheses)
107
223
            consume(TokenType::ParenOpen);
108
109
624k
        while (!has_errors() && !match(TokenType::Eof)) {
110
624k
            parse_callback();
111
112
624k
            if (!match(TokenType::Comma))
113
198
                break;
114
115
624k
            consume(TokenType::Comma);
116
624k
        };
117
118
223
        if (surrounded_by_parentheses)
119
223
            consume(TokenType::ParenClose);
120
223
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_insert_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_1>(bool, SQL::AST::Parser::parse_insert_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_1&&)
Line
Count
Source
105
290
    {
106
290
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
458k
        while (!has_errors() && !match(TokenType::Eof)) {
110
458k
            parse_callback();
111
112
458k
            if (!match(TokenType::Comma))
113
238
                break;
114
115
458k
            consume(TokenType::Comma);
116
458k
        };
117
118
290
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
290
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_update_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0>(bool, SQL::AST::Parser::parse_update_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0&&)
Line
Count
Source
105
731
    {
106
731
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
2.14M
        while (!has_errors() && !match(TokenType::Eof)) {
110
2.14M
            parse_callback();
111
112
2.14M
            if (!match(TokenType::Comma))
113
575
                break;
114
115
2.14M
            consume(TokenType::Comma);
116
2.14M
        };
117
118
731
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
731
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_update_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0::operator()() const::{lambda()#1}>(bool, SQL::AST::Parser::parse_update_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0::operator()() const::{lambda()#1}&&)
Line
Count
Source
105
672
    {
106
672
        if (surrounded_by_parentheses)
107
672
            consume(TokenType::ParenOpen);
108
109
2.74M
        while (!has_errors() && !match(TokenType::Eof)) {
110
2.74M
            parse_callback();
111
112
2.74M
            if (!match(TokenType::Comma))
113
649
                break;
114
115
2.74M
            consume(TokenType::Comma);
116
2.74M
        };
117
118
672
        if (surrounded_by_parentheses)
119
672
            consume(TokenType::ParenClose);
120
672
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_update_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_1>(bool, SQL::AST::Parser::parse_update_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_1&&)
Line
Count
Source
105
105
    {
106
105
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
2.55M
        while (!has_errors() && !match(TokenType::Eof)) {
110
2.55M
            parse_callback();
111
112
2.55M
            if (!match(TokenType::Comma))
113
76
                break;
114
115
2.55M
            consume(TokenType::Comma);
116
2.55M
        };
117
118
105
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
105
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0>(bool, SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_0&&)
Line
Count
Source
105
155k
    {
106
155k
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
19.4M
        while (!has_errors() && !match(TokenType::Eof)) {
110
19.3M
            parse_callback();
111
112
19.3M
            if (!match(TokenType::Comma))
113
145k
                break;
114
115
19.2M
            consume(TokenType::Comma);
116
19.2M
        };
117
118
155k
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
155k
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_1>(bool, SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_1&&)
Line
Count
Source
105
942
    {
106
942
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
3.24M
        while (!has_errors() && !match(TokenType::Eof)) {
110
3.24M
            parse_callback();
111
112
3.24M
            if (!match(TokenType::Comma))
113
719
                break;
114
115
3.24M
            consume(TokenType::Comma);
116
3.24M
        };
117
118
942
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
942
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_2>(bool, SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_2&&)
Line
Count
Source
105
1.34k
    {
106
1.34k
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
1.80M
        while (!has_errors() && !match(TokenType::Eof)) {
110
1.80M
            parse_callback();
111
112
1.80M
            if (!match(TokenType::Comma))
113
602
                break;
114
115
1.80M
            consume(TokenType::Comma);
116
1.80M
        };
117
118
1.34k
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
1.34k
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_3>(bool, SQL::AST::Parser::parse_select_statement(AK::RefPtr<SQL::AST::CommonTableExpressionList>)::$_3&&)
Line
Count
Source
105
1.61k
    {
106
1.61k
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
9.04M
        while (!has_errors() && !match(TokenType::Eof)) {
110
9.04M
            parse_callback();
111
112
9.04M
            if (!match(TokenType::Comma))
113
1.04k
                break;
114
115
9.04M
            consume(TokenType::Comma);
116
9.04M
        };
117
118
1.61k
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
1.61k
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_common_table_expression_list()::$_0>(bool, SQL::AST::Parser::parse_common_table_expression_list()::$_0&&)
Line
Count
Source
105
847
    {
106
847
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
124k
        while (!has_errors() && !match(TokenType::Eof)) {
110
124k
            parse_callback();
111
112
124k
            if (!match(TokenType::Comma))
113
688
                break;
114
115
123k
            consume(TokenType::Comma);
116
123k
        };
117
118
847
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
847
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_chained_expression(bool)::$_0>(bool, SQL::AST::Parser::parse_chained_expression(bool)::$_0&&)
Line
Count
Source
105
786k
    {
106
786k
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
10.4M
        while (!has_errors() && !match(TokenType::Eof)) {
110
10.2M
            parse_callback();
111
112
10.2M
            if (!match(TokenType::Comma))
113
534k
                break;
114
115
9.69M
            consume(TokenType::Comma);
116
9.69M
        };
117
118
786k
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
786k
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_in_expression(AK::NonnullRefPtr<SQL::AST::Expression>, bool)::$_0>(bool, SQL::AST::Parser::parse_in_expression(AK::NonnullRefPtr<SQL::AST::Expression>, bool)::$_0&&)
Line
Count
Source
105
36.9k
    {
106
36.9k
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
641k
        while (!has_errors() && !match(TokenType::Eof)) {
110
605k
            parse_callback();
111
112
605k
            if (!match(TokenType::Comma))
113
706
                break;
114
115
604k
            consume(TokenType::Comma);
116
604k
        };
117
118
36.9k
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
36.9k
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_common_table_expression()::$_0>(bool, SQL::AST::Parser::parse_common_table_expression()::$_0&&)
Line
Count
Source
105
422
    {
106
422
        if (surrounded_by_parentheses)
107
422
            consume(TokenType::ParenOpen);
108
109
1.46M
        while (!has_errors() && !match(TokenType::Eof)) {
110
1.46M
            parse_callback();
111
112
1.46M
            if (!match(TokenType::Comma))
113
376
                break;
114
115
1.46M
            consume(TokenType::Comma);
116
1.46M
        };
117
118
422
        if (surrounded_by_parentheses)
119
422
            consume(TokenType::ParenClose);
120
422
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_returning_clause()::$_0>(bool, SQL::AST::Parser::parse_returning_clause()::$_0&&)
Line
Count
Source
105
228
    {
106
228
        if (surrounded_by_parentheses)
107
0
            consume(TokenType::ParenOpen);
108
109
5.59M
        while (!has_errors() && !match(TokenType::Eof)) {
110
5.59M
            parse_callback();
111
112
5.59M
            if (!match(TokenType::Comma))
113
178
                break;
114
115
5.59M
            consume(TokenType::Comma);
116
5.59M
        };
117
118
228
        if (surrounded_by_parentheses)
119
0
            consume(TokenType::ParenClose);
120
228
    }
Parser.cpp:void SQL::AST::Parser::parse_comma_separated_list<SQL::AST::Parser::parse_table_or_subquery()::$_1>(bool, SQL::AST::Parser::parse_table_or_subquery()::$_1&&)
Line
Count
Source
105
11.3k
    {
106
11.3k
        if (surrounded_by_parentheses)
107
11.3k
            consume(TokenType::ParenOpen);
108
109
4.63M
        while (!has_errors() && !match(TokenType::Eof)) {
110
4.63M
            parse_callback();
111
112
4.63M
            if (!match(TokenType::Comma))
113
10.4k
                break;
114
115
4.62M
            consume(TokenType::Comma);
116
4.62M
        };
117
118
11.3k
        if (surrounded_by_parentheses)
119
11.3k
            consume(TokenType::ParenClose);
120
11.3k
    }
121
122
    Token consume();
123
    Token consume(TokenType type);
124
    bool consume_if(TokenType type);
125
    bool match(TokenType type) const;
126
127
    void expected(StringView what);
128
    void syntax_error(ByteString message);
129
130
    SourcePosition position() const;
131
132
    ParserState m_parser_state;
133
};
134
135
}