SkSLParser.cpp revision d214d6ae69c1dd9ef49fdce8fac699d00bffcdcd
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#ifdef __clang__
14#pragma clang diagnostic push
15#pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
16#pragma clang diagnostic ignored "-Wnull-conversion"
17#pragma clang diagnostic ignored "-Wsign-compare"
18#endif
19#ifdef __GNUC__
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wsign-compare"
22#endif
23#ifdef _MSC_VER
24#pragma warning(push)
25#pragma warning(disable:4018)
26#endif
27#include "lex.sksl.c"
28#ifdef __clang__
29#pragma clang diagnostic pop
30#endif
31#ifdef __GNUC__
32#pragma GCC diagnostic pop
33#endif
34#ifdef _MSC_VER
35#pragma warning(pop)
36#endif
37#undef register
38
39#include "ast/SkSLASTBinaryExpression.h"
40#include "ast/SkSLASTBlock.h"
41#include "ast/SkSLASTBoolLiteral.h"
42#include "ast/SkSLASTBreakStatement.h"
43#include "ast/SkSLASTCallSuffix.h"
44#include "ast/SkSLASTContinueStatement.h"
45#include "ast/SkSLASTDiscardStatement.h"
46#include "ast/SkSLASTDoStatement.h"
47#include "ast/SkSLASTExpression.h"
48#include "ast/SkSLASTExpressionStatement.h"
49#include "ast/SkSLASTExtension.h"
50#include "ast/SkSLASTFieldSuffix.h"
51#include "ast/SkSLASTFloatLiteral.h"
52#include "ast/SkSLASTForStatement.h"
53#include "ast/SkSLASTFunction.h"
54#include "ast/SkSLASTIdentifier.h"
55#include "ast/SkSLASTIfStatement.h"
56#include "ast/SkSLASTIndexSuffix.h"
57#include "ast/SkSLASTInterfaceBlock.h"
58#include "ast/SkSLASTIntLiteral.h"
59#include "ast/SkSLASTParameter.h"
60#include "ast/SkSLASTPrefixExpression.h"
61#include "ast/SkSLASTReturnStatement.h"
62#include "ast/SkSLASTStatement.h"
63#include "ast/SkSLASTSuffixExpression.h"
64#include "ast/SkSLASTTernaryExpression.h"
65#include "ast/SkSLASTType.h"
66#include "ast/SkSLASTVarDeclaration.h"
67#include "ast/SkSLASTVarDeclarationStatement.h"
68#include "ast/SkSLASTWhileStatement.h"
69#include "ir/SkSLSymbolTable.h"
70#include "ir/SkSLType.h"
71
72namespace SkSL {
73
74Parser::Parser(std::string text, SymbolTable& types, ErrorReporter& errors)
75: fPushback(Position(-1, -1), Token::INVALID_TOKEN, "")
76, fTypes(types)
77, fErrors(errors) {
78    sksllex_init(&fScanner);
79    fBuffer = sksl_scan_string(text.c_str(), fScanner);
80    skslset_lineno(1, fScanner);
81
82    if (false) {
83        // avoid unused warning
84        yyunput(0, nullptr, fScanner);
85    }
86}
87
88Parser::~Parser() {
89    sksl_delete_buffer(fBuffer, fScanner);
90    sksllex_destroy(fScanner);
91}
92
93/* (precision | directive | declaration)* END_OF_FILE */
94std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
95    std::vector<std::unique_ptr<ASTDeclaration>> result;
96    for (;;) {
97        switch (this->peek().fKind) {
98            case Token::END_OF_FILE:
99                return result;
100            case Token::PRECISION:
101                this->precision();
102                break;
103            case Token::DIRECTIVE: {
104                std::unique_ptr<ASTDeclaration> decl = this->directive();
105                if (decl) {
106                    result.push_back(std::move(decl));
107                }
108                break;
109            }
110            default: {
111                std::unique_ptr<ASTDeclaration> decl = this->declaration();
112                if (!decl) {
113                    continue;
114                }
115                result.push_back(std::move(decl));
116            }
117        }
118    }
119}
120
121Token Parser::nextToken() {
122    if (fPushback.fKind != Token::INVALID_TOKEN) {
123        Token result = fPushback;
124        fPushback.fKind = Token::INVALID_TOKEN;
125        fPushback.fText = "";
126        return result;
127    }
128    int token = sksllex(fScanner);
129    return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token,
130                 token == Token::END_OF_FILE ? "<end of file>" :
131                                               std::string(skslget_text(fScanner)));
132}
133
134void Parser::pushback(Token t) {
135    ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
136    fPushback = t;
137}
138
139Token Parser::peek() {
140    fPushback = this->nextToken();
141    return fPushback;
142}
143
144bool Parser::expect(Token::Kind kind, std::string expected, Token* result) {
145    Token next = this->nextToken();
146    if (next.fKind == kind) {
147        if (result) {
148            *result = next;
149        }
150        return true;
151    } else {
152        this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText + "'");
153        return false;
154    }
155}
156
157void Parser::error(Position p, std::string msg) {
158    fErrors.error(p, msg);
159}
160
161bool Parser::isType(std::string name) {
162    return nullptr != fTypes[name];
163}
164
165/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
166void Parser::precision() {
167    if (!this->expect(Token::PRECISION, "'precision'")) {
168        return;
169    }
170    Token p = this->nextToken();
171    switch (p.fKind) {
172        case Token::LOWP: // fall through
173        case Token::MEDIUMP: // fall through
174        case Token::HIGHP:
175            // ignored for now
176            break;
177        default:
178            this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
179                                     p.fText + "'");
180            return;
181    }
182    if (!this->type()) {
183        return;
184    }
185    this->expect(Token::SEMICOLON, "';'");
186}
187
188/* DIRECTIVE(#version) INT_LITERAL | DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
189std::unique_ptr<ASTDeclaration> Parser::directive() {
190    Token start;
191    if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
192        return nullptr;
193    }
194    if (start.fText == "#version") {
195        this->expect(Token::INT_LITERAL, "a version number");
196        // ignored for now
197        return nullptr;
198    } else if (start.fText == "#extension") {
199        Token name;
200        if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
201            return nullptr;
202        }
203        if (!this->expect(Token::COLON, "':'")) {
204            return nullptr;
205        }
206        // FIXME: need to start paying attention to this token
207        if (!this->expect(Token::IDENTIFIER, "an identifier")) {
208            return nullptr;
209        }
210        return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
211                                                                std::move(name.fText)));
212    } else {
213        this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
214        return nullptr;
215    }
216}
217
218/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
219   (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
220std::unique_ptr<ASTDeclaration> Parser::declaration() {
221    ASTModifiers modifiers = this->modifiers();
222    Token lookahead = this->peek();
223    if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
224        // we have an identifier that's not a type, could be the start of an interface block
225        return this->interfaceBlock(modifiers);
226    }
227    if (lookahead.fKind == Token::STRUCT) {
228        return this->structVarDeclaration(modifiers);
229    }
230    std::unique_ptr<ASTType> type(this->type());
231    if (!type) {
232        return nullptr;
233    }
234    if (type->fKind == ASTType::kStruct_Kind && peek().fKind == Token::SEMICOLON) {
235        this->nextToken();
236        return nullptr;
237    }
238    Token name;
239    if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
240        return nullptr;
241    }
242    if (!modifiers.fFlags && this->peek().fKind == Token::LPAREN) {
243        this->nextToken();
244        std::vector<std::unique_ptr<ASTParameter>> parameters;
245        while (this->peek().fKind != Token::RPAREN) {
246            if (parameters.size() > 0) {
247                if (!this->expect(Token::COMMA, "','")) {
248                    return nullptr;
249                }
250            }
251            std::unique_ptr<ASTParameter> parameter = this->parameter();
252            if (!parameter) {
253                return nullptr;
254            }
255            parameters.push_back(std::move(parameter));
256        }
257        this->nextToken();
258        std::unique_ptr<ASTBlock> body;
259        if (this->peek().fKind == Token::SEMICOLON) {
260            this->nextToken();
261        } else {
262            body = this->block();
263            if (!body) {
264                return nullptr;
265            }
266        }
267        return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition, std::move(type),
268                                                               std::move(name.fText),
269                                                               std::move(parameters),
270                                                               std::move(body)));
271    } else {
272        return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
273    }
274}
275
276/* modifiers type IDENTIFIER varDeclarationEnd */
277std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
278    ASTModifiers modifiers = this->modifiers();
279    std::unique_ptr<ASTType> type(this->type());
280    if (!type) {
281        return nullptr;
282    }
283    Token name;
284    if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
285        return nullptr;
286    }
287    return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
288}
289
290/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
291std::unique_ptr<ASTType> Parser::structDeclaration() {
292    if (!this->expect(Token::STRUCT, "'struct'")) {
293        return nullptr;
294    }
295    Token name;
296    if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
297        return nullptr;
298    }
299    if (!this->expect(Token::LBRACE, "'{'")) {
300        return nullptr;
301    }
302    std::vector<Type::Field> fields;
303    while (this->peek().fKind != Token::RBRACE) {
304        std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
305        if (!decl) {
306            return nullptr;
307        }
308        for (const auto& var : decl->fVars) {
309            auto type = (const Type*) fTypes[decl->fType->fName];
310            for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
311                if (var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
312                    this->error(decl->fPosition, "array size in struct field must be a constant");
313                }
314                uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
315                std::string name = type->name() + "[" + to_string(columns) + "]";
316                type = new Type(name, Type::kArray_Kind, *type, (int) columns);
317                fTypes.takeOwnership((Type*) type);
318            }
319            fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
320            if (var.fValue) {
321                this->error(decl->fPosition, "initializers are not permitted on struct fields");
322            }
323        }
324    }
325    if (!this->expect(Token::RBRACE, "'}'")) {
326        return nullptr;
327    }
328    fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fText, fields)));
329    return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
330                                                ASTType::kStruct_Kind));
331}
332
333/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
334std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(ASTModifiers modifiers) {
335    std::unique_ptr<ASTType> type = this->structDeclaration();
336    if (!type) {
337        return nullptr;
338    }
339    if (peek().fKind == Token::IDENTIFIER) {
340        Token name = this->nextToken();
341        std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
342                                                                             std::move(type),
343                                                                             std::move(name.fText));
344        if (result) {
345            for (const auto& var : result->fVars) {
346                if (var.fValue) {
347                    this->error(var.fValue->fPosition,
348                                "struct variables cannot be initialized");
349                }
350            }
351        }
352        return result;
353    }
354    this->expect(Token::SEMICOLON, "';'");
355    return nullptr;
356}
357
358/* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER
359   (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */
360std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(ASTModifiers mods,
361                                                              std::unique_ptr<ASTType> type,
362                                                              std::string name) {
363    std::vector<ASTVarDeclaration> vars;
364    std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
365    while (this->peek().fKind == Token::LBRACKET) {
366        this->nextToken();
367        if (this->peek().fKind == Token::RBRACKET) {
368            this->nextToken();
369            currentVarSizes.push_back(nullptr);
370        } else {
371            std::unique_ptr<ASTExpression> size(this->expression());
372            if (!size) {
373                return nullptr;
374            }
375            currentVarSizes.push_back(std::move(size));
376            if (!this->expect(Token::RBRACKET, "']'")) {
377                return nullptr;
378            }
379        }
380    }
381    std::unique_ptr<ASTExpression> value;
382    if (this->peek().fKind == Token::EQ) {
383        this->nextToken();
384        value = this->expression();
385        if (!value) {
386            return nullptr;
387        }
388    }
389    vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
390    while (this->peek().fKind == Token::COMMA) {
391        this->nextToken();
392        Token name;
393        if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
394            return nullptr;
395        }
396        currentVarSizes.clear();
397        value.reset();
398        while (this->peek().fKind == Token::LBRACKET) {
399            this->nextToken();
400            if (this->peek().fKind == Token::RBRACKET) {
401                this->nextToken();
402                currentVarSizes.push_back(nullptr);
403            } else {
404                std::unique_ptr<ASTExpression> size(this->expression());
405                if (!size) {
406                    return nullptr;
407                }
408                currentVarSizes.push_back(std::move(size));
409                if (!this->expect(Token::RBRACKET, "']'")) {
410                    return nullptr;
411                }
412            }
413        }
414        if (this->peek().fKind == Token::EQ) {
415            this->nextToken();
416            value = this->expression();
417            if (!value) {
418                return nullptr;
419            }
420        }
421        vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
422    }
423    if (!this->expect(Token::SEMICOLON, "';'")) {
424        return nullptr;
425    }
426    return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
427                                                                      std::move(type),
428                                                                      std::move(vars)));
429}
430
431/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
432std::unique_ptr<ASTParameter> Parser::parameter() {
433    ASTModifiers modifiers = this->modifiersWithDefaults(ASTModifiers::kIn_Flag);
434    std::unique_ptr<ASTType> type = this->type();
435    if (!type) {
436        return nullptr;
437    }
438    Token name;
439    if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
440        return nullptr;
441    }
442    std::vector<int> sizes;
443    while (this->peek().fKind == Token::LBRACKET) {
444        this->nextToken();
445        Token sizeToken;
446        if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
447            return nullptr;
448        }
449        sizes.push_back(SkSL::stoi(sizeToken.fText));
450        if (!this->expect(Token::RBRACKET, "']'")) {
451            return nullptr;
452        }
453    }
454    return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
455                                                          std::move(type), name.fText,
456                                                          std::move(sizes)));
457}
458
459/** (EQ INT_LITERAL)? */
460int Parser::layoutInt() {
461    if (!this->expect(Token::EQ, "'='")) {
462        return -1;
463    }
464    Token resultToken;
465    if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
466        return SkSL::stoi(resultToken.fText);
467    }
468    return -1;
469}
470
471/* LAYOUT LPAREN IDENTIFIER EQ INT_LITERAL (COMMA IDENTIFIER EQ INT_LITERAL)*
472   RPAREN */
473ASTLayout Parser::layout() {
474    int location = -1;
475    int binding = -1;
476    int index = -1;
477    int set = -1;
478    int builtin = -1;
479    bool originUpperLeft = false;
480    if (this->peek().fKind == Token::LAYOUT) {
481        this->nextToken();
482        if (!this->expect(Token::LPAREN, "'('")) {
483            return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
484        }
485        for (;;) {
486            Token t = this->nextToken();
487            if (t.fText == "location") {
488                location = this->layoutInt();
489            } else if (t.fText == "binding") {
490                binding = this->layoutInt();
491            } else if (t.fText == "index") {
492                index = this->layoutInt();
493            } else if (t.fText == "set") {
494                set = this->layoutInt();
495            } else if (t.fText == "builtin") {
496                builtin = this->layoutInt();
497            } else if (t.fText == "origin_upper_left") {
498                originUpperLeft = true;
499            } else {
500                this->error(t.fPosition, ("'" + t.fText +
501                                          "' is not a valid layout qualifier").c_str());
502            }
503            if (this->peek().fKind == Token::RPAREN) {
504                this->nextToken();
505                break;
506            }
507            if (!this->expect(Token::COMMA, "','")) {
508                break;
509            }
510        }
511    }
512    return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
513}
514
515/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
516ASTModifiers Parser::modifiers() {
517    ASTLayout layout = this->layout();
518    int flags = 0;
519    for (;;) {
520        // TODO: handle duplicate / incompatible flags
521        switch (peek().fKind) {
522            case Token::UNIFORM:
523                this->nextToken();
524                flags |= ASTModifiers::kUniform_Flag;
525                break;
526            case Token::CONST:
527                this->nextToken();
528                flags |= ASTModifiers::kConst_Flag;
529                break;
530            case Token::IN:
531                this->nextToken();
532                flags |= ASTModifiers::kIn_Flag;
533                break;
534            case Token::OUT:
535                this->nextToken();
536                flags |= ASTModifiers::kOut_Flag;
537                break;
538            case Token::INOUT:
539                this->nextToken();
540                flags |= ASTModifiers::kIn_Flag;
541                flags |= ASTModifiers::kOut_Flag;
542                break;
543            case Token::LOWP:
544                this->nextToken();
545                flags |= ASTModifiers::kLowp_Flag;
546                break;
547            case Token::MEDIUMP:
548                this->nextToken();
549                flags |= ASTModifiers::kMediump_Flag;
550                break;
551            case Token::HIGHP:
552                this->nextToken();
553                flags |= ASTModifiers::kHighp_Flag;
554                break;
555            case Token::FLAT:
556                this->nextToken();
557                flags |= ASTModifiers::kFlat_Flag;
558                break;
559            case Token::NOPERSPECTIVE:
560                this->nextToken();
561                flags |= ASTModifiers::kNoPerspective_Flag;
562                break;
563            default:
564                return ASTModifiers(layout, flags);
565        }
566    }
567}
568
569ASTModifiers Parser::modifiersWithDefaults(int defaultFlags) {
570    ASTModifiers result = this->modifiers();
571    if (!result.fFlags) {
572        return ASTModifiers(result.fLayout, defaultFlags);
573    }
574    return result;
575}
576
577/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
578std::unique_ptr<ASTStatement> Parser::statement() {
579    Token start = this->peek();
580    switch (start.fKind) {
581        case Token::IF:
582            return this->ifStatement();
583        case Token::FOR:
584            return this->forStatement();
585        case Token::DO:
586            return this->doStatement();
587        case Token::WHILE:
588            return this->whileStatement();
589        case Token::RETURN:
590            return this->returnStatement();
591        case Token::BREAK:
592            return this->breakStatement();
593        case Token::CONTINUE:
594            return this->continueStatement();
595        case Token::DISCARD:
596            return this->discardStatement();
597        case Token::LBRACE:
598            return this->block();
599        case Token::SEMICOLON:
600            this->nextToken();
601            return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
602                                                     std::vector<std::unique_ptr<ASTStatement>>()));
603        case Token::CONST:   // fall through
604        case Token::HIGHP:   // fall through
605        case Token::MEDIUMP: // fall through
606        case Token::LOWP: {
607            auto decl = this->varDeclarations();
608            if (!decl) {
609                return nullptr;
610            }
611            return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
612        }
613        case Token::IDENTIFIER:
614            if (this->isType(start.fText)) {
615                auto decl = this->varDeclarations();
616                if (!decl) {
617                    return nullptr;
618                }
619                return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
620                                                                                  std::move(decl)));
621            }
622            // fall through
623        default:
624            return this->expressionStatement();
625    }
626}
627
628/* IDENTIFIER(type) */
629std::unique_ptr<ASTType> Parser::type() {
630    Token type;
631    if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
632        return nullptr;
633    }
634    if (!this->isType(type.fText)) {
635        this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
636        return nullptr;
637    }
638    return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
639                                                ASTType::kIdentifier_Kind));
640}
641
642/* IDENTIFIER LBRACE varDeclaration* RBRACE */
643std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(ASTModifiers mods) {
644    Token name;
645    if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
646        return nullptr;
647    }
648    if (peek().fKind != Token::LBRACE) {
649        // we only get into interfaceBlock if we found a top-level identifier which was not a type.
650        // 99% of the time, the user was not actually intending to create an interface block, so
651        // it's better to report it as an unknown type
652        this->error(name.fPosition, "no type named '" + name.fText + "'");
653        return nullptr;
654    }
655    this->nextToken();
656    std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
657    while (this->peek().fKind != Token::RBRACE) {
658        std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
659        if (!decl) {
660            return nullptr;
661        }
662        decls.push_back(std::move(decl));
663    }
664    this->nextToken();
665    std::string valueName;
666    if (this->peek().fKind == Token::IDENTIFIER) {
667        valueName = this->nextToken().fText;
668    }
669    this->expect(Token::SEMICOLON, "';'");
670    return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
671                                                                 name.fText, std::move(valueName),
672                                                                 std::move(decls)));
673}
674
675/* IF LPAREN expression RPAREN statement (ELSE statement)? */
676std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
677    Token start;
678    if (!this->expect(Token::IF, "'if'", &start)) {
679        return nullptr;
680    }
681    if (!this->expect(Token::LPAREN, "'('")) {
682        return nullptr;
683    }
684    std::unique_ptr<ASTExpression> test(this->expression());
685    if (!test) {
686        return nullptr;
687    }
688    if (!this->expect(Token::RPAREN, "')'")) {
689        return nullptr;
690    }
691    std::unique_ptr<ASTStatement> ifTrue(this->statement());
692    if (!ifTrue) {
693        return nullptr;
694    }
695    std::unique_ptr<ASTStatement> ifFalse;
696    if (this->peek().fKind == Token::ELSE) {
697        this->nextToken();
698        ifFalse = this->statement();
699        if (!ifFalse) {
700            return nullptr;
701        }
702    }
703    return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, std::move(test),
704                                                              std::move(ifTrue),
705                                                              std::move(ifFalse)));
706}
707
708/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
709std::unique_ptr<ASTDoStatement> Parser::doStatement() {
710    Token start;
711    if (!this->expect(Token::DO, "'do'", &start)) {
712        return nullptr;
713    }
714    std::unique_ptr<ASTStatement> statement(this->statement());
715    if (!statement) {
716        return nullptr;
717    }
718    if (!this->expect(Token::WHILE, "'while'")) {
719        return nullptr;
720    }
721    if (!this->expect(Token::LPAREN, "'('")) {
722        return nullptr;
723    }
724    std::unique_ptr<ASTExpression> test(this->expression());
725    if (!test) {
726        return nullptr;
727    }
728    if (!this->expect(Token::RPAREN, "')'")) {
729        return nullptr;
730    }
731    if (!this->expect(Token::SEMICOLON, "';'")) {
732        return nullptr;
733    }
734    return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
735                                                              std::move(statement),
736                                                              std::move(test)));
737}
738
739/* WHILE LPAREN expression RPAREN STATEMENT */
740std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
741    Token start;
742    if (!this->expect(Token::WHILE, "'while'", &start)) {
743        return nullptr;
744    }
745    if (!this->expect(Token::LPAREN, "'('")) {
746        return nullptr;
747    }
748    std::unique_ptr<ASTExpression> test(this->expression());
749    if (!test) {
750        return nullptr;
751    }
752    if (!this->expect(Token::RPAREN, "')'")) {
753        return nullptr;
754    }
755    std::unique_ptr<ASTStatement> statement(this->statement());
756    if (!statement) {
757        return nullptr;
758    }
759    return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
760                                                                    std::move(test),
761                                                                    std::move(statement)));
762}
763
764/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
765   STATEMENT */
766std::unique_ptr<ASTForStatement> Parser::forStatement() {
767    Token start;
768    if (!this->expect(Token::FOR, "'for'", &start)) {
769        return nullptr;
770    }
771    if (!this->expect(Token::LPAREN, "'('")) {
772        return nullptr;
773    }
774    std::unique_ptr<ASTStatement> initializer;
775    Token nextToken = this->peek();
776    switch (nextToken.fKind) {
777        case Token::SEMICOLON:
778            break;
779        case Token::CONST:
780            initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
781                                                                          this->varDeclarations()));
782            break;
783        case Token::IDENTIFIER:
784            if (this->isType(nextToken.fText)) {
785                initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
786                                                                          this->varDeclarations()));
787                break;
788            }
789            // fall through
790        default:
791            initializer = this->expressionStatement();
792    }
793    std::unique_ptr<ASTExpression> test;
794    if (this->peek().fKind != Token::SEMICOLON) {
795        test = this->expression();
796        if (!test) {
797            return nullptr;
798        }
799    }
800    if (!this->expect(Token::SEMICOLON, "';'")) {
801        return nullptr;
802    }
803    std::unique_ptr<ASTExpression> next;
804    if (this->peek().fKind != Token::SEMICOLON) {
805        next = this->expression();
806        if (!next) {
807            return nullptr;
808        }
809    }
810    if (!this->expect(Token::RPAREN, "')'")) {
811        return nullptr;
812    }
813    std::unique_ptr<ASTStatement> statement(this->statement());
814    if (!statement) {
815        return nullptr;
816    }
817    return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
818                                                                std::move(initializer),
819                                                                std::move(test), std::move(next),
820                                                                std::move(statement)));
821}
822
823/* RETURN expression? SEMICOLON */
824std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
825    Token start;
826    if (!this->expect(Token::RETURN, "'return'", &start)) {
827        return nullptr;
828    }
829    std::unique_ptr<ASTExpression> expression;
830    if (this->peek().fKind != Token::SEMICOLON) {
831        expression = this->expression();
832        if (!expression) {
833            return nullptr;
834        }
835    }
836    if (!this->expect(Token::SEMICOLON, "';'")) {
837        return nullptr;
838    }
839    return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
840                                                                      std::move(expression)));
841}
842
843/* BREAK SEMICOLON */
844std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
845    Token start;
846    if (!this->expect(Token::BREAK, "'break'", &start)) {
847        return nullptr;
848    }
849    if (!this->expect(Token::SEMICOLON, "';'")) {
850        return nullptr;
851    }
852    return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
853}
854
855/* CONTINUE SEMICOLON */
856std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
857    Token start;
858    if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
859        return nullptr;
860    }
861    if (!this->expect(Token::SEMICOLON, "';'")) {
862        return nullptr;
863    }
864    return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
865}
866
867/* DISCARD SEMICOLON */
868std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
869    Token start;
870    if (!this->expect(Token::DISCARD, "'continue'", &start)) {
871        return nullptr;
872    }
873    if (!this->expect(Token::SEMICOLON, "';'")) {
874        return nullptr;
875    }
876    return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
877}
878
879/* LBRACE statement* RBRACE */
880std::unique_ptr<ASTBlock> Parser::block() {
881    Token start;
882    if (!this->expect(Token::LBRACE, "'{'", &start)) {
883        return nullptr;
884    }
885    std::vector<std::unique_ptr<ASTStatement>> statements;
886    for (;;) {
887        switch (this->peek().fKind) {
888            case Token::RBRACE:
889                this->nextToken();
890                return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
891                                                              std::move(statements)));
892            case Token::END_OF_FILE:
893                this->error(this->peek().fPosition, "expected '}', but found end of file");
894                return nullptr;
895            default: {
896                std::unique_ptr<ASTStatement> statement = this->statement();
897                if (!statement) {
898                    return nullptr;
899                }
900                statements.push_back(std::move(statement));
901            }
902        }
903    }
904}
905
906/* expression SEMICOLON */
907std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
908    std::unique_ptr<ASTExpression> expr = this->expression();
909    if (expr) {
910        if (this->expect(Token::SEMICOLON, "';'")) {
911            ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
912            return std::unique_ptr<ASTExpressionStatement>(result);
913        }
914    }
915    return nullptr;
916}
917
918/* assignmentExpression */
919std::unique_ptr<ASTExpression> Parser::expression() {
920    return this->assignmentExpression();
921}
922
923/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
924   BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
925   assignmentExpression)*
926 */
927std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
928    std::unique_ptr<ASTExpression> result = this->ternaryExpression();
929    if (!result) {
930        return nullptr;
931    }
932    for (;;) {
933        switch (this->peek().fKind) {
934            case Token::EQ:           // fall through
935            case Token::STAREQ:       // fall through
936            case Token::SLASHEQ:      // fall through
937            case Token::PERCENTEQ:    // fall through
938            case Token::PLUSEQ:       // fall through
939            case Token::MINUSEQ:      // fall through
940            case Token::SHLEQ:        // fall through
941            case Token::SHREQ:        // fall through
942            case Token::BITWISEANDEQ: // fall through
943            case Token::BITWISEXOREQ: // fall through
944            case Token::BITWISEOREQ:  // fall through
945            case Token::LOGICALANDEQ: // fall through
946            case Token::LOGICALXOREQ: // fall through
947            case Token::LOGICALOREQ: {
948                Token t = this->nextToken();
949                std::unique_ptr<ASTExpression> right = this->assignmentExpression();
950                if (!right) {
951                    return nullptr;
952                }
953                result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
954                                                                                t,
955                                                                                std::move(right)));
956            }
957            default:
958                return result;
959        }
960    }
961}
962
963/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
964std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
965    std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
966    if (!result) {
967        return nullptr;
968    }
969    if (this->peek().fKind == Token::QUESTION) {
970        Token question = this->nextToken();
971        std::unique_ptr<ASTExpression> trueExpr = this->expression();
972        if (!trueExpr) {
973            return nullptr;
974        }
975        if (this->expect(Token::COLON, "':'")) {
976            std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
977            return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
978                                                                           std::move(trueExpr),
979                                                                           std::move(falseExpr)));
980        }
981        return nullptr;
982    }
983    return result;
984}
985
986/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
987std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
988    std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
989    if (!result) {
990        return nullptr;
991    }
992    while (this->peek().fKind == Token::LOGICALOR) {
993        Token t = this->nextToken();
994        std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
995        if (!right) {
996            return nullptr;
997        }
998        result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
999    }
1000    return result;
1001}
1002
1003/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1004std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1005    std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1006    if (!result) {
1007        return nullptr;
1008    }
1009    while (this->peek().fKind == Token::LOGICALXOR) {
1010        Token t = this->nextToken();
1011        std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1012        if (!right) {
1013            return nullptr;
1014        }
1015        result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1016    }
1017    return result;
1018}
1019
1020/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1021std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1022    std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1023    if (!result) {
1024        return nullptr;
1025    }
1026    while (this->peek().fKind == Token::LOGICALAND) {
1027        Token t = this->nextToken();
1028        std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1029        if (!right) {
1030            return nullptr;
1031        }
1032        result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1033    }
1034    return result;
1035}
1036
1037/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1038std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1039    std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1040    if (!result) {
1041        return nullptr;
1042    }
1043    while (this->peek().fKind == Token::BITWISEOR) {
1044        Token t = this->nextToken();
1045        std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1046        if (!right) {
1047            return nullptr;
1048        }
1049        result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1050    }
1051    return result;
1052}
1053
1054/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1055std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1056    std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1057    if (!result) {
1058        return nullptr;
1059    }
1060    while (this->peek().fKind == Token::BITWISEXOR) {
1061        Token t = this->nextToken();
1062        std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1063        if (!right) {
1064            return nullptr;
1065        }
1066        result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1067    }
1068    return result;
1069}
1070
1071/* equalityExpression (BITWISEAND equalityExpression)* */
1072std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1073    std::unique_ptr<ASTExpression> result = this->equalityExpression();
1074    if (!result) {
1075        return nullptr;
1076    }
1077    while (this->peek().fKind == Token::BITWISEAND) {
1078        Token t = this->nextToken();
1079        std::unique_ptr<ASTExpression> right = this->equalityExpression();
1080        if (!right) {
1081            return nullptr;
1082        }
1083        result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1084    }
1085    return result;
1086}
1087
1088/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1089std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1090    std::unique_ptr<ASTExpression> result = this->relationalExpression();
1091    if (!result) {
1092        return nullptr;
1093    }
1094    for (;;) {
1095        switch (this->peek().fKind) {
1096            case Token::EQEQ:   // fall through
1097            case Token::NEQ: {
1098                Token t = this->nextToken();
1099                std::unique_ptr<ASTExpression> right = this->relationalExpression();
1100                if (!right) {
1101                    return nullptr;
1102                }
1103                result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1104                break;
1105            }
1106            default:
1107                return result;
1108        }
1109    }
1110}
1111
1112/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1113std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1114    std::unique_ptr<ASTExpression> result = this->shiftExpression();
1115    if (!result) {
1116        return nullptr;
1117    }
1118    for (;;) {
1119        switch (this->peek().fKind) {
1120            case Token::LT:   // fall through
1121            case Token::GT:   // fall through
1122            case Token::LTEQ: // fall through
1123            case Token::GTEQ: {
1124                Token t = this->nextToken();
1125                std::unique_ptr<ASTExpression> right = this->shiftExpression();
1126                if (!right) {
1127                    return nullptr;
1128                }
1129                result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1130                break;
1131            }
1132            default:
1133                return result;
1134        }
1135    }
1136}
1137
1138/* additiveExpression ((SHL | SHR) additiveExpression)* */
1139std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1140    std::unique_ptr<ASTExpression> result = this->additiveExpression();
1141    if (!result) {
1142        return nullptr;
1143    }
1144    for (;;) {
1145        switch (this->peek().fKind) {
1146            case Token::SHL: // fall through
1147            case Token::SHR: {
1148                Token t = this->nextToken();
1149                std::unique_ptr<ASTExpression> right = this->additiveExpression();
1150                if (!right) {
1151                    return nullptr;
1152                }
1153                result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1154                break;
1155            }
1156            default:
1157                return result;
1158        }
1159    }
1160}
1161
1162/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1163std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1164    std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1165    if (!result) {
1166        return nullptr;
1167    }
1168    for (;;) {
1169        switch (this->peek().fKind) {
1170            case Token::PLUS: // fall through
1171            case Token::MINUS: {
1172                Token t = this->nextToken();
1173                std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1174                if (!right) {
1175                    return nullptr;
1176                }
1177                result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1178                break;
1179            }
1180            default:
1181                return result;
1182        }
1183    }
1184}
1185
1186/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1187std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1188    std::unique_ptr<ASTExpression> result = this->unaryExpression();
1189    if (!result) {
1190        return nullptr;
1191    }
1192    for (;;) {
1193        switch (this->peek().fKind) {
1194            case Token::STAR: // fall through
1195            case Token::SLASH: // fall through
1196            case Token::PERCENT: {
1197                Token t = this->nextToken();
1198                std::unique_ptr<ASTExpression> right = this->unaryExpression();
1199                if (!right) {
1200                    return nullptr;
1201                }
1202                result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1203                break;
1204            }
1205            default:
1206                return result;
1207        }
1208    }
1209}
1210
1211/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1212std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1213    switch (this->peek().fKind) {
1214        case Token::PLUS:     // fall through
1215        case Token::MINUS:    // fall through
1216        case Token::NOT:      // fall through
1217        case Token::PLUSPLUS: // fall through
1218        case Token::MINUSMINUS: {
1219            Token t = this->nextToken();
1220            std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1221            if (!expr) {
1222                return nullptr;
1223            }
1224            return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
1225        }
1226        default:
1227            return this->postfixExpression();
1228    }
1229}
1230
1231/* term suffix* */
1232std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1233    std::unique_ptr<ASTExpression> result = this->term();
1234    if (!result) {
1235        return nullptr;
1236    }
1237    for (;;) {
1238        switch (this->peek().fKind) {
1239            case Token::LBRACKET: // fall through
1240            case Token::DOT:      // fall through
1241            case Token::LPAREN:   // fall through
1242            case Token::PLUSPLUS: // fall through
1243            case Token::MINUSMINUS: {
1244                std::unique_ptr<ASTSuffix> s = this->suffix();
1245                if (!s) {
1246                    return nullptr;
1247                }
1248                result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1249                break;
1250            }
1251            default:
1252                return result;
1253        }
1254    }
1255}
1256
1257/* LBRACKET expression RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
1258   PLUSPLUS | MINUSMINUS */
1259std::unique_ptr<ASTSuffix> Parser::suffix() {
1260    Token next = this->nextToken();
1261    switch (next.fKind) {
1262        case Token::LBRACKET: {
1263            std::unique_ptr<ASTExpression> e = this->expression();
1264            if (!e) {
1265                return nullptr;
1266            }
1267            this->expect(Token::RBRACKET, "']' to complete array access expression");
1268            return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1269        }
1270        case Token::DOT: {
1271            Position pos = this->peek().fPosition;
1272            std::string text;
1273            if (this->identifier(&text)) {
1274                return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
1275            }
1276            return nullptr;
1277        }
1278        case Token::LPAREN: {
1279            std::vector<std::unique_ptr<ASTExpression>> parameters;
1280            if (this->peek().fKind != Token::RPAREN) {
1281                for (;;) {
1282                    std::unique_ptr<ASTExpression> expr = this->expression();
1283                    if (!expr) {
1284                        return nullptr;
1285                    }
1286                    parameters.push_back(std::move(expr));
1287                    if (this->peek().fKind != Token::COMMA) {
1288                        break;
1289                    }
1290                    this->nextToken();
1291                }
1292            }
1293            this->expect(Token::RPAREN, "')' to complete function parameters");
1294            return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
1295                                                                std::move(parameters)));
1296        }
1297        case Token::PLUSPLUS:
1298            return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1299                                                            ASTSuffix::kPostIncrement_Kind));
1300        case Token::MINUSMINUS:
1301            return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1302                                                            ASTSuffix::kPostDecrement_Kind));
1303        default: {
1304            this->error(next.fPosition,  "expected expression suffix, but found '" + next.fText +
1305                                         "'\n");
1306            return nullptr;
1307        }
1308    }
1309}
1310
1311/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1312std::unique_ptr<ASTExpression> Parser::term() {
1313    std::unique_ptr<ASTExpression> result;
1314    Token t = this->peek();
1315    switch (t.fKind) {
1316        case Token::IDENTIFIER: {
1317            std::string text;
1318            if (this->identifier(&text)) {
1319                result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
1320            }
1321            break;
1322        }
1323        case Token::INT_LITERAL: {
1324            int64_t i;
1325            if (this->intLiteral(&i)) {
1326                result.reset(new ASTIntLiteral(t.fPosition, i));
1327            }
1328            break;
1329        }
1330        case Token::FLOAT_LITERAL: {
1331            double f;
1332            if (this->floatLiteral(&f)) {
1333                result.reset(new ASTFloatLiteral(t.fPosition, f));
1334            }
1335            break;
1336        }
1337        case Token::TRUE_LITERAL: // fall through
1338        case Token::FALSE_LITERAL: {
1339            bool b;
1340            if (this->boolLiteral(&b)) {
1341                result.reset(new ASTBoolLiteral(t.fPosition, b));
1342            }
1343            break;
1344        }
1345        case Token::LPAREN: {
1346            this->nextToken();
1347            result = this->expression();
1348            if (result) {
1349                this->expect(Token::RPAREN, "')' to complete expression");
1350            }
1351            break;
1352        }
1353        default:
1354            this->nextToken();
1355            this->error(t.fPosition,  "expected expression, but found '" + t.fText + "'\n");
1356            result = nullptr;
1357    }
1358    return result;
1359}
1360
1361/* INT_LITERAL */
1362bool Parser::intLiteral(int64_t* dest) {
1363    Token t;
1364    if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1365        *dest = SkSL::stol(t.fText);
1366        return true;
1367    }
1368    return false;
1369}
1370
1371/* FLOAT_LITERAL */
1372bool Parser::floatLiteral(double* dest) {
1373    Token t;
1374    if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1375        *dest = SkSL::stod(t.fText);
1376        return true;
1377    }
1378    return false;
1379}
1380
1381/* TRUE_LITERAL | FALSE_LITERAL */
1382bool Parser::boolLiteral(bool* dest) {
1383    Token t = this->nextToken();
1384    switch (t.fKind) {
1385        case Token::TRUE_LITERAL:
1386            *dest = true;
1387            return true;
1388        case Token::FALSE_LITERAL:
1389            *dest = false;
1390            return true;
1391        default:
1392            this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1393            return false;
1394    }
1395}
1396
1397/* IDENTIFIER */
1398bool Parser::identifier(std::string* dest) {
1399    Token t;
1400    if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
1401        *dest = t.fText;
1402        return true;
1403    }
1404    return false;
1405}
1406
1407} // namespace
1408