blob: ae9d990d86c67b3c67759c3297565f87469dff73 [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"
10#include "SkSLToken.h"
11
12#define register
Ethan Nicholasbfe15f62017-03-01 11:46:51 -050013#include "disable_flex_warnings.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070014#include "lex.sksl.c"
Ethan Nicholas94421942017-03-31 17:06:42 -040015static_assert(YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION * 10 +
16 YY_FLEX_SUBMINOR_VERSION >= 261,
17 "we require Flex 2.6.1 or better for security reasons");
Ethan Nicholasbfe15f62017-03-01 11:46:51 -050018#undef register
ethannicholasb3058bd2016-07-01 08:22:01 -070019#ifdef __clang__
20#pragma clang diagnostic pop
21#endif
ethannicholasf789b382016-08-03 12:43:36 -070022#ifdef __GNUC__
23#pragma GCC diagnostic pop
24#endif
25#ifdef _MSC_VER
26#pragma warning(pop)
27#endif
ethannicholasb3058bd2016-07-01 08:22:01 -070028
Ethan Nicholasbfe15f62017-03-01 11:46:51 -050029#include "lex.layout.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070030#include "ast/SkSLASTBinaryExpression.h"
31#include "ast/SkSLASTBlock.h"
32#include "ast/SkSLASTBoolLiteral.h"
33#include "ast/SkSLASTBreakStatement.h"
34#include "ast/SkSLASTCallSuffix.h"
35#include "ast/SkSLASTContinueStatement.h"
36#include "ast/SkSLASTDiscardStatement.h"
37#include "ast/SkSLASTDoStatement.h"
38#include "ast/SkSLASTExpression.h"
39#include "ast/SkSLASTExpressionStatement.h"
40#include "ast/SkSLASTExtension.h"
41#include "ast/SkSLASTFieldSuffix.h"
42#include "ast/SkSLASTFloatLiteral.h"
43#include "ast/SkSLASTForStatement.h"
44#include "ast/SkSLASTFunction.h"
45#include "ast/SkSLASTIdentifier.h"
46#include "ast/SkSLASTIfStatement.h"
47#include "ast/SkSLASTIndexSuffix.h"
48#include "ast/SkSLASTInterfaceBlock.h"
49#include "ast/SkSLASTIntLiteral.h"
ethannicholas5961bc92016-10-12 06:39:56 -070050#include "ast/SkSLASTModifiersDeclaration.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070051#include "ast/SkSLASTParameter.h"
ethannicholas5961bc92016-10-12 06:39:56 -070052#include "ast/SkSLASTPrecision.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070053#include "ast/SkSLASTPrefixExpression.h"
54#include "ast/SkSLASTReturnStatement.h"
55#include "ast/SkSLASTStatement.h"
56#include "ast/SkSLASTSuffixExpression.h"
Ethan Nicholasaf197692017-02-27 13:26:45 -050057#include "ast/SkSLASTSwitchCase.h"
58#include "ast/SkSLASTSwitchStatement.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070059#include "ast/SkSLASTTernaryExpression.h"
60#include "ast/SkSLASTType.h"
61#include "ast/SkSLASTVarDeclaration.h"
62#include "ast/SkSLASTVarDeclarationStatement.h"
63#include "ast/SkSLASTWhileStatement.h"
64#include "ir/SkSLSymbolTable.h"
Ethan Nicholas11d53972016-11-28 11:23:23 -050065#include "ir/SkSLModifiers.h"
ethannicholasd598f792016-07-25 10:08:54 -070066#include "ir/SkSLType.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070067
68namespace SkSL {
69
ethannicholascad64162016-10-27 10:54:02 -070070#define MAX_PARSE_DEPTH 50
71
72class AutoDepth {
73public:
74 AutoDepth(Parser* p)
75 : fParser(p) {
76 fParser->fDepth++;
77 }
78
79 ~AutoDepth() {
80 fParser->fDepth--;
81 }
82
83 bool checkValid() {
84 if (fParser->fDepth > MAX_PARSE_DEPTH) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -040085 fParser->error(fParser->peek().fPosition, String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070086 return false;
87 }
88 return true;
89 }
90
91private:
92 Parser* fParser;
93};
94
Ethan Nicholas0df1b042017-03-31 13:56:23 -040095Parser::Parser(String text, SymbolTable& types, ErrorReporter& errors)
96: fPushback(Position(-1, -1), Token::INVALID_TOKEN, String())
ethannicholasb3058bd2016-07-01 08:22:01 -070097, fTypes(types)
98, fErrors(errors) {
99 sksllex_init(&fScanner);
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500100 layoutlex_init(&fLayoutScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700101 fBuffer = sksl_scan_string(text.c_str(), fScanner);
102 skslset_lineno(1, fScanner);
103
104 if (false) {
105 // avoid unused warning
106 yyunput(0, nullptr, fScanner);
107 }
108}
109
110Parser::~Parser() {
111 sksl_delete_buffer(fBuffer, fScanner);
ethannicholas69a7e7c2016-07-01 19:09:27 -0700112 sksllex_destroy(fScanner);
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500113 layoutlex_destroy(fLayoutScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700114}
115
116/* (precision | directive | declaration)* END_OF_FILE */
117std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
118 std::vector<std::unique_ptr<ASTDeclaration>> result;
119 for (;;) {
120 switch (this->peek().fKind) {
121 case Token::END_OF_FILE:
122 return result;
ethannicholas5961bc92016-10-12 06:39:56 -0700123 case Token::PRECISION: {
124 std::unique_ptr<ASTDeclaration> precision = this->precision();
125 if (precision) {
126 result.push_back(std::move(precision));
127 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700128 break;
ethannicholas5961bc92016-10-12 06:39:56 -0700129 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700130 case Token::DIRECTIVE: {
131 std::unique_ptr<ASTDeclaration> decl = this->directive();
132 if (decl) {
133 result.push_back(std::move(decl));
134 }
135 break;
136 }
137 default: {
138 std::unique_ptr<ASTDeclaration> decl = this->declaration();
139 if (!decl) {
140 continue;
141 }
142 result.push_back(std::move(decl));
143 }
144 }
145 }
146}
147
148Token Parser::nextToken() {
149 if (fPushback.fKind != Token::INVALID_TOKEN) {
150 Token result = fPushback;
151 fPushback.fKind = Token::INVALID_TOKEN;
152 fPushback.fText = "";
153 return result;
154 }
155 int token = sksllex(fScanner);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400156 String text;
ethannicholas471e8942016-10-28 09:02:46 -0700157 switch ((Token::Kind) token) {
158 case Token::IDENTIFIER: // fall through
159 case Token::INT_LITERAL: // fall through
160 case Token::FLOAT_LITERAL: // fall through
161 case Token::DIRECTIVE:
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400162 text = String(skslget_text(fScanner));
ethannicholas471e8942016-10-28 09:02:46 -0700163 break;
164 default:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500165#ifdef SK_DEBUG
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400166 text = String(skslget_text(fScanner));
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500167#endif
ethannicholas471e8942016-10-28 09:02:46 -0700168 break;
169 }
170 return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token, text);
ethannicholasb3058bd2016-07-01 08:22:01 -0700171}
172
173void Parser::pushback(Token t) {
174 ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
175 fPushback = t;
176}
177
178Token Parser::peek() {
179 fPushback = this->nextToken();
180 return fPushback;
181}
182
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500183
184bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400185 return this->expect(kind, String(expected), result);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500186}
187
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400188bool Parser::expect(Token::Kind kind, String expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700189 Token next = this->nextToken();
190 if (next.fKind == kind) {
191 if (result) {
192 *result = next;
193 }
194 return true;
195 } else {
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500196 if (next.fText.size()) {
197 this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText +
198 "'");
199 } else {
200 this->error(next.fPosition, "parse error, recompile in debug mode for details");
201 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700202 return false;
203 }
204}
205
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500206void Parser::error(Position p, const char* msg) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400207 this->error(p, String(msg));
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500208}
209
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400210void Parser::error(Position p, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700211 fErrors.error(p, msg);
212}
213
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400214bool Parser::isType(String name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700215 return nullptr != fTypes[name];
216}
217
218/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
ethannicholas5961bc92016-10-12 06:39:56 -0700219std::unique_ptr<ASTDeclaration> Parser::precision() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700220 if (!this->expect(Token::PRECISION, "'precision'")) {
ethannicholas5961bc92016-10-12 06:39:56 -0700221 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700222 }
ethannicholas5961bc92016-10-12 06:39:56 -0700223 Modifiers::Flag result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700224 Token p = this->nextToken();
225 switch (p.fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -0700226 case Token::LOWP:
227 result = Modifiers::kLowp_Flag;
228 break;
229 case Token::MEDIUMP:
230 result = Modifiers::kMediump_Flag;
231 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700232 case Token::HIGHP:
ethannicholas5961bc92016-10-12 06:39:56 -0700233 result = Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700234 break;
235 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500236 this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 p.fText + "'");
ethannicholas5961bc92016-10-12 06:39:56 -0700238 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700239 }
ethannicholas5961bc92016-10-12 06:39:56 -0700240 // FIXME handle the type
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 if (!this->type()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700242 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 }
244 this->expect(Token::SEMICOLON, "';'");
ethannicholas5961bc92016-10-12 06:39:56 -0700245 return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
ethannicholasb3058bd2016-07-01 08:22:01 -0700246}
247
Ethan Nicholas11d53972016-11-28 11:23:23 -0500248/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700249 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700250std::unique_ptr<ASTDeclaration> Parser::directive() {
251 Token start;
252 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
253 return nullptr;
254 }
255 if (start.fText == "#version") {
256 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700257 Token next = this->peek();
258 if (next.fText == "es" || next.fText == "compatibility") {
259 this->nextToken();
260 }
261 // version is ignored for now; it will eventually become an error when we stop pretending
262 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 return nullptr;
264 } else if (start.fText == "#extension") {
265 Token name;
266 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
267 return nullptr;
268 }
269 if (!this->expect(Token::COLON, "':'")) {
270 return nullptr;
271 }
272 // FIXME: need to start paying attention to this token
273 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
274 return nullptr;
275 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500276 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700277 std::move(name.fText)));
278 } else {
279 this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
280 return nullptr;
281 }
282}
283
Ethan Nicholas11d53972016-11-28 11:23:23 -0500284/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
286std::unique_ptr<ASTDeclaration> Parser::declaration() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500287 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700288 Token lookahead = this->peek();
289 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
290 // we have an identifier that's not a type, could be the start of an interface block
291 return this->interfaceBlock(modifiers);
292 }
293 if (lookahead.fKind == Token::STRUCT) {
294 return this->structVarDeclaration(modifiers);
295 }
ethannicholas5961bc92016-10-12 06:39:56 -0700296 if (lookahead.fKind == Token::SEMICOLON) {
297 this->nextToken();
298 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
299 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 std::unique_ptr<ASTType> type(this->type());
301 if (!type) {
302 return nullptr;
303 }
304 if (type->fKind == ASTType::kStruct_Kind && peek().fKind == Token::SEMICOLON) {
305 this->nextToken();
306 return nullptr;
307 }
308 Token name;
309 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
310 return nullptr;
311 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400312 if (this->peek().fKind == Token::LPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700313 this->nextToken();
314 std::vector<std::unique_ptr<ASTParameter>> parameters;
315 while (this->peek().fKind != Token::RPAREN) {
316 if (parameters.size() > 0) {
317 if (!this->expect(Token::COMMA, "','")) {
318 return nullptr;
319 }
320 }
321 std::unique_ptr<ASTParameter> parameter = this->parameter();
322 if (!parameter) {
323 return nullptr;
324 }
325 parameters.push_back(std::move(parameter));
326 }
327 this->nextToken();
328 std::unique_ptr<ASTBlock> body;
329 if (this->peek().fKind == Token::SEMICOLON) {
330 this->nextToken();
331 } else {
332 body = this->block();
333 if (!body) {
334 return nullptr;
335 }
336 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400337 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition,
338 modifiers,
339 std::move(type),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500340 std::move(name.fText),
341 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700342 std::move(body)));
343 } else {
344 return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
345 }
346}
347
348/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700349std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500350 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700351 std::unique_ptr<ASTType> type(this->type());
352 if (!type) {
353 return nullptr;
354 }
355 Token name;
356 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
357 return nullptr;
358 }
359 return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
360}
361
362/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
363std::unique_ptr<ASTType> Parser::structDeclaration() {
364 if (!this->expect(Token::STRUCT, "'struct'")) {
365 return nullptr;
366 }
367 Token name;
368 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
369 return nullptr;
370 }
371 if (!this->expect(Token::LBRACE, "'{'")) {
372 return nullptr;
373 }
374 std::vector<Type::Field> fields;
375 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700376 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700377 if (!decl) {
378 return nullptr;
379 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700380 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700381 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700382 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700383 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 this->error(decl->fPosition, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700385 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700386 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700387 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400388 String name = type->name() + "[" + to_string(columns) + "]";
ethannicholasd598f792016-07-25 10:08:54 -0700389 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
390 fTypes.takeOwnership((Type*) type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700391 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700392 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
393 if (var.fValue) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700394 this->error(decl->fPosition, "initializers are not permitted on struct fields");
395 }
396 }
397 }
398 if (!this->expect(Token::RBRACE, "'}'")) {
399 return nullptr;
400 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500401 fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fPosition, name.fText, fields)));
Ethan Nicholas11d53972016-11-28 11:23:23 -0500402 return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500403 ASTType::kStruct_Kind, std::vector<int>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700404}
405
406/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500407std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700408 std::unique_ptr<ASTType> type = this->structDeclaration();
409 if (!type) {
410 return nullptr;
411 }
412 if (peek().fKind == Token::IDENTIFIER) {
413 Token name = this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500414 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
415 std::move(type),
ethannicholas14fe8cc2016-09-07 13:37:16 -0700416 std::move(name.fText));
ethannicholasb3058bd2016-07-01 08:22:01 -0700417 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700418 for (const auto& var : result->fVars) {
419 if (var.fValue) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500420 this->error(var.fValue->fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700421 "struct variables cannot be initialized");
422 }
423 }
424 }
425 return result;
426 }
427 this->expect(Token::SEMICOLON, "';'");
428 return nullptr;
429}
430
Ethan Nicholas11d53972016-11-28 11:23:23 -0500431/* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500433std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700434 std::unique_ptr<ASTType> type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400435 String name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700436 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
438 while (this->peek().fKind == Token::LBRACKET) {
439 this->nextToken();
440 if (this->peek().fKind == Token::RBRACKET) {
441 this->nextToken();
442 currentVarSizes.push_back(nullptr);
443 } else {
444 std::unique_ptr<ASTExpression> size(this->expression());
445 if (!size) {
446 return nullptr;
447 }
448 currentVarSizes.push_back(std::move(size));
449 if (!this->expect(Token::RBRACKET, "']'")) {
450 return nullptr;
451 }
452 }
453 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700454 std::unique_ptr<ASTExpression> value;
ethannicholasb3058bd2016-07-01 08:22:01 -0700455 if (this->peek().fKind == Token::EQ) {
456 this->nextToken();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700457 value = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700458 if (!value) {
459 return nullptr;
460 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700461 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700462 vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700463 while (this->peek().fKind == Token::COMMA) {
464 this->nextToken();
465 Token name;
466 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
467 return nullptr;
468 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700470 value.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -0700471 while (this->peek().fKind == Token::LBRACKET) {
472 this->nextToken();
473 if (this->peek().fKind == Token::RBRACKET) {
474 this->nextToken();
475 currentVarSizes.push_back(nullptr);
476 } else {
477 std::unique_ptr<ASTExpression> size(this->expression());
478 if (!size) {
479 return nullptr;
480 }
481 currentVarSizes.push_back(std::move(size));
482 if (!this->expect(Token::RBRACKET, "']'")) {
483 return nullptr;
484 }
485 }
486 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700487 if (this->peek().fKind == Token::EQ) {
488 this->nextToken();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700489 value = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 if (!value) {
491 return nullptr;
492 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700494 vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 }
496 if (!this->expect(Token::SEMICOLON, "';'")) {
497 return nullptr;
498 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700499 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
500 std::move(type),
501 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700502}
503
504/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
505std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400506 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 std::unique_ptr<ASTType> type = this->type();
508 if (!type) {
509 return nullptr;
510 }
511 Token name;
512 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
513 return nullptr;
514 }
515 std::vector<int> sizes;
516 while (this->peek().fKind == Token::LBRACKET) {
517 this->nextToken();
518 Token sizeToken;
519 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
520 return nullptr;
521 }
522 sizes.push_back(SkSL::stoi(sizeToken.fText));
523 if (!this->expect(Token::RBRACKET, "']'")) {
524 return nullptr;
525 }
526 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500527 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
528 std::move(type), name.fText,
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 std::move(sizes)));
530}
531
532/** (EQ INT_LITERAL)? */
533int Parser::layoutInt() {
534 if (!this->expect(Token::EQ, "'='")) {
535 return -1;
536 }
537 Token resultToken;
538 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
539 return SkSL::stoi(resultToken.fText);
540 }
541 return -1;
542}
543
ethannicholas8ac838d2016-11-22 08:39:36 -0800544/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500545Layout Parser::layout() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700546 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500547 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700548 int binding = -1;
549 int index = -1;
550 int set = -1;
551 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500552 int inputAttachmentIndex = -1;
ethannicholasf789b382016-08-03 12:43:36 -0700553 bool originUpperLeft = false;
ethannicholas5961bc92016-10-12 06:39:56 -0700554 bool overrideCoverage = false;
555 bool blendSupportAllEquations = false;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500556 Layout::Format format = Layout::Format::kUnspecified;
ethannicholas8ac838d2016-11-22 08:39:36 -0800557 bool pushConstant = false;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500558 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
559 int maxVertices = -1;
560 int invocations = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700561 if (this->peek().fKind == Token::LAYOUT) {
562 this->nextToken();
563 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500564 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
Ethan Nicholas11d53972016-11-28 11:23:23 -0500565 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas52cad152017-02-16 16:37:32 -0500566 pushConstant, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 }
568 for (;;) {
569 Token t = this->nextToken();
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500570 YY_BUFFER_STATE buffer;
571 buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner);
572 int token = layoutlex(fLayoutScanner);
573 layout_delete_buffer(buffer, fLayoutScanner);
574 if (token != Token::INVALID_TOKEN) {
575 switch (token) {
576 case Token::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500577 location = this->layoutInt();
578 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500579 case Token::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500580 offset = this->layoutInt();
581 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500582 case Token::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500583 binding = this->layoutInt();
584 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500585 case Token::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500586 index = this->layoutInt();
587 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500588 case Token::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500589 set = this->layoutInt();
590 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500591 case Token::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500592 builtin = this->layoutInt();
593 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500594 case Token::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500595 inputAttachmentIndex = this->layoutInt();
596 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500597 case Token::ORIGIN_UPPER_LEFT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500598 originUpperLeft = true;
599 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500600 case Token::OVERRIDE_COVERAGE:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500601 overrideCoverage = true;
602 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500603 case Token::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500604 blendSupportAllEquations = true;
605 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500606 case Token::PUSH_CONSTANT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500607 pushConstant = true;
608 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500609 case Token::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500610 primitive = Layout::kPoints_Primitive;
611 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500612 case Token::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500613 primitive = Layout::kLines_Primitive;
614 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500615 case Token::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500616 primitive = Layout::kLineStrip_Primitive;
617 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500618 case Token::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500619 primitive = Layout::kLinesAdjacency_Primitive;
620 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500621 case Token::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500622 primitive = Layout::kTriangles_Primitive;
623 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500624 case Token::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500625 primitive = Layout::kTriangleStrip_Primitive;
626 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500627 case Token::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500628 primitive = Layout::kTrianglesAdjacency_Primitive;
629 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500630 case Token::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500631 maxVertices = this->layoutInt();
632 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500633 case Token::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500634 invocations = this->layoutInt();
635 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500636 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500637 } else if (Layout::ReadFormat(t.fText, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500638 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700639 } else {
Greg Daniel64773e62016-11-22 09:44:03 -0500640 this->error(t.fPosition, ("'" + t.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 "' is not a valid layout qualifier").c_str());
642 }
643 if (this->peek().fKind == Token::RPAREN) {
644 this->nextToken();
645 break;
646 }
647 if (!this->expect(Token::COMMA, "','")) {
648 break;
649 }
650 }
651 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500652 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
653 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas52cad152017-02-16 16:37:32 -0500654 pushConstant, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700655}
656
Brian Salomonf9f45122016-11-29 11:59:17 -0500657/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
658 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500659Modifiers Parser::modifiers() {
660 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700661 int flags = 0;
662 for (;;) {
663 // TODO: handle duplicate / incompatible flags
664 switch (peek().fKind) {
665 case Token::UNIFORM:
666 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500667 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700668 break;
669 case Token::CONST:
670 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500671 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700672 break;
673 case Token::IN:
674 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500675 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700676 break;
677 case Token::OUT:
678 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500679 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700680 break;
681 case Token::INOUT:
682 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500683 flags |= Modifiers::kIn_Flag;
684 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700685 break;
686 case Token::LOWP:
687 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500688 flags |= Modifiers::kLowp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700689 break;
690 case Token::MEDIUMP:
691 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500692 flags |= Modifiers::kMediump_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700693 break;
694 case Token::HIGHP:
695 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500696 flags |= Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700697 break;
ethannicholasf789b382016-08-03 12:43:36 -0700698 case Token::FLAT:
699 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500700 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700701 break;
702 case Token::NOPERSPECTIVE:
703 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500704 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700705 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500706 case Token::READONLY:
707 this->nextToken();
708 flags |= Modifiers::kReadOnly_Flag;
709 break;
710 case Token::WRITEONLY:
711 this->nextToken();
712 flags |= Modifiers::kWriteOnly_Flag;
713 break;
714 case Token::COHERENT:
715 this->nextToken();
716 flags |= Modifiers::kCoherent_Flag;
717 break;
718 case Token::VOLATILE:
719 this->nextToken();
720 flags |= Modifiers::kVolatile_Flag;
721 break;
722 case Token::RESTRICT:
723 this->nextToken();
724 flags |= Modifiers::kRestrict_Flag;
725 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400726 case Token::HASSIDEEFFECTS:
727 this->nextToken();
728 flags |= Modifiers::kHasSideEffects_Flag;
729 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700730 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500731 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700732 }
733 }
734}
735
Ethan Nicholas11d53972016-11-28 11:23:23 -0500736Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
737 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700738 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500739 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700740 }
741 return result;
742}
743
744/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
745std::unique_ptr<ASTStatement> Parser::statement() {
746 Token start = this->peek();
747 switch (start.fKind) {
748 case Token::IF:
749 return this->ifStatement();
750 case Token::FOR:
751 return this->forStatement();
752 case Token::DO:
753 return this->doStatement();
754 case Token::WHILE:
755 return this->whileStatement();
Ethan Nicholasaf197692017-02-27 13:26:45 -0500756 case Token::SWITCH:
757 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700758 case Token::RETURN:
759 return this->returnStatement();
760 case Token::BREAK:
761 return this->breakStatement();
762 case Token::CONTINUE:
763 return this->continueStatement();
764 case Token::DISCARD:
765 return this->discardStatement();
766 case Token::LBRACE:
767 return this->block();
768 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500769 this->nextToken();
770 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
ethannicholas0730be72016-09-01 07:59:02 -0700771 std::vector<std::unique_ptr<ASTStatement>>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700772 case Token::CONST: // fall through
773 case Token::HIGHP: // fall through
774 case Token::MEDIUMP: // fall through
775 case Token::LOWP: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700776 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700777 if (!decl) {
778 return nullptr;
779 }
780 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
781 }
782 case Token::IDENTIFIER:
783 if (this->isType(start.fText)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700784 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700785 if (!decl) {
786 return nullptr;
787 }
788 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
789 std::move(decl)));
790 }
791 // fall through
792 default:
793 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500794 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700795}
796
Ethan Nicholas50afc172017-02-16 14:49:57 -0500797/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
ethannicholasb3058bd2016-07-01 08:22:01 -0700798std::unique_ptr<ASTType> Parser::type() {
799 Token type;
800 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
801 return nullptr;
802 }
803 if (!this->isType(type.fText)) {
804 this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
805 return nullptr;
806 }
Ethan Nicholas50afc172017-02-16 14:49:57 -0500807 std::vector<int> sizes;
808 while (this->peek().fKind == Token::LBRACKET) {
809 this->expect(Token::LBRACKET, "'['");
810 if (this->peek().fKind != Token::RBRACKET) {
811 int64_t i;
812 if (this->intLiteral(&i)) {
813 sizes.push_back(i);
814 } else {
815 return nullptr;
816 }
817 } else {
818 sizes.push_back(-1);
819 }
820 this->expect(Token::RBRACKET, "']'");
821 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500822 return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500823 ASTType::kIdentifier_Kind, sizes));
ethannicholasb3058bd2016-07-01 08:22:01 -0700824}
825
Ethan Nicholas50afc172017-02-16 14:49:57 -0500826/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500827std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700828 Token name;
829 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
830 return nullptr;
831 }
832 if (peek().fKind != Token::LBRACE) {
833 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500834 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700835 // it's better to report it as an unknown type
836 this->error(name.fPosition, "no type named '" + name.fText + "'");
837 return nullptr;
838 }
839 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500840 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700841 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700842 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700843 if (!decl) {
844 return nullptr;
845 }
846 decls.push_back(std::move(decl));
847 }
848 this->nextToken();
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400849 String instanceName;
Ethan Nicholas50afc172017-02-16 14:49:57 -0500850 std::vector<std::unique_ptr<ASTExpression>> sizes;
ethannicholasb3058bd2016-07-01 08:22:01 -0700851 if (this->peek().fKind == Token::IDENTIFIER) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500852 instanceName = this->nextToken().fText;
853 while (this->peek().fKind == Token::LBRACKET) {
854 this->expect(Token::LBRACKET, "'['");
855 if (this->peek().fKind != Token::RBRACKET) {
856 std::unique_ptr<ASTExpression> size = this->expression();
857 if (!size) {
858 return nullptr;
859 }
860 sizes.push_back(std::move(size));
861 } else {
862 sizes.push_back(nullptr);
863 }
864 this->expect(Token::RBRACKET, "']'");
865 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700866 }
867 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas11d53972016-11-28 11:23:23 -0500868 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500869 name.fText, std::move(decls),
870 std::move(instanceName),
871 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700872}
873
874/* IF LPAREN expression RPAREN statement (ELSE statement)? */
875std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
876 Token start;
877 if (!this->expect(Token::IF, "'if'", &start)) {
878 return nullptr;
879 }
880 if (!this->expect(Token::LPAREN, "'('")) {
881 return nullptr;
882 }
883 std::unique_ptr<ASTExpression> test(this->expression());
884 if (!test) {
885 return nullptr;
886 }
887 if (!this->expect(Token::RPAREN, "')'")) {
888 return nullptr;
889 }
890 std::unique_ptr<ASTStatement> ifTrue(this->statement());
891 if (!ifTrue) {
892 return nullptr;
893 }
894 std::unique_ptr<ASTStatement> ifFalse;
895 if (this->peek().fKind == Token::ELSE) {
896 this->nextToken();
897 ifFalse = this->statement();
898 if (!ifFalse) {
899 return nullptr;
900 }
901 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500902 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, std::move(test),
903 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -0700904 std::move(ifFalse)));
905}
906
907/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
908std::unique_ptr<ASTDoStatement> Parser::doStatement() {
909 Token start;
910 if (!this->expect(Token::DO, "'do'", &start)) {
911 return nullptr;
912 }
913 std::unique_ptr<ASTStatement> statement(this->statement());
914 if (!statement) {
915 return nullptr;
916 }
917 if (!this->expect(Token::WHILE, "'while'")) {
918 return nullptr;
919 }
920 if (!this->expect(Token::LPAREN, "'('")) {
921 return nullptr;
922 }
923 std::unique_ptr<ASTExpression> test(this->expression());
924 if (!test) {
925 return nullptr;
926 }
927 if (!this->expect(Token::RPAREN, "')'")) {
928 return nullptr;
929 }
930 if (!this->expect(Token::SEMICOLON, "';'")) {
931 return nullptr;
932 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500933 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700934 std::move(statement),
935 std::move(test)));
936}
937
938/* WHILE LPAREN expression RPAREN STATEMENT */
939std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
940 Token start;
941 if (!this->expect(Token::WHILE, "'while'", &start)) {
942 return nullptr;
943 }
944 if (!this->expect(Token::LPAREN, "'('")) {
945 return nullptr;
946 }
947 std::unique_ptr<ASTExpression> test(this->expression());
948 if (!test) {
949 return nullptr;
950 }
951 if (!this->expect(Token::RPAREN, "')'")) {
952 return nullptr;
953 }
954 std::unique_ptr<ASTStatement> statement(this->statement());
955 if (!statement) {
956 return nullptr;
957 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500958 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
959 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -0700960 std::move(statement)));
961}
962
Ethan Nicholasaf197692017-02-27 13:26:45 -0500963/* CASE expression COLON statement* */
964std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
965 Token start;
966 if (!this->expect(Token::CASE, "'case'", &start)) {
967 return nullptr;
968 }
969 std::unique_ptr<ASTExpression> value = this->expression();
970 if (!value) {
971 return nullptr;
972 }
973 if (!this->expect(Token::COLON, "':'")) {
974 return nullptr;
975 }
976 std::vector<std::unique_ptr<ASTStatement>> statements;
977 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
978 this->peek().fKind != Token::DEFAULT) {
979 std::unique_ptr<ASTStatement> s = this->statement();
980 if (!s) {
981 return nullptr;
982 }
983 statements.push_back(std::move(s));
984 }
985 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fPosition, std::move(value),
986 std::move(statements)));
987}
988
989/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
990std::unique_ptr<ASTStatement> Parser::switchStatement() {
991 Token start;
992 if (!this->expect(Token::SWITCH, "'switch'", &start)) {
993 return nullptr;
994 }
995 if (!this->expect(Token::LPAREN, "'('")) {
996 return nullptr;
997 }
998 std::unique_ptr<ASTExpression> value(this->expression());
999 if (!value) {
1000 return nullptr;
1001 }
1002 if (!this->expect(Token::RPAREN, "')'")) {
1003 return nullptr;
1004 }
1005 if (!this->expect(Token::LBRACE, "'{'")) {
1006 return nullptr;
1007 }
1008 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1009 while (this->peek().fKind == Token::CASE) {
1010 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1011 if (!c) {
1012 return nullptr;
1013 }
1014 cases.push_back(std::move(c));
1015 }
1016 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1017 // parts of the compiler may rely upon this assumption.
1018 if (this->peek().fKind == Token::DEFAULT) {
1019 Token defaultStart;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001020 ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001021 if (!this->expect(Token::COLON, "':'")) {
1022 return nullptr;
1023 }
1024 std::vector<std::unique_ptr<ASTStatement>> statements;
1025 while (this->peek().fKind != Token::RBRACE) {
1026 std::unique_ptr<ASTStatement> s = this->statement();
1027 if (!s) {
1028 return nullptr;
1029 }
1030 statements.push_back(std::move(s));
1031 }
1032 cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr,
1033 std::move(statements)));
1034 }
1035 if (!this->expect(Token::RBRACE, "'}'")) {
1036 return nullptr;
1037 }
1038 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition,
1039 std::move(value),
1040 std::move(cases)));
1041}
1042
Ethan Nicholas11d53972016-11-28 11:23:23 -05001043/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001044 STATEMENT */
1045std::unique_ptr<ASTForStatement> Parser::forStatement() {
1046 Token start;
1047 if (!this->expect(Token::FOR, "'for'", &start)) {
1048 return nullptr;
1049 }
1050 if (!this->expect(Token::LPAREN, "'('")) {
1051 return nullptr;
1052 }
1053 std::unique_ptr<ASTStatement> initializer;
1054 Token nextToken = this->peek();
1055 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001056 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001057 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001058 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001059 case Token::CONST: {
1060 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1061 if (!vd) {
1062 return nullptr;
1063 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001064 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001065 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001067 }
1068 case Token::IDENTIFIER: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 if (this->isType(nextToken.fText)) {
ethannicholasa54401d2016-10-14 08:37:32 -07001070 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1071 if (!vd) {
1072 return nullptr;
1073 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001074 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001075 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001076 break;
1077 }
ethannicholasa54401d2016-10-14 08:37:32 -07001078 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 default:
1080 initializer = this->expressionStatement();
1081 }
1082 std::unique_ptr<ASTExpression> test;
1083 if (this->peek().fKind != Token::SEMICOLON) {
1084 test = this->expression();
1085 if (!test) {
1086 return nullptr;
1087 }
1088 }
1089 if (!this->expect(Token::SEMICOLON, "';'")) {
1090 return nullptr;
1091 }
1092 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001093 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 next = this->expression();
1095 if (!next) {
1096 return nullptr;
1097 }
1098 }
1099 if (!this->expect(Token::RPAREN, "')'")) {
1100 return nullptr;
1101 }
1102 std::unique_ptr<ASTStatement> statement(this->statement());
1103 if (!statement) {
1104 return nullptr;
1105 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001106 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 std::move(initializer),
1108 std::move(test), std::move(next),
1109 std::move(statement)));
1110}
1111
1112/* RETURN expression? SEMICOLON */
1113std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1114 Token start;
1115 if (!this->expect(Token::RETURN, "'return'", &start)) {
1116 return nullptr;
1117 }
1118 std::unique_ptr<ASTExpression> expression;
1119 if (this->peek().fKind != Token::SEMICOLON) {
1120 expression = this->expression();
1121 if (!expression) {
1122 return nullptr;
1123 }
1124 }
1125 if (!this->expect(Token::SEMICOLON, "';'")) {
1126 return nullptr;
1127 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001128 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 std::move(expression)));
1130}
1131
1132/* BREAK SEMICOLON */
1133std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1134 Token start;
1135 if (!this->expect(Token::BREAK, "'break'", &start)) {
1136 return nullptr;
1137 }
1138 if (!this->expect(Token::SEMICOLON, "';'")) {
1139 return nullptr;
1140 }
1141 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
1142}
1143
1144/* CONTINUE SEMICOLON */
1145std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1146 Token start;
1147 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1148 return nullptr;
1149 }
1150 if (!this->expect(Token::SEMICOLON, "';'")) {
1151 return nullptr;
1152 }
1153 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
1154}
1155
1156/* DISCARD SEMICOLON */
1157std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1158 Token start;
1159 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1160 return nullptr;
1161 }
1162 if (!this->expect(Token::SEMICOLON, "';'")) {
1163 return nullptr;
1164 }
1165 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
1166}
1167
1168/* LBRACE statement* RBRACE */
1169std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001170 AutoDepth depth(this);
1171 if (!depth.checkValid()) {
1172 return nullptr;
1173 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001174 Token start;
1175 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1176 return nullptr;
1177 }
1178 std::vector<std::unique_ptr<ASTStatement>> statements;
1179 for (;;) {
1180 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001181 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001182 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001183 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001184 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001185 case Token::END_OF_FILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001186 this->error(this->peek().fPosition, "expected '}', but found end of file");
1187 return nullptr;
1188 default: {
1189 std::unique_ptr<ASTStatement> statement = this->statement();
1190 if (!statement) {
1191 return nullptr;
1192 }
1193 statements.push_back(std::move(statement));
1194 }
1195 }
1196 }
1197}
1198
1199/* expression SEMICOLON */
1200std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1201 std::unique_ptr<ASTExpression> expr = this->expression();
1202 if (expr) {
1203 if (this->expect(Token::SEMICOLON, "';'")) {
1204 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1205 return std::unique_ptr<ASTExpressionStatement>(result);
1206 }
1207 }
1208 return nullptr;
1209}
1210
1211/* assignmentExpression */
1212std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001213 AutoDepth depth(this);
1214 if (!depth.checkValid()) {
1215 return nullptr;
1216 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001217 return this->assignmentExpression();
1218}
1219
1220/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1221 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1222 assignmentExpression)*
1223 */
1224std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1225 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1226 if (!result) {
1227 return nullptr;
1228 }
1229 for (;;) {
1230 switch (this->peek().fKind) {
1231 case Token::EQ: // fall through
1232 case Token::STAREQ: // fall through
1233 case Token::SLASHEQ: // fall through
1234 case Token::PERCENTEQ: // fall through
1235 case Token::PLUSEQ: // fall through
1236 case Token::MINUSEQ: // fall through
1237 case Token::SHLEQ: // fall through
1238 case Token::SHREQ: // fall through
1239 case Token::BITWISEANDEQ: // fall through
1240 case Token::BITWISEXOREQ: // fall through
1241 case Token::BITWISEOREQ: // fall through
1242 case Token::LOGICALANDEQ: // fall through
1243 case Token::LOGICALXOREQ: // fall through
1244 case Token::LOGICALOREQ: {
1245 Token t = this->nextToken();
1246 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1247 if (!right) {
1248 return nullptr;
1249 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001250 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
1251 t,
ethannicholasb3058bd2016-07-01 08:22:01 -07001252 std::move(right)));
1253 }
1254 default:
1255 return result;
1256 }
1257 }
1258}
1259
1260/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1261std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1262 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1263 if (!result) {
1264 return nullptr;
1265 }
1266 if (this->peek().fKind == Token::QUESTION) {
1267 Token question = this->nextToken();
1268 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1269 if (!trueExpr) {
1270 return nullptr;
1271 }
1272 if (this->expect(Token::COLON, "':'")) {
1273 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001274 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1275 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001276 std::move(falseExpr)));
1277 }
1278 return nullptr;
1279 }
1280 return result;
1281}
1282
1283/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1284std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1285 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1286 if (!result) {
1287 return nullptr;
1288 }
1289 while (this->peek().fKind == Token::LOGICALOR) {
1290 Token t = this->nextToken();
1291 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
1292 if (!right) {
1293 return nullptr;
1294 }
1295 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1296 }
1297 return result;
1298}
1299
1300/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1301std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1302 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1303 if (!result) {
1304 return nullptr;
1305 }
1306 while (this->peek().fKind == Token::LOGICALXOR) {
1307 Token t = this->nextToken();
1308 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1309 if (!right) {
1310 return nullptr;
1311 }
1312 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1313 }
1314 return result;
1315}
1316
1317/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1318std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1319 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1320 if (!result) {
1321 return nullptr;
1322 }
1323 while (this->peek().fKind == Token::LOGICALAND) {
1324 Token t = this->nextToken();
1325 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1326 if (!right) {
1327 return nullptr;
1328 }
1329 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1330 }
1331 return result;
1332}
1333
1334/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1335std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1336 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1337 if (!result) {
1338 return nullptr;
1339 }
1340 while (this->peek().fKind == Token::BITWISEOR) {
1341 Token t = this->nextToken();
1342 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1343 if (!right) {
1344 return nullptr;
1345 }
1346 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1347 }
1348 return result;
1349}
1350
1351/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1352std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1353 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1354 if (!result) {
1355 return nullptr;
1356 }
1357 while (this->peek().fKind == Token::BITWISEXOR) {
1358 Token t = this->nextToken();
1359 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1360 if (!right) {
1361 return nullptr;
1362 }
1363 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1364 }
1365 return result;
1366}
1367
1368/* equalityExpression (BITWISEAND equalityExpression)* */
1369std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1370 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1371 if (!result) {
1372 return nullptr;
1373 }
1374 while (this->peek().fKind == Token::BITWISEAND) {
1375 Token t = this->nextToken();
1376 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1377 if (!right) {
1378 return nullptr;
1379 }
1380 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1381 }
1382 return result;
1383}
1384
1385/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1386std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1387 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1388 if (!result) {
1389 return nullptr;
1390 }
1391 for (;;) {
1392 switch (this->peek().fKind) {
1393 case Token::EQEQ: // fall through
1394 case Token::NEQ: {
1395 Token t = this->nextToken();
1396 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1397 if (!right) {
1398 return nullptr;
1399 }
1400 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1401 break;
1402 }
1403 default:
1404 return result;
1405 }
1406 }
1407}
1408
1409/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1410std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1411 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1412 if (!result) {
1413 return nullptr;
1414 }
1415 for (;;) {
1416 switch (this->peek().fKind) {
1417 case Token::LT: // fall through
1418 case Token::GT: // fall through
1419 case Token::LTEQ: // fall through
1420 case Token::GTEQ: {
1421 Token t = this->nextToken();
1422 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1423 if (!right) {
1424 return nullptr;
1425 }
1426 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1427 break;
1428 }
1429 default:
1430 return result;
1431 }
1432 }
1433}
1434
1435/* additiveExpression ((SHL | SHR) additiveExpression)* */
1436std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1437 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1438 if (!result) {
1439 return nullptr;
1440 }
1441 for (;;) {
1442 switch (this->peek().fKind) {
1443 case Token::SHL: // fall through
1444 case Token::SHR: {
1445 Token t = this->nextToken();
1446 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1447 if (!right) {
1448 return nullptr;
1449 }
1450 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1451 break;
1452 }
1453 default:
1454 return result;
1455 }
1456 }
1457}
1458
1459/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1460std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1461 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1462 if (!result) {
1463 return nullptr;
1464 }
1465 for (;;) {
1466 switch (this->peek().fKind) {
1467 case Token::PLUS: // fall through
1468 case Token::MINUS: {
1469 Token t = this->nextToken();
1470 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1471 if (!right) {
1472 return nullptr;
1473 }
1474 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1475 break;
1476 }
1477 default:
1478 return result;
1479 }
1480 }
1481}
1482
1483/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1484std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1485 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1486 if (!result) {
1487 return nullptr;
1488 }
1489 for (;;) {
1490 switch (this->peek().fKind) {
1491 case Token::STAR: // fall through
1492 case Token::SLASH: // fall through
1493 case Token::PERCENT: {
1494 Token t = this->nextToken();
1495 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1496 if (!right) {
1497 return nullptr;
1498 }
1499 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1500 break;
1501 }
1502 default:
1503 return result;
1504 }
1505 }
1506}
1507
1508/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1509std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1510 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001511 case Token::PLUS: // fall through
1512 case Token::MINUS: // fall through
1513 case Token::LOGICALNOT: // fall through
1514 case Token::BITWISENOT: // fall through
1515 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 case Token::MINUSMINUS: {
1517 Token t = this->nextToken();
1518 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1519 if (!expr) {
1520 return nullptr;
1521 }
1522 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
1523 }
1524 default:
1525 return this->postfixExpression();
1526 }
1527}
1528
1529/* term suffix* */
1530std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1531 std::unique_ptr<ASTExpression> result = this->term();
1532 if (!result) {
1533 return nullptr;
1534 }
1535 for (;;) {
1536 switch (this->peek().fKind) {
1537 case Token::LBRACKET: // fall through
1538 case Token::DOT: // fall through
1539 case Token::LPAREN: // fall through
1540 case Token::PLUSPLUS: // fall through
1541 case Token::MINUSMINUS: {
1542 std::unique_ptr<ASTSuffix> s = this->suffix();
1543 if (!s) {
1544 return nullptr;
1545 }
1546 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1547 break;
1548 }
1549 default:
1550 return result;
1551 }
1552 }
1553}
1554
Ethan Nicholas11d53972016-11-28 11:23:23 -05001555/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 PLUSPLUS | MINUSMINUS */
1557std::unique_ptr<ASTSuffix> Parser::suffix() {
1558 Token next = this->nextToken();
1559 switch (next.fKind) {
1560 case Token::LBRACKET: {
ethannicholas5961bc92016-10-12 06:39:56 -07001561 if (this->peek().fKind == Token::RBRACKET) {
1562 this->nextToken();
1563 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
1564 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 std::unique_ptr<ASTExpression> e = this->expression();
1566 if (!e) {
1567 return nullptr;
1568 }
1569 this->expect(Token::RBRACKET, "']' to complete array access expression");
1570 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1571 }
1572 case Token::DOT: {
1573 Position pos = this->peek().fPosition;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001574 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 if (this->identifier(&text)) {
1576 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
1577 }
1578 return nullptr;
1579 }
1580 case Token::LPAREN: {
1581 std::vector<std::unique_ptr<ASTExpression>> parameters;
1582 if (this->peek().fKind != Token::RPAREN) {
1583 for (;;) {
1584 std::unique_ptr<ASTExpression> expr = this->expression();
1585 if (!expr) {
1586 return nullptr;
1587 }
1588 parameters.push_back(std::move(expr));
1589 if (this->peek().fKind != Token::COMMA) {
1590 break;
1591 }
1592 this->nextToken();
1593 }
1594 }
1595 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas11d53972016-11-28 11:23:23 -05001596 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 std::move(parameters)));
1598 }
1599 case Token::PLUSPLUS:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001600 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001601 ASTSuffix::kPostIncrement_Kind));
1602 case Token::MINUSMINUS:
1603 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1604 ASTSuffix::kPostDecrement_Kind));
1605 default: {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001606 this->error(next.fPosition, "expected expression suffix, but found '" + next.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -07001607 "'\n");
1608 return nullptr;
1609 }
1610 }
1611}
1612
1613/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1614std::unique_ptr<ASTExpression> Parser::term() {
1615 std::unique_ptr<ASTExpression> result;
1616 Token t = this->peek();
1617 switch (t.fKind) {
1618 case Token::IDENTIFIER: {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001619 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 if (this->identifier(&text)) {
1621 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
1622 }
1623 break;
1624 }
1625 case Token::INT_LITERAL: {
1626 int64_t i;
1627 if (this->intLiteral(&i)) {
1628 result.reset(new ASTIntLiteral(t.fPosition, i));
1629 }
1630 break;
1631 }
1632 case Token::FLOAT_LITERAL: {
1633 double f;
1634 if (this->floatLiteral(&f)) {
1635 result.reset(new ASTFloatLiteral(t.fPosition, f));
1636 }
1637 break;
1638 }
1639 case Token::TRUE_LITERAL: // fall through
1640 case Token::FALSE_LITERAL: {
1641 bool b;
1642 if (this->boolLiteral(&b)) {
1643 result.reset(new ASTBoolLiteral(t.fPosition, b));
1644 }
1645 break;
1646 }
1647 case Token::LPAREN: {
1648 this->nextToken();
1649 result = this->expression();
1650 if (result) {
1651 this->expect(Token::RPAREN, "')' to complete expression");
1652 }
1653 break;
1654 }
1655 default:
1656 this->nextToken();
1657 this->error(t.fPosition, "expected expression, but found '" + t.fText + "'\n");
1658 result = nullptr;
1659 }
1660 return result;
1661}
1662
1663/* INT_LITERAL */
1664bool Parser::intLiteral(int64_t* dest) {
1665 Token t;
1666 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1667 *dest = SkSL::stol(t.fText);
1668 return true;
1669 }
1670 return false;
1671}
1672
1673/* FLOAT_LITERAL */
1674bool Parser::floatLiteral(double* dest) {
1675 Token t;
1676 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1677 *dest = SkSL::stod(t.fText);
1678 return true;
1679 }
1680 return false;
1681}
1682
1683/* TRUE_LITERAL | FALSE_LITERAL */
1684bool Parser::boolLiteral(bool* dest) {
1685 Token t = this->nextToken();
1686 switch (t.fKind) {
1687 case Token::TRUE_LITERAL:
1688 *dest = true;
1689 return true;
1690 case Token::FALSE_LITERAL:
1691 *dest = false;
1692 return true;
1693 default:
1694 this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1695 return false;
1696 }
1697}
1698
1699/* IDENTIFIER */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001700bool Parser::identifier(String* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 Token t;
1702 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001703 *dest = t.fText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001704 return true;
1705 }
1706 return false;
1707}
1708
1709} // namespace