LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/sksl - SkSLParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1003 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 63 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "stdio.h"
       9             : #include "SkSLParser.h"
      10             : #include "SkSLToken.h"
      11             : 
      12             : #define register
      13             : #include "disable_flex_warnings.h"
      14             : #include "lex.sksl.c"
      15             : static_assert(YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION * 10 +
      16             :               YY_FLEX_SUBMINOR_VERSION >= 261,
      17             :               "we require Flex 2.6.1 or better for security reasons");
      18             : #undef register
      19             : #ifdef __clang__
      20             : #pragma clang diagnostic pop
      21             : #endif
      22             : #ifdef __GNUC__
      23             : #pragma GCC diagnostic pop
      24             : #endif
      25             : #ifdef _MSC_VER
      26             : #pragma warning(pop)
      27             : #endif
      28             : 
      29             : #include "lex.layout.h"
      30             : #include "ast/SkSLASTBinaryExpression.h"
      31             : #include "ast/SkSLASTBlock.h"
      32             : #include "ast/SkSLASTBoolLiteral.h"
      33             : #include "ast/SkSLASTBreakStatement.h"
      34             : #include "ast/SkSLASTCallSuffix.h"
      35             : #include "ast/SkSLASTContinueStatement.h"
      36             : #include "ast/SkSLASTDiscardStatement.h"
      37             : #include "ast/SkSLASTDoStatement.h"
      38             : #include "ast/SkSLASTExpression.h"
      39             : #include "ast/SkSLASTExpressionStatement.h"
      40             : #include "ast/SkSLASTExtension.h"
      41             : #include "ast/SkSLASTFieldSuffix.h"
      42             : #include "ast/SkSLASTFloatLiteral.h"
      43             : #include "ast/SkSLASTForStatement.h"
      44             : #include "ast/SkSLASTFunction.h"
      45             : #include "ast/SkSLASTIdentifier.h"
      46             : #include "ast/SkSLASTIfStatement.h"
      47             : #include "ast/SkSLASTIndexSuffix.h"
      48             : #include "ast/SkSLASTInterfaceBlock.h"
      49             : #include "ast/SkSLASTIntLiteral.h"
      50             : #include "ast/SkSLASTModifiersDeclaration.h"
      51             : #include "ast/SkSLASTParameter.h"
      52             : #include "ast/SkSLASTPrecision.h"
      53             : #include "ast/SkSLASTPrefixExpression.h"
      54             : #include "ast/SkSLASTReturnStatement.h"
      55             : #include "ast/SkSLASTStatement.h"
      56             : #include "ast/SkSLASTSuffixExpression.h"
      57             : #include "ast/SkSLASTSwitchCase.h"
      58             : #include "ast/SkSLASTSwitchStatement.h"
      59             : #include "ast/SkSLASTTernaryExpression.h"
      60             : #include "ast/SkSLASTType.h"
      61             : #include "ast/SkSLASTVarDeclaration.h"
      62             : #include "ast/SkSLASTVarDeclarationStatement.h"
      63             : #include "ast/SkSLASTWhileStatement.h"
      64             : #include "ir/SkSLSymbolTable.h"
      65             : #include "ir/SkSLModifiers.h"
      66             : #include "ir/SkSLType.h"
      67             : 
      68             : namespace SkSL {
      69             : 
      70             : #define MAX_PARSE_DEPTH 50
      71             : 
      72             : class AutoDepth {
      73             : public:
      74           0 :     AutoDepth(Parser* p)
      75           0 :     : fParser(p) {
      76           0 :         fParser->fDepth++;
      77           0 :     }
      78             : 
      79           0 :     ~AutoDepth() {
      80           0 :         fParser->fDepth--;
      81           0 :     }
      82             : 
      83           0 :     bool checkValid() {
      84           0 :         if (fParser->fDepth > MAX_PARSE_DEPTH) {
      85           0 :             fParser->error(fParser->peek().fPosition, String("exceeded max parse depth"));
      86           0 :             return false;
      87             :         }
      88           0 :         return true;
      89             :     }
      90             : 
      91             : private:
      92             :     Parser* fParser;
      93             : };
      94             : 
      95           0 : Parser::Parser(String text, SymbolTable& types, ErrorReporter& errors)
      96           0 : : fPushback(Position(-1, -1), Token::INVALID_TOKEN, String())
      97             : , fTypes(types)
      98           0 : , fErrors(errors) {
      99           0 :     sksllex_init(&fScanner);
     100           0 :     layoutlex_init(&fLayoutScanner);
     101           0 :     fBuffer = sksl_scan_string(text.c_str(), fScanner);
     102           0 :     skslset_lineno(1, fScanner);
     103             : 
     104             :     if (false) {
     105             :         // avoid unused warning
     106             :         yyunput(0, nullptr, fScanner);
     107             :     }
     108           0 : }
     109             : 
     110           0 : Parser::~Parser() {
     111           0 :     sksl_delete_buffer(fBuffer, fScanner);
     112           0 :     sksllex_destroy(fScanner);
     113           0 :     layoutlex_destroy(fLayoutScanner);
     114           0 : }
     115             : 
     116             : /* (precision | directive | declaration)* END_OF_FILE */
     117           0 : std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
     118           0 :     std::vector<std::unique_ptr<ASTDeclaration>> result;
     119             :     for (;;) {
     120           0 :         switch (this->peek().fKind) {
     121             :             case Token::END_OF_FILE:
     122           0 :                 return result;
     123             :             case Token::PRECISION: {
     124           0 :                 std::unique_ptr<ASTDeclaration> precision = this->precision();
     125           0 :                 if (precision) {
     126           0 :                     result.push_back(std::move(precision));
     127             :                 }
     128           0 :                 break;
     129             :             }
     130             :             case Token::DIRECTIVE: {
     131           0 :                 std::unique_ptr<ASTDeclaration> decl = this->directive();
     132           0 :                 if (decl) {
     133           0 :                     result.push_back(std::move(decl));
     134             :                 }
     135           0 :                 break;
     136             :             }
     137             :             default: {
     138           0 :                 std::unique_ptr<ASTDeclaration> decl = this->declaration();
     139           0 :                 if (!decl) {
     140           0 :                     continue;
     141             :                 }
     142           0 :                 result.push_back(std::move(decl));
     143             :             }
     144             :         }
     145           0 :     }
     146             : }
     147             : 
     148           0 : Token Parser::nextToken() {
     149           0 :     if (fPushback.fKind != Token::INVALID_TOKEN) {
     150           0 :         Token result = fPushback;
     151           0 :         fPushback.fKind = Token::INVALID_TOKEN;
     152           0 :         fPushback.fText = "";
     153           0 :         return result;
     154             :     }
     155           0 :     int token = sksllex(fScanner);
     156           0 :     String text;
     157           0 :     switch ((Token::Kind) token) {
     158             :         case Token::IDENTIFIER:    // fall through
     159             :         case Token::INT_LITERAL:   // fall through
     160             :         case Token::FLOAT_LITERAL: // fall through
     161             :         case Token::DIRECTIVE:
     162           0 :             text = String(skslget_text(fScanner));
     163           0 :             break;
     164             :         default:
     165             : #ifdef SK_DEBUG
     166           0 :             text = String(skslget_text(fScanner));
     167             : #endif
     168           0 :             break;
     169             :     }
     170           0 :     return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token, text);
     171             : }
     172             : 
     173           0 : void Parser::pushback(Token t) {
     174           0 :     ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
     175           0 :     fPushback = t;
     176           0 : }
     177             : 
     178           0 : Token Parser::peek() {
     179           0 :     fPushback = this->nextToken();
     180           0 :     return fPushback;
     181             : }
     182             : 
     183             : 
     184           0 : bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
     185           0 :     return this->expect(kind, String(expected), result);
     186             : }
     187             : 
     188           0 : bool Parser::expect(Token::Kind kind, String expected, Token* result) {
     189           0 :     Token next = this->nextToken();
     190           0 :     if (next.fKind == kind) {
     191           0 :         if (result) {
     192           0 :             *result = next;
     193             :         }
     194           0 :         return true;
     195             :     } else {
     196           0 :         if (next.fText.size()) {
     197           0 :             this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText +
     198           0 :                                         "'");
     199             :         } else {
     200           0 :             this->error(next.fPosition, "parse error, recompile in debug mode for details");
     201             :         }
     202           0 :         return false;
     203             :     }
     204             : }
     205             : 
     206           0 : void Parser::error(Position p, const char* msg) {
     207           0 :     this->error(p, String(msg));
     208           0 : }
     209             : 
     210           0 : void Parser::error(Position p, String msg) {
     211           0 :     fErrors.error(p, msg);
     212           0 : }
     213             : 
     214           0 : bool Parser::isType(String name) {
     215           0 :     return nullptr != fTypes[name];
     216             : }
     217             : 
     218             : /* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
     219           0 : std::unique_ptr<ASTDeclaration> Parser::precision() {
     220           0 :     if (!this->expect(Token::PRECISION, "'precision'")) {
     221           0 :         return nullptr;
     222             :     }
     223             :     Modifiers::Flag result;
     224           0 :     Token p = this->nextToken();
     225           0 :     switch (p.fKind) {
     226             :         case Token::LOWP:
     227           0 :             result = Modifiers::kLowp_Flag;
     228           0 :             break;
     229             :         case Token::MEDIUMP:
     230           0 :             result = Modifiers::kMediump_Flag;
     231           0 :             break;
     232             :         case Token::HIGHP:
     233           0 :             result = Modifiers::kHighp_Flag;
     234           0 :             break;
     235             :         default:
     236           0 :             this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
     237           0 :                                      p.fText + "'");
     238           0 :             return nullptr;
     239             :     }
     240             :     // FIXME handle the type
     241           0 :     if (!this->type()) {
     242           0 :         return nullptr;
     243             :     }
     244           0 :     this->expect(Token::SEMICOLON, "';'");
     245           0 :     return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
     246             : }
     247             : 
     248             : /* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
     249             :    DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
     250           0 : std::unique_ptr<ASTDeclaration> Parser::directive() {
     251           0 :     Token start;
     252           0 :     if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
     253           0 :         return nullptr;
     254             :     }
     255           0 :     if (start.fText == "#version") {
     256           0 :         this->expect(Token::INT_LITERAL, "a version number");
     257           0 :         Token next = this->peek();
     258           0 :         if (next.fText == "es" || next.fText == "compatibility") {
     259           0 :             this->nextToken();
     260             :         }
     261             :         // version is ignored for now; it will eventually become an error when we stop pretending
     262             :         // to be GLSL
     263           0 :         return nullptr;
     264           0 :     } else if (start.fText == "#extension") {
     265           0 :         Token name;
     266           0 :         if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     267           0 :             return nullptr;
     268             :         }
     269           0 :         if (!this->expect(Token::COLON, "':'")) {
     270           0 :             return nullptr;
     271             :         }
     272             :         // FIXME: need to start paying attention to this token
     273           0 :         if (!this->expect(Token::IDENTIFIER, "an identifier")) {
     274           0 :             return nullptr;
     275             :         }
     276           0 :         return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
     277           0 :                                                                 std::move(name.fText)));
     278             :     } else {
     279           0 :         this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
     280           0 :         return nullptr;
     281             :     }
     282             : }
     283             : 
     284             : /* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
     285             :    (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
     286           0 : std::unique_ptr<ASTDeclaration> Parser::declaration() {
     287           0 :     Modifiers modifiers = this->modifiers();
     288           0 :     Token lookahead = this->peek();
     289           0 :     if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
     290             :         // we have an identifier that's not a type, could be the start of an interface block
     291           0 :         return this->interfaceBlock(modifiers);
     292             :     }
     293           0 :     if (lookahead.fKind == Token::STRUCT) {
     294           0 :         return this->structVarDeclaration(modifiers);
     295             :     }
     296           0 :     if (lookahead.fKind == Token::SEMICOLON) {
     297           0 :         this->nextToken();
     298           0 :         return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
     299             :     }
     300           0 :     std::unique_ptr<ASTType> type(this->type());
     301           0 :     if (!type) {
     302           0 :         return nullptr;
     303             :     }
     304           0 :     if (type->fKind == ASTType::kStruct_Kind && peek().fKind == Token::SEMICOLON) {
     305           0 :         this->nextToken();
     306           0 :         return nullptr;
     307             :     }
     308           0 :     Token name;
     309           0 :     if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     310           0 :         return nullptr;
     311             :     }
     312           0 :     if (!modifiers.fFlags && this->peek().fKind == Token::LPAREN) {
     313           0 :         this->nextToken();
     314           0 :         std::vector<std::unique_ptr<ASTParameter>> parameters;
     315           0 :         while (this->peek().fKind != Token::RPAREN) {
     316           0 :             if (parameters.size() > 0) {
     317           0 :                 if (!this->expect(Token::COMMA, "','")) {
     318           0 :                     return nullptr;
     319             :                 }
     320             :             }
     321           0 :             std::unique_ptr<ASTParameter> parameter = this->parameter();
     322           0 :             if (!parameter) {
     323           0 :                 return nullptr;
     324             :             }
     325           0 :             parameters.push_back(std::move(parameter));
     326             :         }
     327           0 :         this->nextToken();
     328           0 :         std::unique_ptr<ASTBlock> body;
     329           0 :         if (this->peek().fKind == Token::SEMICOLON) {
     330           0 :             this->nextToken();
     331             :         } else {
     332           0 :             body = this->block();
     333           0 :             if (!body) {
     334           0 :                 return nullptr;
     335             :             }
     336             :         }
     337           0 :         return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition, std::move(type),
     338           0 :                                                                std::move(name.fText),
     339           0 :                                                                std::move(parameters),
     340           0 :                                                                std::move(body)));
     341             :     } else {
     342           0 :         return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
     343             :     }
     344             : }
     345             : 
     346             : /* modifiers type IDENTIFIER varDeclarationEnd */
     347           0 : std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
     348           0 :     Modifiers modifiers = this->modifiers();
     349           0 :     std::unique_ptr<ASTType> type(this->type());
     350           0 :     if (!type) {
     351           0 :         return nullptr;
     352             :     }
     353           0 :     Token name;
     354           0 :     if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     355           0 :         return nullptr;
     356             :     }
     357           0 :     return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
     358             : }
     359             : 
     360             : /* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
     361           0 : std::unique_ptr<ASTType> Parser::structDeclaration() {
     362           0 :     if (!this->expect(Token::STRUCT, "'struct'")) {
     363           0 :         return nullptr;
     364             :     }
     365           0 :     Token name;
     366           0 :     if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     367           0 :         return nullptr;
     368             :     }
     369           0 :     if (!this->expect(Token::LBRACE, "'{'")) {
     370           0 :         return nullptr;
     371             :     }
     372           0 :     std::vector<Type::Field> fields;
     373           0 :     while (this->peek().fKind != Token::RBRACE) {
     374           0 :         std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
     375           0 :         if (!decl) {
     376           0 :             return nullptr;
     377             :         }
     378           0 :         for (const auto& var : decl->fVars) {
     379           0 :             auto type = (const Type*) fTypes[decl->fType->fName];
     380           0 :             for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
     381           0 :                 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
     382           0 :                     this->error(decl->fPosition, "array size in struct field must be a constant");
     383           0 :                     return nullptr;
     384             :                 }
     385           0 :                 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
     386           0 :                 String name = type->name() + "[" + to_string(columns) + "]";
     387           0 :                 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
     388           0 :                 fTypes.takeOwnership((Type*) type);
     389             :             }
     390           0 :             fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
     391           0 :             if (var.fValue) {
     392           0 :                 this->error(decl->fPosition, "initializers are not permitted on struct fields");
     393             :             }
     394             :         }
     395             :     }
     396           0 :     if (!this->expect(Token::RBRACE, "'}'")) {
     397           0 :         return nullptr;
     398             :     }
     399           0 :     fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fPosition, name.fText, fields)));
     400           0 :     return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
     401           0 :                                                 ASTType::kStruct_Kind, std::vector<int>()));
     402             : }
     403             : 
     404             : /* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
     405           0 : std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
     406           0 :     std::unique_ptr<ASTType> type = this->structDeclaration();
     407           0 :     if (!type) {
     408           0 :         return nullptr;
     409             :     }
     410           0 :     if (peek().fKind == Token::IDENTIFIER) {
     411           0 :         Token name = this->nextToken();
     412             :         std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
     413           0 :                                                                              std::move(type),
     414           0 :                                                                              std::move(name.fText));
     415           0 :         if (result) {
     416           0 :             for (const auto& var : result->fVars) {
     417           0 :                 if (var.fValue) {
     418           0 :                     this->error(var.fValue->fPosition,
     419           0 :                                 "struct variables cannot be initialized");
     420             :                 }
     421             :             }
     422             :         }
     423           0 :         return result;
     424             :     }
     425           0 :     this->expect(Token::SEMICOLON, "';'");
     426           0 :     return nullptr;
     427             : }
     428             : 
     429             : /* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER
     430             :    (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */
     431           0 : std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
     432             :                                                               std::unique_ptr<ASTType> type,
     433             :                                                               String name) {
     434           0 :     std::vector<ASTVarDeclaration> vars;
     435           0 :     std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
     436           0 :     while (this->peek().fKind == Token::LBRACKET) {
     437           0 :         this->nextToken();
     438           0 :         if (this->peek().fKind == Token::RBRACKET) {
     439           0 :             this->nextToken();
     440           0 :             currentVarSizes.push_back(nullptr);
     441             :         } else {
     442           0 :             std::unique_ptr<ASTExpression> size(this->expression());
     443           0 :             if (!size) {
     444           0 :                 return nullptr;
     445             :             }
     446           0 :             currentVarSizes.push_back(std::move(size));
     447           0 :             if (!this->expect(Token::RBRACKET, "']'")) {
     448           0 :                 return nullptr;
     449             :             }
     450             :         }
     451             :     }
     452           0 :     std::unique_ptr<ASTExpression> value;
     453           0 :     if (this->peek().fKind == Token::EQ) {
     454           0 :         this->nextToken();
     455           0 :         value = this->expression();
     456           0 :         if (!value) {
     457           0 :             return nullptr;
     458             :         }
     459             :     }
     460           0 :     vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
     461           0 :     while (this->peek().fKind == Token::COMMA) {
     462           0 :         this->nextToken();
     463           0 :         Token name;
     464           0 :         if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     465           0 :             return nullptr;
     466             :         }
     467           0 :         currentVarSizes.clear();
     468           0 :         value.reset();
     469           0 :         while (this->peek().fKind == Token::LBRACKET) {
     470           0 :             this->nextToken();
     471           0 :             if (this->peek().fKind == Token::RBRACKET) {
     472           0 :                 this->nextToken();
     473           0 :                 currentVarSizes.push_back(nullptr);
     474             :             } else {
     475           0 :                 std::unique_ptr<ASTExpression> size(this->expression());
     476           0 :                 if (!size) {
     477           0 :                     return nullptr;
     478             :                 }
     479           0 :                 currentVarSizes.push_back(std::move(size));
     480           0 :                 if (!this->expect(Token::RBRACKET, "']'")) {
     481           0 :                     return nullptr;
     482             :                 }
     483             :             }
     484             :         }
     485           0 :         if (this->peek().fKind == Token::EQ) {
     486           0 :             this->nextToken();
     487           0 :             value = this->expression();
     488           0 :             if (!value) {
     489           0 :                 return nullptr;
     490             :             }
     491             :         }
     492           0 :         vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
     493             :     }
     494           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
     495           0 :         return nullptr;
     496             :     }
     497           0 :     return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
     498           0 :                                                                       std::move(type),
     499           0 :                                                                       std::move(vars)));
     500             : }
     501             : 
     502             : /* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
     503           0 : std::unique_ptr<ASTParameter> Parser::parameter() {
     504           0 :     Modifiers modifiers = this->modifiersWithDefaults(0);
     505           0 :     std::unique_ptr<ASTType> type = this->type();
     506           0 :     if (!type) {
     507           0 :         return nullptr;
     508             :     }
     509           0 :     Token name;
     510           0 :     if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     511           0 :         return nullptr;
     512             :     }
     513           0 :     std::vector<int> sizes;
     514           0 :     while (this->peek().fKind == Token::LBRACKET) {
     515           0 :         this->nextToken();
     516           0 :         Token sizeToken;
     517           0 :         if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
     518           0 :             return nullptr;
     519             :         }
     520           0 :         sizes.push_back(SkSL::stoi(sizeToken.fText));
     521           0 :         if (!this->expect(Token::RBRACKET, "']'")) {
     522           0 :             return nullptr;
     523             :         }
     524             :     }
     525           0 :     return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
     526           0 :                                                           std::move(type), name.fText,
     527           0 :                                                           std::move(sizes)));
     528             : }
     529             : 
     530             : /** (EQ INT_LITERAL)? */
     531           0 : int Parser::layoutInt() {
     532           0 :     if (!this->expect(Token::EQ, "'='")) {
     533           0 :         return -1;
     534             :     }
     535           0 :     Token resultToken;
     536           0 :     if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
     537           0 :         return SkSL::stoi(resultToken.fText);
     538             :     }
     539           0 :     return -1;
     540             : }
     541             : 
     542             : /* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
     543           0 : Layout Parser::layout() {
     544           0 :     int location = -1;
     545           0 :     int offset = -1;
     546           0 :     int binding = -1;
     547           0 :     int index = -1;
     548           0 :     int set = -1;
     549           0 :     int builtin = -1;
     550           0 :     int inputAttachmentIndex = -1;
     551           0 :     bool originUpperLeft = false;
     552           0 :     bool overrideCoverage = false;
     553           0 :     bool blendSupportAllEquations = false;
     554           0 :     Layout::Format format = Layout::Format::kUnspecified;
     555           0 :     bool pushConstant = false;
     556           0 :     Layout::Primitive primitive = Layout::kUnspecified_Primitive;
     557           0 :     int maxVertices = -1;
     558           0 :     int invocations = -1;
     559           0 :     if (this->peek().fKind == Token::LAYOUT) {
     560           0 :         this->nextToken();
     561           0 :         if (!this->expect(Token::LPAREN, "'('")) {
     562             :             return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
     563             :                           originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
     564           0 :                           pushConstant, primitive, maxVertices, invocations);
     565             :         }
     566             :         for (;;) {
     567           0 :             Token t = this->nextToken();
     568             :             YY_BUFFER_STATE buffer;
     569           0 :             buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner);
     570           0 :             int token = layoutlex(fLayoutScanner);
     571           0 :             layout_delete_buffer(buffer, fLayoutScanner);
     572           0 :             if (token != Token::INVALID_TOKEN) {
     573           0 :                 switch (token) {
     574             :                     case Token::LOCATION:
     575           0 :                         location = this->layoutInt();
     576           0 :                         break;
     577             :                     case Token::OFFSET:
     578           0 :                         offset = this->layoutInt();
     579           0 :                         break;
     580             :                     case Token::BINDING:
     581           0 :                         binding = this->layoutInt();
     582           0 :                         break;
     583             :                     case Token::INDEX:
     584           0 :                         index = this->layoutInt();
     585           0 :                         break;
     586             :                     case Token::SET:
     587           0 :                         set = this->layoutInt();
     588           0 :                         break;
     589             :                     case Token::BUILTIN:
     590           0 :                         builtin = this->layoutInt();
     591           0 :                         break;
     592             :                     case Token::INPUT_ATTACHMENT_INDEX:
     593           0 :                         inputAttachmentIndex = this->layoutInt();
     594           0 :                         break;
     595             :                     case Token::ORIGIN_UPPER_LEFT:
     596           0 :                         originUpperLeft = true;
     597           0 :                         break;
     598             :                     case Token::OVERRIDE_COVERAGE:
     599           0 :                         overrideCoverage = true;
     600           0 :                         break;
     601             :                     case Token::BLEND_SUPPORT_ALL_EQUATIONS:
     602           0 :                         blendSupportAllEquations = true;
     603           0 :                         break;
     604             :                     case Token::PUSH_CONSTANT:
     605           0 :                         pushConstant = true;
     606           0 :                         break;
     607             :                     case Token::POINTS:
     608           0 :                         primitive = Layout::kPoints_Primitive;
     609           0 :                         break;
     610             :                     case Token::LINES:
     611           0 :                         primitive = Layout::kLines_Primitive;
     612           0 :                         break;
     613             :                     case Token::LINE_STRIP:
     614           0 :                         primitive = Layout::kLineStrip_Primitive;
     615           0 :                         break;
     616             :                     case Token::LINES_ADJACENCY:
     617           0 :                         primitive = Layout::kLinesAdjacency_Primitive;
     618           0 :                         break;
     619             :                     case Token::TRIANGLES:
     620           0 :                         primitive = Layout::kTriangles_Primitive;
     621           0 :                         break;
     622             :                     case Token::TRIANGLE_STRIP:
     623           0 :                         primitive = Layout::kTriangleStrip_Primitive;
     624           0 :                         break;
     625             :                     case Token::TRIANGLES_ADJACENCY:
     626           0 :                         primitive = Layout::kTrianglesAdjacency_Primitive;
     627           0 :                         break;
     628             :                     case Token::MAX_VERTICES:
     629           0 :                         maxVertices = this->layoutInt();
     630           0 :                         break;
     631             :                     case Token::INVOCATIONS:
     632           0 :                         invocations = this->layoutInt();
     633           0 :                         break;
     634             :                 }
     635           0 :             } else if (Layout::ReadFormat(t.fText, &format)) {
     636             :                // AST::ReadFormat stored the result in 'format'.
     637             :             } else {
     638           0 :                 this->error(t.fPosition, ("'" + t.fText +
     639           0 :                                           "' is not a valid layout qualifier").c_str());
     640             :             }
     641           0 :             if (this->peek().fKind == Token::RPAREN) {
     642           0 :                 this->nextToken();
     643           0 :                 break;
     644             :             }
     645           0 :             if (!this->expect(Token::COMMA, "','")) {
     646           0 :                 break;
     647             :             }
     648           0 :         }
     649             :     }
     650             :     return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
     651             :                   originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
     652           0 :                   pushConstant, primitive, maxVertices, invocations);
     653             : }
     654             : 
     655             : /* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
     656             :             READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT)* */
     657           0 : Modifiers Parser::modifiers() {
     658           0 :     Layout layout = this->layout();
     659           0 :     int flags = 0;
     660             :     for (;;) {
     661             :         // TODO: handle duplicate / incompatible flags
     662           0 :         switch (peek().fKind) {
     663             :             case Token::UNIFORM:
     664           0 :                 this->nextToken();
     665           0 :                 flags |= Modifiers::kUniform_Flag;
     666           0 :                 break;
     667             :             case Token::CONST:
     668           0 :                 this->nextToken();
     669           0 :                 flags |= Modifiers::kConst_Flag;
     670           0 :                 break;
     671             :             case Token::IN:
     672           0 :                 this->nextToken();
     673           0 :                 flags |= Modifiers::kIn_Flag;
     674           0 :                 break;
     675             :             case Token::OUT:
     676           0 :                 this->nextToken();
     677           0 :                 flags |= Modifiers::kOut_Flag;
     678           0 :                 break;
     679             :             case Token::INOUT:
     680           0 :                 this->nextToken();
     681           0 :                 flags |= Modifiers::kIn_Flag;
     682           0 :                 flags |= Modifiers::kOut_Flag;
     683           0 :                 break;
     684             :             case Token::LOWP:
     685           0 :                 this->nextToken();
     686           0 :                 flags |= Modifiers::kLowp_Flag;
     687           0 :                 break;
     688             :             case Token::MEDIUMP:
     689           0 :                 this->nextToken();
     690           0 :                 flags |= Modifiers::kMediump_Flag;
     691           0 :                 break;
     692             :             case Token::HIGHP:
     693           0 :                 this->nextToken();
     694           0 :                 flags |= Modifiers::kHighp_Flag;
     695           0 :                 break;
     696             :             case Token::FLAT:
     697           0 :                 this->nextToken();
     698           0 :                 flags |= Modifiers::kFlat_Flag;
     699           0 :                 break;
     700             :             case Token::NOPERSPECTIVE:
     701           0 :                 this->nextToken();
     702           0 :                 flags |= Modifiers::kNoPerspective_Flag;
     703           0 :                 break;
     704             :             case Token::READONLY:
     705           0 :                 this->nextToken();
     706           0 :                 flags |= Modifiers::kReadOnly_Flag;
     707           0 :                 break;
     708             :             case Token::WRITEONLY:
     709           0 :                 this->nextToken();
     710           0 :                 flags |= Modifiers::kWriteOnly_Flag;
     711           0 :                 break;
     712             :             case Token::COHERENT:
     713           0 :                 this->nextToken();
     714           0 :                 flags |= Modifiers::kCoherent_Flag;
     715           0 :                 break;
     716             :             case Token::VOLATILE:
     717           0 :                 this->nextToken();
     718           0 :                 flags |= Modifiers::kVolatile_Flag;
     719           0 :                 break;
     720             :             case Token::RESTRICT:
     721           0 :                 this->nextToken();
     722           0 :                 flags |= Modifiers::kRestrict_Flag;
     723           0 :                 break;
     724             :             default:
     725           0 :                 return Modifiers(layout, flags);
     726             :         }
     727             :     }
     728             : }
     729             : 
     730           0 : Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
     731           0 :     Modifiers result = this->modifiers();
     732           0 :     if (!result.fFlags) {
     733           0 :         return Modifiers(result.fLayout, defaultFlags);
     734             :     }
     735           0 :     return result;
     736             : }
     737             : 
     738             : /* ifStatement | forStatement | doStatement | whileStatement | block | expression */
     739           0 : std::unique_ptr<ASTStatement> Parser::statement() {
     740           0 :     Token start = this->peek();
     741           0 :     switch (start.fKind) {
     742             :         case Token::IF:
     743           0 :             return this->ifStatement();
     744             :         case Token::FOR:
     745           0 :             return this->forStatement();
     746             :         case Token::DO:
     747           0 :             return this->doStatement();
     748             :         case Token::WHILE:
     749           0 :             return this->whileStatement();
     750             :         case Token::SWITCH:
     751           0 :             return this->switchStatement();
     752             :         case Token::RETURN:
     753           0 :             return this->returnStatement();
     754             :         case Token::BREAK:
     755           0 :             return this->breakStatement();
     756             :         case Token::CONTINUE:
     757           0 :             return this->continueStatement();
     758             :         case Token::DISCARD:
     759           0 :             return this->discardStatement();
     760             :         case Token::LBRACE:
     761           0 :             return this->block();
     762             :         case Token::SEMICOLON:
     763           0 :             this->nextToken();
     764           0 :             return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
     765           0 :                                                      std::vector<std::unique_ptr<ASTStatement>>()));
     766             :         case Token::CONST:   // fall through
     767             :         case Token::HIGHP:   // fall through
     768             :         case Token::MEDIUMP: // fall through
     769             :         case Token::LOWP: {
     770           0 :             auto decl = this->varDeclarations();
     771           0 :             if (!decl) {
     772           0 :                 return nullptr;
     773             :             }
     774           0 :             return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
     775             :         }
     776             :         case Token::IDENTIFIER:
     777           0 :             if (this->isType(start.fText)) {
     778           0 :                 auto decl = this->varDeclarations();
     779           0 :                 if (!decl) {
     780           0 :                     return nullptr;
     781             :                 }
     782             :                 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
     783           0 :                                                                                   std::move(decl)));
     784             :             }
     785             :             // fall through
     786             :         default:
     787           0 :             return this->expressionStatement();
     788             :     }
     789             : }
     790             : 
     791             : /* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
     792           0 : std::unique_ptr<ASTType> Parser::type() {
     793           0 :     Token type;
     794           0 :     if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
     795           0 :         return nullptr;
     796             :     }
     797           0 :     if (!this->isType(type.fText)) {
     798           0 :         this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
     799           0 :         return nullptr;
     800             :     }
     801           0 :     std::vector<int> sizes;
     802           0 :     while (this->peek().fKind == Token::LBRACKET) {
     803           0 :         this->expect(Token::LBRACKET, "'['");
     804           0 :         if (this->peek().fKind != Token::RBRACKET) {
     805             :             int64_t i;
     806           0 :             if (this->intLiteral(&i)) {
     807           0 :                 sizes.push_back(i);
     808             :             } else {
     809           0 :                 return nullptr;
     810             :             }
     811             :         } else {
     812           0 :             sizes.push_back(-1);
     813             :         }
     814           0 :         this->expect(Token::RBRACKET, "']'");
     815             :     }
     816           0 :     return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
     817           0 :                                                 ASTType::kIdentifier_Kind, sizes));
     818             : }
     819             : 
     820             : /* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
     821           0 : std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
     822           0 :     Token name;
     823           0 :     if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
     824           0 :         return nullptr;
     825             :     }
     826           0 :     if (peek().fKind != Token::LBRACE) {
     827             :         // we only get into interfaceBlock if we found a top-level identifier which was not a type.
     828             :         // 99% of the time, the user was not actually intending to create an interface block, so
     829             :         // it's better to report it as an unknown type
     830           0 :         this->error(name.fPosition, "no type named '" + name.fText + "'");
     831           0 :         return nullptr;
     832             :     }
     833           0 :     this->nextToken();
     834           0 :     std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
     835           0 :     while (this->peek().fKind != Token::RBRACE) {
     836           0 :         std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
     837           0 :         if (!decl) {
     838           0 :             return nullptr;
     839             :         }
     840           0 :         decls.push_back(std::move(decl));
     841             :     }
     842           0 :     this->nextToken();
     843           0 :     String instanceName;
     844           0 :     std::vector<std::unique_ptr<ASTExpression>> sizes;
     845           0 :     if (this->peek().fKind == Token::IDENTIFIER) {
     846           0 :         instanceName = this->nextToken().fText;
     847           0 :         while (this->peek().fKind == Token::LBRACKET) {
     848           0 :             this->expect(Token::LBRACKET, "'['");
     849           0 :             if (this->peek().fKind != Token::RBRACKET) {
     850           0 :                 std::unique_ptr<ASTExpression> size = this->expression();
     851           0 :                 if (!size) {
     852           0 :                     return nullptr;
     853             :                 }
     854           0 :                 sizes.push_back(std::move(size));
     855             :             } else {
     856           0 :                 sizes.push_back(nullptr);
     857             :             }
     858           0 :             this->expect(Token::RBRACKET, "']'");
     859             :         }
     860             :     }
     861           0 :     this->expect(Token::SEMICOLON, "';'");
     862           0 :     return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
     863           0 :                                                                  name.fText, std::move(decls),
     864           0 :                                                                  std::move(instanceName),
     865           0 :                                                                  std::move(sizes)));
     866             : }
     867             : 
     868             : /* IF LPAREN expression RPAREN statement (ELSE statement)? */
     869           0 : std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
     870           0 :     Token start;
     871           0 :     if (!this->expect(Token::IF, "'if'", &start)) {
     872           0 :         return nullptr;
     873             :     }
     874           0 :     if (!this->expect(Token::LPAREN, "'('")) {
     875           0 :         return nullptr;
     876             :     }
     877           0 :     std::unique_ptr<ASTExpression> test(this->expression());
     878           0 :     if (!test) {
     879           0 :         return nullptr;
     880             :     }
     881           0 :     if (!this->expect(Token::RPAREN, "')'")) {
     882           0 :         return nullptr;
     883             :     }
     884           0 :     std::unique_ptr<ASTStatement> ifTrue(this->statement());
     885           0 :     if (!ifTrue) {
     886           0 :         return nullptr;
     887             :     }
     888           0 :     std::unique_ptr<ASTStatement> ifFalse;
     889           0 :     if (this->peek().fKind == Token::ELSE) {
     890           0 :         this->nextToken();
     891           0 :         ifFalse = this->statement();
     892           0 :         if (!ifFalse) {
     893           0 :             return nullptr;
     894             :         }
     895             :     }
     896           0 :     return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, std::move(test),
     897           0 :                                                               std::move(ifTrue),
     898           0 :                                                               std::move(ifFalse)));
     899             : }
     900             : 
     901             : /* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
     902           0 : std::unique_ptr<ASTDoStatement> Parser::doStatement() {
     903           0 :     Token start;
     904           0 :     if (!this->expect(Token::DO, "'do'", &start)) {
     905           0 :         return nullptr;
     906             :     }
     907           0 :     std::unique_ptr<ASTStatement> statement(this->statement());
     908           0 :     if (!statement) {
     909           0 :         return nullptr;
     910             :     }
     911           0 :     if (!this->expect(Token::WHILE, "'while'")) {
     912           0 :         return nullptr;
     913             :     }
     914           0 :     if (!this->expect(Token::LPAREN, "'('")) {
     915           0 :         return nullptr;
     916             :     }
     917           0 :     std::unique_ptr<ASTExpression> test(this->expression());
     918           0 :     if (!test) {
     919           0 :         return nullptr;
     920             :     }
     921           0 :     if (!this->expect(Token::RPAREN, "')'")) {
     922           0 :         return nullptr;
     923             :     }
     924           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
     925           0 :         return nullptr;
     926             :     }
     927           0 :     return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
     928           0 :                                                               std::move(statement),
     929           0 :                                                               std::move(test)));
     930             : }
     931             : 
     932             : /* WHILE LPAREN expression RPAREN STATEMENT */
     933           0 : std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
     934           0 :     Token start;
     935           0 :     if (!this->expect(Token::WHILE, "'while'", &start)) {
     936           0 :         return nullptr;
     937             :     }
     938           0 :     if (!this->expect(Token::LPAREN, "'('")) {
     939           0 :         return nullptr;
     940             :     }
     941           0 :     std::unique_ptr<ASTExpression> test(this->expression());
     942           0 :     if (!test) {
     943           0 :         return nullptr;
     944             :     }
     945           0 :     if (!this->expect(Token::RPAREN, "')'")) {
     946           0 :         return nullptr;
     947             :     }
     948           0 :     std::unique_ptr<ASTStatement> statement(this->statement());
     949           0 :     if (!statement) {
     950           0 :         return nullptr;
     951             :     }
     952           0 :     return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
     953           0 :                                                                     std::move(test),
     954           0 :                                                                     std::move(statement)));
     955             : }
     956             : 
     957             : /* CASE expression COLON statement* */
     958           0 : std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
     959           0 :     Token start;
     960           0 :     if (!this->expect(Token::CASE, "'case'", &start)) {
     961           0 :         return nullptr;
     962             :     }
     963           0 :     std::unique_ptr<ASTExpression> value = this->expression();
     964           0 :     if (!value) {
     965           0 :         return nullptr;
     966             :     }
     967           0 :     if (!this->expect(Token::COLON, "':'")) {
     968           0 :         return nullptr;
     969             :     }
     970           0 :     std::vector<std::unique_ptr<ASTStatement>> statements;
     971           0 :     while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
     972           0 :            this->peek().fKind != Token::DEFAULT) {
     973           0 :         std::unique_ptr<ASTStatement> s = this->statement();
     974           0 :         if (!s) {
     975           0 :             return nullptr;
     976             :         }
     977           0 :         statements.push_back(std::move(s));
     978             :     }
     979           0 :     return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fPosition, std::move(value),
     980           0 :                                                             std::move(statements)));
     981             : }
     982             : 
     983             : /* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
     984           0 : std::unique_ptr<ASTStatement> Parser::switchStatement() {
     985           0 :     Token start;
     986           0 :     if (!this->expect(Token::SWITCH, "'switch'", &start)) {
     987           0 :         return nullptr;
     988             :     }
     989           0 :     if (!this->expect(Token::LPAREN, "'('")) {
     990           0 :         return nullptr;
     991             :     }
     992           0 :     std::unique_ptr<ASTExpression> value(this->expression());
     993           0 :     if (!value) {
     994           0 :         return nullptr;
     995             :     }
     996           0 :     if (!this->expect(Token::RPAREN, "')'")) {
     997           0 :         return nullptr;
     998             :     }
     999           0 :     if (!this->expect(Token::LBRACE, "'{'")) {
    1000           0 :         return nullptr;
    1001             :     }
    1002           0 :     std::vector<std::unique_ptr<ASTSwitchCase>> cases;
    1003           0 :     while (this->peek().fKind == Token::CASE) {
    1004           0 :         std::unique_ptr<ASTSwitchCase> c = this->switchCase();
    1005           0 :         if (!c) {
    1006           0 :             return nullptr;
    1007             :         }
    1008           0 :         cases.push_back(std::move(c));
    1009             :     }
    1010             :     // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
    1011             :     // parts of the compiler may rely upon this assumption.
    1012           0 :     if (this->peek().fKind == Token::DEFAULT) {
    1013           0 :         Token defaultStart;
    1014           0 :         ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
    1015           0 :         if (!this->expect(Token::COLON, "':'")) {
    1016           0 :             return nullptr;
    1017             :         }
    1018           0 :         std::vector<std::unique_ptr<ASTStatement>> statements;
    1019           0 :         while (this->peek().fKind != Token::RBRACE) {
    1020           0 :             std::unique_ptr<ASTStatement> s = this->statement();
    1021           0 :             if (!s) {
    1022           0 :                 return nullptr;
    1023             :             }
    1024           0 :             statements.push_back(std::move(s));
    1025             :         }
    1026           0 :         cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr,
    1027           0 :                                              std::move(statements)));
    1028             :     }
    1029           0 :     if (!this->expect(Token::RBRACE, "'}'")) {
    1030           0 :         return nullptr;
    1031             :     }
    1032           0 :     return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition,
    1033           0 :                                                                 std::move(value),
    1034           0 :                                                                 std::move(cases)));
    1035             : }
    1036             : 
    1037             : /* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
    1038             :    STATEMENT */
    1039           0 : std::unique_ptr<ASTForStatement> Parser::forStatement() {
    1040           0 :     Token start;
    1041           0 :     if (!this->expect(Token::FOR, "'for'", &start)) {
    1042           0 :         return nullptr;
    1043             :     }
    1044           0 :     if (!this->expect(Token::LPAREN, "'('")) {
    1045           0 :         return nullptr;
    1046             :     }
    1047           0 :     std::unique_ptr<ASTStatement> initializer;
    1048           0 :     Token nextToken = this->peek();
    1049           0 :     switch (nextToken.fKind) {
    1050             :         case Token::SEMICOLON:
    1051           0 :             this->nextToken();
    1052           0 :             break;
    1053             :         case Token::CONST: {
    1054           0 :             std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
    1055           0 :             if (!vd) {
    1056           0 :                 return nullptr;
    1057             :             }
    1058           0 :             initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
    1059           0 :                                                                                     std::move(vd)));
    1060           0 :             break;
    1061             :         }
    1062             :         case Token::IDENTIFIER: {
    1063           0 :             if (this->isType(nextToken.fText)) {
    1064           0 :                 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
    1065           0 :                 if (!vd) {
    1066           0 :                     return nullptr;
    1067             :                 }
    1068           0 :                 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
    1069           0 :                                                                                     std::move(vd)));
    1070           0 :                 break;
    1071             :             }
    1072             :         } // fall through
    1073             :         default:
    1074           0 :             initializer = this->expressionStatement();
    1075             :     }
    1076           0 :     std::unique_ptr<ASTExpression> test;
    1077           0 :     if (this->peek().fKind != Token::SEMICOLON) {
    1078           0 :         test = this->expression();
    1079           0 :         if (!test) {
    1080           0 :             return nullptr;
    1081             :         }
    1082             :     }
    1083           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
    1084           0 :         return nullptr;
    1085             :     }
    1086           0 :     std::unique_ptr<ASTExpression> next;
    1087           0 :     if (this->peek().fKind != Token::RPAREN) {
    1088           0 :         next = this->expression();
    1089           0 :         if (!next) {
    1090           0 :             return nullptr;
    1091             :         }
    1092             :     }
    1093           0 :     if (!this->expect(Token::RPAREN, "')'")) {
    1094           0 :         return nullptr;
    1095             :     }
    1096           0 :     std::unique_ptr<ASTStatement> statement(this->statement());
    1097           0 :     if (!statement) {
    1098           0 :         return nullptr;
    1099             :     }
    1100           0 :     return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
    1101           0 :                                                                 std::move(initializer),
    1102           0 :                                                                 std::move(test), std::move(next),
    1103           0 :                                                                 std::move(statement)));
    1104             : }
    1105             : 
    1106             : /* RETURN expression? SEMICOLON */
    1107           0 : std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
    1108           0 :     Token start;
    1109           0 :     if (!this->expect(Token::RETURN, "'return'", &start)) {
    1110           0 :         return nullptr;
    1111             :     }
    1112           0 :     std::unique_ptr<ASTExpression> expression;
    1113           0 :     if (this->peek().fKind != Token::SEMICOLON) {
    1114           0 :         expression = this->expression();
    1115           0 :         if (!expression) {
    1116           0 :             return nullptr;
    1117             :         }
    1118             :     }
    1119           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
    1120           0 :         return nullptr;
    1121             :     }
    1122           0 :     return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
    1123           0 :                                                                       std::move(expression)));
    1124             : }
    1125             : 
    1126             : /* BREAK SEMICOLON */
    1127           0 : std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
    1128           0 :     Token start;
    1129           0 :     if (!this->expect(Token::BREAK, "'break'", &start)) {
    1130           0 :         return nullptr;
    1131             :     }
    1132           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
    1133           0 :         return nullptr;
    1134             :     }
    1135           0 :     return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
    1136             : }
    1137             : 
    1138             : /* CONTINUE SEMICOLON */
    1139           0 : std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
    1140           0 :     Token start;
    1141           0 :     if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
    1142           0 :         return nullptr;
    1143             :     }
    1144           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
    1145           0 :         return nullptr;
    1146             :     }
    1147           0 :     return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
    1148             : }
    1149             : 
    1150             : /* DISCARD SEMICOLON */
    1151           0 : std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
    1152           0 :     Token start;
    1153           0 :     if (!this->expect(Token::DISCARD, "'continue'", &start)) {
    1154           0 :         return nullptr;
    1155             :     }
    1156           0 :     if (!this->expect(Token::SEMICOLON, "';'")) {
    1157           0 :         return nullptr;
    1158             :     }
    1159           0 :     return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
    1160             : }
    1161             : 
    1162             : /* LBRACE statement* RBRACE */
    1163           0 : std::unique_ptr<ASTBlock> Parser::block() {
    1164           0 :     AutoDepth depth(this);
    1165           0 :     if (!depth.checkValid()) {
    1166           0 :         return nullptr;
    1167             :     }
    1168           0 :     Token start;
    1169           0 :     if (!this->expect(Token::LBRACE, "'{'", &start)) {
    1170           0 :         return nullptr;
    1171             :     }
    1172           0 :     std::vector<std::unique_ptr<ASTStatement>> statements;
    1173             :     for (;;) {
    1174           0 :         switch (this->peek().fKind) {
    1175             :             case Token::RBRACE:
    1176           0 :                 this->nextToken();
    1177           0 :                 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
    1178           0 :                                                               std::move(statements)));
    1179             :             case Token::END_OF_FILE:
    1180           0 :                 this->error(this->peek().fPosition, "expected '}', but found end of file");
    1181           0 :                 return nullptr;
    1182             :             default: {
    1183           0 :                 std::unique_ptr<ASTStatement> statement = this->statement();
    1184           0 :                 if (!statement) {
    1185           0 :                     return nullptr;
    1186             :                 }
    1187           0 :                 statements.push_back(std::move(statement));
    1188             :             }
    1189             :         }
    1190           0 :     }
    1191             : }
    1192             : 
    1193             : /* expression SEMICOLON */
    1194           0 : std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
    1195           0 :     std::unique_ptr<ASTExpression> expr = this->expression();
    1196           0 :     if (expr) {
    1197           0 :         if (this->expect(Token::SEMICOLON, "';'")) {
    1198           0 :             ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
    1199           0 :             return std::unique_ptr<ASTExpressionStatement>(result);
    1200             :         }
    1201             :     }
    1202           0 :     return nullptr;
    1203             : }
    1204             : 
    1205             : /* assignmentExpression */
    1206           0 : std::unique_ptr<ASTExpression> Parser::expression() {
    1207           0 :     AutoDepth depth(this);
    1208           0 :     if (!depth.checkValid()) {
    1209           0 :         return nullptr;
    1210             :     }
    1211           0 :     return this->assignmentExpression();
    1212             : }
    1213             : 
    1214             : /* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
    1215             :    BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
    1216             :    assignmentExpression)*
    1217             :  */
    1218           0 : std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
    1219           0 :     std::unique_ptr<ASTExpression> result = this->ternaryExpression();
    1220           0 :     if (!result) {
    1221           0 :         return nullptr;
    1222             :     }
    1223             :     for (;;) {
    1224           0 :         switch (this->peek().fKind) {
    1225             :             case Token::EQ:           // fall through
    1226             :             case Token::STAREQ:       // fall through
    1227             :             case Token::SLASHEQ:      // fall through
    1228             :             case Token::PERCENTEQ:    // fall through
    1229             :             case Token::PLUSEQ:       // fall through
    1230             :             case Token::MINUSEQ:      // fall through
    1231             :             case Token::SHLEQ:        // fall through
    1232             :             case Token::SHREQ:        // fall through
    1233             :             case Token::BITWISEANDEQ: // fall through
    1234             :             case Token::BITWISEXOREQ: // fall through
    1235             :             case Token::BITWISEOREQ:  // fall through
    1236             :             case Token::LOGICALANDEQ: // fall through
    1237             :             case Token::LOGICALXOREQ: // fall through
    1238             :             case Token::LOGICALOREQ: {
    1239           0 :                 Token t = this->nextToken();
    1240           0 :                 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
    1241           0 :                 if (!right) {
    1242           0 :                     return nullptr;
    1243             :                 }
    1244           0 :                 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
    1245             :                                                                                 t,
    1246           0 :                                                                                 std::move(right)));
    1247             :             }
    1248             :             default:
    1249           0 :                 return result;
    1250             :         }
    1251             :     }
    1252             : }
    1253             : 
    1254             : /* logicalOrExpression ('?' expression ':' assignmentExpression)? */
    1255           0 : std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
    1256           0 :     std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
    1257           0 :     if (!result) {
    1258           0 :         return nullptr;
    1259             :     }
    1260           0 :     if (this->peek().fKind == Token::QUESTION) {
    1261           0 :         Token question = this->nextToken();
    1262           0 :         std::unique_ptr<ASTExpression> trueExpr = this->expression();
    1263           0 :         if (!trueExpr) {
    1264           0 :             return nullptr;
    1265             :         }
    1266           0 :         if (this->expect(Token::COLON, "':'")) {
    1267           0 :             std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
    1268           0 :             return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
    1269           0 :                                                                            std::move(trueExpr),
    1270           0 :                                                                            std::move(falseExpr)));
    1271             :         }
    1272           0 :         return nullptr;
    1273             :     }
    1274           0 :     return result;
    1275             : }
    1276             : 
    1277             : /* logicalXorExpression (LOGICALOR logicalXorExpression)* */
    1278           0 : std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
    1279           0 :     std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
    1280           0 :     if (!result) {
    1281           0 :         return nullptr;
    1282             :     }
    1283           0 :     while (this->peek().fKind == Token::LOGICALOR) {
    1284           0 :         Token t = this->nextToken();
    1285           0 :         std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
    1286           0 :         if (!right) {
    1287           0 :             return nullptr;
    1288             :         }
    1289           0 :         result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1290             :     }
    1291           0 :     return result;
    1292             : }
    1293             : 
    1294             : /* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
    1295           0 : std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
    1296           0 :     std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
    1297           0 :     if (!result) {
    1298           0 :         return nullptr;
    1299             :     }
    1300           0 :     while (this->peek().fKind == Token::LOGICALXOR) {
    1301           0 :         Token t = this->nextToken();
    1302           0 :         std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
    1303           0 :         if (!right) {
    1304           0 :             return nullptr;
    1305             :         }
    1306           0 :         result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1307             :     }
    1308           0 :     return result;
    1309             : }
    1310             : 
    1311             : /* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
    1312           0 : std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
    1313           0 :     std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
    1314           0 :     if (!result) {
    1315           0 :         return nullptr;
    1316             :     }
    1317           0 :     while (this->peek().fKind == Token::LOGICALAND) {
    1318           0 :         Token t = this->nextToken();
    1319           0 :         std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
    1320           0 :         if (!right) {
    1321           0 :             return nullptr;
    1322             :         }
    1323           0 :         result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1324             :     }
    1325           0 :     return result;
    1326             : }
    1327             : 
    1328             : /* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
    1329           0 : std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
    1330           0 :     std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
    1331           0 :     if (!result) {
    1332           0 :         return nullptr;
    1333             :     }
    1334           0 :     while (this->peek().fKind == Token::BITWISEOR) {
    1335           0 :         Token t = this->nextToken();
    1336           0 :         std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
    1337           0 :         if (!right) {
    1338           0 :             return nullptr;
    1339             :         }
    1340           0 :         result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1341             :     }
    1342           0 :     return result;
    1343             : }
    1344             : 
    1345             : /* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
    1346           0 : std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
    1347           0 :     std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
    1348           0 :     if (!result) {
    1349           0 :         return nullptr;
    1350             :     }
    1351           0 :     while (this->peek().fKind == Token::BITWISEXOR) {
    1352           0 :         Token t = this->nextToken();
    1353           0 :         std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
    1354           0 :         if (!right) {
    1355           0 :             return nullptr;
    1356             :         }
    1357           0 :         result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1358             :     }
    1359           0 :     return result;
    1360             : }
    1361             : 
    1362             : /* equalityExpression (BITWISEAND equalityExpression)* */
    1363           0 : std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
    1364           0 :     std::unique_ptr<ASTExpression> result = this->equalityExpression();
    1365           0 :     if (!result) {
    1366           0 :         return nullptr;
    1367             :     }
    1368           0 :     while (this->peek().fKind == Token::BITWISEAND) {
    1369           0 :         Token t = this->nextToken();
    1370           0 :         std::unique_ptr<ASTExpression> right = this->equalityExpression();
    1371           0 :         if (!right) {
    1372           0 :             return nullptr;
    1373             :         }
    1374           0 :         result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1375             :     }
    1376           0 :     return result;
    1377             : }
    1378             : 
    1379             : /* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
    1380           0 : std::unique_ptr<ASTExpression> Parser::equalityExpression() {
    1381           0 :     std::unique_ptr<ASTExpression> result = this->relationalExpression();
    1382           0 :     if (!result) {
    1383           0 :         return nullptr;
    1384             :     }
    1385             :     for (;;) {
    1386           0 :         switch (this->peek().fKind) {
    1387             :             case Token::EQEQ:   // fall through
    1388             :             case Token::NEQ: {
    1389           0 :                 Token t = this->nextToken();
    1390           0 :                 std::unique_ptr<ASTExpression> right = this->relationalExpression();
    1391           0 :                 if (!right) {
    1392           0 :                     return nullptr;
    1393             :                 }
    1394           0 :                 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1395           0 :                 break;
    1396             :             }
    1397             :             default:
    1398           0 :                 return result;
    1399             :         }
    1400           0 :     }
    1401             : }
    1402             : 
    1403             : /* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
    1404           0 : std::unique_ptr<ASTExpression> Parser::relationalExpression() {
    1405           0 :     std::unique_ptr<ASTExpression> result = this->shiftExpression();
    1406           0 :     if (!result) {
    1407           0 :         return nullptr;
    1408             :     }
    1409             :     for (;;) {
    1410           0 :         switch (this->peek().fKind) {
    1411             :             case Token::LT:   // fall through
    1412             :             case Token::GT:   // fall through
    1413             :             case Token::LTEQ: // fall through
    1414             :             case Token::GTEQ: {
    1415           0 :                 Token t = this->nextToken();
    1416           0 :                 std::unique_ptr<ASTExpression> right = this->shiftExpression();
    1417           0 :                 if (!right) {
    1418           0 :                     return nullptr;
    1419             :                 }
    1420           0 :                 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1421           0 :                 break;
    1422             :             }
    1423             :             default:
    1424           0 :                 return result;
    1425             :         }
    1426           0 :     }
    1427             : }
    1428             : 
    1429             : /* additiveExpression ((SHL | SHR) additiveExpression)* */
    1430           0 : std::unique_ptr<ASTExpression> Parser::shiftExpression() {
    1431           0 :     std::unique_ptr<ASTExpression> result = this->additiveExpression();
    1432           0 :     if (!result) {
    1433           0 :         return nullptr;
    1434             :     }
    1435             :     for (;;) {
    1436           0 :         switch (this->peek().fKind) {
    1437             :             case Token::SHL: // fall through
    1438             :             case Token::SHR: {
    1439           0 :                 Token t = this->nextToken();
    1440           0 :                 std::unique_ptr<ASTExpression> right = this->additiveExpression();
    1441           0 :                 if (!right) {
    1442           0 :                     return nullptr;
    1443             :                 }
    1444           0 :                 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1445           0 :                 break;
    1446             :             }
    1447             :             default:
    1448           0 :                 return result;
    1449             :         }
    1450           0 :     }
    1451             : }
    1452             : 
    1453             : /* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
    1454           0 : std::unique_ptr<ASTExpression> Parser::additiveExpression() {
    1455           0 :     std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
    1456           0 :     if (!result) {
    1457           0 :         return nullptr;
    1458             :     }
    1459             :     for (;;) {
    1460           0 :         switch (this->peek().fKind) {
    1461             :             case Token::PLUS: // fall through
    1462             :             case Token::MINUS: {
    1463           0 :                 Token t = this->nextToken();
    1464           0 :                 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
    1465           0 :                 if (!right) {
    1466           0 :                     return nullptr;
    1467             :                 }
    1468           0 :                 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1469           0 :                 break;
    1470             :             }
    1471             :             default:
    1472           0 :                 return result;
    1473             :         }
    1474           0 :     }
    1475             : }
    1476             : 
    1477             : /* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
    1478           0 : std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
    1479           0 :     std::unique_ptr<ASTExpression> result = this->unaryExpression();
    1480           0 :     if (!result) {
    1481           0 :         return nullptr;
    1482             :     }
    1483             :     for (;;) {
    1484           0 :         switch (this->peek().fKind) {
    1485             :             case Token::STAR: // fall through
    1486             :             case Token::SLASH: // fall through
    1487             :             case Token::PERCENT: {
    1488           0 :                 Token t = this->nextToken();
    1489           0 :                 std::unique_ptr<ASTExpression> right = this->unaryExpression();
    1490           0 :                 if (!right) {
    1491           0 :                     return nullptr;
    1492             :                 }
    1493           0 :                 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
    1494           0 :                 break;
    1495             :             }
    1496             :             default:
    1497           0 :                 return result;
    1498             :         }
    1499           0 :     }
    1500             : }
    1501             : 
    1502             : /* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
    1503           0 : std::unique_ptr<ASTExpression> Parser::unaryExpression() {
    1504           0 :     switch (this->peek().fKind) {
    1505             :         case Token::PLUS:       // fall through
    1506             :         case Token::MINUS:      // fall through
    1507             :         case Token::LOGICALNOT: // fall through
    1508             :         case Token::BITWISENOT: // fall through
    1509             :         case Token::PLUSPLUS:   // fall through
    1510             :         case Token::MINUSMINUS: {
    1511           0 :             Token t = this->nextToken();
    1512           0 :             std::unique_ptr<ASTExpression> expr = this->unaryExpression();
    1513           0 :             if (!expr) {
    1514           0 :                 return nullptr;
    1515             :             }
    1516           0 :             return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
    1517             :         }
    1518             :         default:
    1519           0 :             return this->postfixExpression();
    1520             :     }
    1521             : }
    1522             : 
    1523             : /* term suffix* */
    1524           0 : std::unique_ptr<ASTExpression> Parser::postfixExpression() {
    1525           0 :     std::unique_ptr<ASTExpression> result = this->term();
    1526           0 :     if (!result) {
    1527           0 :         return nullptr;
    1528             :     }
    1529             :     for (;;) {
    1530           0 :         switch (this->peek().fKind) {
    1531             :             case Token::LBRACKET: // fall through
    1532             :             case Token::DOT:      // fall through
    1533             :             case Token::LPAREN:   // fall through
    1534             :             case Token::PLUSPLUS: // fall through
    1535             :             case Token::MINUSMINUS: {
    1536           0 :                 std::unique_ptr<ASTSuffix> s = this->suffix();
    1537           0 :                 if (!s) {
    1538           0 :                     return nullptr;
    1539             :                 }
    1540           0 :                 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
    1541           0 :                 break;
    1542             :             }
    1543             :             default:
    1544           0 :                 return result;
    1545             :         }
    1546           0 :     }
    1547             : }
    1548             : 
    1549             : /* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
    1550             :    PLUSPLUS | MINUSMINUS */
    1551           0 : std::unique_ptr<ASTSuffix> Parser::suffix() {
    1552           0 :     Token next = this->nextToken();
    1553           0 :     switch (next.fKind) {
    1554             :         case Token::LBRACKET: {
    1555           0 :             if (this->peek().fKind == Token::RBRACKET) {
    1556           0 :                 this->nextToken();
    1557           0 :                 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
    1558             :             }
    1559           0 :             std::unique_ptr<ASTExpression> e = this->expression();
    1560           0 :             if (!e) {
    1561           0 :                 return nullptr;
    1562             :             }
    1563           0 :             this->expect(Token::RBRACKET, "']' to complete array access expression");
    1564           0 :             return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
    1565             :         }
    1566             :         case Token::DOT: {
    1567           0 :             Position pos = this->peek().fPosition;
    1568           0 :             String text;
    1569           0 :             if (this->identifier(&text)) {
    1570           0 :                 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
    1571             :             }
    1572           0 :             return nullptr;
    1573             :         }
    1574             :         case Token::LPAREN: {
    1575           0 :             std::vector<std::unique_ptr<ASTExpression>> parameters;
    1576           0 :             if (this->peek().fKind != Token::RPAREN) {
    1577             :                 for (;;) {
    1578           0 :                     std::unique_ptr<ASTExpression> expr = this->expression();
    1579           0 :                     if (!expr) {
    1580           0 :                         return nullptr;
    1581             :                     }
    1582           0 :                     parameters.push_back(std::move(expr));
    1583           0 :                     if (this->peek().fKind != Token::COMMA) {
    1584           0 :                         break;
    1585             :                     }
    1586           0 :                     this->nextToken();
    1587           0 :                 }
    1588             :             }
    1589           0 :             this->expect(Token::RPAREN, "')' to complete function parameters");
    1590           0 :             return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
    1591           0 :                                                                 std::move(parameters)));
    1592             :         }
    1593             :         case Token::PLUSPLUS:
    1594           0 :             return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
    1595           0 :                                                             ASTSuffix::kPostIncrement_Kind));
    1596             :         case Token::MINUSMINUS:
    1597           0 :             return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
    1598           0 :                                                             ASTSuffix::kPostDecrement_Kind));
    1599             :         default: {
    1600           0 :             this->error(next.fPosition,  "expected expression suffix, but found '" + next.fText +
    1601           0 :                                          "'\n");
    1602           0 :             return nullptr;
    1603             :         }
    1604             :     }
    1605             : }
    1606             : 
    1607             : /* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
    1608           0 : std::unique_ptr<ASTExpression> Parser::term() {
    1609           0 :     std::unique_ptr<ASTExpression> result;
    1610           0 :     Token t = this->peek();
    1611           0 :     switch (t.fKind) {
    1612             :         case Token::IDENTIFIER: {
    1613           0 :             String text;
    1614           0 :             if (this->identifier(&text)) {
    1615           0 :                 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
    1616             :             }
    1617           0 :             break;
    1618             :         }
    1619             :         case Token::INT_LITERAL: {
    1620             :             int64_t i;
    1621           0 :             if (this->intLiteral(&i)) {
    1622           0 :                 result.reset(new ASTIntLiteral(t.fPosition, i));
    1623             :             }
    1624           0 :             break;
    1625             :         }
    1626             :         case Token::FLOAT_LITERAL: {
    1627             :             double f;
    1628           0 :             if (this->floatLiteral(&f)) {
    1629           0 :                 result.reset(new ASTFloatLiteral(t.fPosition, f));
    1630             :             }
    1631           0 :             break;
    1632             :         }
    1633             :         case Token::TRUE_LITERAL: // fall through
    1634             :         case Token::FALSE_LITERAL: {
    1635             :             bool b;
    1636           0 :             if (this->boolLiteral(&b)) {
    1637           0 :                 result.reset(new ASTBoolLiteral(t.fPosition, b));
    1638             :             }
    1639           0 :             break;
    1640             :         }
    1641             :         case Token::LPAREN: {
    1642           0 :             this->nextToken();
    1643           0 :             result = this->expression();
    1644           0 :             if (result) {
    1645           0 :                 this->expect(Token::RPAREN, "')' to complete expression");
    1646             :             }
    1647           0 :             break;
    1648             :         }
    1649             :         default:
    1650           0 :             this->nextToken();
    1651           0 :             this->error(t.fPosition,  "expected expression, but found '" + t.fText + "'\n");
    1652           0 :             result = nullptr;
    1653             :     }
    1654           0 :     return result;
    1655             : }
    1656             : 
    1657             : /* INT_LITERAL */
    1658           0 : bool Parser::intLiteral(int64_t* dest) {
    1659           0 :     Token t;
    1660           0 :     if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
    1661           0 :         *dest = SkSL::stol(t.fText);
    1662           0 :         return true;
    1663             :     }
    1664           0 :     return false;
    1665             : }
    1666             : 
    1667             : /* FLOAT_LITERAL */
    1668           0 : bool Parser::floatLiteral(double* dest) {
    1669           0 :     Token t;
    1670           0 :     if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
    1671           0 :         *dest = SkSL::stod(t.fText);
    1672           0 :         return true;
    1673             :     }
    1674           0 :     return false;
    1675             : }
    1676             : 
    1677             : /* TRUE_LITERAL | FALSE_LITERAL */
    1678           0 : bool Parser::boolLiteral(bool* dest) {
    1679           0 :     Token t = this->nextToken();
    1680           0 :     switch (t.fKind) {
    1681             :         case Token::TRUE_LITERAL:
    1682           0 :             *dest = true;
    1683           0 :             return true;
    1684             :         case Token::FALSE_LITERAL:
    1685           0 :             *dest = false;
    1686           0 :             return true;
    1687             :         default:
    1688           0 :             this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
    1689           0 :             return false;
    1690             :     }
    1691             : }
    1692             : 
    1693             : /* IDENTIFIER */
    1694           0 : bool Parser::identifier(String* dest) {
    1695           0 :     Token t;
    1696           0 :     if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
    1697           0 :         *dest = t.fText;
    1698           0 :         return true;
    1699             :     }
    1700           0 :     return false;
    1701             : }
    1702             : 
    1703             : } // namespace

Generated by: LCOV version 1.13