blob: 2a88d306937d2656587b15dc4be771ff0403ee01 [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 Nicholas0dd30d92017-05-01 16:57:07 -040015static_assert(YY_FLEX_MAJOR_VERSION * 10000 + YY_FLEX_MINOR_VERSION * 100 +
16 YY_FLEX_SUBMINOR_VERSION >= 20601,
Ethan Nicholas94421942017-03-31 17:06:42 -040017 "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"
Ethan Nicholas762466e2017-06-29 10:03:38 -040055#include "ast/SkSLASTSection.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070056#include "ast/SkSLASTStatement.h"
57#include "ast/SkSLASTSuffixExpression.h"
Ethan Nicholasaf197692017-02-27 13:26:45 -050058#include "ast/SkSLASTSwitchCase.h"
59#include "ast/SkSLASTSwitchStatement.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070060#include "ast/SkSLASTTernaryExpression.h"
61#include "ast/SkSLASTType.h"
62#include "ast/SkSLASTVarDeclaration.h"
63#include "ast/SkSLASTVarDeclarationStatement.h"
64#include "ast/SkSLASTWhileStatement.h"
65#include "ir/SkSLSymbolTable.h"
Ethan Nicholas11d53972016-11-28 11:23:23 -050066#include "ir/SkSLModifiers.h"
ethannicholasd598f792016-07-25 10:08:54 -070067#include "ir/SkSLType.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070068
69namespace SkSL {
70
ethannicholascad64162016-10-27 10:54:02 -070071#define MAX_PARSE_DEPTH 50
72
73class AutoDepth {
74public:
75 AutoDepth(Parser* p)
76 : fParser(p) {
77 fParser->fDepth++;
78 }
79
80 ~AutoDepth() {
81 fParser->fDepth--;
82 }
83
84 bool checkValid() {
85 if (fParser->fDepth > MAX_PARSE_DEPTH) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -040086 fParser->error(fParser->peek().fPosition, String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070087 return false;
88 }
89 return true;
90 }
91
92private:
93 Parser* fParser;
94};
95
Ethan Nicholas0df1b042017-03-31 13:56:23 -040096Parser::Parser(String text, SymbolTable& types, ErrorReporter& errors)
97: fPushback(Position(-1, -1), Token::INVALID_TOKEN, String())
ethannicholasb3058bd2016-07-01 08:22:01 -070098, fTypes(types)
99, fErrors(errors) {
100 sksllex_init(&fScanner);
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500101 layoutlex_init(&fLayoutScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700102 fBuffer = sksl_scan_string(text.c_str(), fScanner);
103 skslset_lineno(1, fScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700104}
105
106Parser::~Parser() {
107 sksl_delete_buffer(fBuffer, fScanner);
ethannicholas69a7e7c2016-07-01 19:09:27 -0700108 sksllex_destroy(fScanner);
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500109 layoutlex_destroy(fLayoutScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700110}
111
Ethan Nicholas762466e2017-06-29 10:03:38 -0400112/* (precision | directive | section | declaration)* END_OF_FILE */
ethannicholasb3058bd2016-07-01 08:22:01 -0700113std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
114 std::vector<std::unique_ptr<ASTDeclaration>> result;
115 for (;;) {
116 switch (this->peek().fKind) {
117 case Token::END_OF_FILE:
118 return result;
ethannicholas5961bc92016-10-12 06:39:56 -0700119 case Token::PRECISION: {
120 std::unique_ptr<ASTDeclaration> precision = this->precision();
121 if (precision) {
122 result.push_back(std::move(precision));
123 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700124 break;
ethannicholas5961bc92016-10-12 06:39:56 -0700125 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700126 case Token::DIRECTIVE: {
127 std::unique_ptr<ASTDeclaration> decl = this->directive();
128 if (decl) {
129 result.push_back(std::move(decl));
130 }
131 break;
132 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400133 case Token::SECTION: {
134 std::unique_ptr<ASTDeclaration> section = this->section();
135 if (section) {
136 result.push_back(std::move(section));
137 }
138 break;
139 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700140 default: {
141 std::unique_ptr<ASTDeclaration> decl = this->declaration();
142 if (!decl) {
143 continue;
144 }
145 result.push_back(std::move(decl));
146 }
147 }
148 }
149}
150
Ethan Nicholas762466e2017-06-29 10:03:38 -0400151Token Parser::nextRawToken() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700152 if (fPushback.fKind != Token::INVALID_TOKEN) {
153 Token result = fPushback;
154 fPushback.fKind = Token::INVALID_TOKEN;
155 fPushback.fText = "";
156 return result;
157 }
158 int token = sksllex(fScanner);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400159 return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token,
160 String(skslget_text(fScanner)));
161}
162
163Token Parser::nextToken() {
164 Token token;
165 do {
166 token = this->nextRawToken();
167 } while (token.fKind == Token::WHITESPACE);
168 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700169}
170
171void Parser::pushback(Token t) {
172 ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
173 fPushback = t;
174}
175
176Token Parser::peek() {
177 fPushback = this->nextToken();
178 return fPushback;
179}
180
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400181bool Parser::checkNext(Token::Kind kind, Token* result) {
182 Token next = this->nextToken();
183 if (next.fKind == kind) {
184 if (result) {
185 *result = next;
186 }
187 return true;
188 }
189 this->pushback(next);
190 return false;
191}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500192
193bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400194 return this->expect(kind, String(expected), result);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500195}
196
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400197bool Parser::expect(Token::Kind kind, String expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700198 Token next = this->nextToken();
199 if (next.fKind == kind) {
200 if (result) {
201 *result = next;
202 }
203 return true;
204 } else {
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500205 if (next.fText.size()) {
206 this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText +
207 "'");
208 } else {
209 this->error(next.fPosition, "parse error, recompile in debug mode for details");
210 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700211 return false;
212 }
213}
214
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500215void Parser::error(Position p, const char* msg) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400216 this->error(p, String(msg));
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500217}
218
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400219void Parser::error(Position p, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700220 fErrors.error(p, msg);
221}
222
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400223bool Parser::isType(String name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700224 return nullptr != fTypes[name];
225}
226
227/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
ethannicholas5961bc92016-10-12 06:39:56 -0700228std::unique_ptr<ASTDeclaration> Parser::precision() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700229 if (!this->expect(Token::PRECISION, "'precision'")) {
ethannicholas5961bc92016-10-12 06:39:56 -0700230 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700231 }
ethannicholas5961bc92016-10-12 06:39:56 -0700232 Modifiers::Flag result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 Token p = this->nextToken();
234 switch (p.fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -0700235 case Token::LOWP:
236 result = Modifiers::kLowp_Flag;
237 break;
238 case Token::MEDIUMP:
239 result = Modifiers::kMediump_Flag;
240 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 case Token::HIGHP:
ethannicholas5961bc92016-10-12 06:39:56 -0700242 result = Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 break;
244 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500245 this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 p.fText + "'");
ethannicholas5961bc92016-10-12 06:39:56 -0700247 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700248 }
ethannicholas5961bc92016-10-12 06:39:56 -0700249 // FIXME handle the type
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 if (!this->type()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700251 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700252 }
253 this->expect(Token::SEMICOLON, "';'");
ethannicholas5961bc92016-10-12 06:39:56 -0700254 return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
ethannicholasb3058bd2016-07-01 08:22:01 -0700255}
256
Ethan Nicholas11d53972016-11-28 11:23:23 -0500257/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700258 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700259std::unique_ptr<ASTDeclaration> Parser::directive() {
260 Token start;
261 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
262 return nullptr;
263 }
264 if (start.fText == "#version") {
265 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700266 Token next = this->peek();
267 if (next.fText == "es" || next.fText == "compatibility") {
268 this->nextToken();
269 }
270 // version is ignored for now; it will eventually become an error when we stop pretending
271 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700272 return nullptr;
273 } else if (start.fText == "#extension") {
274 Token name;
275 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
276 return nullptr;
277 }
278 if (!this->expect(Token::COLON, "':'")) {
279 return nullptr;
280 }
281 // FIXME: need to start paying attention to this token
282 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
283 return nullptr;
284 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500285 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700286 std::move(name.fText)));
287 } else {
288 this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
289 return nullptr;
290 }
291}
292
Ethan Nicholas762466e2017-06-29 10:03:38 -0400293/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
294 RBRACE */
295std::unique_ptr<ASTDeclaration> Parser::section() {
296 Token start;
297 if (!this->expect(Token::SECTION, "a section token", &start)) {
298 return nullptr;
299 }
300 String argument;
301 if (this->peek().fKind == Token::LPAREN) {
302 this->nextToken();
303 Token argToken;
304 if (!this->expect(Token::IDENTIFIER, "an identifier", &argToken)) {
305 return nullptr;
306 }
307 argument = argToken.fText;
308 if (!this->expect(Token::RPAREN, "')'")) {
309 return nullptr;
310 }
311 }
312 if (!this->expect(Token::LBRACE, "'{'")) {
313 return nullptr;
314 }
315 String text;
316 int level = 1;
317 for (;;) {
318 Token next = this->nextRawToken();
319 switch (next.fKind) {
320 case Token::LBRACE:
321 ++level;
322 break;
323 case Token::RBRACE:
324 --level;
325 break;
326 case Token::END_OF_FILE:
327 this->error(start.fPosition, "reached end of file while parsing section");
328 return nullptr;
329 default:
330 break;
331 }
332 if (!level) {
333 break;
334 }
335 text += next.fText;
336 }
337 return std::unique_ptr<ASTDeclaration>(new ASTSection(start.fPosition,
338 String(start.fText.c_str() + 1),
339 argument,
340 text));
341}
342
Ethan Nicholas11d53972016-11-28 11:23:23 -0500343/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700344 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
345std::unique_ptr<ASTDeclaration> Parser::declaration() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500346 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700347 Token lookahead = this->peek();
348 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
349 // we have an identifier that's not a type, could be the start of an interface block
350 return this->interfaceBlock(modifiers);
351 }
352 if (lookahead.fKind == Token::STRUCT) {
353 return this->structVarDeclaration(modifiers);
354 }
ethannicholas5961bc92016-10-12 06:39:56 -0700355 if (lookahead.fKind == Token::SEMICOLON) {
356 this->nextToken();
357 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
358 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700359 std::unique_ptr<ASTType> type(this->type());
360 if (!type) {
361 return nullptr;
362 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400363 if (type->fKind == ASTType::kStruct_Kind && this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700364 return nullptr;
365 }
366 Token name;
367 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
368 return nullptr;
369 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400370 if (this->checkNext(Token::LPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700371 std::vector<std::unique_ptr<ASTParameter>> parameters;
372 while (this->peek().fKind != Token::RPAREN) {
373 if (parameters.size() > 0) {
374 if (!this->expect(Token::COMMA, "','")) {
375 return nullptr;
376 }
377 }
378 std::unique_ptr<ASTParameter> parameter = this->parameter();
379 if (!parameter) {
380 return nullptr;
381 }
382 parameters.push_back(std::move(parameter));
383 }
384 this->nextToken();
385 std::unique_ptr<ASTBlock> body;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400386 if (!this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700387 body = this->block();
388 if (!body) {
389 return nullptr;
390 }
391 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400392 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition,
393 modifiers,
394 std::move(type),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500395 std::move(name.fText),
396 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700397 std::move(body)));
398 } else {
399 return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
400 }
401}
402
403/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700404std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500405 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700406 std::unique_ptr<ASTType> type(this->type());
407 if (!type) {
408 return nullptr;
409 }
410 Token name;
411 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
412 return nullptr;
413 }
414 return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
415}
416
417/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
418std::unique_ptr<ASTType> Parser::structDeclaration() {
419 if (!this->expect(Token::STRUCT, "'struct'")) {
420 return nullptr;
421 }
422 Token name;
423 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
424 return nullptr;
425 }
426 if (!this->expect(Token::LBRACE, "'{'")) {
427 return nullptr;
428 }
429 std::vector<Type::Field> fields;
430 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700431 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 if (!decl) {
433 return nullptr;
434 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700435 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700436 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700437 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700438 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 this->error(decl->fPosition, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700440 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700442 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400443 String name = type->name() + "[" + to_string(columns) + "]";
ethannicholasd598f792016-07-25 10:08:54 -0700444 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
445 fTypes.takeOwnership((Type*) type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700446 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700447 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
448 if (var.fValue) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700449 this->error(decl->fPosition, "initializers are not permitted on struct fields");
450 }
451 }
452 }
453 if (!this->expect(Token::RBRACE, "'}'")) {
454 return nullptr;
455 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500456 fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fPosition, name.fText, fields)));
Ethan Nicholas11d53972016-11-28 11:23:23 -0500457 return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500458 ASTType::kStruct_Kind, std::vector<int>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700459}
460
461/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500462std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700463 std::unique_ptr<ASTType> type = this->structDeclaration();
464 if (!type) {
465 return nullptr;
466 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400467 Token name;
468 if (this->checkNext(Token::IDENTIFIER, &name)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500469 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
470 std::move(type),
ethannicholas14fe8cc2016-09-07 13:37:16 -0700471 std::move(name.fText));
ethannicholasb3058bd2016-07-01 08:22:01 -0700472 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700473 for (const auto& var : result->fVars) {
474 if (var.fValue) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500475 this->error(var.fValue->fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 "struct variables cannot be initialized");
477 }
478 }
479 }
480 return result;
481 }
482 this->expect(Token::SEMICOLON, "';'");
483 return nullptr;
484}
485
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400486/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
487 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500488std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700489 std::unique_ptr<ASTType> type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400490 String name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700491 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700492 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400493 while (this->checkNext(Token::LBRACKET)) {
494 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 currentVarSizes.push_back(nullptr);
496 } else {
497 std::unique_ptr<ASTExpression> size(this->expression());
498 if (!size) {
499 return nullptr;
500 }
501 currentVarSizes.push_back(std::move(size));
502 if (!this->expect(Token::RBRACKET, "']'")) {
503 return nullptr;
504 }
505 }
506 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700507 std::unique_ptr<ASTExpression> value;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400508 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400509 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700510 if (!value) {
511 return nullptr;
512 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700514 vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400515 while (this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700516 Token name;
517 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
518 return nullptr;
519 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700520 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700521 value.reset();
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400522 while (this->checkNext(Token::LBRACKET)) {
523 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700524 currentVarSizes.push_back(nullptr);
525 } else {
526 std::unique_ptr<ASTExpression> size(this->expression());
527 if (!size) {
528 return nullptr;
529 }
530 currentVarSizes.push_back(std::move(size));
531 if (!this->expect(Token::RBRACKET, "']'")) {
532 return nullptr;
533 }
534 }
535 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400536 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400537 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700538 if (!value) {
539 return nullptr;
540 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700541 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700542 vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700543 }
544 if (!this->expect(Token::SEMICOLON, "';'")) {
545 return nullptr;
546 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700547 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
548 std::move(type),
549 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700550}
551
552/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
553std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400554 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700555 std::unique_ptr<ASTType> type = this->type();
556 if (!type) {
557 return nullptr;
558 }
559 Token name;
560 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
561 return nullptr;
562 }
563 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400564 while (this->checkNext(Token::LBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 Token sizeToken;
566 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
567 return nullptr;
568 }
569 sizes.push_back(SkSL::stoi(sizeToken.fText));
570 if (!this->expect(Token::RBRACKET, "']'")) {
571 return nullptr;
572 }
573 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500574 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
575 std::move(type), name.fText,
ethannicholasb3058bd2016-07-01 08:22:01 -0700576 std::move(sizes)));
577}
578
579/** (EQ INT_LITERAL)? */
580int Parser::layoutInt() {
581 if (!this->expect(Token::EQ, "'='")) {
582 return -1;
583 }
584 Token resultToken;
585 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
586 return SkSL::stoi(resultToken.fText);
587 }
588 return -1;
589}
590
Ethan Nicholas762466e2017-06-29 10:03:38 -0400591/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
592String Parser::layoutCode() {
593 if (!this->expect(Token::EQ, "'='")) {
594 return "";
595 }
596 Token start = this->peek();
597 String code;
598 int level = 1;
599 bool done = false;
600 while (!done) {
601 Token next = this->peek();
602 switch (next.fKind) {
603 case Token::LPAREN:
604 ++level;
605 break;
606 case Token::RPAREN:
607 --level;
608 break;
609 case Token::COMMA:
610 if (level == 1) {
611 done = true;
612 }
613 break;
614 case Token::END_OF_FILE:
615 this->error(start.fPosition, "reached end of file while parsing layout");
616 return nullptr;
617 default:
618 break;
619 }
620 if (!level) {
621 done = true;
622 }
623 if (!done) {
624 code += this->nextRawToken().fText;
625 }
626 }
627 return code;
628}
629
630/** (EQ IDENTIFIER('identity'))? */
631Layout::Key Parser::layoutKey() {
632 if (this->peek().fKind == Token::EQ) {
633 this->expect(Token::EQ, "'='");
634 Token key;
635 if (this->expect(Token::IDENTIFIER, "an identifer", &key)) {
636 if (key.fText == "identity") {
637 return Layout::kIdentity_Key;
638 } else {
639 this->error(key.fPosition, "unsupported layout key");
640 }
641 }
642 }
643 return Layout::kKey_Key;
644}
645
ethannicholas8ac838d2016-11-22 08:39:36 -0800646/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500647Layout Parser::layout() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700648 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500649 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700650 int binding = -1;
651 int index = -1;
652 int set = -1;
653 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500654 int inputAttachmentIndex = -1;
ethannicholasf789b382016-08-03 12:43:36 -0700655 bool originUpperLeft = false;
ethannicholas5961bc92016-10-12 06:39:56 -0700656 bool overrideCoverage = false;
657 bool blendSupportAllEquations = false;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500658 Layout::Format format = Layout::Format::kUnspecified;
ethannicholas8ac838d2016-11-22 08:39:36 -0800659 bool pushConstant = false;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500660 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
661 int maxVertices = -1;
662 int invocations = -1;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400663 String when;
664 Layout::Key key = Layout::kNo_Key;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400665 if (this->checkNext(Token::LAYOUT)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700666 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500667 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
Ethan Nicholas11d53972016-11-28 11:23:23 -0500668 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400669 pushConstant, primitive, maxVertices, invocations, when, key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700670 }
671 for (;;) {
672 Token t = this->nextToken();
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500673 YY_BUFFER_STATE buffer;
674 buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner);
675 int token = layoutlex(fLayoutScanner);
676 layout_delete_buffer(buffer, fLayoutScanner);
677 if (token != Token::INVALID_TOKEN) {
678 switch (token) {
679 case Token::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500680 location = this->layoutInt();
681 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500682 case Token::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500683 offset = this->layoutInt();
684 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500685 case Token::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500686 binding = this->layoutInt();
687 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500688 case Token::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500689 index = this->layoutInt();
690 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500691 case Token::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500692 set = this->layoutInt();
693 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500694 case Token::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500695 builtin = this->layoutInt();
696 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500697 case Token::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500698 inputAttachmentIndex = this->layoutInt();
699 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500700 case Token::ORIGIN_UPPER_LEFT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500701 originUpperLeft = true;
702 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500703 case Token::OVERRIDE_COVERAGE:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500704 overrideCoverage = true;
705 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500706 case Token::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500707 blendSupportAllEquations = true;
708 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500709 case Token::PUSH_CONSTANT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500710 pushConstant = true;
711 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500712 case Token::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500713 primitive = Layout::kPoints_Primitive;
714 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500715 case Token::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500716 primitive = Layout::kLines_Primitive;
717 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500718 case Token::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500719 primitive = Layout::kLineStrip_Primitive;
720 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500721 case Token::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500722 primitive = Layout::kLinesAdjacency_Primitive;
723 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500724 case Token::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500725 primitive = Layout::kTriangles_Primitive;
726 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500727 case Token::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500728 primitive = Layout::kTriangleStrip_Primitive;
729 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500730 case Token::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500731 primitive = Layout::kTrianglesAdjacency_Primitive;
732 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500733 case Token::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500734 maxVertices = this->layoutInt();
735 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500736 case Token::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500737 invocations = this->layoutInt();
738 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400739 case Token::WHEN:
740 when = this->layoutCode();
741 break;
742 case Token::KEY:
743 key = this->layoutKey();
744 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500745 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500746 } else if (Layout::ReadFormat(t.fText, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500747 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700748 } else {
Greg Daniel64773e62016-11-22 09:44:03 -0500749 this->error(t.fPosition, ("'" + t.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -0700750 "' is not a valid layout qualifier").c_str());
751 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400752 if (this->checkNext(Token::RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700753 break;
754 }
755 if (!this->expect(Token::COMMA, "','")) {
756 break;
757 }
758 }
759 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500760 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
761 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400762 pushConstant, primitive, maxVertices, invocations, when, key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700763}
764
Brian Salomonf9f45122016-11-29 11:59:17 -0500765/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400766 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500767Modifiers Parser::modifiers() {
768 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700769 int flags = 0;
770 for (;;) {
771 // TODO: handle duplicate / incompatible flags
772 switch (peek().fKind) {
773 case Token::UNIFORM:
774 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500775 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700776 break;
777 case Token::CONST:
778 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500779 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700780 break;
781 case Token::IN:
782 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500783 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700784 break;
785 case Token::OUT:
786 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500787 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700788 break;
789 case Token::INOUT:
790 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500791 flags |= Modifiers::kIn_Flag;
792 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700793 break;
794 case Token::LOWP:
795 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500796 flags |= Modifiers::kLowp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700797 break;
798 case Token::MEDIUMP:
799 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500800 flags |= Modifiers::kMediump_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700801 break;
802 case Token::HIGHP:
803 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500804 flags |= Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700805 break;
ethannicholasf789b382016-08-03 12:43:36 -0700806 case Token::FLAT:
807 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500808 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700809 break;
810 case Token::NOPERSPECTIVE:
811 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500812 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700813 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500814 case Token::READONLY:
815 this->nextToken();
816 flags |= Modifiers::kReadOnly_Flag;
817 break;
818 case Token::WRITEONLY:
819 this->nextToken();
820 flags |= Modifiers::kWriteOnly_Flag;
821 break;
822 case Token::COHERENT:
823 this->nextToken();
824 flags |= Modifiers::kCoherent_Flag;
825 break;
826 case Token::VOLATILE:
827 this->nextToken();
828 flags |= Modifiers::kVolatile_Flag;
829 break;
830 case Token::RESTRICT:
831 this->nextToken();
832 flags |= Modifiers::kRestrict_Flag;
833 break;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400834 case Token::BUFFER:
835 this->nextToken();
836 flags |= Modifiers::kBuffer_Flag;
837 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400838 case Token::HASSIDEEFFECTS:
839 this->nextToken();
840 flags |= Modifiers::kHasSideEffects_Flag;
841 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700842 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500843 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700844 }
845 }
846}
847
Ethan Nicholas11d53972016-11-28 11:23:23 -0500848Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
849 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700850 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500851 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700852 }
853 return result;
854}
855
856/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
857std::unique_ptr<ASTStatement> Parser::statement() {
858 Token start = this->peek();
859 switch (start.fKind) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400860 case Token::IF: // fall through
861 case Token::STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -0700862 return this->ifStatement();
863 case Token::FOR:
864 return this->forStatement();
865 case Token::DO:
866 return this->doStatement();
867 case Token::WHILE:
868 return this->whileStatement();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400869 case Token::SWITCH: // fall through
870 case Token::STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500871 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700872 case Token::RETURN:
873 return this->returnStatement();
874 case Token::BREAK:
875 return this->breakStatement();
876 case Token::CONTINUE:
877 return this->continueStatement();
878 case Token::DISCARD:
879 return this->discardStatement();
880 case Token::LBRACE:
881 return this->block();
882 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500883 this->nextToken();
884 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
ethannicholas0730be72016-09-01 07:59:02 -0700885 std::vector<std::unique_ptr<ASTStatement>>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700886 case Token::CONST: // fall through
887 case Token::HIGHP: // fall through
888 case Token::MEDIUMP: // fall through
889 case Token::LOWP: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700890 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700891 if (!decl) {
892 return nullptr;
893 }
894 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
895 }
896 case Token::IDENTIFIER:
897 if (this->isType(start.fText)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700898 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700899 if (!decl) {
900 return nullptr;
901 }
902 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
903 std::move(decl)));
904 }
905 // fall through
906 default:
907 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500908 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700909}
910
Ethan Nicholas50afc172017-02-16 14:49:57 -0500911/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
ethannicholasb3058bd2016-07-01 08:22:01 -0700912std::unique_ptr<ASTType> Parser::type() {
913 Token type;
914 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
915 return nullptr;
916 }
917 if (!this->isType(type.fText)) {
918 this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
919 return nullptr;
920 }
Ethan Nicholas50afc172017-02-16 14:49:57 -0500921 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400922 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500923 if (this->peek().fKind != Token::RBRACKET) {
924 int64_t i;
925 if (this->intLiteral(&i)) {
926 sizes.push_back(i);
927 } else {
928 return nullptr;
929 }
930 } else {
931 sizes.push_back(-1);
932 }
933 this->expect(Token::RBRACKET, "']'");
934 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500935 return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500936 ASTType::kIdentifier_Kind, sizes));
ethannicholasb3058bd2016-07-01 08:22:01 -0700937}
938
Ethan Nicholas50afc172017-02-16 14:49:57 -0500939/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500940std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700941 Token name;
942 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
943 return nullptr;
944 }
945 if (peek().fKind != Token::LBRACE) {
946 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500947 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700948 // it's better to report it as an unknown type
949 this->error(name.fPosition, "no type named '" + name.fText + "'");
950 return nullptr;
951 }
952 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500953 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700954 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700955 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700956 if (!decl) {
957 return nullptr;
958 }
959 decls.push_back(std::move(decl));
960 }
961 this->nextToken();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500962 std::vector<std::unique_ptr<ASTExpression>> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400963 Token instanceName;
964 if (this->checkNext(Token::IDENTIFIER, &instanceName)) {
965 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500966 if (this->peek().fKind != Token::RBRACKET) {
967 std::unique_ptr<ASTExpression> size = this->expression();
968 if (!size) {
969 return nullptr;
970 }
971 sizes.push_back(std::move(size));
972 } else {
973 sizes.push_back(nullptr);
974 }
975 this->expect(Token::RBRACKET, "']'");
976 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700977 }
978 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas11d53972016-11-28 11:23:23 -0500979 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500980 name.fText, std::move(decls),
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400981 std::move(instanceName.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500982 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700983}
984
985/* IF LPAREN expression RPAREN statement (ELSE statement)? */
986std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
987 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400988 bool isStatic = this->checkNext(Token::STATIC_IF, &start);
989 if (!isStatic && !this->expect(Token::IF, "'if'", &start)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700990 return nullptr;
991 }
992 if (!this->expect(Token::LPAREN, "'('")) {
993 return nullptr;
994 }
995 std::unique_ptr<ASTExpression> test(this->expression());
996 if (!test) {
997 return nullptr;
998 }
999 if (!this->expect(Token::RPAREN, "')'")) {
1000 return nullptr;
1001 }
1002 std::unique_ptr<ASTStatement> ifTrue(this->statement());
1003 if (!ifTrue) {
1004 return nullptr;
1005 }
1006 std::unique_ptr<ASTStatement> ifFalse;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001007 if (this->checkNext(Token::ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001008 ifFalse = this->statement();
1009 if (!ifFalse) {
1010 return nullptr;
1011 }
1012 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001013 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition,
1014 isStatic,
1015 std::move(test),
Ethan Nicholas11d53972016-11-28 11:23:23 -05001016 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -07001017 std::move(ifFalse)));
1018}
1019
1020/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
1021std::unique_ptr<ASTDoStatement> Parser::doStatement() {
1022 Token start;
1023 if (!this->expect(Token::DO, "'do'", &start)) {
1024 return nullptr;
1025 }
1026 std::unique_ptr<ASTStatement> statement(this->statement());
1027 if (!statement) {
1028 return nullptr;
1029 }
1030 if (!this->expect(Token::WHILE, "'while'")) {
1031 return nullptr;
1032 }
1033 if (!this->expect(Token::LPAREN, "'('")) {
1034 return nullptr;
1035 }
1036 std::unique_ptr<ASTExpression> test(this->expression());
1037 if (!test) {
1038 return nullptr;
1039 }
1040 if (!this->expect(Token::RPAREN, "')'")) {
1041 return nullptr;
1042 }
1043 if (!this->expect(Token::SEMICOLON, "';'")) {
1044 return nullptr;
1045 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001046 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 std::move(statement),
1048 std::move(test)));
1049}
1050
1051/* WHILE LPAREN expression RPAREN STATEMENT */
1052std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
1053 Token start;
1054 if (!this->expect(Token::WHILE, "'while'", &start)) {
1055 return nullptr;
1056 }
1057 if (!this->expect(Token::LPAREN, "'('")) {
1058 return nullptr;
1059 }
1060 std::unique_ptr<ASTExpression> test(this->expression());
1061 if (!test) {
1062 return nullptr;
1063 }
1064 if (!this->expect(Token::RPAREN, "')'")) {
1065 return nullptr;
1066 }
1067 std::unique_ptr<ASTStatement> statement(this->statement());
1068 if (!statement) {
1069 return nullptr;
1070 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001071 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
1072 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 std::move(statement)));
1074}
1075
Ethan Nicholasaf197692017-02-27 13:26:45 -05001076/* CASE expression COLON statement* */
1077std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
1078 Token start;
1079 if (!this->expect(Token::CASE, "'case'", &start)) {
1080 return nullptr;
1081 }
1082 std::unique_ptr<ASTExpression> value = this->expression();
1083 if (!value) {
1084 return nullptr;
1085 }
1086 if (!this->expect(Token::COLON, "':'")) {
1087 return nullptr;
1088 }
1089 std::vector<std::unique_ptr<ASTStatement>> statements;
1090 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
1091 this->peek().fKind != Token::DEFAULT) {
1092 std::unique_ptr<ASTStatement> s = this->statement();
1093 if (!s) {
1094 return nullptr;
1095 }
1096 statements.push_back(std::move(s));
1097 }
1098 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fPosition, std::move(value),
1099 std::move(statements)));
1100}
1101
1102/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
1103std::unique_ptr<ASTStatement> Parser::switchStatement() {
1104 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001105 bool isStatic = this->checkNext(Token::STATIC_SWITCH, &start);
1106 if (!isStatic && !this->expect(Token::SWITCH, "'switch'", &start)) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001107 return nullptr;
1108 }
1109 if (!this->expect(Token::LPAREN, "'('")) {
1110 return nullptr;
1111 }
1112 std::unique_ptr<ASTExpression> value(this->expression());
1113 if (!value) {
1114 return nullptr;
1115 }
1116 if (!this->expect(Token::RPAREN, "')'")) {
1117 return nullptr;
1118 }
1119 if (!this->expect(Token::LBRACE, "'{'")) {
1120 return nullptr;
1121 }
1122 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1123 while (this->peek().fKind == Token::CASE) {
1124 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1125 if (!c) {
1126 return nullptr;
1127 }
1128 cases.push_back(std::move(c));
1129 }
1130 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1131 // parts of the compiler may rely upon this assumption.
1132 if (this->peek().fKind == Token::DEFAULT) {
1133 Token defaultStart;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001134 ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001135 if (!this->expect(Token::COLON, "':'")) {
1136 return nullptr;
1137 }
1138 std::vector<std::unique_ptr<ASTStatement>> statements;
1139 while (this->peek().fKind != Token::RBRACE) {
1140 std::unique_ptr<ASTStatement> s = this->statement();
1141 if (!s) {
1142 return nullptr;
1143 }
1144 statements.push_back(std::move(s));
1145 }
1146 cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr,
1147 std::move(statements)));
1148 }
1149 if (!this->expect(Token::RBRACE, "'}'")) {
1150 return nullptr;
1151 }
1152 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001153 isStatic,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001154 std::move(value),
1155 std::move(cases)));
1156}
1157
Ethan Nicholas11d53972016-11-28 11:23:23 -05001158/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001159 STATEMENT */
1160std::unique_ptr<ASTForStatement> Parser::forStatement() {
1161 Token start;
1162 if (!this->expect(Token::FOR, "'for'", &start)) {
1163 return nullptr;
1164 }
1165 if (!this->expect(Token::LPAREN, "'('")) {
1166 return nullptr;
1167 }
1168 std::unique_ptr<ASTStatement> initializer;
1169 Token nextToken = this->peek();
1170 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001171 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001172 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001173 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001174 case Token::CONST: {
1175 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1176 if (!vd) {
1177 return nullptr;
1178 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001179 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001180 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001181 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001182 }
1183 case Token::IDENTIFIER: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001184 if (this->isType(nextToken.fText)) {
ethannicholasa54401d2016-10-14 08:37:32 -07001185 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1186 if (!vd) {
1187 return nullptr;
1188 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001189 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001190 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001191 break;
1192 }
ethannicholasa54401d2016-10-14 08:37:32 -07001193 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001194 default:
1195 initializer = this->expressionStatement();
1196 }
1197 std::unique_ptr<ASTExpression> test;
1198 if (this->peek().fKind != Token::SEMICOLON) {
1199 test = this->expression();
1200 if (!test) {
1201 return nullptr;
1202 }
1203 }
1204 if (!this->expect(Token::SEMICOLON, "';'")) {
1205 return nullptr;
1206 }
1207 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001208 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001209 next = this->expression();
1210 if (!next) {
1211 return nullptr;
1212 }
1213 }
1214 if (!this->expect(Token::RPAREN, "')'")) {
1215 return nullptr;
1216 }
1217 std::unique_ptr<ASTStatement> statement(this->statement());
1218 if (!statement) {
1219 return nullptr;
1220 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001221 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001222 std::move(initializer),
1223 std::move(test), std::move(next),
1224 std::move(statement)));
1225}
1226
1227/* RETURN expression? SEMICOLON */
1228std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1229 Token start;
1230 if (!this->expect(Token::RETURN, "'return'", &start)) {
1231 return nullptr;
1232 }
1233 std::unique_ptr<ASTExpression> expression;
1234 if (this->peek().fKind != Token::SEMICOLON) {
1235 expression = this->expression();
1236 if (!expression) {
1237 return nullptr;
1238 }
1239 }
1240 if (!this->expect(Token::SEMICOLON, "';'")) {
1241 return nullptr;
1242 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001243 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001244 std::move(expression)));
1245}
1246
1247/* BREAK SEMICOLON */
1248std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1249 Token start;
1250 if (!this->expect(Token::BREAK, "'break'", &start)) {
1251 return nullptr;
1252 }
1253 if (!this->expect(Token::SEMICOLON, "';'")) {
1254 return nullptr;
1255 }
1256 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
1257}
1258
1259/* CONTINUE SEMICOLON */
1260std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1261 Token start;
1262 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1263 return nullptr;
1264 }
1265 if (!this->expect(Token::SEMICOLON, "';'")) {
1266 return nullptr;
1267 }
1268 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
1269}
1270
1271/* DISCARD SEMICOLON */
1272std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1273 Token start;
1274 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1275 return nullptr;
1276 }
1277 if (!this->expect(Token::SEMICOLON, "';'")) {
1278 return nullptr;
1279 }
1280 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
1281}
1282
1283/* LBRACE statement* RBRACE */
1284std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001285 AutoDepth depth(this);
1286 if (!depth.checkValid()) {
1287 return nullptr;
1288 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001289 Token start;
1290 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1291 return nullptr;
1292 }
1293 std::vector<std::unique_ptr<ASTStatement>> statements;
1294 for (;;) {
1295 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001296 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001297 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001298 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001299 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001300 case Token::END_OF_FILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001301 this->error(this->peek().fPosition, "expected '}', but found end of file");
1302 return nullptr;
1303 default: {
1304 std::unique_ptr<ASTStatement> statement = this->statement();
1305 if (!statement) {
1306 return nullptr;
1307 }
1308 statements.push_back(std::move(statement));
1309 }
1310 }
1311 }
1312}
1313
1314/* expression SEMICOLON */
1315std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1316 std::unique_ptr<ASTExpression> expr = this->expression();
1317 if (expr) {
1318 if (this->expect(Token::SEMICOLON, "';'")) {
1319 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1320 return std::unique_ptr<ASTExpressionStatement>(result);
1321 }
1322 }
1323 return nullptr;
1324}
1325
1326/* assignmentExpression */
1327std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001328 AutoDepth depth(this);
1329 if (!depth.checkValid()) {
1330 return nullptr;
1331 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001332 return this->commaExpression();
1333}
1334
1335/* assignmentExpression (COMMA assignmentExpression)* */
1336std::unique_ptr<ASTExpression> Parser::commaExpression() {
1337 std::unique_ptr<ASTExpression> result = this->assignmentExpression();
1338 if (!result) {
1339 return nullptr;
1340 }
1341 Token t;
1342 while (this->checkNext(Token::COMMA, &t)) {
1343 std::unique_ptr<ASTExpression> right = this->commaExpression();
1344 if (!right) {
1345 return nullptr;
1346 }
1347 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1348 }
1349 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001350}
1351
1352/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1353 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1354 assignmentExpression)*
1355 */
1356std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1357 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1358 if (!result) {
1359 return nullptr;
1360 }
1361 for (;;) {
1362 switch (this->peek().fKind) {
1363 case Token::EQ: // fall through
1364 case Token::STAREQ: // fall through
1365 case Token::SLASHEQ: // fall through
1366 case Token::PERCENTEQ: // fall through
1367 case Token::PLUSEQ: // fall through
1368 case Token::MINUSEQ: // fall through
1369 case Token::SHLEQ: // fall through
1370 case Token::SHREQ: // fall through
1371 case Token::BITWISEANDEQ: // fall through
1372 case Token::BITWISEXOREQ: // fall through
1373 case Token::BITWISEOREQ: // fall through
1374 case Token::LOGICALANDEQ: // fall through
1375 case Token::LOGICALXOREQ: // fall through
1376 case Token::LOGICALOREQ: {
1377 Token t = this->nextToken();
1378 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1379 if (!right) {
1380 return nullptr;
1381 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001382 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
1383 t,
ethannicholasb3058bd2016-07-01 08:22:01 -07001384 std::move(right)));
1385 }
1386 default:
1387 return result;
1388 }
1389 }
1390}
1391
1392/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1393std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1394 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1395 if (!result) {
1396 return nullptr;
1397 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001398 if (this->checkNext(Token::QUESTION)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001399 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1400 if (!trueExpr) {
1401 return nullptr;
1402 }
1403 if (this->expect(Token::COLON, "':'")) {
1404 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001405 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1406 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001407 std::move(falseExpr)));
1408 }
1409 return nullptr;
1410 }
1411 return result;
1412}
1413
1414/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1415std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1416 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1417 if (!result) {
1418 return nullptr;
1419 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001420 Token t;
1421 while (this->checkNext(Token::LOGICALOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
1423 if (!right) {
1424 return nullptr;
1425 }
1426 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1427 }
1428 return result;
1429}
1430
1431/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1432std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1433 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1434 if (!result) {
1435 return nullptr;
1436 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001437 Token t;
1438 while (this->checkNext(Token::LOGICALXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001439 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1440 if (!right) {
1441 return nullptr;
1442 }
1443 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1444 }
1445 return result;
1446}
1447
1448/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1449std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1450 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1451 if (!result) {
1452 return nullptr;
1453 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001454 Token t;
1455 while (this->checkNext(Token::LOGICALAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001456 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1457 if (!right) {
1458 return nullptr;
1459 }
1460 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1461 }
1462 return result;
1463}
1464
1465/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1466std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1467 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1468 if (!result) {
1469 return nullptr;
1470 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001471 Token t;
1472 while (this->checkNext(Token::BITWISEOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001473 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1474 if (!right) {
1475 return nullptr;
1476 }
1477 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1478 }
1479 return result;
1480}
1481
1482/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1483std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1484 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1485 if (!result) {
1486 return nullptr;
1487 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001488 Token t;
1489 while (this->checkNext(Token::BITWISEXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001490 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1491 if (!right) {
1492 return nullptr;
1493 }
1494 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1495 }
1496 return result;
1497}
1498
1499/* equalityExpression (BITWISEAND equalityExpression)* */
1500std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1501 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1502 if (!result) {
1503 return nullptr;
1504 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001505 Token t;
1506 while (this->checkNext(Token::BITWISEAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001507 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1508 if (!right) {
1509 return nullptr;
1510 }
1511 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1512 }
1513 return result;
1514}
1515
1516/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1517std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1518 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1519 if (!result) {
1520 return nullptr;
1521 }
1522 for (;;) {
1523 switch (this->peek().fKind) {
1524 case Token::EQEQ: // fall through
1525 case Token::NEQ: {
1526 Token t = this->nextToken();
1527 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1528 if (!right) {
1529 return nullptr;
1530 }
1531 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1532 break;
1533 }
1534 default:
1535 return result;
1536 }
1537 }
1538}
1539
1540/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1541std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1542 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1543 if (!result) {
1544 return nullptr;
1545 }
1546 for (;;) {
1547 switch (this->peek().fKind) {
1548 case Token::LT: // fall through
1549 case Token::GT: // fall through
1550 case Token::LTEQ: // fall through
1551 case Token::GTEQ: {
1552 Token t = this->nextToken();
1553 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1554 if (!right) {
1555 return nullptr;
1556 }
1557 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1558 break;
1559 }
1560 default:
1561 return result;
1562 }
1563 }
1564}
1565
1566/* additiveExpression ((SHL | SHR) additiveExpression)* */
1567std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1568 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1569 if (!result) {
1570 return nullptr;
1571 }
1572 for (;;) {
1573 switch (this->peek().fKind) {
1574 case Token::SHL: // fall through
1575 case Token::SHR: {
1576 Token t = this->nextToken();
1577 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1578 if (!right) {
1579 return nullptr;
1580 }
1581 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1582 break;
1583 }
1584 default:
1585 return result;
1586 }
1587 }
1588}
1589
1590/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1591std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1592 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1593 if (!result) {
1594 return nullptr;
1595 }
1596 for (;;) {
1597 switch (this->peek().fKind) {
1598 case Token::PLUS: // fall through
1599 case Token::MINUS: {
1600 Token t = this->nextToken();
1601 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1602 if (!right) {
1603 return nullptr;
1604 }
1605 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1606 break;
1607 }
1608 default:
1609 return result;
1610 }
1611 }
1612}
1613
1614/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1615std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1616 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1617 if (!result) {
1618 return nullptr;
1619 }
1620 for (;;) {
1621 switch (this->peek().fKind) {
1622 case Token::STAR: // fall through
1623 case Token::SLASH: // fall through
1624 case Token::PERCENT: {
1625 Token t = this->nextToken();
1626 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1627 if (!right) {
1628 return nullptr;
1629 }
1630 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1631 break;
1632 }
1633 default:
1634 return result;
1635 }
1636 }
1637}
1638
1639/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1640std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1641 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001642 case Token::PLUS: // fall through
1643 case Token::MINUS: // fall through
1644 case Token::LOGICALNOT: // fall through
1645 case Token::BITWISENOT: // fall through
1646 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 case Token::MINUSMINUS: {
1648 Token t = this->nextToken();
1649 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1650 if (!expr) {
1651 return nullptr;
1652 }
1653 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
1654 }
1655 default:
1656 return this->postfixExpression();
1657 }
1658}
1659
1660/* term suffix* */
1661std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1662 std::unique_ptr<ASTExpression> result = this->term();
1663 if (!result) {
1664 return nullptr;
1665 }
1666 for (;;) {
1667 switch (this->peek().fKind) {
1668 case Token::LBRACKET: // fall through
1669 case Token::DOT: // fall through
1670 case Token::LPAREN: // fall through
1671 case Token::PLUSPLUS: // fall through
1672 case Token::MINUSMINUS: {
1673 std::unique_ptr<ASTSuffix> s = this->suffix();
1674 if (!s) {
1675 return nullptr;
1676 }
1677 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1678 break;
1679 }
1680 default:
1681 return result;
1682 }
1683 }
1684}
1685
Ethan Nicholas11d53972016-11-28 11:23:23 -05001686/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 PLUSPLUS | MINUSMINUS */
1688std::unique_ptr<ASTSuffix> Parser::suffix() {
1689 Token next = this->nextToken();
1690 switch (next.fKind) {
1691 case Token::LBRACKET: {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001692 if (this->checkNext(Token::RBRACKET)) {
ethannicholas5961bc92016-10-12 06:39:56 -07001693 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
1694 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001695 std::unique_ptr<ASTExpression> e = this->expression();
1696 if (!e) {
1697 return nullptr;
1698 }
1699 this->expect(Token::RBRACKET, "']' to complete array access expression");
1700 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1701 }
1702 case Token::DOT: {
1703 Position pos = this->peek().fPosition;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001704 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 if (this->identifier(&text)) {
1706 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
1707 }
1708 return nullptr;
1709 }
1710 case Token::LPAREN: {
1711 std::vector<std::unique_ptr<ASTExpression>> parameters;
1712 if (this->peek().fKind != Token::RPAREN) {
1713 for (;;) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001714 std::unique_ptr<ASTExpression> expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001715 if (!expr) {
1716 return nullptr;
1717 }
1718 parameters.push_back(std::move(expr));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001719 if (!this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001720 break;
1721 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001722 }
1723 }
1724 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas11d53972016-11-28 11:23:23 -05001725 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 std::move(parameters)));
1727 }
1728 case Token::PLUSPLUS:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001729 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 ASTSuffix::kPostIncrement_Kind));
1731 case Token::MINUSMINUS:
1732 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1733 ASTSuffix::kPostDecrement_Kind));
1734 default: {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001735 this->error(next.fPosition, "expected expression suffix, but found '" + next.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 "'\n");
1737 return nullptr;
1738 }
1739 }
1740}
1741
1742/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1743std::unique_ptr<ASTExpression> Parser::term() {
1744 std::unique_ptr<ASTExpression> result;
1745 Token t = this->peek();
1746 switch (t.fKind) {
1747 case Token::IDENTIFIER: {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001748 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001749 if (this->identifier(&text)) {
1750 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
1751 }
1752 break;
1753 }
1754 case Token::INT_LITERAL: {
1755 int64_t i;
1756 if (this->intLiteral(&i)) {
1757 result.reset(new ASTIntLiteral(t.fPosition, i));
1758 }
1759 break;
1760 }
1761 case Token::FLOAT_LITERAL: {
1762 double f;
1763 if (this->floatLiteral(&f)) {
1764 result.reset(new ASTFloatLiteral(t.fPosition, f));
1765 }
1766 break;
1767 }
1768 case Token::TRUE_LITERAL: // fall through
1769 case Token::FALSE_LITERAL: {
1770 bool b;
1771 if (this->boolLiteral(&b)) {
1772 result.reset(new ASTBoolLiteral(t.fPosition, b));
1773 }
1774 break;
1775 }
1776 case Token::LPAREN: {
1777 this->nextToken();
1778 result = this->expression();
1779 if (result) {
1780 this->expect(Token::RPAREN, "')' to complete expression");
1781 }
1782 break;
1783 }
1784 default:
1785 this->nextToken();
1786 this->error(t.fPosition, "expected expression, but found '" + t.fText + "'\n");
1787 result = nullptr;
1788 }
1789 return result;
1790}
1791
1792/* INT_LITERAL */
1793bool Parser::intLiteral(int64_t* dest) {
1794 Token t;
1795 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1796 *dest = SkSL::stol(t.fText);
1797 return true;
1798 }
1799 return false;
1800}
1801
1802/* FLOAT_LITERAL */
1803bool Parser::floatLiteral(double* dest) {
1804 Token t;
1805 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1806 *dest = SkSL::stod(t.fText);
1807 return true;
1808 }
1809 return false;
1810}
1811
1812/* TRUE_LITERAL | FALSE_LITERAL */
1813bool Parser::boolLiteral(bool* dest) {
1814 Token t = this->nextToken();
1815 switch (t.fKind) {
1816 case Token::TRUE_LITERAL:
1817 *dest = true;
1818 return true;
1819 case Token::FALSE_LITERAL:
1820 *dest = false;
1821 return true;
1822 default:
1823 this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1824 return false;
1825 }
1826}
1827
1828/* IDENTIFIER */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001829bool Parser::identifier(String* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001830 Token t;
1831 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001832 *dest = t.fText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001833 return true;
1834 }
1835 return false;
1836}
1837
1838} // namespace