LCOV - code coverage report
Current view: top level - src/parse - Parser.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 737 750 98.3 %
Date: 2025-03-25 01:19:55 Functions: 68 69 98.6 %
Branches: 1027 1733 59.3 %

           Branch data     Line data    Source code
       1                 :            : #include "parse/Parser.hpp"
       2                 :            : 
       3                 :            : #include <cerrno>
       4                 :            : #include <cstdlib>
       5                 :            : #include <initializer_list>
       6                 :            : #include <mutable/catalog/Catalog.hpp>
       7                 :          1 : #include <mutable/catalog/Schema.hpp>
       8                 :          1 : #include <utility>
       9                 :          1 : 
      10                 :          1 : 
      11                 :          1 : using namespace m;
      12                 :          1 : using namespace m::ast;
      13                 :          1 : 
      14                 :          1 : 
      15                 :          1 : namespace {
      16                 :          1 : 
      17                 :          1 : /** Returns the precedence of an operator.  A higher value means the operator has higher precedence. */
      18                 :       6480 : int get_precedence(const TokenType tt)
      19                 :          1 : {
      20                 :       6480 :     int p = 0;
      21                 :          1 :     /* List all binary operators.  The higher up an operator is in the switch statement, the higher its precedence. */
      22   [ +  +  +  +  :       6480 :     switch (tt) {
             +  +  +  +  
                      + ]
      23                 :       5113 :         default:                    return -1;
      24                 :          1 :         /* bitwise NOT */
      25                 :         90 :         case TK_TILDE:              ++p;
      26                 :          1 :         /* multiplicative */
      27                 :          1 :         case TK_ASTERISK:
      28                 :          1 :         case TK_SLASH:
      29                 :        158 :         case TK_PERCENT:            ++p;
      30                 :          1 :         /* additive */
      31                 :          1 :         case TK_PLUS:
      32                 :        232 :         case TK_MINUS:              ++p;
      33                 :          1 :         /* string concat */
      34                 :        246 :         case TK_DOTDOT:             ++p;
      35                 :          1 :         /* comparison */
      36                 :          1 :         case TK_LESS:
      37                 :          1 :         case TK_GREATER:
      38                 :          1 :         case TK_LESS_EQUAL:
      39                 :          1 :         case TK_GREATER_EQUAL:
      40                 :          1 :         case TK_EQUAL:
      41                 :          1 :         case TK_BANG_EQUAL:
      42                 :        770 :         case TK_Like:               ++p;
      43                 :          1 :         /* logical NOT */
      44                 :        805 :         case TK_Not:                ++p;
      45                 :            :         /* logical AND */
      46                 :       1339 :         case TK_And:                ++p;
      47                 :            :         /* logical OR */
      48                 :       1367 :         case TK_Or:                 ++p;
      49                 :       1367 :     }
      50                 :       1367 :     return p;
      51                 :       6479 : }
      52                 :            : 
      53                 :            : /** Returns `true` if \p tt is an integral `TokenType`. */
      54                 :          4 : bool is_integer(TokenType tt)
      55                 :            : {
      56         [ +  + ]:          4 :     switch (tt) {
      57                 :            :         case TK_OCT_INT:
      58                 :            :         case TK_DEC_INT:
      59                 :            :         case TK_HEX_INT:
      60                 :          3 :             return true;
      61                 :            : 
      62                 :            :         default:
      63                 :          1 :             return false;
      64                 :            :     }
      65                 :          4 : }
      66                 :            : 
      67                 :          0 : }
      68                 :            : 
      69                 :            : 
      70                 :            : /*======================================================================================================================
      71                 :            :  * Follow sets
      72                 :            :  *====================================================================================================================*/
      73                 :            : 
      74                 :          1 : namespace {
      75                 :            : 
      76                 :         38 : constexpr Parser::follow_set_t make_follow_set(std::initializer_list<TokenType> tokens)
      77                 :            : {
      78                 :         38 :     Parser::follow_set_t F{};
      79         [ +  + ]:        359 :     for (TokenType tk : tokens) {
      80                 :        321 :         M_insist(tk < TokenType::TokenType_MAX);
      81                 :        321 :         F[tk] = true;
      82                 :            :     }
      83                 :         38 :     return F;
      84                 :            : }
      85                 :            : 
      86                 :            : #define M_FOLLOW(NAME, SET) \
      87                 :            : const Parser::follow_set_t follow_set_##NAME = make_follow_set SET ;
      88                 :            : #include "tables/FollowSet.tbl"
      89                 :            : #undef M_FOLLOW
      90                 :            : 
      91                 :            : }
      92                 :            : 
      93                 :            : 
      94                 :            : /*======================================================================================================================
      95                 :            :  * Parser
      96                 :            :  *====================================================================================================================*/
      97                 :            : 
      98                 :        203 : std::unique_ptr<Command> Parser::parse()
      99                 :            : {
     100         [ +  + ]:        203 :     if (token().type == TK_INSTRUCTION)
     101                 :          3 :         return parse_Instruction();
     102                 :            :     else
     103                 :        200 :         return parse_Stmt();
     104                 :        203 : }
     105                 :            : 
     106                 :         19 : std::unique_ptr<Instruction> Parser::parse_Instruction()
     107                 :            : {
     108                 :         19 :     auto &C = Catalog::Get();
     109                 :         19 :     M_insist(is(TK_INSTRUCTION));
     110                 :            : 
     111                 :         19 :     Token instr = consume();
     112         [ +  - ]:         19 :     std::string_view sv(*(instr.text));
     113                 :         19 :     const char *delimiter = " \n";
     114                 :            : 
     115                 :            :     /*----- Isolate the instruction's name -----*/
     116                 :         19 :     std::string::size_type end = sv.find_first_of(delimiter);
     117   [ +  -  +  - ]:         19 :     ThreadSafePooledString instruction_name = C.pool(sv.substr(1, end - 1)); // skip leading `\`
     118                 :            : 
     119                 :            :     /*----- Separate the arguments. -----*/
     120                 :         19 :     std::vector<std::string> args;
     121                 :         45 :     for (;;) {
     122                 :         45 :         std::string::size_type start = sv.find_first_not_of(delimiter, end);
     123         [ +  + ]:         45 :         if (start == std::string::npos)
     124                 :         19 :             break;
     125                 :         26 :         end = sv.find_first_of(delimiter, start);
     126   [ +  -  +  - ]:         26 :         args.emplace_back(sv.substr(start, end - start));
     127                 :            :     }
     128                 :            : 
     129         [ +  - ]:         19 :     expect(TK_SEMICOL);
     130         [ +  - ]:         19 :     return std::make_unique<Instruction>(std::move(instr), std::move(instruction_name), std::move(args));
     131                 :         19 : }
     132                 :            : 
     133                 :       1358 : std::unique_ptr<Stmt> Parser::parse_Stmt()
     134                 :            : {
     135                 :       1358 :     Token start = token();
     136                 :       1358 :     std::unique_ptr<Stmt> stmt = nullptr;
     137   [ +  -  +  +  :       1358 :     switch (token().type) {
          +  +  +  +  +  
                +  +  + ]
     138                 :            :         default:
     139   [ +  -  +  - ]:          2 :             stmt = std::make_unique<ErrorStmt>(token());
     140   [ +  -  +  -  :          2 :             diag.e(token().pos) << "expected a statement, got " << token().text << '\n';
          +  -  +  -  +  
                -  +  - ]
     141         [ +  - ]:          2 :             consume();
     142   [ +  -  +  - ]:          2 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     143                 :            : 
     144   [ +  -  +  - ]:          1 :         case TK_SEMICOL: return std::make_unique<EmptyStmt>(consume());
     145                 :            : 
     146                 :            :         case TK_Create:
     147   [ +  -  +  +  :         41 :             switch (token<1>().type) {
                   +  + ]
     148                 :            :                 default:
     149   [ +  -  +  - ]:          1 :                     stmt = std::make_unique<ErrorStmt>(token());
     150   [ +  -  +  -  :          1 :                     diag.e(token<1>().pos) << "expected a create database statement or a create table statement, got "
                   +  - ]
     151   [ +  -  +  -  :          1 :                                            << token<1>().text << '\n';
                   +  - ]
     152         [ +  - ]:          1 :                     consume();
     153   [ +  -  -  + ]:          1 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     154                 :            : 
     155         [ +  - ]:          4 :                 case TK_Database: stmt = parse_CreateDatabaseStmt(); break;
     156         [ +  - ]:         29 :                 case TK_Table:    stmt = parse_CreateTableStmt(); break;
     157                 :            :                 case TK_Unique:
     158         [ +  - ]:          7 :                 case TK_Index:    stmt = parse_CreateIndexStmt(); break;
     159                 :            :             }
     160                 :         40 :             break;
     161                 :            : 
     162                 :            :         case TK_Drop:
     163   [ +  -  -  +  :         11 :             switch (token<1>().type) {
                   +  + ]
     164                 :            :                 default:
     165   [ #  #  #  # ]:          0 :                     stmt = std::make_unique<ErrorStmt>(token());
     166   [ #  #  #  #  :          0 :                     diag.e(token().pos) << "expected a drop database, table, or index statement, got "
                   #  # ]
     167   [ #  #  #  #  :          0 :                                         << token().text << '\n';
                   #  # ]
     168         [ #  # ]:          0 :                     consume();
     169   [ #  #  #  # ]:          0 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     170                 :            : 
     171         [ +  - ]:          3 :                 case TK_Database: stmt = parse_DropDatabaseStmt(); break;
     172         [ +  - ]:          4 :                 case TK_Table:    stmt = parse_DropTableStmt(); break;
     173         [ +  - ]:          4 :                 case TK_Index:    stmt = parse_DropIndexStmt(); break;
     174                 :            :             }
     175                 :         11 :             break;
     176                 :            : 
     177         [ +  - ]:          6 :         case TK_Use:    stmt = parse_UseDatabaseStmt(); break;
     178         [ +  - ]:        511 :         case TK_Select: stmt = parse_SelectStmt(); break;
     179         [ +  - ]:        770 :         case TK_Insert: stmt = parse_InsertStmt(); break;
     180         [ +  - ]:          3 :         case TK_Update: stmt = parse_UpdateStmt(); break;
     181         [ +  - ]:          2 :         case TK_Delete: stmt = parse_DeleteStmt(); break;
     182         [ +  - ]:         11 :         case TK_Import: stmt = parse_ImportStmt(); break;
     183                 :            :     }
     184         [ +  - ]:       1354 :     expect(TK_SEMICOL);
     185                 :       1354 :     return stmt;
     186                 :       1358 : }
     187                 :            : 
     188                 :            : /*======================================================================================================================
     189                 :            :  * statements
     190                 :            :  *====================================================================================================================*/
     191                 :            : 
     192                 :         12 : std::unique_ptr<Stmt> Parser::parse_CreateDatabaseStmt()
     193                 :            : {
     194                 :         12 :     Token start = token();
     195                 :            : 
     196                 :            :     /* 'CREATE' 'DATABASE' identifier */
     197   [ +  -  +  + ]:         12 :     if (not expect(TK_Create)) {
     198         [ +  - ]:          1 :         consume();
     199   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     200                 :            :     }
     201                 :            : 
     202   [ +  -  +  + ]:         11 :     if (not expect(TK_Database))
     203   [ +  -  +  - ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     204                 :            : 
     205   [ +  -  +  - ]:          8 :     Token database_name = token();
     206   [ +  -  +  + ]:          8 :     if (not expect(TK_IDENTIFIER))
     207   [ +  -  -  + ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     208                 :            : 
     209         [ +  - ]:          6 :     return std::make_unique<CreateDatabaseStmt>(std::move(database_name));
     210                 :         12 : }
     211                 :            : 
     212                 :         15 : std::unique_ptr<Stmt> Parser::parse_DropDatabaseStmt()
     213                 :            : {
     214                 :         15 :     Token start = token();
     215                 :            : 
     216                 :            :     /* 'DROP' 'DATABASE' */
     217   [ +  -  +  + ]:         15 :     if (not expect(TK_Drop)) {
     218         [ +  - ]:          2 :         consume();
     219   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     220                 :            :     }
     221                 :            : 
     222   [ +  -  +  + ]:         13 :     if (not expect(TK_Database))
     223   [ +  -  +  - ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     224                 :            : 
     225                 :            :     /* [ 'IF' 'EXISTS' ] */
     226                 :         10 :     bool has_if_exists = false;
     227   [ +  -  +  + ]:         10 :     if (accept(TK_If)) {
     228   [ +  -  +  + ]:          5 :         if (not expect(TK_Exists))
     229   [ +  -  -  + ]:          2 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     230                 :          3 :         has_if_exists = true;
     231                 :          3 :     }
     232                 :            : 
     233                 :            :     /* identifier */
     234   [ +  -  +  - ]:          8 :     Token database_name = token();
     235   [ +  -  +  + ]:          8 :     if (not expect(TK_IDENTIFIER))
     236   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     237                 :            : 
     238         [ +  - ]:          7 :     return std::make_unique<DropDatabaseStmt>(std::move(database_name), has_if_exists);
     239                 :         15 : }
     240                 :            : 
     241                 :         13 : std::unique_ptr<Stmt> Parser::parse_UseDatabaseStmt()
     242                 :            : {
     243                 :         13 :     Token start = token();
     244                 :            : 
     245                 :            :     /* 'USE' identifier */
     246   [ +  -  +  + ]:         13 :     if (not expect(TK_Use)) {
     247         [ +  - ]:          2 :         consume();
     248   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     249                 :            :     }
     250                 :            : 
     251   [ +  -  +  - ]:         11 :     Token database_name = token();
     252   [ +  -  +  + ]:         11 :     if (not expect(TK_IDENTIFIER))
     253   [ +  -  -  + ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     254                 :            : 
     255         [ +  - ]:          8 :     return std::make_unique<UseDatabaseStmt>(std::move(database_name));
     256                 :         13 : }
     257                 :            : 
     258                 :         59 : std::unique_ptr<Stmt> Parser::parse_CreateTableStmt()
     259                 :            : {
     260                 :         59 :     Token start = token();
     261                 :         59 :     std::vector<std::unique_ptr<CreateTableStmt::attribute_definition>> attrs;
     262                 :            : 
     263                 :            :     /* 'CREATE' 'TABLE' identifier '(' */
     264   [ +  -  +  + ]:         59 :     if (not expect(TK_Create)) {
     265         [ +  - ]:          1 :         consume();
     266   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     267                 :            :     }
     268                 :            : 
     269   [ +  -  +  + ]:         58 :     if (not expect(TK_Table))
     270   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     271                 :            : 
     272   [ +  -  +  - ]:         56 :     Token table_name = token();
     273   [ +  -  +  + ]:         56 :     if (not expect(TK_IDENTIFIER))
     274   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     275                 :            : 
     276   [ +  -  +  + ]:         54 :     if (not expect(TK_LPAR))
     277   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     278                 :            : 
     279                 :            :     /* identifier data-type { constraint } [ ',' identifier data-type { constraint } ] */
     280                 :         53 :     do {
     281   [ +  -  +  - ]:         98 :         Token id = token();
     282   [ +  -  +  + ]:         98 :         if (not expect(TK_IDENTIFIER))
     283   [ +  -  +  - ]:          3 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     284                 :            : 
     285   [ +  -  +  - ]:         95 :         const Type *type = M_notnull(parse_data_type());
     286                 :            : 
     287                 :            :         /* Parse the list of constraints. */
     288                 :         95 :         std::vector<std::unique_ptr<Constraint>> constraints;
     289                 :        140 :         for (;;) {
     290   [ +  -  +  +  :        140 :             switch (token().type) {
             +  +  +  + ]
     291                 :            :                 /* 'PRIMARY' 'KEY' */
     292                 :            :                 case TK_Primary: {
     293         [ +  - ]:         19 :                     Token tok = consume();
     294   [ +  -  +  + ]:         19 :                     if (not expect(TK_Key)) goto constraint_error_recovery;
     295   [ +  -  +  - ]:         18 :                     constraints.push_back(std::make_unique<PrimaryKeyConstraint>(std::move(tok)));
     296                 :         18 :                     break;
     297                 :         19 :                 }
     298                 :            : 
     299                 :            :                 /* 'NOT' 'NULL' */
     300                 :            :                 case TK_Not: {
     301         [ +  - ]:          7 :                     Token tok = consume();
     302   [ +  -  +  + ]:          7 :                     if (not expect(TK_Null)) goto constraint_error_recovery;
     303   [ +  -  +  - ]:          6 :                     constraints.push_back(std::make_unique<NotNullConstraint>(std::move(tok)));
     304                 :          6 :                     break;
     305         [ -  + ]:          7 :                 }
     306                 :            : 
     307                 :            :                 /* 'UNIQUE' */
     308                 :            :                 case TK_Unique: {
     309         [ +  - ]:          6 :                     Token tok = consume();
     310   [ +  -  +  - ]:          6 :                     constraints.push_back(std::make_unique<UniqueConstraint>(std::move(tok)));
     311                 :            :                     break;
     312                 :          6 :                 }
     313                 :            : 
     314                 :            :                 /* 'CHECK' '(' expression ')' */
     315                 :            :                 case TK_Check: {
     316         [ +  - ]:          8 :                     Token tok = consume();
     317   [ +  -  +  + ]:          8 :                     if (not expect(TK_LPAR)) goto constraint_error_recovery;
     318         [ +  - ]:          7 :                     std::unique_ptr<Expr> cond = parse_Expr();
     319   [ +  -  +  - ]:          7 :                     if (not expect(TK_RPAR)) goto constraint_error_recovery;
     320   [ +  -  -  + ]:          7 :                     constraints.push_back(std::make_unique<CheckConditionConstraint>(std::move(tok), std::move(cond)));
     321                 :          7 :                     break;
     322                 :          8 :                 }
     323                 :            : 
     324                 :            :                 /* 'REFERENCES' identifier '(' identifier ')' */
     325                 :            :                 case TK_References: {
     326         [ +  - ]:         12 :                     Token tok = consume();
     327   [ +  -  +  - ]:         12 :                     Token ref_table_name = token();
     328   [ +  -  +  + ]:         12 :                     if (not expect(TK_IDENTIFIER)) goto constraint_error_recovery;
     329   [ +  -  +  + ]:         10 :                     if (not expect(TK_LPAR)) goto constraint_error_recovery;
     330   [ +  -  +  - ]:          8 :                     Token attr_name = token();
     331   [ +  -  +  - ]:          8 :                     if (not expect(TK_IDENTIFIER)) goto constraint_error_recovery;
     332   [ +  -  +  - ]:          8 :                     if (not expect(TK_RPAR)) goto constraint_error_recovery;
     333   [ +  -  +  - ]:          8 :                     constraints.push_back(std::make_unique<ReferenceConstraint>(
     334                 :            :                         std::move(tok),
     335                 :            :                         std::move(ref_table_name),
     336                 :            :                         std::move(attr_name),
     337                 :          8 :                         ReferenceConstraint::ON_DELETE_RESTRICT)
     338                 :            :                     );
     339                 :          8 :                     break;
     340                 :         12 :                 }
     341                 :            : 
     342                 :            :                 default:
     343                 :         88 :                     goto exit_constraints;
     344                 :            :             }
     345                 :            : 
     346                 :            :         }
     347                 :            : constraint_error_recovery:
     348         [ +  - ]:          7 :         recover(follow_set_CONSTRAINT);
     349                 :            : exit_constraints:
     350   [ +  -  +  - ]:         95 :         attrs.push_back(std::make_unique<CreateTableStmt::attribute_definition>(std::move(id),
     351                 :            :                                                                                 std::move(type),
     352                 :            :                                                                                 std::move(constraints)));
     353   [ +  +  +  -  :         98 :     } while (accept(TK_COMMA));
                   +  + ]
     354                 :            : 
     355                 :            :     /* ')' */
     356   [ +  -  +  + ]:         50 :     if (not expect(TK_RPAR))
     357   [ +  -  +  - ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     358                 :            : 
     359         [ +  - ]:         47 :     return std::make_unique<CreateTableStmt>(std::move(table_name), std::move(attrs));
     360                 :         59 : }
     361                 :            : 
     362                 :         20 : std::unique_ptr<Stmt> Parser::parse_DropTableStmt()
     363                 :            : {
     364                 :         20 :     Token start = token();
     365                 :            : 
     366                 :            :     /* 'DROP' 'TABLE' */
     367   [ +  -  +  + ]:         20 :     if (not expect(TK_Drop)) {
     368         [ +  - ]:          2 :         consume();
     369   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     370                 :            :     }
     371                 :            : 
     372   [ +  -  +  + ]:         18 :     if (not expect(TK_Table))
     373   [ +  -  +  - ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     374                 :            : 
     375                 :            :     /* [ 'IF' 'EXISTS' ] */
     376                 :         15 :     bool has_if_exists = false;
     377   [ +  -  +  + ]:         15 :     if (accept(TK_If)) {
     378   [ +  -  +  + ]:          8 :         if (not expect(TK_Exists))
     379   [ +  -  -  + ]:          2 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     380                 :          6 :         has_if_exists = true;
     381                 :          6 :     }
     382                 :            : 
     383                 :            :     /* identifier { ',' identifier } */
     384                 :         13 :     std::vector<std::unique_ptr<Token>> table_names;
     385                 :         13 :     do {
     386   [ +  -  +  - ]:         17 :         Token table_name = token();
     387   [ +  -  +  + ]:         17 :         if (not expect(TK_IDENTIFIER))
     388   [ +  -  +  - ]:          5 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     389   [ +  -  +  - ]:         12 :         table_names.emplace_back(std::make_unique<Token>(std::move(table_name)));
     390   [ +  +  +  -  :         17 :     } while (accept(TK_COMMA));
                   +  + ]
     391                 :            : 
     392         [ +  - ]:          8 :     return std::make_unique<DropTableStmt>(std::move(table_names), has_if_exists);
     393                 :         20 : }
     394                 :            : 
     395                 :         32 : std::unique_ptr<Stmt> Parser::parse_CreateIndexStmt()
     396                 :            : {
     397                 :         32 :     Token start = token();
     398                 :            : 
     399                 :            :     /* 'CREATE' [ 'UNIQUE' ] 'INDEX' */
     400   [ +  -  +  + ]:         32 :     if (not expect(TK_Create))
     401   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     402                 :            : 
     403         [ +  - ]:         31 :     Token has_unique = Token::CreateArtificial();
     404   [ +  -  +  -  :         31 :     if (token() == TK_Unique)
                   +  + ]
     405   [ +  -  +  - ]:          3 :         has_unique = consume();
     406                 :            : 
     407   [ +  -  +  + ]:         31 :     if (not expect(TK_Index))
     408   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     409                 :            : 
     410                 :            :     /* [ [ 'IF' 'NOT' 'EXISTS' ] identifier ] */
     411                 :         29 :     bool has_if_not_exists = false;
     412         [ +  - ]:         29 :     Token index_name = Token::CreateArtificial();
     413   [ +  -  +  + ]:         29 :     if (accept(TK_If)) {
     414   [ +  -  -  + ]:          3 :         if (not expect(TK_Not))
     415   [ #  #  #  # ]:          0 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     416   [ +  -  -  + ]:          3 :         if (not expect(TK_Exists))
     417   [ #  #  #  # ]:          0 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     418                 :          3 :         has_if_not_exists = true;
     419   [ +  -  +  - ]:          3 :         index_name = token();
     420   [ +  -  +  + ]:          3 :         if (not expect(TK_IDENTIFIER))
     421   [ +  -  +  - ]:          1 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     422   [ +  -  +  + ]:         28 :     } else if (token().type == TK_IDENTIFIER)
     423   [ +  -  +  - ]:          5 :         index_name = consume();
     424                 :            : 
     425                 :            :     /* 'ON' identifier */
     426   [ +  -  +  + ]:         28 :     if (not expect(TK_On))
     427   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     428                 :            : 
     429   [ +  -  +  - ]:         27 :     Token table_name = token();
     430   [ +  -  +  + ]:         27 :     if (not expect(TK_IDENTIFIER))
     431   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     432                 :            : 
     433                 :            :     /* [ 'USING' identifier */
     434         [ +  - ]:         26 :     Token method = Token::CreateArtificial();
     435   [ +  -  +  + ]:         26 :     if (accept(TK_Using)) {
     436   [ +  -  +  +  :          5 :         if (token().type != TK_IDENTIFIER and token().type != TK_Default) {
             +  -  +  + ]
     437   [ +  -  +  -  :          1 :             diag.e(token().pos) << "expected an identifier or DEFAULT, got " << token().text << '\n';
          +  -  +  -  +  
                -  +  - ]
     438   [ +  -  +  - ]:          1 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     439                 :            :         }
     440   [ +  -  +  - ]:          4 :         method = consume();
     441                 :          4 :     }
     442                 :            : 
     443                 :            :     /* '(' key_field { ',' key_field } ')' */
     444   [ +  -  +  + ]:         25 :     if (not expect(TK_LPAR))
     445   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     446                 :         23 :     std::vector<std::unique_ptr<Expr>> key_fields;
     447                 :         23 :     do {
     448   [ +  -  +  +  :         29 :         switch (token().type) {
                      + ]
     449                 :            :             /* identifier */
     450                 :            :             case TK_IDENTIFIER: {
     451   [ +  -  +  - ]:         21 :                 auto id = std::make_unique<Designator>(consume());
     452         [ +  - ]:         21 :                 key_fields.emplace_back(std::move(id));
     453                 :            :                 break;
     454                 :         21 :             }
     455                 :            :             /* '(' expression ')' */
     456                 :            :             case TK_LPAR: {
     457         [ +  - ]:          6 :                 auto expr = parse_Expr();
     458         [ +  - ]:          6 :                 key_fields.emplace_back(std::move(expr));
     459                 :            :                 break;
     460                 :          6 :             }
     461                 :            :             default: {
     462   [ +  -  +  -  :          2 :                 diag.e(token().pos) << "expected an identifier or expression, got " << token().text << '\n';
          +  -  +  -  +  
                -  +  - ]
     463   [ +  -  +  - ]:          2 :                 return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     464                 :            :             }
     465                 :            :         }
     466   [ +  -  +  + ]:         27 :     } while(accept(TK_COMMA));
     467   [ +  -  +  + ]:         21 :     if (not expect(TK_RPAR))
     468   [ +  -  -  + ]:          5 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     469                 :            : 
     470         [ +  - ]:         16 :     return std::make_unique<CreateIndexStmt>(
     471                 :            :         /* has_unique=        */ std::move(has_unique),
     472                 :            :         /* has_if_not_exists= */ has_if_not_exists,
     473                 :            :         /* index_name=        */ std::move(index_name),
     474                 :            :         /* table_name=        */ std::move(table_name),
     475                 :            :         /* method=            */ std::move(method),
     476                 :            :         /* key_fields=        */ std::move(key_fields)
     477                 :            :     );
     478                 :         32 : }
     479                 :            : 
     480                 :         20 : std::unique_ptr<Stmt> Parser::parse_DropIndexStmt()
     481                 :            : {
     482                 :         20 :     Token start = token();
     483                 :            : 
     484                 :            :     /* 'DROP' 'INDEX' */
     485   [ +  -  +  + ]:         20 :     if (not expect(TK_Drop)) {
     486         [ +  - ]:          2 :         consume();
     487   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     488                 :            :     }
     489                 :            : 
     490   [ +  -  +  + ]:         18 :     if (not expect(TK_Index))
     491   [ +  -  +  - ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     492                 :            : 
     493                 :            :     /* [ 'IF' 'EXISTS' ] */
     494                 :         15 :     bool has_if_exists = false;
     495   [ +  -  +  + ]:         15 :     if (accept(TK_If)) {
     496   [ +  -  +  + ]:          8 :         if (not expect(TK_Exists))
     497   [ +  -  -  + ]:          2 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     498                 :          6 :         has_if_exists = true;
     499                 :          6 :     }
     500                 :            : 
     501                 :            :     /* identifier { ',' identifier } */
     502                 :         13 :     std::vector<std::unique_ptr<Token>> index_names;
     503                 :         13 :     do {
     504   [ +  -  +  - ]:         17 :         Token index_name = token();
     505   [ +  -  +  + ]:         17 :         if (not expect(TK_IDENTIFIER))
     506   [ +  -  +  - ]:          5 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     507   [ +  -  +  - ]:         12 :         index_names.emplace_back(std::make_unique<Token>(std::move(index_name)));
     508   [ +  +  +  -  :         17 :     } while (accept(TK_COMMA));
                   +  + ]
     509                 :            : 
     510         [ +  - ]:          8 :     return std::make_unique<DropIndexStmt>(std::move(index_names), has_if_exists);
     511                 :         20 : }
     512                 :            : 
     513                 :        608 : std::unique_ptr<Stmt> Parser::parse_SelectStmt()
     514                 :            : {
     515                 :        608 :     std::unique_ptr<Clause> select = parse_SelectClause();
     516                 :        608 :     std::unique_ptr<Clause> from = nullptr;
     517                 :        608 :     std::unique_ptr<Clause> where = nullptr;
     518                 :        608 :     std::unique_ptr<Clause> group_by = nullptr;
     519                 :        608 :     std::unique_ptr<Clause> having = nullptr;
     520                 :        608 :     std::unique_ptr<Clause> order_by = nullptr;
     521                 :        608 :     std::unique_ptr<Clause> limit = nullptr;
     522                 :            : 
     523   [ +  -  +  -  :        608 :     if (token() == TK_From)
                   +  + ]
     524         [ +  - ]:        564 :         from = parse_FromClause();
     525   [ +  -  +  -  :        608 :     if (token() == TK_Where)
                   +  + ]
     526         [ +  - ]:        203 :         where = parse_WhereClause();
     527   [ +  -  +  -  :        608 :     if (token() == TK_Group)
                   +  + ]
     528         [ +  - ]:         62 :         group_by = parse_GroupByClause();
     529   [ +  -  +  -  :        608 :     if (token() == TK_Having)
                   +  + ]
     530         [ +  - ]:         44 :         having = parse_HavingClause();
     531   [ +  -  +  -  :        608 :     if (token() == TK_Order)
                   +  + ]
     532         [ +  - ]:         37 :         order_by = parse_OrderByClause();
     533   [ +  -  +  -  :        608 :     if (token() == TK_Limit)
                   +  + ]
     534         [ +  - ]:          8 :         limit = parse_LimitClause();
     535                 :            : 
     536         [ +  - ]:        608 :     return std::make_unique<SelectStmt>(std::move(select),
     537                 :            :                                         std::move(from),
     538                 :            :                                         std::move(where),
     539                 :            :                                         std::move(group_by),
     540                 :            :                                         std::move(having),
     541                 :            :                                         std::move(order_by),
     542                 :            :                                         std::move(limit));
     543                 :        608 : }
     544                 :            : 
     545                 :        788 : std::unique_ptr<Stmt> Parser::parse_InsertStmt()
     546                 :            : {
     547                 :        788 :     Token start = token();
     548                 :            : 
     549                 :            :     /* 'INSERT' 'INTO' identifier 'VALUES' */
     550   [ +  -  +  + ]:        788 :     if (not expect(TK_Insert)) {
     551         [ +  - ]:          1 :         consume();
     552   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     553                 :            :     }
     554                 :            : 
     555   [ +  -  +  + ]:        787 :     if (not expect(TK_Into))
     556   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     557                 :            : 
     558   [ +  -  +  - ]:        785 :     Token table_name = token();
     559   [ +  -  +  + ]:        785 :     if (not expect(TK_IDENTIFIER))
     560   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     561                 :            : 
     562   [ +  -  +  + ]:        783 :     if (not expect(TK_Values))
     563   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     564                 :            : 
     565                 :            :     /* tuple { ',' tuple } */
     566                 :        781 :     std::vector<InsertStmt::tuple_t> tuples;
     567                 :        781 :     do {
     568                 :            :         /* '(' ( 'DEFAULT' | 'NULL' | expression ) { ',' ( 'DEFAULT' | 'NULL' | expression ) } ')' */
     569                 :        861 :         InsertStmt::tuple_t tuple;
     570   [ +  -  +  + ]:        861 :         if (not expect(TK_LPAR)) goto tuple_error_recovery;
     571                 :        859 :         do {
     572   [ +  -  +  +  :       3422 :             switch (token().type) {
                      + ]
     573                 :            :                 case TK_Default:
     574         [ +  - ]:          6 :                     consume();
     575         [ +  - ]:          6 :                     tuple.emplace_back(InsertStmt::I_Default, nullptr);
     576                 :          6 :                     break;
     577                 :            : 
     578                 :            :                 case TK_Null:
     579         [ +  - ]:        186 :                     consume();
     580         [ +  - ]:        186 :                     tuple.emplace_back(InsertStmt::I_Null, nullptr);
     581                 :        186 :                     break;
     582                 :            : 
     583                 :            :                 default: {
     584         [ -  + ]:       3230 :                     auto e = parse_Expr();
     585         [ +  - ]:       3230 :                     tuple.emplace_back(InsertStmt::I_Expr, std::move(e));
     586                 :            :                     break;
     587                 :       3230 :                 }
     588                 :            :             }
     589   [ +  -  +  + ]:       3422 :         } while (accept(TK_COMMA));
     590   [ +  -  +  + ]:        859 :         if (not expect(TK_RPAR)) goto tuple_error_recovery;
     591         [ +  - ]:        858 :         tuples.emplace_back(std::move(tuple));
     592                 :        858 :         continue;
     593                 :            : tuple_error_recovery:
     594         [ +  - ]:          3 :         recover(follow_set_TUPLE);
     595   [ -  +  +  +  :        861 :     } while (accept(TK_COMMA));
                -  +  + ]
     596                 :            : 
     597         [ +  - ]:        781 :     return std::make_unique<InsertStmt>(std::move(table_name), std::move(tuples));
     598                 :        788 : }
     599                 :            : 
     600                 :         14 : std::unique_ptr<Stmt> Parser::parse_UpdateStmt()
     601                 :            : {
     602                 :         14 :     Token start = token();
     603                 :            : 
     604                 :            :     /* 'UPDATE' identifier 'SET' */
     605   [ +  -  +  + ]:         14 :     if (not expect(TK_Update)) {
     606         [ +  - ]:          1 :         consume();
     607   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     608                 :            :     }
     609                 :            : 
     610   [ +  -  +  - ]:         13 :     Token table_name = token();
     611   [ +  -  +  + ]:         13 :     if (not expect(TK_IDENTIFIER))
     612   [ +  -  +  - ]:          1 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     613                 :            : 
     614   [ +  -  +  + ]:         12 :     if (not expect(TK_Set))
     615   [ +  -  -  + ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     616                 :            : 
     617                 :            :     /* identifier '=' expression { ',' identifier '=' expression } ; */
     618                 :         10 :     std::vector<UpdateStmt::set_type> set;
     619                 :         10 :     do {
     620   [ +  -  +  - ]:         12 :         auto id = token();
     621   [ +  -  -  + ]:         12 :         if (not expect(TK_IDENTIFIER))
     622   [ #  #  #  # ]:          0 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     623                 :            : 
     624   [ +  -  +  + ]:         12 :         if (not expect(TK_EQUAL))
     625   [ +  -  +  - ]:          2 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     626                 :            : 
     627         [ +  - ]:         10 :         auto e = parse_Expr();
     628         [ +  - ]:         10 :         set.emplace_back(id, std::move(e));
     629   [ +  +  +  -  :         12 :     } while (accept(TK_COMMA));
                   +  + ]
     630                 :            : 
     631                 :            :     /* [ where-clause ] */
     632                 :          8 :     std::unique_ptr<Clause> where = nullptr;
     633   [ +  -  +  -  :          8 :     if (token() == TK_Where)
                   +  + ]
     634         [ +  - ]:          1 :         where = parse_WhereClause();
     635                 :            : 
     636         [ +  - ]:          8 :     return std::make_unique<UpdateStmt>(std::move(table_name), std::move(set), std::move(where));
     637                 :         14 : }
     638                 :            : 
     639                 :         14 : std::unique_ptr<Stmt> Parser::parse_DeleteStmt()
     640                 :            : {
     641                 :         14 :     Token start = token();
     642                 :            : 
     643                 :            :     /* 'DELETE' 'FROM' identifier */
     644   [ +  -  +  + ]:         14 :     if (not expect(TK_Delete)) {
     645         [ +  - ]:          2 :         consume();
     646   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     647                 :            :     }
     648                 :            : 
     649   [ +  -  +  + ]:         12 :     if (not expect(TK_From))
     650   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     651                 :            : 
     652   [ +  -  +  - ]:         10 :     Token table_name = token();
     653   [ +  -  +  + ]:         10 :     if (not expect(TK_IDENTIFIER))
     654   [ +  -  -  + ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     655                 :            : 
     656                 :            :     /*[ where-clause ] ; */
     657                 :          7 :     std::unique_ptr<Clause> where = nullptr;
     658   [ +  -  +  -  :          7 :     if (token() == TK_Where)
                   +  + ]
     659         [ +  - ]:          2 :         where = parse_WhereClause();
     660                 :            : 
     661         [ +  - ]:          7 :     return std::make_unique<DeleteStmt>(std::move(table_name), std::move(where));
     662                 :         14 : }
     663                 :            : 
     664                 :         41 : std::unique_ptr<Stmt> Parser::parse_ImportStmt()
     665                 :            : {
     666                 :         41 :     Token start = token();
     667                 :            : 
     668                 :            :     /* 'IMPORT' 'INTO' identifier */
     669   [ +  -  +  + ]:         41 :     if (not expect(TK_Import)) {
     670         [ +  - ]:          3 :         consume();
     671   [ +  -  +  - ]:          3 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     672                 :            :     }
     673                 :            : 
     674   [ +  -  +  + ]:         38 :     if (not expect(TK_Into))
     675   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     676                 :            : 
     677   [ +  -  +  - ]:         36 :     Token table_name = token();
     678   [ +  -  +  + ]:         36 :     if (not expect(TK_IDENTIFIER))
     679   [ +  -  +  - ]:          2 :         return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     680                 :            : 
     681   [ +  -  +  + ]:         34 :     switch (token().type) {
     682                 :            :         /* 'DSV' string-literal */
     683                 :            :         case TK_Dsv: {
     684         [ +  - ]:         33 :             consume();
     685   [ +  -  +  - ]:         33 :             DSVImportStmt stmt(std::move(table_name));
     686   [ +  -  +  - ]:         33 :             stmt.path = token();
     687                 :            : 
     688   [ +  -  +  + ]:         33 :             if (not expect(TK_STRING_LITERAL))
     689   [ +  -  +  - ]:          4 :                 return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     690                 :            : 
     691                 :            :             /* [ 'ROWS' integer-constant ] */
     692   [ +  -  +  + ]:         29 :             if (accept(TK_Rows)) {
     693   [ +  -  +  - ]:          1 :                 stmt.rows = token();
     694   [ +  -  +  -  :          1 :                 if (token() == TK_DEC_INT or token() == TK_OCT_INT) {
          -  +  #  #  #  
                #  #  # ]
     695         [ +  - ]:          1 :                     consume();
     696                 :          1 :                 } else {
     697   [ #  #  #  #  :          0 :                     diag.e(token().pos) << "expected a decimal integer, got " << token().text << '\n';
          #  #  #  #  #  
                #  #  # ]
     698   [ #  #  #  # ]:          0 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     699                 :            :                 }
     700                 :          1 :             }
     701                 :            : 
     702                 :            :             /* [ 'DELIMITER' string-literal ] */
     703   [ +  -  +  + ]:         29 :             if (accept(TK_Delimiter)) {
     704   [ +  -  +  - ]:          6 :                 stmt.delimiter = token();
     705   [ +  -  +  + ]:          6 :                 if (not expect(TK_STRING_LITERAL))
     706   [ +  -  +  - ]:          1 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     707                 :          5 :             }
     708                 :            : 
     709                 :            :             /* [ 'ESCAPE' string-literal ] */
     710   [ +  -  +  + ]:         28 :             if (accept(TK_Escape)) {
     711   [ +  -  +  - ]:          5 :                 stmt.escape = token();
     712   [ +  -  +  + ]:          5 :                 if (not expect(TK_STRING_LITERAL))
     713   [ +  -  +  - ]:          1 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     714                 :          4 :             }
     715                 :            : 
     716                 :            :             /* [ 'QUOTE' string-literal ] */
     717   [ +  -  +  + ]:         27 :             if (accept(TK_Quote)) {
     718   [ +  -  +  - ]:          6 :                 stmt.quote = token();
     719   [ +  -  +  + ]:          6 :                 if (not expect(TK_STRING_LITERAL))
     720   [ +  -  +  - ]:          1 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     721                 :          5 :             }
     722                 :            : 
     723                 :            :             /* [ 'HAS' 'HEADER' ] */
     724   [ +  -  +  + ]:         26 :             if (accept(TK_Has)) {
     725   [ +  -  +  + ]:          4 :                 if (not expect(TK_Header))
     726   [ +  -  +  - ]:          1 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     727                 :          3 :                 stmt.has_header = true;
     728                 :          3 :             }
     729                 :            : 
     730                 :            :             /* [ 'SKIP' 'HEADER' ] */
     731   [ +  -  +  + ]:         25 :             if (accept(TK_Skip)) {
     732   [ +  -  +  + ]:          5 :                 if (not expect(TK_Header))
     733   [ +  -  -  + ]:          1 :                     return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     734                 :          4 :                 stmt.skip_header = true;
     735                 :          4 :             }
     736                 :            : 
     737         [ +  - ]:         24 :             return std::make_unique<DSVImportStmt>(stmt);
     738                 :         33 :         }
     739                 :            : 
     740                 :            :         default:
     741   [ +  -  +  -  :          1 :             diag.e(token().pos) << "Unrecognized input format \"" << token().text << "\".\n";
          +  -  +  -  +  
                -  +  - ]
     742   [ +  -  +  - ]:          1 :             return recover<ErrorStmt>(std::move(start), follow_set_STATEMENT);
     743                 :            :     }
     744                 :         41 : }
     745                 :            : 
     746                 :            : /*======================================================================================================================
     747                 :            :  * Clauses
     748                 :            :  *====================================================================================================================*/
     749                 :            : 
     750                 :        639 : std::unique_ptr<Clause> Parser::parse_SelectClause()
     751                 :            : {
     752                 :        639 :     Token start = token();
     753                 :            : 
     754                 :            :     /* 'SELECT' */
     755   [ +  -  +  + ]:        639 :     if (not expect(TK_Select)) {
     756         [ +  - ]:          5 :         consume();
     757   [ +  -  +  - ]:          5 :         return recover<ErrorClause>(std::move(start), follow_set_SELECT_CLAUSE);
     758                 :            :     }
     759                 :            : 
     760                 :            :     /* ( '*' | expression [ [ 'AS' ] identifier ] ) */
     761         [ +  - ]:        634 :     Token select_all = Token::CreateArtificial();
     762                 :        634 :     std::vector<SelectClause::select_type> select;
     763   [ +  -  +  -  :        634 :     if (token() == TK_ASTERISK) {
                   +  + ]
     764   [ +  -  +  - ]:        296 :         select_all = token();
     765         [ +  - ]:        296 :         consume();
     766                 :        296 :     } else {
     767         [ +  - ]:        338 :         auto e = parse_Expr();
     768         [ +  - ]:        338 :         Token tok = Token::CreateArtificial();
     769   [ +  -  +  + ]:        338 :         if (accept(TK_As)) {
     770   [ +  -  +  - ]:         37 :             tok = token();
     771   [ +  -  +  + ]:         37 :             if (not expect(TK_IDENTIFIER))
     772   [ +  -  -  + ]:          2 :                 return recover<ErrorClause>(std::move(start), follow_set_SELECT_CLAUSE);
     773   [ +  -  +  + ]:        336 :         } else if (token().type == TK_IDENTIFIER) {
     774   [ +  -  +  - ]:          5 :             tok = token();
     775         [ +  - ]:          5 :             consume();
     776                 :          5 :         }
     777         [ +  - ]:        336 :         select.emplace_back(std::move(e), std::move(tok));
     778         [ +  + ]:        338 :     }
     779                 :            : 
     780                 :            :     /* { ',' expression [ [ 'AS' ] identifier ] } */
     781   [ +  -  +  + ]:        696 :     while (accept(TK_COMMA)) {
     782         [ +  - ]:         64 :         auto e = parse_Expr();
     783         [ +  - ]:         64 :         Token tok = Token::CreateArtificial();
     784   [ +  -  +  + ]:         64 :         if (accept(TK_As)) {
     785   [ +  -  +  - ]:         29 :             tok = token();
     786   [ +  -  -  + ]:         29 :             if (not expect(TK_IDENTIFIER))
     787   [ #  #  #  # ]:          0 :                 return recover<ErrorClause>(std::move(start), follow_set_SELECT_CLAUSE);
     788   [ +  -  +  + ]:         64 :         } else if (token().type == TK_IDENTIFIER) {
     789   [ +  -  +  - ]:          1 :             tok = token();
     790         [ +  - ]:          1 :             consume();
     791                 :          1 :         }
     792         [ +  - ]:         64 :         select.emplace_back(std::move(e), std::move(tok));
     793         [ -  + ]:         64 :     }
     794                 :            : 
     795         [ +  - ]:        632 :     return std::make_unique<SelectClause>(std::move(start), std::move(select), std::move(select_all));
     796                 :        639 : }
     797                 :            : 
     798                 :        587 : std::unique_ptr<Clause> Parser::parse_FromClause()
     799                 :            : {
     800                 :        587 :     Token start = token();
     801                 :            : 
     802                 :            :     /* 'FROM' */
     803   [ +  -  +  + ]:        587 :     if (not expect(TK_From)) {
     804         [ +  - ]:          2 :         consume();
     805   [ +  -  -  + ]:          2 :         return recover<ErrorClause>(std::move(start), follow_set_FROM_CLAUSE);
     806                 :            :     }
     807                 :            : 
     808                 :            :     /* table-or-select-statement { ',' table-or-select-statement } */
     809                 :        585 :     std::vector<FromClause::from_type> from;
     810                 :        585 :     do {
     811         [ +  - ]:        848 :         Token alias = Token::CreateArtificial();
     812   [ +  -  +  + ]:        848 :         if (accept(TK_LPAR)) {
     813         [ +  - ]:         30 :             std::unique_ptr<Stmt> S = parse_SelectStmt();
     814   [ +  -  -  + ]:         30 :             if (not expect(TK_RPAR))
     815   [ #  #  #  # ]:          0 :                 return recover<ErrorClause>(std::move(start), follow_set_FROM_CLAUSE);
     816         [ +  - ]:         30 :             accept(TK_As);
     817   [ +  -  +  - ]:         30 :             alias = token();
     818   [ +  -  +  + ]:         30 :             if (not expect(TK_IDENTIFIER))
     819   [ +  -  +  - ]:          1 :                 return recover<ErrorClause>(std::move(start), follow_set_FROM_CLAUSE);
     820         [ +  - ]:         29 :             from.emplace_back(std::move(S), std::move(alias));
     821         [ +  + ]:         30 :         } else {
     822   [ +  -  +  - ]:        818 :             Token table = token();
     823   [ +  -  +  + ]:        818 :             if (not expect(TK_IDENTIFIER))
     824   [ +  -  +  - ]:          5 :                 return recover<ErrorClause>(std::move(start), follow_set_FROM_CLAUSE);
     825   [ +  -  +  + ]:        813 :             if (accept(TK_As)) {
     826   [ +  -  +  - ]:         54 :                 alias = token();
     827   [ +  -  +  + ]:         54 :                 if (not expect(TK_IDENTIFIER))
     828   [ +  -  +  - ]:          2 :                     return recover<ErrorClause>(std::move(start), follow_set_FROM_CLAUSE);
     829   [ +  -  +  + ]:        811 :             } else if (token().type == TK_IDENTIFIER) {
     830   [ +  -  +  - ]:          6 :                 alias = token();
     831         [ +  - ]:          6 :                 consume();
     832                 :          6 :             }
     833         [ +  - ]:        811 :             from.emplace_back(std::move(table), std::move(alias));
     834         [ +  + ]:        818 :         }
     835   [ +  +  +  -  :        848 :     } while (accept(TK_COMMA));
                   +  + ]
     836                 :            : 
     837         [ +  - ]:        577 :     return std::make_unique<FromClause>(std::move(start), std::move(from));
     838                 :        587 : }
     839                 :            : 
     840                 :        213 : std::unique_ptr<Clause> Parser::parse_WhereClause()
     841                 :            : {
     842                 :        213 :     Token start = token();
     843                 :            : 
     844                 :            :     /* 'WHERE' */
     845   [ +  -  +  + ]:        213 :     if (not expect(TK_Where)) {
     846         [ +  - ]:          2 :         consume();
     847   [ +  -  -  + ]:          2 :         return recover<ErrorClause>(std::move(start), follow_set_WHERE_CLAUSE);
     848                 :            :     }
     849                 :            : 
     850                 :            :     /* expression */
     851         [ +  - ]:        211 :     std::unique_ptr<Expr> where = parse_Expr();
     852                 :            : 
     853         [ +  - ]:        211 :     return std::make_unique<WhereClause>(std::move(start), std::move(where));
     854                 :        213 : }
     855                 :            : 
     856                 :         84 : std::unique_ptr<Clause> Parser::parse_GroupByClause()
     857                 :            : {
     858                 :         84 :     Token start = token();
     859                 :            : 
     860                 :            :     /* 'GROUP' 'BY' */
     861   [ +  -  +  + ]:         84 :     if (not expect(TK_Group)) {
     862         [ +  - ]:          3 :         consume();
     863   [ +  -  -  + ]:          3 :         return recover<ErrorClause>(std::move(start), follow_set_GROUP_BY_CLAUSE);
     864                 :            :     }
     865   [ +  -  +  + ]:         81 :     if (not expect(TK_By))
     866   [ +  -  -  + ]:          1 :         return recover<ErrorClause>(std::move(start), follow_set_GROUP_BY_CLAUSE);
     867                 :            : 
     868                 :            :     /* expr [ 'AS' identifier ] { ',' expr [ 'AS' identifier ] } */
     869                 :         80 :     std::vector<GroupByClause::group_type> group_by;
     870                 :         80 :     do {
     871         [ +  - ]:         84 :         auto e = parse_Expr();
     872         [ +  - ]:         84 :         Token tok = Token::CreateArtificial();
     873   [ +  -  +  + ]:         84 :         if (accept(TK_As)) {
     874   [ +  -  +  - ]:         12 :             tok = token();
     875   [ +  -  +  + ]:         12 :             if (not expect(TK_IDENTIFIER))
     876   [ +  -  +  - ]:          2 :                 return recover<ErrorClause>(std::move(start), follow_set_GROUP_BY_CLAUSE);
     877   [ +  -  +  + ]:         82 :         } else if (token().type == TK_IDENTIFIER) {
     878   [ +  -  +  - ]:          5 :             tok = token();
     879         [ +  - ]:          5 :             consume();
     880                 :          5 :         }
     881         [ +  - ]:         82 :         group_by.emplace_back(std::move(e), std::move(tok));
     882   [ +  +  +  -  :         84 :     } while (accept(TK_COMMA));
                   +  + ]
     883                 :            : 
     884         [ +  - ]:         78 :     return std::make_unique<GroupByClause>(std::move(start), std::move(group_by));
     885                 :         84 : }
     886                 :            : 
     887                 :         51 : std::unique_ptr<Clause> Parser::parse_HavingClause()
     888                 :            : {
     889                 :         51 :     Token start = token();
     890                 :            : 
     891                 :            :     /* 'HAVING' */
     892   [ +  -  +  + ]:         51 :     if (not expect(TK_Having)) {
     893         [ +  - ]:          2 :         consume();
     894   [ +  -  -  + ]:          2 :         return recover<ErrorClause>(std::move(start), follow_set_HAVING_CLAUSE);
     895                 :            :     }
     896                 :            : 
     897                 :            :     /* expression */
     898         [ +  - ]:         49 :     std::unique_ptr<Expr> having = parse_Expr();
     899                 :            : 
     900         [ +  - ]:         49 :     return std::make_unique<HavingClause>(std::move(start), std::move(having));
     901                 :         51 : }
     902                 :            : 
     903                 :         51 : std::unique_ptr<Clause> Parser::parse_OrderByClause()
     904                 :            : {
     905                 :         51 :     Token start = token();
     906                 :            : 
     907                 :            :     /* 'ORDER' 'BY' */
     908   [ +  -  +  + ]:         51 :     if (not expect(TK_Order)) {
     909         [ +  - ]:          3 :         consume();
     910   [ +  -  -  + ]:          3 :         return recover<ErrorClause>(std::move(start), follow_set_ORDER_BY_CLAUSE);
     911                 :            :     }
     912   [ +  -  +  + ]:         48 :     if (not expect(TK_By))
     913   [ +  -  -  + ]:          1 :         return recover<ErrorClause>(std::move(start), follow_set_ORDER_BY_CLAUSE);
     914                 :            : 
     915                 :            :     /* expression [ 'ASC' | 'DESC' ] { ',' expression [ 'ASC' | 'DESC' ] } */
     916                 :         47 :     std::vector<OrderByClause::order_type> order_by;
     917                 :         47 :     do {
     918         [ +  - ]:         60 :         auto e = parse_Expr();
     919   [ +  -  +  + ]:         60 :         if (accept(TK_Descending)) {
     920         [ +  - ]:         13 :             order_by.emplace_back(std::move(e), false);
     921                 :         13 :         } else {
     922         [ +  - ]:         47 :             accept(TK_Ascending);
     923         [ +  - ]:         47 :             order_by.emplace_back(std::move(e), true);
     924                 :            :         }
     925   [ +  -  +  + ]:         60 :     } while (accept(TK_COMMA));
     926                 :            : 
     927         [ +  - ]:         47 :     return std::make_unique<OrderByClause>(std::move(start), std::move(order_by));
     928                 :         51 : }
     929                 :            : 
     930                 :         25 : std::unique_ptr<Clause> Parser::parse_LimitClause()
     931                 :            : {
     932                 :         25 :     Token start = token();
     933                 :            : 
     934                 :            :     /* 'LIMIT' integer-constant */
     935   [ +  -  +  + ]:         25 :     if (not expect(TK_Limit)) {
     936         [ +  - ]:          4 :         consume();
     937   [ +  -  +  - ]:          4 :         return recover<ErrorClause>(std::move(start), follow_set_LIMIT_CLAUSE);
     938                 :            :     }
     939   [ +  -  +  - ]:         21 :     Token limit = token();
     940   [ +  +  +  +  :         21 :     if (limit.type == TK_DEC_INT or limit.type == TK_OCT_INT or limit.type == TK_HEX_INT) {
                   +  + ]
     941         [ +  - ]:         15 :         consume();
     942                 :         15 :     } else {
     943   [ +  -  +  -  :          6 :         diag.e(limit.pos) << "expected integer limit, got " << limit.text << '\n';
             +  -  +  - ]
     944   [ +  -  +  - ]:          6 :         return recover<ErrorClause>(std::move(start), follow_set_LIMIT_CLAUSE);
     945                 :            :     }
     946                 :            : 
     947                 :            :     /* [ 'OFFSET' integer-constant ] */
     948         [ +  - ]:         15 :     Token offset = Token::CreateArtificial();
     949   [ +  -  +  + ]:         15 :     if (accept(TK_Offset)) {
     950   [ +  -  +  - ]:          7 :         offset = token();
     951   [ +  +  +  +  :          7 :         if (offset.type == TK_DEC_INT or offset.type == TK_OCT_INT or offset.type == TK_HEX_INT) {
                   +  + ]
     952         [ +  - ]:          5 :             consume();
     953                 :          5 :         } else {
     954   [ +  -  +  -  :          2 :             diag.e(offset.pos) << "expected integer offset, got " << offset.text << '\n';
             +  -  +  - ]
     955   [ +  -  +  - ]:          2 :             return recover<ErrorClause>(std::move(start), follow_set_LIMIT_CLAUSE);
     956                 :            :         }
     957                 :          5 :     }
     958                 :            : 
     959         [ +  - ]:         13 :     return std::make_unique<LimitClause>(std::move(start), std::move(limit), std::move(offset));
     960                 :         25 : }
     961                 :            : 
     962                 :            : /*======================================================================================================================
     963                 :            :  * Expressions
     964                 :            :  *====================================================================================================================*/
     965                 :            : 
     966                 :       5493 : std::unique_ptr<Expr> Parser::parse_Expr(const int precedence_lhs, std::unique_ptr<Expr> lhs)
     967                 :            : {
     968                 :            :     /*
     969                 :            :      * primary-expression ::= designator | constant | '(' expression ')' | '(' select-statement ')' ;
     970                 :            :      * unary-expression ::= [ '+' | '-' | '~' ] postfix-expression ;
     971                 :            :      * logical-not-expression ::= 'NOT' logical-not-expression | comparative-expression ;
     972                 :            :      */
     973   [ +  +  +  +  :       5493 :     switch (token().type) {
                   +  + ]
     974                 :            :         /* primary-expression */
     975                 :            :         case TK_IDENTIFIER:
     976                 :       1473 :             lhs = parse_designator(); // XXX For SUM(x), 'SUM' is parsed as designator; should be identifier.
     977                 :       1473 :             break;
     978                 :            :         case TK_Null:
     979                 :            :         case TK_True:
     980                 :            :         case TK_False:
     981                 :            :         case TK_STRING_LITERAL:
     982                 :            :         case TK_DATE:
     983                 :            :         case TK_DATE_TIME:
     984                 :            :         case TK_OCT_INT:
     985                 :            :         case TK_DEC_INT:
     986                 :            :         case TK_HEX_INT:
     987                 :            :         case TK_DEC_FLOAT:
     988                 :            :         case TK_HEX_FLOAT:
     989         [ +  - ]:       3759 :             lhs = std::make_unique<Constant>(consume());
     990                 :       3759 :             break;
     991                 :            :         case TK_LPAR:
     992                 :         80 :             consume();
     993         [ +  + ]:         80 :             if (token().type == TK_Select)
     994         [ -  + ]:         47 :                 lhs = std::make_unique<QueryExpr>(token(), parse_SelectStmt());
     995                 :            :             else
     996         [ -  + ]:         33 :                 lhs = parse_Expr();
     997         [ +  + ]:         80 :             if (not expect(TK_RPAR)) {
     998                 :         10 :                 recover(follow_set_PRIMARY_EXPRESSION);
     999                 :         10 :             }
    1000                 :         80 :             break;
    1001                 :            : 
    1002                 :            :         /* unary-expression */
    1003                 :            :         case TK_PLUS:
    1004                 :            :         case TK_MINUS:
    1005                 :            :         case TK_TILDE: {
    1006                 :         89 :             auto tok = consume();
    1007         [ +  - ]:         89 :             int p = get_precedence(TK_TILDE); // the precedence of TK_TILDE equals that of unary plus and minus
    1008   [ +  -  +  - ]:         89 :             lhs = std::make_unique<UnaryExpr>(std::move(tok), parse_Expr(p));
    1009                 :            :             break;
    1010                 :         89 :         }
    1011                 :            : 
    1012                 :            :         /* logical-NOT-expression */
    1013                 :            :         case TK_Not: {
    1014                 :         35 :             auto tok = consume();
    1015         [ +  - ]:         35 :             int p = get_precedence(tok.type);
    1016   [ +  -  +  - ]:         35 :             lhs = std::make_unique<UnaryExpr>(std::move(tok), parse_Expr(p));
    1017                 :            :             break;
    1018                 :         35 :         }
    1019                 :            : 
    1020                 :            :         default:
    1021                 :         57 :             diag.e(token().pos) << "expected expression, got " << token().text << '\n';
    1022                 :         57 :             recover(follow_set_EXPRESSION);
    1023                 :         57 :             return std::make_unique<ErrorExpr>(token());
    1024                 :            :     }
    1025                 :            : 
    1026                 :            :     /* postfix-expression ::= postfix-expression '(' [ expression { ',' expression } ] ')' | primary-expression */
    1027         [ +  + ]:       5531 :     while (token() == TK_LPAR) {
    1028                 :         95 :         Token lpar = consume();
    1029                 :         95 :         std::vector<std::unique_ptr<Expr>> args;
    1030   [ +  -  +  + ]:         95 :         if (token().type == TK_ASTERISK) {
    1031         [ +  - ]:          2 :             consume();
    1032   [ +  -  +  + ]:         95 :         } else if (token().type != TK_RPAR) {
    1033                 :         88 :             do
    1034   [ +  -  +  -  :        185 :                 args.push_back(parse_Expr());
                   +  + ]
    1035         [ +  - ]:         97 :             while (accept(TK_COMMA));
    1036                 :         88 :         }
    1037   [ +  -  +  + ]:         95 :         if (not expect(TK_RPAR)) {
    1038         [ +  - ]:          4 :             recover(follow_set_POSTFIX_EXPRESSION);
    1039   [ +  -  +  - ]:          4 :             lhs = std::make_unique<ErrorExpr>(token());
    1040                 :          4 :             continue;
    1041                 :            :         }
    1042         [ +  - ]:         91 :         lhs = std::make_unique<FnApplicationExpr>(std::move(lpar), std::move(lhs), std::move(args));
    1043         [ +  + ]:         95 :     }
    1044                 :            : 
    1045                 :       6355 :     for (;;) {
    1046                 :       6355 :         Token op = token();
    1047   [ +  -  +  - ]:       6355 :         int p = get_precedence(op);
    1048         [ +  + ]:       6355 :         if (precedence_lhs > p) return lhs; // left operator has higher precedence_lhs
    1049         [ +  - ]:        919 :         consume();
    1050                 :            : 
    1051         [ +  - ]:        919 :         auto rhs = parse_Expr(p + 1);
    1052         [ +  - ]:        919 :         lhs = std::make_unique<BinaryExpr>(std::move(op), std::move(lhs), std::move(rhs));
    1053         [ +  + ]:       6355 :     }
    1054                 :       5493 : }
    1055                 :            : 
    1056                 :       1479 : std::unique_ptr<Expr> Parser::parse_designator()
    1057                 :            : {
    1058                 :       1479 :     Token lhs = token();
    1059   [ +  -  +  + ]:       1479 :     if (not expect(TK_IDENTIFIER)) {
    1060         [ +  - ]:          1 :         recover(follow_set_DESIGNATOR);
    1061         [ +  - ]:          1 :         return std::make_unique<ErrorExpr>(std::move(lhs));
    1062                 :            :     }
    1063   [ +  -  +  -  :       1478 :     if (token() == TK_DOT) {
                   +  + ]
    1064         [ +  - ]:        821 :         Token dot = consume();
    1065   [ +  -  +  - ]:        821 :         Token rhs = token();
    1066   [ +  -  +  + ]:        821 :         if (not expect(TK_IDENTIFIER)) {
    1067         [ +  - ]:          1 :             recover(follow_set_DESIGNATOR);
    1068         [ +  - ]:          1 :             return std::make_unique<ErrorExpr>(std::move(rhs));
    1069                 :            :         }
    1070         [ +  - ]:        820 :         return std::make_unique<Designator>(std::move(dot), std::move(lhs), std::move(rhs)); // tbl.attr
    1071                 :        821 :     }
    1072         [ +  - ]:        657 :     return std::make_unique<Designator>(std::move(lhs)); // attr
    1073                 :       1479 : }
    1074                 :            : 
    1075                 :          4 : std::unique_ptr<Expr> Parser::expect_integer()
    1076                 :            : {
    1077         [ +  + ]:          4 :     if (is_integer(token().type)) {
    1078         [ -  + ]:          3 :         return std::make_unique<Constant>(consume());
    1079                 :            :     } else {
    1080                 :          1 :         diag.e(token().pos) << "expected integer constant, got " << token().text << '\n';
    1081                 :          1 :         return std::make_unique<ErrorExpr>(token());
    1082                 :            :     }
    1083                 :          4 : }
    1084                 :            : 
    1085                 :            : /*======================================================================================================================
    1086                 :            :  * Types
    1087                 :            :  *====================================================================================================================*/
    1088                 :            : 
    1089                 :        123 : const Type * Parser::parse_data_type()
    1090                 :            : {
    1091   [ +  +  +  +  :        123 :     switch (token().type) {
             +  +  +  +  
                      + ]
    1092                 :            :         default:
    1093                 :          2 :             diag.e(token().pos) << "expected data-type, got " << token().text << '\n';
    1094                 :          2 :             goto error_recovery;
    1095                 :            : 
    1096                 :            :         /* BOOL */
    1097                 :            :         case TK_Bool:
    1098                 :         23 :             consume();
    1099         [ +  - ]:         23 :             return Type::Get_Boolean(Type::TY_Scalar);
    1100                 :            : 
    1101                 :            :         /* 'CHAR' '(' decimal-constant ')' */
    1102                 :            :         case TK_Char:
    1103                 :            :         /* 'VARCHAR' '(' decimal-constant ')' */
    1104                 :            :         case TK_Varchar: {
    1105                 :          6 :             bool is_varying = token().type == TK_Varchar;
    1106                 :          6 :             consume();
    1107         [ +  - ]:          6 :             if (not expect(TK_LPAR)) goto error_recovery;
    1108                 :          6 :             Token tok = token();
    1109   [ +  -  +  + ]:          6 :             if (not expect(TK_DEC_INT)) goto error_recovery;
    1110   [ +  -  +  - ]:          5 :             if (not expect(TK_RPAR)) goto error_recovery;
    1111                 :          5 :             errno = 0;
    1112         [ +  - ]:          5 :             std::size_t length = strtoul(*(tok.text), nullptr, 10);
    1113         [ +  + ]:          5 :             if (errno) {
    1114   [ +  -  +  -  :          1 :                 diag.e(tok.pos) << tok.text << " is not a valid length\n";
                   +  - ]
    1115                 :          1 :                 goto error_recovery;
    1116                 :            :             }
    1117   [ +  +  +  -  :          4 :             return is_varying ? Type::Get_Varchar(Type::TY_Scalar, length) : Type::Get_Char(Type::TY_Scalar, length);
             +  -  +  - ]
    1118         [ +  + ]:          6 :         }
    1119                 :            : 
    1120                 :            :         /* DATE */
    1121                 :            :         case TK_Date:
    1122                 :          2 :             consume();
    1123         [ +  - ]:          2 :             return Type::Get_Date(Type::TY_Scalar);
    1124                 :            : 
    1125                 :            :         /* DATETIME */
    1126                 :            :         case TK_Datetime:
    1127                 :          2 :             consume();
    1128         [ +  - ]:          2 :             return Type::Get_Datetime(Type::TY_Scalar);
    1129                 :            : 
    1130                 :            :         /* 'INT' '(' decimal-constant ')' */
    1131                 :            :         case TK_Int: {
    1132                 :         63 :             consume();
    1133         [ +  + ]:         63 :             if (not expect(TK_LPAR)) goto error_recovery;
    1134                 :         62 :             Token tok = token();
    1135   [ +  -  +  + ]:         62 :             if (not expect(TK_DEC_INT)) goto error_recovery;
    1136   [ +  -  +  + ]:         58 :             if (not expect(TK_RPAR)) goto error_recovery;
    1137                 :         56 :             errno = 0;
    1138         [ +  - ]:         56 :             std::size_t bytes = strtoul(*(tok.text), nullptr, 10);
    1139         [ +  + ]:         56 :             if (errno) {
    1140   [ +  -  +  -  :          1 :                 diag.e(tok.pos) << tok.text << " is not a valid size for an INT\n";
                   +  - ]
    1141                 :          1 :                 goto error_recovery;
    1142                 :            :             }
    1143   [ +  -  +  - ]:         55 :             return Type::Get_Integer(Type::TY_Scalar, bytes);
    1144                 :         62 :         }
    1145                 :            : 
    1146                 :            :         /* 'FLOAT' */
    1147                 :            :         case TK_Float:
    1148                 :          9 :             consume();
    1149         [ +  - ]:          9 :             return Type::Get_Float(Type::TY_Scalar);
    1150                 :            : 
    1151                 :            :         /* 'DOUBLE' */
    1152                 :            :         case TK_Double:
    1153                 :          4 :             consume();
    1154         [ +  - ]:          4 :             return Type::Get_Double(Type::TY_Scalar);
    1155                 :            : 
    1156                 :            :         /* 'DECIMAL' '(' decimal-constant [ ',' decimal-constant ] ')' */
    1157                 :            :         case TK_Decimal: {
    1158                 :         12 :             consume();
    1159         [ +  - ]:         12 :             if (not expect(TK_LPAR)) goto error_recovery;
    1160                 :         12 :             Token precision = token();
    1161         [ +  - ]:         12 :             Token scale = Token::CreateArtificial();
    1162   [ +  -  +  + ]:         12 :             if (not expect(TK_DEC_INT)) goto error_recovery;
    1163   [ +  -  +  + ]:         10 :             if (accept(TK_COMMA)) {
    1164   [ +  -  +  - ]:          9 :                 scale = token();
    1165   [ +  -  +  + ]:          9 :                 if (not expect(TK_DEC_INT)) goto error_recovery;
    1166                 :          6 :             }
    1167   [ +  -  +  + ]:          7 :             if (not expect(TK_RPAR)) goto error_recovery;
    1168                 :          6 :             errno = 0;
    1169         [ +  - ]:          6 :             std::size_t p = strtoul(*(precision.text), nullptr, 10);
    1170         [ +  + ]:          6 :             if (errno) {
    1171   [ +  -  +  -  :          1 :                 diag.e(precision.pos) << precision.text << " is not a valid precision for a DECIMAL\n";
                   +  - ]
    1172                 :          1 :                 goto error_recovery;
    1173                 :            :             }
    1174                 :          5 :             errno = 0;
    1175   [ +  -  +  +  :          5 :             std::size_t s = scale.text.has_value() ? strtoul(*(scale.text), nullptr, 10) : 0;
                   +  - ]
    1176         [ +  + ]:          5 :             if (errno) {
    1177   [ +  -  +  -  :          1 :                 diag.e(scale.pos) << scale.text << " is not a valid scale for a DECIMAL\n";
                   +  - ]
    1178                 :          1 :                 goto error_recovery;
    1179                 :            :             }
    1180   [ +  -  +  - ]:          4 :             return Type::Get_Decimal(Type::TY_Scalar, p, s);
    1181                 :         12 :         }
    1182                 :            :     }
    1183                 :            : 
    1184                 :            : error_recovery:
    1185                 :         20 :     recover(follow_set_DATA_TYPE);
    1186         [ +  - ]:         20 :     return Type::Get_Error();
    1187                 :        145 : }

Generated by: LCOV version 1.16