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