blob: d8ecc618bcced935d31c9c6e0a820176e4644f6d [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
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 */
Ethan Nicholas11d53972016-11-28 11:23:23 -05007
ethannicholasb3058bd2016-07-01 08:22:01 -07008#include "stdio.h"
9#include "SkSLParser.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070010#include "ast/SkSLASTBinaryExpression.h"
11#include "ast/SkSLASTBlock.h"
12#include "ast/SkSLASTBoolLiteral.h"
13#include "ast/SkSLASTBreakStatement.h"
14#include "ast/SkSLASTCallSuffix.h"
15#include "ast/SkSLASTContinueStatement.h"
16#include "ast/SkSLASTDiscardStatement.h"
17#include "ast/SkSLASTDoStatement.h"
18#include "ast/SkSLASTExpression.h"
19#include "ast/SkSLASTExpressionStatement.h"
20#include "ast/SkSLASTExtension.h"
21#include "ast/SkSLASTFieldSuffix.h"
22#include "ast/SkSLASTFloatLiteral.h"
23#include "ast/SkSLASTForStatement.h"
24#include "ast/SkSLASTFunction.h"
25#include "ast/SkSLASTIdentifier.h"
26#include "ast/SkSLASTIfStatement.h"
27#include "ast/SkSLASTIndexSuffix.h"
28#include "ast/SkSLASTInterfaceBlock.h"
29#include "ast/SkSLASTIntLiteral.h"
ethannicholas5961bc92016-10-12 06:39:56 -070030#include "ast/SkSLASTModifiersDeclaration.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070031#include "ast/SkSLASTParameter.h"
Brian Salomon1d816b92017-08-17 11:07:59 -040032#include "ast/SkSLASTPrecision.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070033#include "ast/SkSLASTPrefixExpression.h"
34#include "ast/SkSLASTReturnStatement.h"
Ethan Nicholas762466e2017-06-29 10:03:38 -040035#include "ast/SkSLASTSection.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070036#include "ast/SkSLASTStatement.h"
37#include "ast/SkSLASTSuffixExpression.h"
Ethan Nicholasaf197692017-02-27 13:26:45 -050038#include "ast/SkSLASTSwitchCase.h"
39#include "ast/SkSLASTSwitchStatement.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070040#include "ast/SkSLASTTernaryExpression.h"
41#include "ast/SkSLASTType.h"
42#include "ast/SkSLASTVarDeclaration.h"
43#include "ast/SkSLASTVarDeclarationStatement.h"
44#include "ast/SkSLASTWhileStatement.h"
45#include "ir/SkSLSymbolTable.h"
Ethan Nicholas11d53972016-11-28 11:23:23 -050046#include "ir/SkSLModifiers.h"
ethannicholasd598f792016-07-25 10:08:54 -070047#include "ir/SkSLType.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070048
49namespace SkSL {
50
ethannicholascad64162016-10-27 10:54:02 -070051#define MAX_PARSE_DEPTH 50
52
53class AutoDepth {
54public:
55 AutoDepth(Parser* p)
56 : fParser(p) {
57 fParser->fDepth++;
58 }
59
60 ~AutoDepth() {
61 fParser->fDepth--;
62 }
63
64 bool checkValid() {
65 if (fParser->fDepth > MAX_PARSE_DEPTH) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070066 fParser->error(fParser->peek(), String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070067 return false;
68 }
69 return true;
70 }
71
72private:
73 Parser* fParser;
74};
75
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070076Parser::Parser(const char* text, size_t length, SymbolTable& types, ErrorReporter& errors)
77: fText(text)
78, fPushback(Token::INVALID, -1, -1)
ethannicholasb3058bd2016-07-01 08:22:01 -070079, fTypes(types)
80, fErrors(errors) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070081 fLexer.start(text, length);
ethannicholasb3058bd2016-07-01 08:22:01 -070082}
83
Brian Salomon1d816b92017-08-17 11:07:59 -040084/* (precision | directive | section | declaration)* END_OF_FILE */
ethannicholasb3058bd2016-07-01 08:22:01 -070085std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
86 std::vector<std::unique_ptr<ASTDeclaration>> result;
87 for (;;) {
88 switch (this->peek().fKind) {
89 case Token::END_OF_FILE:
90 return result;
Brian Salomon1d816b92017-08-17 11:07:59 -040091 case Token::PRECISION: {
92 std::unique_ptr<ASTDeclaration> precision = this->precision();
93 if (precision) {
94 result.push_back(std::move(precision));
95 }
96 break;
97 }
ethannicholasb3058bd2016-07-01 08:22:01 -070098 case Token::DIRECTIVE: {
99 std::unique_ptr<ASTDeclaration> decl = this->directive();
100 if (decl) {
101 result.push_back(std::move(decl));
102 }
103 break;
104 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400105 case Token::SECTION: {
106 std::unique_ptr<ASTDeclaration> section = this->section();
107 if (section) {
108 result.push_back(std::move(section));
109 }
110 break;
111 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700112 default: {
113 std::unique_ptr<ASTDeclaration> decl = this->declaration();
114 if (!decl) {
115 continue;
116 }
117 result.push_back(std::move(decl));
118 }
119 }
120 }
121}
122
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700123Token Parser::nextRawToken() {
124 if (fPushback.fKind != Token::INVALID) {
125 Token result = fPushback;
126 fPushback.fKind = Token::INVALID;
ethannicholasb3058bd2016-07-01 08:22:01 -0700127 return result;
128 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700129 Token result = fLexer.next();
130 return result;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400131}
132
133Token Parser::nextToken() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700134 Token token = this->nextRawToken();
135 while (token.fKind == Token::WHITESPACE || token.fKind == Token::LINE_COMMENT ||
136 token.fKind == Token::BLOCK_COMMENT) {
137 token = this->nextRawToken();
138 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400139 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700140}
141
142void Parser::pushback(Token t) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700143 ASSERT(fPushback.fKind == Token::INVALID);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400144 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700145}
146
147Token Parser::peek() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700148 if (fPushback.fKind == Token::INVALID) {
Brian Osman634624a2017-08-15 11:14:30 -0400149 fPushback = this->nextToken();
150 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700151 return fPushback;
152}
153
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400154bool Parser::checkNext(Token::Kind kind, Token* result) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700155 if (fPushback.fKind != Token::INVALID && fPushback.fKind != kind) {
Brian Osman634624a2017-08-15 11:14:30 -0400156 return false;
157 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400158 Token next = this->nextToken();
159 if (next.fKind == kind) {
160 if (result) {
161 *result = next;
162 }
163 return true;
164 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400165 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400166 return false;
167}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500168
169bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 Token next = this->nextToken();
171 if (next.fKind == kind) {
172 if (result) {
Brian Osman634624a2017-08-15 11:14:30 -0400173 *result = std::move(next);
ethannicholasb3058bd2016-07-01 08:22:01 -0700174 }
175 return true;
176 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700177 this->error(next, "expected " + String(expected) + ", but found '" +
178 this->text(next) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700179 return false;
180 }
181}
182
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700183StringFragment Parser::text(Token token) {
184 return StringFragment(fText + token.fOffset, token.fLength);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500185}
186
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700187void Parser::error(Token token, String msg) {
188 this->error(token.fOffset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -0700189}
190
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700191void Parser::error(int offset, String msg) {
192 fErrors.error(offset, msg);
193}
194
195bool Parser::isType(StringFragment name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700196 return nullptr != fTypes[name];
197}
198
Brian Salomon1d816b92017-08-17 11:07:59 -0400199/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
200std::unique_ptr<ASTDeclaration> Parser::precision() {
201 if (!this->expect(Token::PRECISION, "'precision'")) {
202 return nullptr;
203 }
204 Modifiers::Flag result;
205 Token p = this->nextToken();
206 switch (p.fKind) {
207 case Token::LOWP:
208 result = Modifiers::kLowp_Flag;
209 break;
210 case Token::MEDIUMP:
211 result = Modifiers::kMediump_Flag;
212 break;
213 case Token::HIGHP:
214 result = Modifiers::kHighp_Flag;
215 break;
216 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700217 this->error(p, "expected 'lowp', 'mediump', or 'highp', but found '" +
218 this->text(p) + "'");
Brian Salomon1d816b92017-08-17 11:07:59 -0400219 return nullptr;
220 }
221 // FIXME handle the type
222 if (!this->type()) {
223 return nullptr;
224 }
225 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700226 return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fOffset, result));
Brian Salomon1d816b92017-08-17 11:07:59 -0400227}
228
Ethan Nicholas11d53972016-11-28 11:23:23 -0500229/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700230 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700231std::unique_ptr<ASTDeclaration> Parser::directive() {
232 Token start;
233 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
234 return nullptr;
235 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700236 StringFragment text = this->text(start);
237 if (text == "#version") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700238 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700239 Token next = this->peek();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700240 StringFragment nextText = this->text(next);
241 if (nextText == "es" || nextText == "compatibility") {
ethannicholas5961bc92016-10-12 06:39:56 -0700242 this->nextToken();
243 }
244 // version is ignored for now; it will eventually become an error when we stop pretending
245 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 return nullptr;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700247 } else if (text == "#extension") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700248 Token name;
249 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
250 return nullptr;
251 }
252 if (!this->expect(Token::COLON, "':'")) {
253 return nullptr;
254 }
255 // FIXME: need to start paying attention to this token
256 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
257 return nullptr;
258 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700259 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fOffset,
260 String(this->text(name))));
ethannicholasb3058bd2016-07-01 08:22:01 -0700261 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700262 this->error(start, "unsupported directive '" + this->text(start) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 return nullptr;
264 }
265}
266
Ethan Nicholas762466e2017-06-29 10:03:38 -0400267/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
268 RBRACE */
269std::unique_ptr<ASTDeclaration> Parser::section() {
270 Token start;
271 if (!this->expect(Token::SECTION, "a section token", &start)) {
272 return nullptr;
273 }
274 String argument;
275 if (this->peek().fKind == Token::LPAREN) {
276 this->nextToken();
277 Token argToken;
278 if (!this->expect(Token::IDENTIFIER, "an identifier", &argToken)) {
279 return nullptr;
280 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700281 argument = this->text(argToken);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400282 if (!this->expect(Token::RPAREN, "')'")) {
283 return nullptr;
284 }
285 }
286 if (!this->expect(Token::LBRACE, "'{'")) {
287 return nullptr;
288 }
289 String text;
290 int level = 1;
291 for (;;) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700292 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400293 switch (next.fKind) {
294 case Token::LBRACE:
295 ++level;
296 break;
297 case Token::RBRACE:
298 --level;
299 break;
300 case Token::END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700301 this->error(start, "reached end of file while parsing section");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400302 return nullptr;
303 default:
304 break;
305 }
306 if (!level) {
307 break;
308 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700309 text += this->text(next);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400310 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700311 StringFragment name = this->text(start);
312 ++name.fChars;
313 --name.fLength;
314 return std::unique_ptr<ASTDeclaration>(new ASTSection(start.fOffset,
315 String(name),
Ethan Nicholas762466e2017-06-29 10:03:38 -0400316 argument,
317 text));
318}
319
Ethan Nicholas11d53972016-11-28 11:23:23 -0500320/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700321 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
322std::unique_ptr<ASTDeclaration> Parser::declaration() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500323 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700324 Token lookahead = this->peek();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700325 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(this->text(lookahead))) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700326 // we have an identifier that's not a type, could be the start of an interface block
327 return this->interfaceBlock(modifiers);
328 }
329 if (lookahead.fKind == Token::STRUCT) {
330 return this->structVarDeclaration(modifiers);
331 }
ethannicholas5961bc92016-10-12 06:39:56 -0700332 if (lookahead.fKind == Token::SEMICOLON) {
333 this->nextToken();
334 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
335 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700336 std::unique_ptr<ASTType> type(this->type());
337 if (!type) {
338 return nullptr;
339 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400340 if (type->fKind == ASTType::kStruct_Kind && this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700341 return nullptr;
342 }
343 Token name;
344 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
345 return nullptr;
346 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400347 if (this->checkNext(Token::LPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700348 std::vector<std::unique_ptr<ASTParameter>> parameters;
349 while (this->peek().fKind != Token::RPAREN) {
350 if (parameters.size() > 0) {
351 if (!this->expect(Token::COMMA, "','")) {
352 return nullptr;
353 }
354 }
355 std::unique_ptr<ASTParameter> parameter = this->parameter();
356 if (!parameter) {
357 return nullptr;
358 }
359 parameters.push_back(std::move(parameter));
360 }
361 this->nextToken();
362 std::unique_ptr<ASTBlock> body;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400363 if (!this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700364 body = this->block();
365 if (!body) {
366 return nullptr;
367 }
368 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700369 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fOffset,
Ethan Nicholascb670962017-04-20 19:31:52 -0400370 modifiers,
371 std::move(type),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700372 this->text(name),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500373 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700374 std::move(body)));
375 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700376 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700377 }
378}
379
380/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700381std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500382 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700383 std::unique_ptr<ASTType> type(this->type());
384 if (!type) {
385 return nullptr;
386 }
387 Token name;
388 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
389 return nullptr;
390 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700391 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700392}
393
394/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
395std::unique_ptr<ASTType> Parser::structDeclaration() {
396 if (!this->expect(Token::STRUCT, "'struct'")) {
397 return nullptr;
398 }
399 Token name;
400 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
401 return nullptr;
402 }
403 if (!this->expect(Token::LBRACE, "'{'")) {
404 return nullptr;
405 }
406 std::vector<Type::Field> fields;
407 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700408 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700409 if (!decl) {
410 return nullptr;
411 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700412 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700413 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700414 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700415 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700416 this->error(decl->fOffset, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700417 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700418 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700419 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400420 String name = type->name() + "[" + to_string(columns) + "]";
ethannicholasd598f792016-07-25 10:08:54 -0700421 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
422 fTypes.takeOwnership((Type*) type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700423 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700424 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
425 if (var.fValue) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700426 this->error(decl->fOffset, "initializers are not permitted on struct fields");
ethannicholasb3058bd2016-07-01 08:22:01 -0700427 }
428 }
429 }
430 if (!this->expect(Token::RBRACE, "'}'")) {
431 return nullptr;
432 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700433 fTypes.add(this->text(name), std::unique_ptr<Type>(new Type(name.fOffset, this->text(name),
434 fields)));
435 return std::unique_ptr<ASTType>(new ASTType(name.fOffset, this->text(name),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500436 ASTType::kStruct_Kind, std::vector<int>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700437}
438
439/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500440std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 std::unique_ptr<ASTType> type = this->structDeclaration();
442 if (!type) {
443 return nullptr;
444 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400445 Token name;
446 if (this->checkNext(Token::IDENTIFIER, &name)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500447 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
448 std::move(type),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700449 this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700450 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700451 for (const auto& var : result->fVars) {
452 if (var.fValue) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700453 this->error(var.fValue->fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700454 "struct variables cannot be initialized");
455 }
456 }
457 }
458 return result;
459 }
460 this->expect(Token::SEMICOLON, "';'");
461 return nullptr;
462}
463
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400464/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
465 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500466std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700467 std::unique_ptr<ASTType> type,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700468 StringFragment name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700469 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700470 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400471 while (this->checkNext(Token::LBRACKET)) {
472 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700473 currentVarSizes.push_back(nullptr);
474 } else {
475 std::unique_ptr<ASTExpression> size(this->expression());
476 if (!size) {
477 return nullptr;
478 }
479 currentVarSizes.push_back(std::move(size));
480 if (!this->expect(Token::RBRACKET, "']'")) {
481 return nullptr;
482 }
483 }
484 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700485 std::unique_ptr<ASTExpression> value;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400486 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400487 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 if (!value) {
489 return nullptr;
490 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700492 vars.emplace_back(name, std::move(currentVarSizes), std::move(value));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400493 while (this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 Token name;
495 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
496 return nullptr;
497 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700499 value.reset();
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400500 while (this->checkNext(Token::LBRACKET)) {
501 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 currentVarSizes.push_back(nullptr);
503 } else {
504 std::unique_ptr<ASTExpression> size(this->expression());
505 if (!size) {
506 return nullptr;
507 }
508 currentVarSizes.push_back(std::move(size));
509 if (!this->expect(Token::RBRACKET, "']'")) {
510 return nullptr;
511 }
512 }
513 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400514 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400515 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700516 if (!value) {
517 return nullptr;
518 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700520 vars.emplace_back(this->text(name), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700521 }
522 if (!this->expect(Token::SEMICOLON, "';'")) {
523 return nullptr;
524 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700525 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
526 std::move(type),
527 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700528}
529
530/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
531std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400532 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 std::unique_ptr<ASTType> type = this->type();
534 if (!type) {
535 return nullptr;
536 }
537 Token name;
538 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
539 return nullptr;
540 }
541 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400542 while (this->checkNext(Token::LBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700543 Token sizeToken;
544 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
545 return nullptr;
546 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700547 sizes.push_back(SkSL::stoi(this->text(sizeToken)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700548 if (!this->expect(Token::RBRACKET, "']'")) {
549 return nullptr;
550 }
551 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700552 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fOffset, modifiers, std::move(type),
553 this->text(name), std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700554}
555
556/** (EQ INT_LITERAL)? */
557int Parser::layoutInt() {
558 if (!this->expect(Token::EQ, "'='")) {
559 return -1;
560 }
561 Token resultToken;
562 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700563 return SkSL::stoi(this->text(resultToken));
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 }
565 return -1;
566}
567
Ethan Nicholas762466e2017-06-29 10:03:38 -0400568/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
569String Parser::layoutCode() {
570 if (!this->expect(Token::EQ, "'='")) {
571 return "";
572 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700573 Token start = this->nextRawToken();
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400574 this->pushback(start);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400575 String code;
576 int level = 1;
577 bool done = false;
578 while (!done) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700579 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400580 switch (next.fKind) {
581 case Token::LPAREN:
582 ++level;
583 break;
584 case Token::RPAREN:
585 --level;
586 break;
587 case Token::COMMA:
588 if (level == 1) {
589 done = true;
590 }
591 break;
592 case Token::END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700593 this->error(start, "reached end of file while parsing layout");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400594 return nullptr;
595 default:
596 break;
597 }
598 if (!level) {
599 done = true;
600 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400601 if (done) {
602 this->pushback(std::move(next));
603 }
604 else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700605 code += this->text(next);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400606 }
607 }
608 return code;
609}
610
611/** (EQ IDENTIFIER('identity'))? */
612Layout::Key Parser::layoutKey() {
613 if (this->peek().fKind == Token::EQ) {
614 this->expect(Token::EQ, "'='");
615 Token key;
616 if (this->expect(Token::IDENTIFIER, "an identifer", &key)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700617 if (this->text(key) == "identity") {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400618 return Layout::kIdentity_Key;
619 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700620 this->error(key, "unsupported layout key");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400621 }
622 }
623 }
624 return Layout::kKey_Key;
625}
626
ethannicholas8ac838d2016-11-22 08:39:36 -0800627/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500628Layout Parser::layout() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500630 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 int binding = -1;
632 int index = -1;
633 int set = -1;
634 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500635 int inputAttachmentIndex = -1;
ethannicholasf789b382016-08-03 12:43:36 -0700636 bool originUpperLeft = false;
ethannicholas5961bc92016-10-12 06:39:56 -0700637 bool overrideCoverage = false;
638 bool blendSupportAllEquations = false;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500639 Layout::Format format = Layout::Format::kUnspecified;
ethannicholas8ac838d2016-11-22 08:39:36 -0800640 bool pushConstant = false;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500641 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
642 int maxVertices = -1;
643 int invocations = -1;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400644 String when;
645 Layout::Key key = Layout::kNo_Key;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400646 if (this->checkNext(Token::LAYOUT)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700647 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500648 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
Ethan Nicholas11d53972016-11-28 11:23:23 -0500649 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400650 pushConstant, primitive, maxVertices, invocations, when, key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700651 }
652 for (;;) {
653 Token t = this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700654 String text = this->text(t);
655 fLayoutLexer.start(text.c_str(), text.size());
656 int token = fLayoutLexer.next().fKind;
657 if (token != LayoutToken::INVALID) {
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500658 switch (token) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700659 case LayoutToken::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500660 location = this->layoutInt();
661 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700662 case LayoutToken::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500663 offset = this->layoutInt();
664 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700665 case LayoutToken::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500666 binding = this->layoutInt();
667 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700668 case LayoutToken::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500669 index = this->layoutInt();
670 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700671 case LayoutToken::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500672 set = this->layoutInt();
673 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700674 case LayoutToken::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500675 builtin = this->layoutInt();
676 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700677 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500678 inputAttachmentIndex = this->layoutInt();
679 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700680 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500681 originUpperLeft = true;
682 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700683 case LayoutToken::OVERRIDE_COVERAGE:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500684 overrideCoverage = true;
685 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700686 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500687 blendSupportAllEquations = true;
688 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700689 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500690 pushConstant = true;
691 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700692 case LayoutToken::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500693 primitive = Layout::kPoints_Primitive;
694 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700695 case LayoutToken::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500696 primitive = Layout::kLines_Primitive;
697 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700698 case LayoutToken::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500699 primitive = Layout::kLineStrip_Primitive;
700 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700701 case LayoutToken::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500702 primitive = Layout::kLinesAdjacency_Primitive;
703 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700704 case LayoutToken::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500705 primitive = Layout::kTriangles_Primitive;
706 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700707 case LayoutToken::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500708 primitive = Layout::kTriangleStrip_Primitive;
709 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700710 case LayoutToken::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500711 primitive = Layout::kTrianglesAdjacency_Primitive;
712 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700713 case LayoutToken::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500714 maxVertices = this->layoutInt();
715 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700716 case LayoutToken::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500717 invocations = this->layoutInt();
718 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700719 case LayoutToken::WHEN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400720 when = this->layoutCode();
721 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700722 case LayoutToken::KEY:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400723 key = this->layoutKey();
724 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700725 default:
726 ASSERT(false);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500727 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700728 } else if (Layout::ReadFormat(this->text(t), &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500729 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700730 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700731 this->error(t, ("'" + this->text(t) + "' is not a valid layout qualifier").c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -0700732 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400733 if (this->checkNext(Token::RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700734 break;
735 }
736 if (!this->expect(Token::COMMA, "','")) {
737 break;
738 }
739 }
740 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500741 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
742 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400743 pushConstant, primitive, maxVertices, invocations, when, key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700744}
745
Brian Salomonf9f45122016-11-29 11:59:17 -0500746/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400747 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500748Modifiers Parser::modifiers() {
749 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700750 int flags = 0;
751 for (;;) {
752 // TODO: handle duplicate / incompatible flags
753 switch (peek().fKind) {
754 case Token::UNIFORM:
755 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500756 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700757 break;
758 case Token::CONST:
759 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500760 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700761 break;
762 case Token::IN:
763 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500764 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700765 break;
766 case Token::OUT:
767 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500768 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700769 break;
770 case Token::INOUT:
771 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500772 flags |= Modifiers::kIn_Flag;
773 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700774 break;
775 case Token::LOWP:
776 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500777 flags |= Modifiers::kLowp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700778 break;
779 case Token::MEDIUMP:
780 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500781 flags |= Modifiers::kMediump_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700782 break;
783 case Token::HIGHP:
784 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500785 flags |= Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700786 break;
ethannicholasf789b382016-08-03 12:43:36 -0700787 case Token::FLAT:
788 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500789 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700790 break;
791 case Token::NOPERSPECTIVE:
792 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500793 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700794 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500795 case Token::READONLY:
796 this->nextToken();
797 flags |= Modifiers::kReadOnly_Flag;
798 break;
799 case Token::WRITEONLY:
800 this->nextToken();
801 flags |= Modifiers::kWriteOnly_Flag;
802 break;
803 case Token::COHERENT:
804 this->nextToken();
805 flags |= Modifiers::kCoherent_Flag;
806 break;
807 case Token::VOLATILE:
808 this->nextToken();
809 flags |= Modifiers::kVolatile_Flag;
810 break;
811 case Token::RESTRICT:
812 this->nextToken();
813 flags |= Modifiers::kRestrict_Flag;
814 break;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400815 case Token::BUFFER:
816 this->nextToken();
817 flags |= Modifiers::kBuffer_Flag;
818 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400819 case Token::HASSIDEEFFECTS:
820 this->nextToken();
821 flags |= Modifiers::kHasSideEffects_Flag;
822 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700823 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500824 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700825 }
826 }
827}
828
Ethan Nicholas11d53972016-11-28 11:23:23 -0500829Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
830 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700831 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500832 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700833 }
834 return result;
835}
836
837/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
838std::unique_ptr<ASTStatement> Parser::statement() {
839 Token start = this->peek();
840 switch (start.fKind) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400841 case Token::IF: // fall through
842 case Token::STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -0700843 return this->ifStatement();
844 case Token::FOR:
845 return this->forStatement();
846 case Token::DO:
847 return this->doStatement();
848 case Token::WHILE:
849 return this->whileStatement();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400850 case Token::SWITCH: // fall through
851 case Token::STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500852 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700853 case Token::RETURN:
854 return this->returnStatement();
855 case Token::BREAK:
856 return this->breakStatement();
857 case Token::CONTINUE:
858 return this->continueStatement();
859 case Token::DISCARD:
860 return this->discardStatement();
861 case Token::LBRACE:
862 return this->block();
863 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500864 this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700865 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fOffset,
ethannicholas0730be72016-09-01 07:59:02 -0700866 std::vector<std::unique_ptr<ASTStatement>>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700867 case Token::CONST: // fall through
868 case Token::HIGHP: // fall through
869 case Token::MEDIUMP: // fall through
870 case Token::LOWP: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700871 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700872 if (!decl) {
873 return nullptr;
874 }
875 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
876 }
877 case Token::IDENTIFIER:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700878 if (this->isType(this->text(start))) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700879 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700880 if (!decl) {
881 return nullptr;
882 }
883 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
884 std::move(decl)));
885 }
886 // fall through
887 default:
888 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500889 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700890}
891
Ethan Nicholas50afc172017-02-16 14:49:57 -0500892/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
ethannicholasb3058bd2016-07-01 08:22:01 -0700893std::unique_ptr<ASTType> Parser::type() {
894 Token type;
895 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
896 return nullptr;
897 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700898 if (!this->isType(this->text(type))) {
899 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -0700900 return nullptr;
901 }
Ethan Nicholas50afc172017-02-16 14:49:57 -0500902 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400903 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500904 if (this->peek().fKind != Token::RBRACKET) {
905 int64_t i;
906 if (this->intLiteral(&i)) {
907 sizes.push_back(i);
908 } else {
909 return nullptr;
910 }
911 } else {
912 sizes.push_back(-1);
913 }
914 this->expect(Token::RBRACKET, "']'");
915 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700916 return std::unique_ptr<ASTType>(new ASTType(type.fOffset, this->text(type),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500917 ASTType::kIdentifier_Kind, sizes));
ethannicholasb3058bd2016-07-01 08:22:01 -0700918}
919
Ethan Nicholas50afc172017-02-16 14:49:57 -0500920/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500921std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700922 Token name;
923 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
924 return nullptr;
925 }
926 if (peek().fKind != Token::LBRACE) {
927 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500928 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700929 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700930 this->error(name, "no type named '" + this->text(name) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700931 return nullptr;
932 }
933 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500934 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700935 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700936 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700937 if (!decl) {
938 return nullptr;
939 }
940 decls.push_back(std::move(decl));
941 }
942 this->nextToken();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500943 std::vector<std::unique_ptr<ASTExpression>> sizes;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700944 StringFragment instanceName;
945 Token instanceNameToken;
946 if (this->checkNext(Token::IDENTIFIER, &instanceNameToken)) {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400947 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500948 if (this->peek().fKind != Token::RBRACKET) {
949 std::unique_ptr<ASTExpression> size = this->expression();
950 if (!size) {
951 return nullptr;
952 }
953 sizes.push_back(std::move(size));
954 } else {
955 sizes.push_back(nullptr);
956 }
957 this->expect(Token::RBRACKET, "']'");
958 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700959 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -0700960 }
961 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700962 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fOffset, mods,
963 this->text(name),
Brian Osman634624a2017-08-15 11:14:30 -0400964 std::move(decls),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700965 instanceName,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500966 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700967}
968
969/* IF LPAREN expression RPAREN statement (ELSE statement)? */
970std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
971 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400972 bool isStatic = this->checkNext(Token::STATIC_IF, &start);
973 if (!isStatic && !this->expect(Token::IF, "'if'", &start)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700974 return nullptr;
975 }
976 if (!this->expect(Token::LPAREN, "'('")) {
977 return nullptr;
978 }
979 std::unique_ptr<ASTExpression> test(this->expression());
980 if (!test) {
981 return nullptr;
982 }
983 if (!this->expect(Token::RPAREN, "')'")) {
984 return nullptr;
985 }
986 std::unique_ptr<ASTStatement> ifTrue(this->statement());
987 if (!ifTrue) {
988 return nullptr;
989 }
990 std::unique_ptr<ASTStatement> ifFalse;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400991 if (this->checkNext(Token::ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700992 ifFalse = this->statement();
993 if (!ifFalse) {
994 return nullptr;
995 }
996 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700997 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400998 isStatic,
999 std::move(test),
Ethan Nicholas11d53972016-11-28 11:23:23 -05001000 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -07001001 std::move(ifFalse)));
1002}
1003
1004/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
1005std::unique_ptr<ASTDoStatement> Parser::doStatement() {
1006 Token start;
1007 if (!this->expect(Token::DO, "'do'", &start)) {
1008 return nullptr;
1009 }
1010 std::unique_ptr<ASTStatement> statement(this->statement());
1011 if (!statement) {
1012 return nullptr;
1013 }
1014 if (!this->expect(Token::WHILE, "'while'")) {
1015 return nullptr;
1016 }
1017 if (!this->expect(Token::LPAREN, "'('")) {
1018 return nullptr;
1019 }
1020 std::unique_ptr<ASTExpression> test(this->expression());
1021 if (!test) {
1022 return nullptr;
1023 }
1024 if (!this->expect(Token::RPAREN, "')'")) {
1025 return nullptr;
1026 }
1027 if (!this->expect(Token::SEMICOLON, "';'")) {
1028 return nullptr;
1029 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001030 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001031 std::move(statement),
1032 std::move(test)));
1033}
1034
1035/* WHILE LPAREN expression RPAREN STATEMENT */
1036std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
1037 Token start;
1038 if (!this->expect(Token::WHILE, "'while'", &start)) {
1039 return nullptr;
1040 }
1041 if (!this->expect(Token::LPAREN, "'('")) {
1042 return nullptr;
1043 }
1044 std::unique_ptr<ASTExpression> test(this->expression());
1045 if (!test) {
1046 return nullptr;
1047 }
1048 if (!this->expect(Token::RPAREN, "')'")) {
1049 return nullptr;
1050 }
1051 std::unique_ptr<ASTStatement> statement(this->statement());
1052 if (!statement) {
1053 return nullptr;
1054 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001055 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fOffset,
Ethan Nicholas11d53972016-11-28 11:23:23 -05001056 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -07001057 std::move(statement)));
1058}
1059
Ethan Nicholasaf197692017-02-27 13:26:45 -05001060/* CASE expression COLON statement* */
1061std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
1062 Token start;
1063 if (!this->expect(Token::CASE, "'case'", &start)) {
1064 return nullptr;
1065 }
1066 std::unique_ptr<ASTExpression> value = this->expression();
1067 if (!value) {
1068 return nullptr;
1069 }
1070 if (!this->expect(Token::COLON, "':'")) {
1071 return nullptr;
1072 }
1073 std::vector<std::unique_ptr<ASTStatement>> statements;
1074 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
1075 this->peek().fKind != Token::DEFAULT) {
1076 std::unique_ptr<ASTStatement> s = this->statement();
1077 if (!s) {
1078 return nullptr;
1079 }
1080 statements.push_back(std::move(s));
1081 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001082 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fOffset, std::move(value),
Ethan Nicholasaf197692017-02-27 13:26:45 -05001083 std::move(statements)));
1084}
1085
1086/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
1087std::unique_ptr<ASTStatement> Parser::switchStatement() {
1088 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001089 bool isStatic = this->checkNext(Token::STATIC_SWITCH, &start);
1090 if (!isStatic && !this->expect(Token::SWITCH, "'switch'", &start)) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001091 return nullptr;
1092 }
1093 if (!this->expect(Token::LPAREN, "'('")) {
1094 return nullptr;
1095 }
1096 std::unique_ptr<ASTExpression> value(this->expression());
1097 if (!value) {
1098 return nullptr;
1099 }
1100 if (!this->expect(Token::RPAREN, "')'")) {
1101 return nullptr;
1102 }
1103 if (!this->expect(Token::LBRACE, "'{'")) {
1104 return nullptr;
1105 }
1106 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1107 while (this->peek().fKind == Token::CASE) {
1108 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1109 if (!c) {
1110 return nullptr;
1111 }
1112 cases.push_back(std::move(c));
1113 }
1114 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1115 // parts of the compiler may rely upon this assumption.
1116 if (this->peek().fKind == Token::DEFAULT) {
1117 Token defaultStart;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001118 ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001119 if (!this->expect(Token::COLON, "':'")) {
1120 return nullptr;
1121 }
1122 std::vector<std::unique_ptr<ASTStatement>> statements;
1123 while (this->peek().fKind != Token::RBRACE) {
1124 std::unique_ptr<ASTStatement> s = this->statement();
1125 if (!s) {
1126 return nullptr;
1127 }
1128 statements.push_back(std::move(s));
1129 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001130 cases.emplace_back(new ASTSwitchCase(defaultStart.fOffset, nullptr,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001131 std::move(statements)));
1132 }
1133 if (!this->expect(Token::RBRACE, "'}'")) {
1134 return nullptr;
1135 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001136 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001137 isStatic,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001138 std::move(value),
1139 std::move(cases)));
1140}
1141
Ethan Nicholas11d53972016-11-28 11:23:23 -05001142/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001143 STATEMENT */
1144std::unique_ptr<ASTForStatement> Parser::forStatement() {
1145 Token start;
1146 if (!this->expect(Token::FOR, "'for'", &start)) {
1147 return nullptr;
1148 }
1149 if (!this->expect(Token::LPAREN, "'('")) {
1150 return nullptr;
1151 }
1152 std::unique_ptr<ASTStatement> initializer;
1153 Token nextToken = this->peek();
1154 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001155 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001156 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001157 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001158 case Token::CONST: {
1159 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1160 if (!vd) {
1161 return nullptr;
1162 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001163 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001164 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001165 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001166 }
1167 case Token::IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001168 if (this->isType(this->text(nextToken))) {
ethannicholasa54401d2016-10-14 08:37:32 -07001169 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1170 if (!vd) {
1171 return nullptr;
1172 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001173 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001174 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001175 break;
1176 }
ethannicholasa54401d2016-10-14 08:37:32 -07001177 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001178 default:
1179 initializer = this->expressionStatement();
1180 }
1181 std::unique_ptr<ASTExpression> test;
1182 if (this->peek().fKind != Token::SEMICOLON) {
1183 test = this->expression();
1184 if (!test) {
1185 return nullptr;
1186 }
1187 }
1188 if (!this->expect(Token::SEMICOLON, "';'")) {
1189 return nullptr;
1190 }
1191 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001192 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001193 next = this->expression();
1194 if (!next) {
1195 return nullptr;
1196 }
1197 }
1198 if (!this->expect(Token::RPAREN, "')'")) {
1199 return nullptr;
1200 }
1201 std::unique_ptr<ASTStatement> statement(this->statement());
1202 if (!statement) {
1203 return nullptr;
1204 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001205 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001206 std::move(initializer),
1207 std::move(test), std::move(next),
1208 std::move(statement)));
1209}
1210
1211/* RETURN expression? SEMICOLON */
1212std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1213 Token start;
1214 if (!this->expect(Token::RETURN, "'return'", &start)) {
1215 return nullptr;
1216 }
1217 std::unique_ptr<ASTExpression> expression;
1218 if (this->peek().fKind != Token::SEMICOLON) {
1219 expression = this->expression();
1220 if (!expression) {
1221 return nullptr;
1222 }
1223 }
1224 if (!this->expect(Token::SEMICOLON, "';'")) {
1225 return nullptr;
1226 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001227 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001228 std::move(expression)));
1229}
1230
1231/* BREAK SEMICOLON */
1232std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1233 Token start;
1234 if (!this->expect(Token::BREAK, "'break'", &start)) {
1235 return nullptr;
1236 }
1237 if (!this->expect(Token::SEMICOLON, "';'")) {
1238 return nullptr;
1239 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001240 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -07001241}
1242
1243/* CONTINUE SEMICOLON */
1244std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1245 Token start;
1246 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1247 return nullptr;
1248 }
1249 if (!this->expect(Token::SEMICOLON, "';'")) {
1250 return nullptr;
1251 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001252 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -07001253}
1254
1255/* DISCARD SEMICOLON */
1256std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1257 Token start;
1258 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1259 return nullptr;
1260 }
1261 if (!this->expect(Token::SEMICOLON, "';'")) {
1262 return nullptr;
1263 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001264 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -07001265}
1266
1267/* LBRACE statement* RBRACE */
1268std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001269 AutoDepth depth(this);
1270 if (!depth.checkValid()) {
1271 return nullptr;
1272 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001273 Token start;
1274 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1275 return nullptr;
1276 }
1277 std::vector<std::unique_ptr<ASTStatement>> statements;
1278 for (;;) {
1279 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001280 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001281 this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001282 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001283 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001284 case Token::END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001285 this->error(this->peek(), "expected '}', but found end of file");
ethannicholasb3058bd2016-07-01 08:22:01 -07001286 return nullptr;
1287 default: {
1288 std::unique_ptr<ASTStatement> statement = this->statement();
1289 if (!statement) {
1290 return nullptr;
1291 }
1292 statements.push_back(std::move(statement));
1293 }
1294 }
1295 }
1296}
1297
1298/* expression SEMICOLON */
1299std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1300 std::unique_ptr<ASTExpression> expr = this->expression();
1301 if (expr) {
1302 if (this->expect(Token::SEMICOLON, "';'")) {
1303 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1304 return std::unique_ptr<ASTExpressionStatement>(result);
1305 }
1306 }
1307 return nullptr;
1308}
1309
1310/* assignmentExpression */
1311std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001312 AutoDepth depth(this);
1313 if (!depth.checkValid()) {
1314 return nullptr;
1315 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001316 return this->commaExpression();
1317}
1318
1319/* assignmentExpression (COMMA assignmentExpression)* */
1320std::unique_ptr<ASTExpression> Parser::commaExpression() {
1321 std::unique_ptr<ASTExpression> result = this->assignmentExpression();
1322 if (!result) {
1323 return nullptr;
1324 }
1325 Token t;
1326 while (this->checkNext(Token::COMMA, &t)) {
1327 std::unique_ptr<ASTExpression> right = this->commaExpression();
1328 if (!right) {
1329 return nullptr;
1330 }
Brian Osman634624a2017-08-15 11:14:30 -04001331 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001332 }
1333 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001334}
1335
1336/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1337 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1338 assignmentExpression)*
1339 */
1340std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1341 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1342 if (!result) {
1343 return nullptr;
1344 }
1345 for (;;) {
1346 switch (this->peek().fKind) {
1347 case Token::EQ: // fall through
1348 case Token::STAREQ: // fall through
1349 case Token::SLASHEQ: // fall through
1350 case Token::PERCENTEQ: // fall through
1351 case Token::PLUSEQ: // fall through
1352 case Token::MINUSEQ: // fall through
1353 case Token::SHLEQ: // fall through
1354 case Token::SHREQ: // fall through
1355 case Token::BITWISEANDEQ: // fall through
1356 case Token::BITWISEXOREQ: // fall through
1357 case Token::BITWISEOREQ: // fall through
1358 case Token::LOGICALANDEQ: // fall through
1359 case Token::LOGICALXOREQ: // fall through
1360 case Token::LOGICALOREQ: {
1361 Token t = this->nextToken();
1362 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1363 if (!right) {
1364 return nullptr;
1365 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001366 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
Brian Osman634624a2017-08-15 11:14:30 -04001367 std::move(t),
ethannicholasb3058bd2016-07-01 08:22:01 -07001368 std::move(right)));
1369 }
1370 default:
1371 return result;
1372 }
1373 }
1374}
1375
1376/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1377std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1378 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1379 if (!result) {
1380 return nullptr;
1381 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001382 if (this->checkNext(Token::QUESTION)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001383 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1384 if (!trueExpr) {
1385 return nullptr;
1386 }
1387 if (this->expect(Token::COLON, "':'")) {
1388 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001389 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1390 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001391 std::move(falseExpr)));
1392 }
1393 return nullptr;
1394 }
1395 return result;
1396}
1397
1398/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1399std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1400 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1401 if (!result) {
1402 return nullptr;
1403 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001404 Token t;
1405 while (this->checkNext(Token::LOGICALOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001406 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
1407 if (!right) {
1408 return nullptr;
1409 }
Brian Osman634624a2017-08-15 11:14:30 -04001410 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001411 }
1412 return result;
1413}
1414
1415/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1416std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1417 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1418 if (!result) {
1419 return nullptr;
1420 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001421 Token t;
1422 while (this->checkNext(Token::LOGICALXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001423 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1424 if (!right) {
1425 return nullptr;
1426 }
Brian Osman634624a2017-08-15 11:14:30 -04001427 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 }
1429 return result;
1430}
1431
1432/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1433std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1434 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1435 if (!result) {
1436 return nullptr;
1437 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001438 Token t;
1439 while (this->checkNext(Token::LOGICALAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001440 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1441 if (!right) {
1442 return nullptr;
1443 }
Brian Osman634624a2017-08-15 11:14:30 -04001444 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001445 }
1446 return result;
1447}
1448
1449/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1450std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1451 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1452 if (!result) {
1453 return nullptr;
1454 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001455 Token t;
1456 while (this->checkNext(Token::BITWISEOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001457 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1458 if (!right) {
1459 return nullptr;
1460 }
Brian Osman634624a2017-08-15 11:14:30 -04001461 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001462 }
1463 return result;
1464}
1465
1466/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1467std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1468 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1469 if (!result) {
1470 return nullptr;
1471 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001472 Token t;
1473 while (this->checkNext(Token::BITWISEXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001474 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1475 if (!right) {
1476 return nullptr;
1477 }
Brian Osman634624a2017-08-15 11:14:30 -04001478 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001479 }
1480 return result;
1481}
1482
1483/* equalityExpression (BITWISEAND equalityExpression)* */
1484std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1485 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1486 if (!result) {
1487 return nullptr;
1488 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001489 Token t;
1490 while (this->checkNext(Token::BITWISEAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001491 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1492 if (!right) {
1493 return nullptr;
1494 }
Brian Osman634624a2017-08-15 11:14:30 -04001495 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001496 }
1497 return result;
1498}
1499
1500/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1501std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1502 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1503 if (!result) {
1504 return nullptr;
1505 }
1506 for (;;) {
1507 switch (this->peek().fKind) {
1508 case Token::EQEQ: // fall through
1509 case Token::NEQ: {
1510 Token t = this->nextToken();
1511 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1512 if (!right) {
1513 return nullptr;
1514 }
Brian Osman634624a2017-08-15 11:14:30 -04001515 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 break;
1517 }
1518 default:
1519 return result;
1520 }
1521 }
1522}
1523
1524/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1525std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1526 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1527 if (!result) {
1528 return nullptr;
1529 }
1530 for (;;) {
1531 switch (this->peek().fKind) {
1532 case Token::LT: // fall through
1533 case Token::GT: // fall through
1534 case Token::LTEQ: // fall through
1535 case Token::GTEQ: {
1536 Token t = this->nextToken();
1537 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1538 if (!right) {
1539 return nullptr;
1540 }
Brian Osman634624a2017-08-15 11:14:30 -04001541 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1542 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001543 break;
1544 }
1545 default:
1546 return result;
1547 }
1548 }
1549}
1550
1551/* additiveExpression ((SHL | SHR) additiveExpression)* */
1552std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1553 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1554 if (!result) {
1555 return nullptr;
1556 }
1557 for (;;) {
1558 switch (this->peek().fKind) {
1559 case Token::SHL: // fall through
1560 case Token::SHR: {
1561 Token t = this->nextToken();
1562 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1563 if (!right) {
1564 return nullptr;
1565 }
Brian Osman634624a2017-08-15 11:14:30 -04001566 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1567 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 break;
1569 }
1570 default:
1571 return result;
1572 }
1573 }
1574}
1575
1576/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1577std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1578 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1579 if (!result) {
1580 return nullptr;
1581 }
1582 for (;;) {
1583 switch (this->peek().fKind) {
1584 case Token::PLUS: // fall through
1585 case Token::MINUS: {
1586 Token t = this->nextToken();
1587 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1588 if (!right) {
1589 return nullptr;
1590 }
Brian Osman634624a2017-08-15 11:14:30 -04001591 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1592 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001593 break;
1594 }
1595 default:
1596 return result;
1597 }
1598 }
1599}
1600
1601/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1602std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1603 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1604 if (!result) {
1605 return nullptr;
1606 }
1607 for (;;) {
1608 switch (this->peek().fKind) {
1609 case Token::STAR: // fall through
1610 case Token::SLASH: // fall through
1611 case Token::PERCENT: {
1612 Token t = this->nextToken();
1613 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1614 if (!right) {
1615 return nullptr;
1616 }
Brian Osman634624a2017-08-15 11:14:30 -04001617 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1618 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001619 break;
1620 }
1621 default:
1622 return result;
1623 }
1624 }
1625}
1626
1627/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1628std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1629 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001630 case Token::PLUS: // fall through
1631 case Token::MINUS: // fall through
1632 case Token::LOGICALNOT: // fall through
1633 case Token::BITWISENOT: // fall through
1634 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 case Token::MINUSMINUS: {
1636 Token t = this->nextToken();
1637 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1638 if (!expr) {
1639 return nullptr;
1640 }
Brian Osman634624a2017-08-15 11:14:30 -04001641 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(std::move(t),
1642 std::move(expr)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 }
1644 default:
1645 return this->postfixExpression();
1646 }
1647}
1648
1649/* term suffix* */
1650std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1651 std::unique_ptr<ASTExpression> result = this->term();
1652 if (!result) {
1653 return nullptr;
1654 }
1655 for (;;) {
1656 switch (this->peek().fKind) {
1657 case Token::LBRACKET: // fall through
1658 case Token::DOT: // fall through
1659 case Token::LPAREN: // fall through
1660 case Token::PLUSPLUS: // fall through
1661 case Token::MINUSMINUS: {
1662 std::unique_ptr<ASTSuffix> s = this->suffix();
1663 if (!s) {
1664 return nullptr;
1665 }
1666 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1667 break;
1668 }
1669 default:
1670 return result;
1671 }
1672 }
1673}
1674
Ethan Nicholas11d53972016-11-28 11:23:23 -05001675/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 PLUSPLUS | MINUSMINUS */
1677std::unique_ptr<ASTSuffix> Parser::suffix() {
1678 Token next = this->nextToken();
1679 switch (next.fKind) {
1680 case Token::LBRACKET: {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001681 if (this->checkNext(Token::RBRACKET)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001682 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fOffset));
ethannicholas5961bc92016-10-12 06:39:56 -07001683 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001684 std::unique_ptr<ASTExpression> e = this->expression();
1685 if (!e) {
1686 return nullptr;
1687 }
1688 this->expect(Token::RBRACKET, "']' to complete array access expression");
1689 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1690 }
1691 case Token::DOT: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001692 int offset = this->peek().fOffset;
1693 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001694 if (this->identifier(&text)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001695 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(offset, std::move(text)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001696 }
1697 return nullptr;
1698 }
1699 case Token::LPAREN: {
1700 std::vector<std::unique_ptr<ASTExpression>> parameters;
1701 if (this->peek().fKind != Token::RPAREN) {
1702 for (;;) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001703 std::unique_ptr<ASTExpression> expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001704 if (!expr) {
1705 return nullptr;
1706 }
1707 parameters.push_back(std::move(expr));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001708 if (!this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001709 break;
1710 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001711 }
1712 }
1713 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001714 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001715 std::move(parameters)));
1716 }
1717 case Token::PLUSPLUS:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001718 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001719 ASTSuffix::kPostIncrement_Kind));
1720 case Token::MINUSMINUS:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001721 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001722 ASTSuffix::kPostDecrement_Kind));
1723 default: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001724 this->error(next, "expected expression suffix, but found '" + this->text(next) +
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 "'\n");
1726 return nullptr;
1727 }
1728 }
1729}
1730
1731/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1732std::unique_ptr<ASTExpression> Parser::term() {
1733 std::unique_ptr<ASTExpression> result;
1734 Token t = this->peek();
1735 switch (t.fKind) {
1736 case Token::IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001737 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001738 if (this->identifier(&text)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001739 result.reset(new ASTIdentifier(t.fOffset, std::move(text)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001740 }
1741 break;
1742 }
1743 case Token::INT_LITERAL: {
1744 int64_t i;
1745 if (this->intLiteral(&i)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001746 result.reset(new ASTIntLiteral(t.fOffset, i));
ethannicholasb3058bd2016-07-01 08:22:01 -07001747 }
1748 break;
1749 }
1750 case Token::FLOAT_LITERAL: {
1751 double f;
1752 if (this->floatLiteral(&f)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001753 result.reset(new ASTFloatLiteral(t.fOffset, f));
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 }
1755 break;
1756 }
1757 case Token::TRUE_LITERAL: // fall through
1758 case Token::FALSE_LITERAL: {
1759 bool b;
1760 if (this->boolLiteral(&b)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001761 result.reset(new ASTBoolLiteral(t.fOffset, b));
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 }
1763 break;
1764 }
1765 case Token::LPAREN: {
1766 this->nextToken();
1767 result = this->expression();
1768 if (result) {
1769 this->expect(Token::RPAREN, "')' to complete expression");
1770 }
1771 break;
1772 }
1773 default:
1774 this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001775 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 result = nullptr;
1777 }
1778 return result;
1779}
1780
1781/* INT_LITERAL */
1782bool Parser::intLiteral(int64_t* dest) {
1783 Token t;
1784 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001785 *dest = SkSL::stol(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 return true;
1787 }
1788 return false;
1789}
1790
1791/* FLOAT_LITERAL */
1792bool Parser::floatLiteral(double* dest) {
1793 Token t;
1794 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001795 *dest = SkSL::stod(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07001796 return true;
1797 }
1798 return false;
1799}
1800
1801/* TRUE_LITERAL | FALSE_LITERAL */
1802bool Parser::boolLiteral(bool* dest) {
1803 Token t = this->nextToken();
1804 switch (t.fKind) {
1805 case Token::TRUE_LITERAL:
1806 *dest = true;
1807 return true;
1808 case Token::FALSE_LITERAL:
1809 *dest = false;
1810 return true;
1811 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001812 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 return false;
1814 }
1815}
1816
1817/* IDENTIFIER */
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001818bool Parser::identifier(StringFragment* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001819 Token t;
1820 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001821 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 return true;
1823 }
1824 return false;
1825}
1826
1827} // namespace