blob: d3e1d5712c4d1e92176fc734387f4ca56d259b3f [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 Nicholas08b79b72017-08-14 10:35:37 -0400151Token Parser::nextRawToken(bool needText) {
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 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400158 Token::Kind kind = (Token::Kind) sksllex(fScanner);
159 if (!needText) {
160 switch (kind) {
161 case Token::Kind::DIRECTIVE: // fall through
162 case Token::Kind::IDENTIFIER: // fall through
163 case Token::Kind::INT_LITERAL: // fall through
164 case Token::Kind::FLOAT_LITERAL: // fall through
165 case Token::Kind::SECTION:
166 needText = true;
167 default:
168 break;
169 }
170 }
171 static String unavailable("<unavailable>");
172 return Token(Position(skslget_lineno(fScanner), -1), kind,
173 needText ? String(skslget_text(fScanner)) : unavailable);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400174}
175
176Token Parser::nextToken() {
177 Token token;
178 do {
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400179 token = this->nextRawToken(false);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400180 } while (token.fKind == Token::WHITESPACE);
181 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700182}
183
184void Parser::pushback(Token t) {
185 ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400186 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700187}
188
189Token Parser::peek() {
190 fPushback = this->nextToken();
191 return fPushback;
192}
193
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400194bool Parser::checkNext(Token::Kind kind, Token* result) {
195 Token next = this->nextToken();
196 if (next.fKind == kind) {
197 if (result) {
198 *result = next;
199 }
200 return true;
201 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400202 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400203 return false;
204}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500205
206bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400207 return this->expect(kind, String(expected), result);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500208}
209
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400210bool Parser::expect(Token::Kind kind, String expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700211 Token next = this->nextToken();
212 if (next.fKind == kind) {
213 if (result) {
214 *result = next;
215 }
216 return true;
217 } else {
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500218 if (next.fText.size()) {
219 this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText +
220 "'");
221 } else {
222 this->error(next.fPosition, "parse error, recompile in debug mode for details");
223 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700224 return false;
225 }
226}
227
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500228void Parser::error(Position p, const char* msg) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400229 this->error(p, String(msg));
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500230}
231
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400232void Parser::error(Position p, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 fErrors.error(p, msg);
234}
235
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400236bool Parser::isType(String name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 return nullptr != fTypes[name];
238}
239
240/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
ethannicholas5961bc92016-10-12 06:39:56 -0700241std::unique_ptr<ASTDeclaration> Parser::precision() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700242 if (!this->expect(Token::PRECISION, "'precision'")) {
ethannicholas5961bc92016-10-12 06:39:56 -0700243 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700244 }
ethannicholas5961bc92016-10-12 06:39:56 -0700245 Modifiers::Flag result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 Token p = this->nextToken();
247 switch (p.fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -0700248 case Token::LOWP:
249 result = Modifiers::kLowp_Flag;
250 break;
251 case Token::MEDIUMP:
252 result = Modifiers::kMediump_Flag;
253 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 case Token::HIGHP:
ethannicholas5961bc92016-10-12 06:39:56 -0700255 result = Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 break;
257 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500258 this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
ethannicholasb3058bd2016-07-01 08:22:01 -0700259 p.fText + "'");
ethannicholas5961bc92016-10-12 06:39:56 -0700260 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700261 }
ethannicholas5961bc92016-10-12 06:39:56 -0700262 // FIXME handle the type
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 if (!this->type()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700264 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700265 }
266 this->expect(Token::SEMICOLON, "';'");
ethannicholas5961bc92016-10-12 06:39:56 -0700267 return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
ethannicholasb3058bd2016-07-01 08:22:01 -0700268}
269
Ethan Nicholas11d53972016-11-28 11:23:23 -0500270/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700271 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700272std::unique_ptr<ASTDeclaration> Parser::directive() {
273 Token start;
274 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
275 return nullptr;
276 }
277 if (start.fText == "#version") {
278 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700279 Token next = this->peek();
280 if (next.fText == "es" || next.fText == "compatibility") {
281 this->nextToken();
282 }
283 // version is ignored for now; it will eventually become an error when we stop pretending
284 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 return nullptr;
286 } else if (start.fText == "#extension") {
287 Token name;
288 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
289 return nullptr;
290 }
291 if (!this->expect(Token::COLON, "':'")) {
292 return nullptr;
293 }
294 // FIXME: need to start paying attention to this token
295 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
296 return nullptr;
297 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500298 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 std::move(name.fText)));
300 } else {
301 this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
302 return nullptr;
303 }
304}
305
Ethan Nicholas762466e2017-06-29 10:03:38 -0400306/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
307 RBRACE */
308std::unique_ptr<ASTDeclaration> Parser::section() {
309 Token start;
310 if (!this->expect(Token::SECTION, "a section token", &start)) {
311 return nullptr;
312 }
313 String argument;
314 if (this->peek().fKind == Token::LPAREN) {
315 this->nextToken();
316 Token argToken;
317 if (!this->expect(Token::IDENTIFIER, "an identifier", &argToken)) {
318 return nullptr;
319 }
320 argument = argToken.fText;
321 if (!this->expect(Token::RPAREN, "')'")) {
322 return nullptr;
323 }
324 }
325 if (!this->expect(Token::LBRACE, "'{'")) {
326 return nullptr;
327 }
328 String text;
329 int level = 1;
330 for (;;) {
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400331 Token next = this->nextRawToken(true);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400332 switch (next.fKind) {
333 case Token::LBRACE:
334 ++level;
335 break;
336 case Token::RBRACE:
337 --level;
338 break;
339 case Token::END_OF_FILE:
340 this->error(start.fPosition, "reached end of file while parsing section");
341 return nullptr;
342 default:
343 break;
344 }
345 if (!level) {
346 break;
347 }
348 text += next.fText;
349 }
350 return std::unique_ptr<ASTDeclaration>(new ASTSection(start.fPosition,
351 String(start.fText.c_str() + 1),
352 argument,
353 text));
354}
355
Ethan Nicholas11d53972016-11-28 11:23:23 -0500356/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700357 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
358std::unique_ptr<ASTDeclaration> Parser::declaration() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500359 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700360 Token lookahead = this->peek();
361 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
362 // we have an identifier that's not a type, could be the start of an interface block
363 return this->interfaceBlock(modifiers);
364 }
365 if (lookahead.fKind == Token::STRUCT) {
366 return this->structVarDeclaration(modifiers);
367 }
ethannicholas5961bc92016-10-12 06:39:56 -0700368 if (lookahead.fKind == Token::SEMICOLON) {
369 this->nextToken();
370 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
371 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700372 std::unique_ptr<ASTType> type(this->type());
373 if (!type) {
374 return nullptr;
375 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400376 if (type->fKind == ASTType::kStruct_Kind && this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700377 return nullptr;
378 }
379 Token name;
380 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
381 return nullptr;
382 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400383 if (this->checkNext(Token::LPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 std::vector<std::unique_ptr<ASTParameter>> parameters;
385 while (this->peek().fKind != Token::RPAREN) {
386 if (parameters.size() > 0) {
387 if (!this->expect(Token::COMMA, "','")) {
388 return nullptr;
389 }
390 }
391 std::unique_ptr<ASTParameter> parameter = this->parameter();
392 if (!parameter) {
393 return nullptr;
394 }
395 parameters.push_back(std::move(parameter));
396 }
397 this->nextToken();
398 std::unique_ptr<ASTBlock> body;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400399 if (!this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700400 body = this->block();
401 if (!body) {
402 return nullptr;
403 }
404 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400405 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition,
406 modifiers,
407 std::move(type),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500408 std::move(name.fText),
409 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700410 std::move(body)));
411 } else {
412 return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
413 }
414}
415
416/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700417std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500418 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700419 std::unique_ptr<ASTType> type(this->type());
420 if (!type) {
421 return nullptr;
422 }
423 Token name;
424 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
425 return nullptr;
426 }
427 return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
428}
429
430/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
431std::unique_ptr<ASTType> Parser::structDeclaration() {
432 if (!this->expect(Token::STRUCT, "'struct'")) {
433 return nullptr;
434 }
435 Token name;
436 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
437 return nullptr;
438 }
439 if (!this->expect(Token::LBRACE, "'{'")) {
440 return nullptr;
441 }
442 std::vector<Type::Field> fields;
443 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700444 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 if (!decl) {
446 return nullptr;
447 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700448 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700449 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700450 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700451 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700452 this->error(decl->fPosition, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700453 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700454 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700455 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400456 String name = type->name() + "[" + to_string(columns) + "]";
ethannicholasd598f792016-07-25 10:08:54 -0700457 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
458 fTypes.takeOwnership((Type*) type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700459 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700460 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
461 if (var.fValue) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700462 this->error(decl->fPosition, "initializers are not permitted on struct fields");
463 }
464 }
465 }
466 if (!this->expect(Token::RBRACE, "'}'")) {
467 return nullptr;
468 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500469 fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fPosition, name.fText, fields)));
Ethan Nicholas11d53972016-11-28 11:23:23 -0500470 return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500471 ASTType::kStruct_Kind, std::vector<int>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700472}
473
474/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500475std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 std::unique_ptr<ASTType> type = this->structDeclaration();
477 if (!type) {
478 return nullptr;
479 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400480 Token name;
481 if (this->checkNext(Token::IDENTIFIER, &name)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500482 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
483 std::move(type),
ethannicholas14fe8cc2016-09-07 13:37:16 -0700484 std::move(name.fText));
ethannicholasb3058bd2016-07-01 08:22:01 -0700485 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700486 for (const auto& var : result->fVars) {
487 if (var.fValue) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500488 this->error(var.fValue->fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 "struct variables cannot be initialized");
490 }
491 }
492 }
493 return result;
494 }
495 this->expect(Token::SEMICOLON, "';'");
496 return nullptr;
497}
498
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400499/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
500 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500501std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700502 std::unique_ptr<ASTType> type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400503 String name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700504 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400506 while (this->checkNext(Token::LBRACKET)) {
507 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 currentVarSizes.push_back(nullptr);
509 } else {
510 std::unique_ptr<ASTExpression> size(this->expression());
511 if (!size) {
512 return nullptr;
513 }
514 currentVarSizes.push_back(std::move(size));
515 if (!this->expect(Token::RBRACKET, "']'")) {
516 return nullptr;
517 }
518 }
519 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700520 std::unique_ptr<ASTExpression> value;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400521 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400522 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 if (!value) {
524 return nullptr;
525 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700526 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700527 vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400528 while (this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 Token name;
530 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
531 return nullptr;
532 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700534 value.reset();
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400535 while (this->checkNext(Token::LBRACKET)) {
536 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 currentVarSizes.push_back(nullptr);
538 } else {
539 std::unique_ptr<ASTExpression> size(this->expression());
540 if (!size) {
541 return nullptr;
542 }
543 currentVarSizes.push_back(std::move(size));
544 if (!this->expect(Token::RBRACKET, "']'")) {
545 return nullptr;
546 }
547 }
548 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400549 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400550 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700551 if (!value) {
552 return nullptr;
553 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700554 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700555 vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700556 }
557 if (!this->expect(Token::SEMICOLON, "';'")) {
558 return nullptr;
559 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700560 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
561 std::move(type),
562 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700563}
564
565/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
566std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400567 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700568 std::unique_ptr<ASTType> type = this->type();
569 if (!type) {
570 return nullptr;
571 }
572 Token name;
573 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
574 return nullptr;
575 }
576 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400577 while (this->checkNext(Token::LBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700578 Token sizeToken;
579 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
580 return nullptr;
581 }
582 sizes.push_back(SkSL::stoi(sizeToken.fText));
583 if (!this->expect(Token::RBRACKET, "']'")) {
584 return nullptr;
585 }
586 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500587 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
588 std::move(type), name.fText,
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 std::move(sizes)));
590}
591
592/** (EQ INT_LITERAL)? */
593int Parser::layoutInt() {
594 if (!this->expect(Token::EQ, "'='")) {
595 return -1;
596 }
597 Token resultToken;
598 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
599 return SkSL::stoi(resultToken.fText);
600 }
601 return -1;
602}
603
Ethan Nicholas762466e2017-06-29 10:03:38 -0400604/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
605String Parser::layoutCode() {
606 if (!this->expect(Token::EQ, "'='")) {
607 return "";
608 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400609 Token start = this->nextRawToken(true);
610 this->pushback(start);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400611 String code;
612 int level = 1;
613 bool done = false;
614 while (!done) {
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400615 Token next = this->nextRawToken(true);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400616 switch (next.fKind) {
617 case Token::LPAREN:
618 ++level;
619 break;
620 case Token::RPAREN:
621 --level;
622 break;
623 case Token::COMMA:
624 if (level == 1) {
625 done = true;
626 }
627 break;
628 case Token::END_OF_FILE:
629 this->error(start.fPosition, "reached end of file while parsing layout");
630 return nullptr;
631 default:
632 break;
633 }
634 if (!level) {
635 done = true;
636 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400637 if (done) {
638 this->pushback(std::move(next));
639 }
640 else {
641 code += next.fText;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400642 }
643 }
644 return code;
645}
646
647/** (EQ IDENTIFIER('identity'))? */
648Layout::Key Parser::layoutKey() {
649 if (this->peek().fKind == Token::EQ) {
650 this->expect(Token::EQ, "'='");
651 Token key;
652 if (this->expect(Token::IDENTIFIER, "an identifer", &key)) {
653 if (key.fText == "identity") {
654 return Layout::kIdentity_Key;
655 } else {
656 this->error(key.fPosition, "unsupported layout key");
657 }
658 }
659 }
660 return Layout::kKey_Key;
661}
662
ethannicholas8ac838d2016-11-22 08:39:36 -0800663/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500664Layout Parser::layout() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700665 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500666 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700667 int binding = -1;
668 int index = -1;
669 int set = -1;
670 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500671 int inputAttachmentIndex = -1;
ethannicholasf789b382016-08-03 12:43:36 -0700672 bool originUpperLeft = false;
ethannicholas5961bc92016-10-12 06:39:56 -0700673 bool overrideCoverage = false;
674 bool blendSupportAllEquations = false;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500675 Layout::Format format = Layout::Format::kUnspecified;
ethannicholas8ac838d2016-11-22 08:39:36 -0800676 bool pushConstant = false;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500677 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
678 int maxVertices = -1;
679 int invocations = -1;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400680 String when;
681 Layout::Key key = Layout::kNo_Key;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400682 if (this->checkNext(Token::LAYOUT)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700683 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500684 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
Ethan Nicholas11d53972016-11-28 11:23:23 -0500685 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400686 pushConstant, primitive, maxVertices, invocations, when, key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700687 }
688 for (;;) {
689 Token t = this->nextToken();
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500690 YY_BUFFER_STATE buffer;
691 buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner);
692 int token = layoutlex(fLayoutScanner);
693 layout_delete_buffer(buffer, fLayoutScanner);
694 if (token != Token::INVALID_TOKEN) {
695 switch (token) {
696 case Token::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500697 location = this->layoutInt();
698 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500699 case Token::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500700 offset = this->layoutInt();
701 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500702 case Token::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500703 binding = this->layoutInt();
704 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500705 case Token::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500706 index = this->layoutInt();
707 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500708 case Token::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500709 set = this->layoutInt();
710 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500711 case Token::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500712 builtin = this->layoutInt();
713 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500714 case Token::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500715 inputAttachmentIndex = this->layoutInt();
716 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500717 case Token::ORIGIN_UPPER_LEFT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500718 originUpperLeft = true;
719 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500720 case Token::OVERRIDE_COVERAGE:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500721 overrideCoverage = true;
722 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500723 case Token::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500724 blendSupportAllEquations = true;
725 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500726 case Token::PUSH_CONSTANT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500727 pushConstant = true;
728 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500729 case Token::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500730 primitive = Layout::kPoints_Primitive;
731 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500732 case Token::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500733 primitive = Layout::kLines_Primitive;
734 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500735 case Token::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500736 primitive = Layout::kLineStrip_Primitive;
737 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500738 case Token::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500739 primitive = Layout::kLinesAdjacency_Primitive;
740 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500741 case Token::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500742 primitive = Layout::kTriangles_Primitive;
743 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500744 case Token::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500745 primitive = Layout::kTriangleStrip_Primitive;
746 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500747 case Token::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500748 primitive = Layout::kTrianglesAdjacency_Primitive;
749 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500750 case Token::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500751 maxVertices = this->layoutInt();
752 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500753 case Token::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500754 invocations = this->layoutInt();
755 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400756 case Token::WHEN:
757 when = this->layoutCode();
758 break;
759 case Token::KEY:
760 key = this->layoutKey();
761 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500762 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500763 } else if (Layout::ReadFormat(t.fText, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500764 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700765 } else {
Greg Daniel64773e62016-11-22 09:44:03 -0500766 this->error(t.fPosition, ("'" + t.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -0700767 "' is not a valid layout qualifier").c_str());
768 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400769 if (this->checkNext(Token::RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700770 break;
771 }
772 if (!this->expect(Token::COMMA, "','")) {
773 break;
774 }
775 }
776 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500777 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
778 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400779 pushConstant, primitive, maxVertices, invocations, when, key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700780}
781
Brian Salomonf9f45122016-11-29 11:59:17 -0500782/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400783 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500784Modifiers Parser::modifiers() {
785 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700786 int flags = 0;
787 for (;;) {
788 // TODO: handle duplicate / incompatible flags
789 switch (peek().fKind) {
790 case Token::UNIFORM:
791 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500792 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700793 break;
794 case Token::CONST:
795 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500796 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700797 break;
798 case Token::IN:
799 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500800 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700801 break;
802 case Token::OUT:
803 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500804 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700805 break;
806 case Token::INOUT:
807 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500808 flags |= Modifiers::kIn_Flag;
809 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700810 break;
811 case Token::LOWP:
812 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500813 flags |= Modifiers::kLowp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700814 break;
815 case Token::MEDIUMP:
816 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500817 flags |= Modifiers::kMediump_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700818 break;
819 case Token::HIGHP:
820 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500821 flags |= Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700822 break;
ethannicholasf789b382016-08-03 12:43:36 -0700823 case Token::FLAT:
824 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500825 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700826 break;
827 case Token::NOPERSPECTIVE:
828 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500829 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700830 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500831 case Token::READONLY:
832 this->nextToken();
833 flags |= Modifiers::kReadOnly_Flag;
834 break;
835 case Token::WRITEONLY:
836 this->nextToken();
837 flags |= Modifiers::kWriteOnly_Flag;
838 break;
839 case Token::COHERENT:
840 this->nextToken();
841 flags |= Modifiers::kCoherent_Flag;
842 break;
843 case Token::VOLATILE:
844 this->nextToken();
845 flags |= Modifiers::kVolatile_Flag;
846 break;
847 case Token::RESTRICT:
848 this->nextToken();
849 flags |= Modifiers::kRestrict_Flag;
850 break;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400851 case Token::BUFFER:
852 this->nextToken();
853 flags |= Modifiers::kBuffer_Flag;
854 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400855 case Token::HASSIDEEFFECTS:
856 this->nextToken();
857 flags |= Modifiers::kHasSideEffects_Flag;
858 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700859 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500860 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700861 }
862 }
863}
864
Ethan Nicholas11d53972016-11-28 11:23:23 -0500865Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
866 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700867 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500868 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700869 }
870 return result;
871}
872
873/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
874std::unique_ptr<ASTStatement> Parser::statement() {
875 Token start = this->peek();
876 switch (start.fKind) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400877 case Token::IF: // fall through
878 case Token::STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -0700879 return this->ifStatement();
880 case Token::FOR:
881 return this->forStatement();
882 case Token::DO:
883 return this->doStatement();
884 case Token::WHILE:
885 return this->whileStatement();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400886 case Token::SWITCH: // fall through
887 case Token::STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500888 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700889 case Token::RETURN:
890 return this->returnStatement();
891 case Token::BREAK:
892 return this->breakStatement();
893 case Token::CONTINUE:
894 return this->continueStatement();
895 case Token::DISCARD:
896 return this->discardStatement();
897 case Token::LBRACE:
898 return this->block();
899 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500900 this->nextToken();
901 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
ethannicholas0730be72016-09-01 07:59:02 -0700902 std::vector<std::unique_ptr<ASTStatement>>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700903 case Token::CONST: // fall through
904 case Token::HIGHP: // fall through
905 case Token::MEDIUMP: // fall through
906 case Token::LOWP: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700907 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700908 if (!decl) {
909 return nullptr;
910 }
911 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
912 }
913 case Token::IDENTIFIER:
914 if (this->isType(start.fText)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700915 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700916 if (!decl) {
917 return nullptr;
918 }
919 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
920 std::move(decl)));
921 }
922 // fall through
923 default:
924 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500925 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700926}
927
Ethan Nicholas50afc172017-02-16 14:49:57 -0500928/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
ethannicholasb3058bd2016-07-01 08:22:01 -0700929std::unique_ptr<ASTType> Parser::type() {
930 Token type;
931 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
932 return nullptr;
933 }
934 if (!this->isType(type.fText)) {
935 this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
936 return nullptr;
937 }
Ethan Nicholas50afc172017-02-16 14:49:57 -0500938 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400939 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500940 if (this->peek().fKind != Token::RBRACKET) {
941 int64_t i;
942 if (this->intLiteral(&i)) {
943 sizes.push_back(i);
944 } else {
945 return nullptr;
946 }
947 } else {
948 sizes.push_back(-1);
949 }
950 this->expect(Token::RBRACKET, "']'");
951 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500952 return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500953 ASTType::kIdentifier_Kind, sizes));
ethannicholasb3058bd2016-07-01 08:22:01 -0700954}
955
Ethan Nicholas50afc172017-02-16 14:49:57 -0500956/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500957std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700958 Token name;
959 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
960 return nullptr;
961 }
962 if (peek().fKind != Token::LBRACE) {
963 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500964 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700965 // it's better to report it as an unknown type
966 this->error(name.fPosition, "no type named '" + name.fText + "'");
967 return nullptr;
968 }
969 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500970 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700971 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700972 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700973 if (!decl) {
974 return nullptr;
975 }
976 decls.push_back(std::move(decl));
977 }
978 this->nextToken();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500979 std::vector<std::unique_ptr<ASTExpression>> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400980 Token instanceName;
981 if (this->checkNext(Token::IDENTIFIER, &instanceName)) {
982 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500983 if (this->peek().fKind != Token::RBRACKET) {
984 std::unique_ptr<ASTExpression> size = this->expression();
985 if (!size) {
986 return nullptr;
987 }
988 sizes.push_back(std::move(size));
989 } else {
990 sizes.push_back(nullptr);
991 }
992 this->expect(Token::RBRACKET, "']'");
993 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700994 }
995 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas11d53972016-11-28 11:23:23 -0500996 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500997 name.fText, std::move(decls),
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400998 std::move(instanceName.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500999 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001000}
1001
1002/* IF LPAREN expression RPAREN statement (ELSE statement)? */
1003std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
1004 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001005 bool isStatic = this->checkNext(Token::STATIC_IF, &start);
1006 if (!isStatic && !this->expect(Token::IF, "'if'", &start)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001007 return nullptr;
1008 }
1009 if (!this->expect(Token::LPAREN, "'('")) {
1010 return nullptr;
1011 }
1012 std::unique_ptr<ASTExpression> test(this->expression());
1013 if (!test) {
1014 return nullptr;
1015 }
1016 if (!this->expect(Token::RPAREN, "')'")) {
1017 return nullptr;
1018 }
1019 std::unique_ptr<ASTStatement> ifTrue(this->statement());
1020 if (!ifTrue) {
1021 return nullptr;
1022 }
1023 std::unique_ptr<ASTStatement> ifFalse;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001024 if (this->checkNext(Token::ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001025 ifFalse = this->statement();
1026 if (!ifFalse) {
1027 return nullptr;
1028 }
1029 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001030 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition,
1031 isStatic,
1032 std::move(test),
Ethan Nicholas11d53972016-11-28 11:23:23 -05001033 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -07001034 std::move(ifFalse)));
1035}
1036
1037/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
1038std::unique_ptr<ASTDoStatement> Parser::doStatement() {
1039 Token start;
1040 if (!this->expect(Token::DO, "'do'", &start)) {
1041 return nullptr;
1042 }
1043 std::unique_ptr<ASTStatement> statement(this->statement());
1044 if (!statement) {
1045 return nullptr;
1046 }
1047 if (!this->expect(Token::WHILE, "'while'")) {
1048 return nullptr;
1049 }
1050 if (!this->expect(Token::LPAREN, "'('")) {
1051 return nullptr;
1052 }
1053 std::unique_ptr<ASTExpression> test(this->expression());
1054 if (!test) {
1055 return nullptr;
1056 }
1057 if (!this->expect(Token::RPAREN, "')'")) {
1058 return nullptr;
1059 }
1060 if (!this->expect(Token::SEMICOLON, "';'")) {
1061 return nullptr;
1062 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001063 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001064 std::move(statement),
1065 std::move(test)));
1066}
1067
1068/* WHILE LPAREN expression RPAREN STATEMENT */
1069std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
1070 Token start;
1071 if (!this->expect(Token::WHILE, "'while'", &start)) {
1072 return nullptr;
1073 }
1074 if (!this->expect(Token::LPAREN, "'('")) {
1075 return nullptr;
1076 }
1077 std::unique_ptr<ASTExpression> test(this->expression());
1078 if (!test) {
1079 return nullptr;
1080 }
1081 if (!this->expect(Token::RPAREN, "')'")) {
1082 return nullptr;
1083 }
1084 std::unique_ptr<ASTStatement> statement(this->statement());
1085 if (!statement) {
1086 return nullptr;
1087 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001088 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
1089 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -07001090 std::move(statement)));
1091}
1092
Ethan Nicholasaf197692017-02-27 13:26:45 -05001093/* CASE expression COLON statement* */
1094std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
1095 Token start;
1096 if (!this->expect(Token::CASE, "'case'", &start)) {
1097 return nullptr;
1098 }
1099 std::unique_ptr<ASTExpression> value = this->expression();
1100 if (!value) {
1101 return nullptr;
1102 }
1103 if (!this->expect(Token::COLON, "':'")) {
1104 return nullptr;
1105 }
1106 std::vector<std::unique_ptr<ASTStatement>> statements;
1107 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
1108 this->peek().fKind != Token::DEFAULT) {
1109 std::unique_ptr<ASTStatement> s = this->statement();
1110 if (!s) {
1111 return nullptr;
1112 }
1113 statements.push_back(std::move(s));
1114 }
1115 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fPosition, std::move(value),
1116 std::move(statements)));
1117}
1118
1119/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
1120std::unique_ptr<ASTStatement> Parser::switchStatement() {
1121 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001122 bool isStatic = this->checkNext(Token::STATIC_SWITCH, &start);
1123 if (!isStatic && !this->expect(Token::SWITCH, "'switch'", &start)) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001124 return nullptr;
1125 }
1126 if (!this->expect(Token::LPAREN, "'('")) {
1127 return nullptr;
1128 }
1129 std::unique_ptr<ASTExpression> value(this->expression());
1130 if (!value) {
1131 return nullptr;
1132 }
1133 if (!this->expect(Token::RPAREN, "')'")) {
1134 return nullptr;
1135 }
1136 if (!this->expect(Token::LBRACE, "'{'")) {
1137 return nullptr;
1138 }
1139 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1140 while (this->peek().fKind == Token::CASE) {
1141 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1142 if (!c) {
1143 return nullptr;
1144 }
1145 cases.push_back(std::move(c));
1146 }
1147 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1148 // parts of the compiler may rely upon this assumption.
1149 if (this->peek().fKind == Token::DEFAULT) {
1150 Token defaultStart;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001151 ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001152 if (!this->expect(Token::COLON, "':'")) {
1153 return nullptr;
1154 }
1155 std::vector<std::unique_ptr<ASTStatement>> statements;
1156 while (this->peek().fKind != Token::RBRACE) {
1157 std::unique_ptr<ASTStatement> s = this->statement();
1158 if (!s) {
1159 return nullptr;
1160 }
1161 statements.push_back(std::move(s));
1162 }
1163 cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr,
1164 std::move(statements)));
1165 }
1166 if (!this->expect(Token::RBRACE, "'}'")) {
1167 return nullptr;
1168 }
1169 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001170 isStatic,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001171 std::move(value),
1172 std::move(cases)));
1173}
1174
Ethan Nicholas11d53972016-11-28 11:23:23 -05001175/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001176 STATEMENT */
1177std::unique_ptr<ASTForStatement> Parser::forStatement() {
1178 Token start;
1179 if (!this->expect(Token::FOR, "'for'", &start)) {
1180 return nullptr;
1181 }
1182 if (!this->expect(Token::LPAREN, "'('")) {
1183 return nullptr;
1184 }
1185 std::unique_ptr<ASTStatement> initializer;
1186 Token nextToken = this->peek();
1187 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001188 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001189 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001190 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001191 case Token::CONST: {
1192 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1193 if (!vd) {
1194 return nullptr;
1195 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001196 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001197 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001198 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001199 }
1200 case Token::IDENTIFIER: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001201 if (this->isType(nextToken.fText)) {
ethannicholasa54401d2016-10-14 08:37:32 -07001202 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1203 if (!vd) {
1204 return nullptr;
1205 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001206 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001207 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001208 break;
1209 }
ethannicholasa54401d2016-10-14 08:37:32 -07001210 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001211 default:
1212 initializer = this->expressionStatement();
1213 }
1214 std::unique_ptr<ASTExpression> test;
1215 if (this->peek().fKind != Token::SEMICOLON) {
1216 test = this->expression();
1217 if (!test) {
1218 return nullptr;
1219 }
1220 }
1221 if (!this->expect(Token::SEMICOLON, "';'")) {
1222 return nullptr;
1223 }
1224 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001225 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001226 next = this->expression();
1227 if (!next) {
1228 return nullptr;
1229 }
1230 }
1231 if (!this->expect(Token::RPAREN, "')'")) {
1232 return nullptr;
1233 }
1234 std::unique_ptr<ASTStatement> statement(this->statement());
1235 if (!statement) {
1236 return nullptr;
1237 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001238 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001239 std::move(initializer),
1240 std::move(test), std::move(next),
1241 std::move(statement)));
1242}
1243
1244/* RETURN expression? SEMICOLON */
1245std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1246 Token start;
1247 if (!this->expect(Token::RETURN, "'return'", &start)) {
1248 return nullptr;
1249 }
1250 std::unique_ptr<ASTExpression> expression;
1251 if (this->peek().fKind != Token::SEMICOLON) {
1252 expression = this->expression();
1253 if (!expression) {
1254 return nullptr;
1255 }
1256 }
1257 if (!this->expect(Token::SEMICOLON, "';'")) {
1258 return nullptr;
1259 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001260 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001261 std::move(expression)));
1262}
1263
1264/* BREAK SEMICOLON */
1265std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1266 Token start;
1267 if (!this->expect(Token::BREAK, "'break'", &start)) {
1268 return nullptr;
1269 }
1270 if (!this->expect(Token::SEMICOLON, "';'")) {
1271 return nullptr;
1272 }
1273 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
1274}
1275
1276/* CONTINUE SEMICOLON */
1277std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1278 Token start;
1279 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1280 return nullptr;
1281 }
1282 if (!this->expect(Token::SEMICOLON, "';'")) {
1283 return nullptr;
1284 }
1285 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
1286}
1287
1288/* DISCARD SEMICOLON */
1289std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1290 Token start;
1291 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1292 return nullptr;
1293 }
1294 if (!this->expect(Token::SEMICOLON, "';'")) {
1295 return nullptr;
1296 }
1297 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
1298}
1299
1300/* LBRACE statement* RBRACE */
1301std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001302 AutoDepth depth(this);
1303 if (!depth.checkValid()) {
1304 return nullptr;
1305 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001306 Token start;
1307 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1308 return nullptr;
1309 }
1310 std::vector<std::unique_ptr<ASTStatement>> statements;
1311 for (;;) {
1312 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001313 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001314 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001315 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001316 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001317 case Token::END_OF_FILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001318 this->error(this->peek().fPosition, "expected '}', but found end of file");
1319 return nullptr;
1320 default: {
1321 std::unique_ptr<ASTStatement> statement = this->statement();
1322 if (!statement) {
1323 return nullptr;
1324 }
1325 statements.push_back(std::move(statement));
1326 }
1327 }
1328 }
1329}
1330
1331/* expression SEMICOLON */
1332std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1333 std::unique_ptr<ASTExpression> expr = this->expression();
1334 if (expr) {
1335 if (this->expect(Token::SEMICOLON, "';'")) {
1336 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1337 return std::unique_ptr<ASTExpressionStatement>(result);
1338 }
1339 }
1340 return nullptr;
1341}
1342
1343/* assignmentExpression */
1344std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001345 AutoDepth depth(this);
1346 if (!depth.checkValid()) {
1347 return nullptr;
1348 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001349 return this->commaExpression();
1350}
1351
1352/* assignmentExpression (COMMA assignmentExpression)* */
1353std::unique_ptr<ASTExpression> Parser::commaExpression() {
1354 std::unique_ptr<ASTExpression> result = this->assignmentExpression();
1355 if (!result) {
1356 return nullptr;
1357 }
1358 Token t;
1359 while (this->checkNext(Token::COMMA, &t)) {
1360 std::unique_ptr<ASTExpression> right = this->commaExpression();
1361 if (!right) {
1362 return nullptr;
1363 }
1364 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1365 }
1366 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001367}
1368
1369/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1370 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1371 assignmentExpression)*
1372 */
1373std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1374 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1375 if (!result) {
1376 return nullptr;
1377 }
1378 for (;;) {
1379 switch (this->peek().fKind) {
1380 case Token::EQ: // fall through
1381 case Token::STAREQ: // fall through
1382 case Token::SLASHEQ: // fall through
1383 case Token::PERCENTEQ: // fall through
1384 case Token::PLUSEQ: // fall through
1385 case Token::MINUSEQ: // fall through
1386 case Token::SHLEQ: // fall through
1387 case Token::SHREQ: // fall through
1388 case Token::BITWISEANDEQ: // fall through
1389 case Token::BITWISEXOREQ: // fall through
1390 case Token::BITWISEOREQ: // fall through
1391 case Token::LOGICALANDEQ: // fall through
1392 case Token::LOGICALXOREQ: // fall through
1393 case Token::LOGICALOREQ: {
1394 Token t = this->nextToken();
1395 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1396 if (!right) {
1397 return nullptr;
1398 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001399 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
1400 t,
ethannicholasb3058bd2016-07-01 08:22:01 -07001401 std::move(right)));
1402 }
1403 default:
1404 return result;
1405 }
1406 }
1407}
1408
1409/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1410std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1411 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1412 if (!result) {
1413 return nullptr;
1414 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001415 if (this->checkNext(Token::QUESTION)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001416 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1417 if (!trueExpr) {
1418 return nullptr;
1419 }
1420 if (this->expect(Token::COLON, "':'")) {
1421 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001422 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1423 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 std::move(falseExpr)));
1425 }
1426 return nullptr;
1427 }
1428 return result;
1429}
1430
1431/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1432std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1433 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1434 if (!result) {
1435 return nullptr;
1436 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001437 Token t;
1438 while (this->checkNext(Token::LOGICALOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001439 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
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/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1449std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1450 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1451 if (!result) {
1452 return nullptr;
1453 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001454 Token t;
1455 while (this->checkNext(Token::LOGICALXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001456 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
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/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1466std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1467 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1468 if (!result) {
1469 return nullptr;
1470 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001471 Token t;
1472 while (this->checkNext(Token::LOGICALAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001473 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
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/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1483std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1484 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1485 if (!result) {
1486 return nullptr;
1487 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001488 Token t;
1489 while (this->checkNext(Token::BITWISEOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001490 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
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/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1500std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1501 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1502 if (!result) {
1503 return nullptr;
1504 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001505 Token t;
1506 while (this->checkNext(Token::BITWISEXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001507 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
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/* equalityExpression (BITWISEAND equalityExpression)* */
1517std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1518 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1519 if (!result) {
1520 return nullptr;
1521 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001522 Token t;
1523 while (this->checkNext(Token::BITWISEAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001524 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1525 if (!right) {
1526 return nullptr;
1527 }
1528 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1529 }
1530 return result;
1531}
1532
1533/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1534std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1535 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1536 if (!result) {
1537 return nullptr;
1538 }
1539 for (;;) {
1540 switch (this->peek().fKind) {
1541 case Token::EQEQ: // fall through
1542 case Token::NEQ: {
1543 Token t = this->nextToken();
1544 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1545 if (!right) {
1546 return nullptr;
1547 }
1548 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1549 break;
1550 }
1551 default:
1552 return result;
1553 }
1554 }
1555}
1556
1557/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1558std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1559 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1560 if (!result) {
1561 return nullptr;
1562 }
1563 for (;;) {
1564 switch (this->peek().fKind) {
1565 case Token::LT: // fall through
1566 case Token::GT: // fall through
1567 case Token::LTEQ: // fall through
1568 case Token::GTEQ: {
1569 Token t = this->nextToken();
1570 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1571 if (!right) {
1572 return nullptr;
1573 }
1574 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1575 break;
1576 }
1577 default:
1578 return result;
1579 }
1580 }
1581}
1582
1583/* additiveExpression ((SHL | SHR) additiveExpression)* */
1584std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1585 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1586 if (!result) {
1587 return nullptr;
1588 }
1589 for (;;) {
1590 switch (this->peek().fKind) {
1591 case Token::SHL: // fall through
1592 case Token::SHR: {
1593 Token t = this->nextToken();
1594 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1595 if (!right) {
1596 return nullptr;
1597 }
1598 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1599 break;
1600 }
1601 default:
1602 return result;
1603 }
1604 }
1605}
1606
1607/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1608std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1609 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1610 if (!result) {
1611 return nullptr;
1612 }
1613 for (;;) {
1614 switch (this->peek().fKind) {
1615 case Token::PLUS: // fall through
1616 case Token::MINUS: {
1617 Token t = this->nextToken();
1618 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1619 if (!right) {
1620 return nullptr;
1621 }
1622 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1623 break;
1624 }
1625 default:
1626 return result;
1627 }
1628 }
1629}
1630
1631/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1632std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1633 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1634 if (!result) {
1635 return nullptr;
1636 }
1637 for (;;) {
1638 switch (this->peek().fKind) {
1639 case Token::STAR: // fall through
1640 case Token::SLASH: // fall through
1641 case Token::PERCENT: {
1642 Token t = this->nextToken();
1643 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1644 if (!right) {
1645 return nullptr;
1646 }
1647 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1648 break;
1649 }
1650 default:
1651 return result;
1652 }
1653 }
1654}
1655
1656/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1657std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1658 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001659 case Token::PLUS: // fall through
1660 case Token::MINUS: // fall through
1661 case Token::LOGICALNOT: // fall through
1662 case Token::BITWISENOT: // fall through
1663 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001664 case Token::MINUSMINUS: {
1665 Token t = this->nextToken();
1666 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1667 if (!expr) {
1668 return nullptr;
1669 }
1670 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
1671 }
1672 default:
1673 return this->postfixExpression();
1674 }
1675}
1676
1677/* term suffix* */
1678std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1679 std::unique_ptr<ASTExpression> result = this->term();
1680 if (!result) {
1681 return nullptr;
1682 }
1683 for (;;) {
1684 switch (this->peek().fKind) {
1685 case Token::LBRACKET: // fall through
1686 case Token::DOT: // fall through
1687 case Token::LPAREN: // fall through
1688 case Token::PLUSPLUS: // fall through
1689 case Token::MINUSMINUS: {
1690 std::unique_ptr<ASTSuffix> s = this->suffix();
1691 if (!s) {
1692 return nullptr;
1693 }
1694 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1695 break;
1696 }
1697 default:
1698 return result;
1699 }
1700 }
1701}
1702
Ethan Nicholas11d53972016-11-28 11:23:23 -05001703/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
ethannicholasb3058bd2016-07-01 08:22:01 -07001704 PLUSPLUS | MINUSMINUS */
1705std::unique_ptr<ASTSuffix> Parser::suffix() {
1706 Token next = this->nextToken();
1707 switch (next.fKind) {
1708 case Token::LBRACKET: {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001709 if (this->checkNext(Token::RBRACKET)) {
ethannicholas5961bc92016-10-12 06:39:56 -07001710 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
1711 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001712 std::unique_ptr<ASTExpression> e = this->expression();
1713 if (!e) {
1714 return nullptr;
1715 }
1716 this->expect(Token::RBRACKET, "']' to complete array access expression");
1717 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1718 }
1719 case Token::DOT: {
1720 Position pos = this->peek().fPosition;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001721 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001722 if (this->identifier(&text)) {
1723 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
1724 }
1725 return nullptr;
1726 }
1727 case Token::LPAREN: {
1728 std::vector<std::unique_ptr<ASTExpression>> parameters;
1729 if (this->peek().fKind != Token::RPAREN) {
1730 for (;;) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001731 std::unique_ptr<ASTExpression> expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001732 if (!expr) {
1733 return nullptr;
1734 }
1735 parameters.push_back(std::move(expr));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001736 if (!this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001737 break;
1738 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001739 }
1740 }
1741 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas11d53972016-11-28 11:23:23 -05001742 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001743 std::move(parameters)));
1744 }
1745 case Token::PLUSPLUS:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001746 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001747 ASTSuffix::kPostIncrement_Kind));
1748 case Token::MINUSMINUS:
1749 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1750 ASTSuffix::kPostDecrement_Kind));
1751 default: {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001752 this->error(next.fPosition, "expected expression suffix, but found '" + next.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -07001753 "'\n");
1754 return nullptr;
1755 }
1756 }
1757}
1758
1759/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1760std::unique_ptr<ASTExpression> Parser::term() {
1761 std::unique_ptr<ASTExpression> result;
1762 Token t = this->peek();
1763 switch (t.fKind) {
1764 case Token::IDENTIFIER: {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001765 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001766 if (this->identifier(&text)) {
1767 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
1768 }
1769 break;
1770 }
1771 case Token::INT_LITERAL: {
1772 int64_t i;
1773 if (this->intLiteral(&i)) {
1774 result.reset(new ASTIntLiteral(t.fPosition, i));
1775 }
1776 break;
1777 }
1778 case Token::FLOAT_LITERAL: {
1779 double f;
1780 if (this->floatLiteral(&f)) {
1781 result.reset(new ASTFloatLiteral(t.fPosition, f));
1782 }
1783 break;
1784 }
1785 case Token::TRUE_LITERAL: // fall through
1786 case Token::FALSE_LITERAL: {
1787 bool b;
1788 if (this->boolLiteral(&b)) {
1789 result.reset(new ASTBoolLiteral(t.fPosition, b));
1790 }
1791 break;
1792 }
1793 case Token::LPAREN: {
1794 this->nextToken();
1795 result = this->expression();
1796 if (result) {
1797 this->expect(Token::RPAREN, "')' to complete expression");
1798 }
1799 break;
1800 }
1801 default:
1802 this->nextToken();
1803 this->error(t.fPosition, "expected expression, but found '" + t.fText + "'\n");
1804 result = nullptr;
1805 }
1806 return result;
1807}
1808
1809/* INT_LITERAL */
1810bool Parser::intLiteral(int64_t* dest) {
1811 Token t;
1812 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1813 *dest = SkSL::stol(t.fText);
1814 return true;
1815 }
1816 return false;
1817}
1818
1819/* FLOAT_LITERAL */
1820bool Parser::floatLiteral(double* dest) {
1821 Token t;
1822 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1823 *dest = SkSL::stod(t.fText);
1824 return true;
1825 }
1826 return false;
1827}
1828
1829/* TRUE_LITERAL | FALSE_LITERAL */
1830bool Parser::boolLiteral(bool* dest) {
1831 Token t = this->nextToken();
1832 switch (t.fKind) {
1833 case Token::TRUE_LITERAL:
1834 *dest = true;
1835 return true;
1836 case Token::FALSE_LITERAL:
1837 *dest = false;
1838 return true;
1839 default:
1840 this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1841 return false;
1842 }
1843}
1844
1845/* IDENTIFIER */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001846bool Parser::identifier(String* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001847 Token t;
1848 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001849 *dest = t.fText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 return true;
1851 }
1852 return false;
1853}
1854
1855} // namespace