blob: f466f6fdcad4ff5edf9f9b91341f6f765ec0f83b [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"
55#include "ast/SkSLASTStatement.h"
56#include "ast/SkSLASTSuffixExpression.h"
Ethan Nicholasaf197692017-02-27 13:26:45 -050057#include "ast/SkSLASTSwitchCase.h"
58#include "ast/SkSLASTSwitchStatement.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070059#include "ast/SkSLASTTernaryExpression.h"
60#include "ast/SkSLASTType.h"
61#include "ast/SkSLASTVarDeclaration.h"
62#include "ast/SkSLASTVarDeclarationStatement.h"
63#include "ast/SkSLASTWhileStatement.h"
64#include "ir/SkSLSymbolTable.h"
Ethan Nicholas11d53972016-11-28 11:23:23 -050065#include "ir/SkSLModifiers.h"
ethannicholasd598f792016-07-25 10:08:54 -070066#include "ir/SkSLType.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070067
68namespace SkSL {
69
ethannicholascad64162016-10-27 10:54:02 -070070#define MAX_PARSE_DEPTH 50
71
72class AutoDepth {
73public:
74 AutoDepth(Parser* p)
75 : fParser(p) {
76 fParser->fDepth++;
77 }
78
79 ~AutoDepth() {
80 fParser->fDepth--;
81 }
82
83 bool checkValid() {
84 if (fParser->fDepth > MAX_PARSE_DEPTH) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -040085 fParser->error(fParser->peek().fPosition, String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070086 return false;
87 }
88 return true;
89 }
90
91private:
92 Parser* fParser;
93};
94
Ethan Nicholas0df1b042017-03-31 13:56:23 -040095Parser::Parser(String text, SymbolTable& types, ErrorReporter& errors)
96: fPushback(Position(-1, -1), Token::INVALID_TOKEN, String())
ethannicholasb3058bd2016-07-01 08:22:01 -070097, fTypes(types)
98, fErrors(errors) {
99 sksllex_init(&fScanner);
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500100 layoutlex_init(&fLayoutScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700101 fBuffer = sksl_scan_string(text.c_str(), fScanner);
102 skslset_lineno(1, fScanner);
103
104 if (false) {
105 // avoid unused warning
106 yyunput(0, nullptr, fScanner);
107 }
108}
109
110Parser::~Parser() {
111 sksl_delete_buffer(fBuffer, fScanner);
ethannicholas69a7e7c2016-07-01 19:09:27 -0700112 sksllex_destroy(fScanner);
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500113 layoutlex_destroy(fLayoutScanner);
ethannicholasb3058bd2016-07-01 08:22:01 -0700114}
115
116/* (precision | directive | declaration)* END_OF_FILE */
117std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
118 std::vector<std::unique_ptr<ASTDeclaration>> result;
119 for (;;) {
120 switch (this->peek().fKind) {
121 case Token::END_OF_FILE:
122 return result;
ethannicholas5961bc92016-10-12 06:39:56 -0700123 case Token::PRECISION: {
124 std::unique_ptr<ASTDeclaration> precision = this->precision();
125 if (precision) {
126 result.push_back(std::move(precision));
127 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700128 break;
ethannicholas5961bc92016-10-12 06:39:56 -0700129 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700130 case Token::DIRECTIVE: {
131 std::unique_ptr<ASTDeclaration> decl = this->directive();
132 if (decl) {
133 result.push_back(std::move(decl));
134 }
135 break;
136 }
137 default: {
138 std::unique_ptr<ASTDeclaration> decl = this->declaration();
139 if (!decl) {
140 continue;
141 }
142 result.push_back(std::move(decl));
143 }
144 }
145 }
146}
147
148Token Parser::nextToken() {
149 if (fPushback.fKind != Token::INVALID_TOKEN) {
150 Token result = fPushback;
151 fPushback.fKind = Token::INVALID_TOKEN;
152 fPushback.fText = "";
153 return result;
154 }
155 int token = sksllex(fScanner);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400156 String text;
ethannicholas471e8942016-10-28 09:02:46 -0700157 switch ((Token::Kind) token) {
158 case Token::IDENTIFIER: // fall through
159 case Token::INT_LITERAL: // fall through
160 case Token::FLOAT_LITERAL: // fall through
161 case Token::DIRECTIVE:
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400162 text = String(skslget_text(fScanner));
ethannicholas471e8942016-10-28 09:02:46 -0700163 break;
164 default:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500165#ifdef SK_DEBUG
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400166 text = String(skslget_text(fScanner));
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500167#endif
ethannicholas471e8942016-10-28 09:02:46 -0700168 break;
169 }
170 return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token, text);
ethannicholasb3058bd2016-07-01 08:22:01 -0700171}
172
173void Parser::pushback(Token t) {
174 ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
175 fPushback = t;
176}
177
178Token Parser::peek() {
179 fPushback = this->nextToken();
180 return fPushback;
181}
182
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400183bool Parser::checkNext(Token::Kind kind, Token* result) {
184 Token next = this->nextToken();
185 if (next.fKind == kind) {
186 if (result) {
187 *result = next;
188 }
189 return true;
190 }
191 this->pushback(next);
192 return false;
193}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500194
195bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400196 return this->expect(kind, String(expected), result);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500197}
198
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400199bool Parser::expect(Token::Kind kind, String expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700200 Token next = this->nextToken();
201 if (next.fKind == kind) {
202 if (result) {
203 *result = next;
204 }
205 return true;
206 } else {
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500207 if (next.fText.size()) {
208 this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText +
209 "'");
210 } else {
211 this->error(next.fPosition, "parse error, recompile in debug mode for details");
212 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700213 return false;
214 }
215}
216
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500217void Parser::error(Position p, const char* msg) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400218 this->error(p, String(msg));
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500219}
220
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400221void Parser::error(Position p, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700222 fErrors.error(p, msg);
223}
224
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400225bool Parser::isType(String name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700226 return nullptr != fTypes[name];
227}
228
229/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
ethannicholas5961bc92016-10-12 06:39:56 -0700230std::unique_ptr<ASTDeclaration> Parser::precision() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700231 if (!this->expect(Token::PRECISION, "'precision'")) {
ethannicholas5961bc92016-10-12 06:39:56 -0700232 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 }
ethannicholas5961bc92016-10-12 06:39:56 -0700234 Modifiers::Flag result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700235 Token p = this->nextToken();
236 switch (p.fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -0700237 case Token::LOWP:
238 result = Modifiers::kLowp_Flag;
239 break;
240 case Token::MEDIUMP:
241 result = Modifiers::kMediump_Flag;
242 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 case Token::HIGHP:
ethannicholas5961bc92016-10-12 06:39:56 -0700244 result = Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 break;
246 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500247 this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
ethannicholasb3058bd2016-07-01 08:22:01 -0700248 p.fText + "'");
ethannicholas5961bc92016-10-12 06:39:56 -0700249 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 }
ethannicholas5961bc92016-10-12 06:39:56 -0700251 // FIXME handle the type
ethannicholasb3058bd2016-07-01 08:22:01 -0700252 if (!this->type()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700253 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 }
255 this->expect(Token::SEMICOLON, "';'");
ethannicholas5961bc92016-10-12 06:39:56 -0700256 return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
ethannicholasb3058bd2016-07-01 08:22:01 -0700257}
258
Ethan Nicholas11d53972016-11-28 11:23:23 -0500259/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700260 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700261std::unique_ptr<ASTDeclaration> Parser::directive() {
262 Token start;
263 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
264 return nullptr;
265 }
266 if (start.fText == "#version") {
267 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700268 Token next = this->peek();
269 if (next.fText == "es" || next.fText == "compatibility") {
270 this->nextToken();
271 }
272 // version is ignored for now; it will eventually become an error when we stop pretending
273 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700274 return nullptr;
275 } else if (start.fText == "#extension") {
276 Token name;
277 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
278 return nullptr;
279 }
280 if (!this->expect(Token::COLON, "':'")) {
281 return nullptr;
282 }
283 // FIXME: need to start paying attention to this token
284 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
285 return nullptr;
286 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500287 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700288 std::move(name.fText)));
289 } else {
290 this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
291 return nullptr;
292 }
293}
294
Ethan Nicholas11d53972016-11-28 11:23:23 -0500295/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700296 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
297std::unique_ptr<ASTDeclaration> Parser::declaration() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500298 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 Token lookahead = this->peek();
300 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
301 // we have an identifier that's not a type, could be the start of an interface block
302 return this->interfaceBlock(modifiers);
303 }
304 if (lookahead.fKind == Token::STRUCT) {
305 return this->structVarDeclaration(modifiers);
306 }
ethannicholas5961bc92016-10-12 06:39:56 -0700307 if (lookahead.fKind == Token::SEMICOLON) {
308 this->nextToken();
309 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
310 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700311 std::unique_ptr<ASTType> type(this->type());
312 if (!type) {
313 return nullptr;
314 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400315 if (type->fKind == ASTType::kStruct_Kind && this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700316 return nullptr;
317 }
318 Token name;
319 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
320 return nullptr;
321 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400322 if (this->checkNext(Token::LPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700323 std::vector<std::unique_ptr<ASTParameter>> parameters;
324 while (this->peek().fKind != Token::RPAREN) {
325 if (parameters.size() > 0) {
326 if (!this->expect(Token::COMMA, "','")) {
327 return nullptr;
328 }
329 }
330 std::unique_ptr<ASTParameter> parameter = this->parameter();
331 if (!parameter) {
332 return nullptr;
333 }
334 parameters.push_back(std::move(parameter));
335 }
336 this->nextToken();
337 std::unique_ptr<ASTBlock> body;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400338 if (!this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 body = this->block();
340 if (!body) {
341 return nullptr;
342 }
343 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400344 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition,
345 modifiers,
346 std::move(type),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500347 std::move(name.fText),
348 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700349 std::move(body)));
350 } else {
351 return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
352 }
353}
354
355/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700356std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500357 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700358 std::unique_ptr<ASTType> type(this->type());
359 if (!type) {
360 return nullptr;
361 }
362 Token name;
363 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
364 return nullptr;
365 }
366 return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
367}
368
369/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
370std::unique_ptr<ASTType> Parser::structDeclaration() {
371 if (!this->expect(Token::STRUCT, "'struct'")) {
372 return nullptr;
373 }
374 Token name;
375 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
376 return nullptr;
377 }
378 if (!this->expect(Token::LBRACE, "'{'")) {
379 return nullptr;
380 }
381 std::vector<Type::Field> fields;
382 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700383 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 if (!decl) {
385 return nullptr;
386 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700387 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700388 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700389 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700390 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700391 this->error(decl->fPosition, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700392 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700393 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700394 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400395 String name = type->name() + "[" + to_string(columns) + "]";
ethannicholasd598f792016-07-25 10:08:54 -0700396 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
397 fTypes.takeOwnership((Type*) type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700398 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700399 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
400 if (var.fValue) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700401 this->error(decl->fPosition, "initializers are not permitted on struct fields");
402 }
403 }
404 }
405 if (!this->expect(Token::RBRACE, "'}'")) {
406 return nullptr;
407 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500408 fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fPosition, name.fText, fields)));
Ethan Nicholas11d53972016-11-28 11:23:23 -0500409 return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500410 ASTType::kStruct_Kind, std::vector<int>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700411}
412
413/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500414std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700415 std::unique_ptr<ASTType> type = this->structDeclaration();
416 if (!type) {
417 return nullptr;
418 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400419 Token name;
420 if (this->checkNext(Token::IDENTIFIER, &name)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500421 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
422 std::move(type),
ethannicholas14fe8cc2016-09-07 13:37:16 -0700423 std::move(name.fText));
ethannicholasb3058bd2016-07-01 08:22:01 -0700424 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700425 for (const auto& var : result->fVars) {
426 if (var.fValue) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500427 this->error(var.fValue->fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 "struct variables cannot be initialized");
429 }
430 }
431 }
432 return result;
433 }
434 this->expect(Token::SEMICOLON, "';'");
435 return nullptr;
436}
437
Ethan Nicholas11d53972016-11-28 11:23:23 -0500438/* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500440std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700441 std::unique_ptr<ASTType> type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400442 String name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700443 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400445 while (this->checkNext(Token::LBRACKET)) {
446 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700447 currentVarSizes.push_back(nullptr);
448 } else {
449 std::unique_ptr<ASTExpression> size(this->expression());
450 if (!size) {
451 return nullptr;
452 }
453 currentVarSizes.push_back(std::move(size));
454 if (!this->expect(Token::RBRACKET, "']'")) {
455 return nullptr;
456 }
457 }
458 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700459 std::unique_ptr<ASTExpression> value;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400460 if (this->checkNext(Token::EQ)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700461 value = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700462 if (!value) {
463 return nullptr;
464 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700465 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700466 vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400467 while (this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700468 Token name;
469 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
470 return nullptr;
471 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700472 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700473 value.reset();
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400474 while (this->checkNext(Token::LBRACKET)) {
475 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 currentVarSizes.push_back(nullptr);
477 } else {
478 std::unique_ptr<ASTExpression> size(this->expression());
479 if (!size) {
480 return nullptr;
481 }
482 currentVarSizes.push_back(std::move(size));
483 if (!this->expect(Token::RBRACKET, "']'")) {
484 return nullptr;
485 }
486 }
487 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400488 if (this->checkNext(Token::EQ)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700489 value = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 if (!value) {
491 return nullptr;
492 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700494 vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 }
496 if (!this->expect(Token::SEMICOLON, "';'")) {
497 return nullptr;
498 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700499 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
500 std::move(type),
501 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700502}
503
504/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
505std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400506 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 std::unique_ptr<ASTType> type = this->type();
508 if (!type) {
509 return nullptr;
510 }
511 Token name;
512 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
513 return nullptr;
514 }
515 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400516 while (this->checkNext(Token::LBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700517 Token sizeToken;
518 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
519 return nullptr;
520 }
521 sizes.push_back(SkSL::stoi(sizeToken.fText));
522 if (!this->expect(Token::RBRACKET, "']'")) {
523 return nullptr;
524 }
525 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500526 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
527 std::move(type), name.fText,
ethannicholasb3058bd2016-07-01 08:22:01 -0700528 std::move(sizes)));
529}
530
531/** (EQ INT_LITERAL)? */
532int Parser::layoutInt() {
533 if (!this->expect(Token::EQ, "'='")) {
534 return -1;
535 }
536 Token resultToken;
537 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
538 return SkSL::stoi(resultToken.fText);
539 }
540 return -1;
541}
542
ethannicholas8ac838d2016-11-22 08:39:36 -0800543/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500544Layout Parser::layout() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700545 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500546 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700547 int binding = -1;
548 int index = -1;
549 int set = -1;
550 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500551 int inputAttachmentIndex = -1;
ethannicholasf789b382016-08-03 12:43:36 -0700552 bool originUpperLeft = false;
ethannicholas5961bc92016-10-12 06:39:56 -0700553 bool overrideCoverage = false;
554 bool blendSupportAllEquations = false;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500555 Layout::Format format = Layout::Format::kUnspecified;
ethannicholas8ac838d2016-11-22 08:39:36 -0800556 bool pushConstant = false;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500557 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
558 int maxVertices = -1;
559 int invocations = -1;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400560 if (this->checkNext(Token::LAYOUT)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700561 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500562 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
Ethan Nicholas11d53972016-11-28 11:23:23 -0500563 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas52cad152017-02-16 16:37:32 -0500564 pushConstant, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 }
566 for (;;) {
567 Token t = this->nextToken();
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500568 YY_BUFFER_STATE buffer;
569 buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner);
570 int token = layoutlex(fLayoutScanner);
571 layout_delete_buffer(buffer, fLayoutScanner);
572 if (token != Token::INVALID_TOKEN) {
573 switch (token) {
574 case Token::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500575 location = this->layoutInt();
576 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500577 case Token::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500578 offset = this->layoutInt();
579 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500580 case Token::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500581 binding = this->layoutInt();
582 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500583 case Token::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500584 index = this->layoutInt();
585 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500586 case Token::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500587 set = this->layoutInt();
588 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500589 case Token::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500590 builtin = this->layoutInt();
591 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500592 case Token::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500593 inputAttachmentIndex = this->layoutInt();
594 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500595 case Token::ORIGIN_UPPER_LEFT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500596 originUpperLeft = true;
597 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500598 case Token::OVERRIDE_COVERAGE:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500599 overrideCoverage = true;
600 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500601 case Token::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500602 blendSupportAllEquations = true;
603 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500604 case Token::PUSH_CONSTANT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500605 pushConstant = true;
606 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500607 case Token::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500608 primitive = Layout::kPoints_Primitive;
609 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500610 case Token::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500611 primitive = Layout::kLines_Primitive;
612 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500613 case Token::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500614 primitive = Layout::kLineStrip_Primitive;
615 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500616 case Token::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500617 primitive = Layout::kLinesAdjacency_Primitive;
618 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500619 case Token::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500620 primitive = Layout::kTriangles_Primitive;
621 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500622 case Token::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500623 primitive = Layout::kTriangleStrip_Primitive;
624 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500625 case Token::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500626 primitive = Layout::kTrianglesAdjacency_Primitive;
627 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500628 case Token::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500629 maxVertices = this->layoutInt();
630 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500631 case Token::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500632 invocations = this->layoutInt();
633 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500634 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500635 } else if (Layout::ReadFormat(t.fText, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500636 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700637 } else {
Greg Daniel64773e62016-11-22 09:44:03 -0500638 this->error(t.fPosition, ("'" + t.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -0700639 "' is not a valid layout qualifier").c_str());
640 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400641 if (this->checkNext(Token::RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700642 break;
643 }
644 if (!this->expect(Token::COMMA, "','")) {
645 break;
646 }
647 }
648 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500649 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
650 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas52cad152017-02-16 16:37:32 -0500651 pushConstant, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700652}
653
Brian Salomonf9f45122016-11-29 11:59:17 -0500654/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400655 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500656Modifiers Parser::modifiers() {
657 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700658 int flags = 0;
659 for (;;) {
660 // TODO: handle duplicate / incompatible flags
661 switch (peek().fKind) {
662 case Token::UNIFORM:
663 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500664 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700665 break;
666 case Token::CONST:
667 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500668 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700669 break;
670 case Token::IN:
671 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500672 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700673 break;
674 case Token::OUT:
675 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500676 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700677 break;
678 case Token::INOUT:
679 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500680 flags |= Modifiers::kIn_Flag;
681 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700682 break;
683 case Token::LOWP:
684 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500685 flags |= Modifiers::kLowp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700686 break;
687 case Token::MEDIUMP:
688 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500689 flags |= Modifiers::kMediump_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700690 break;
691 case Token::HIGHP:
692 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500693 flags |= Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700694 break;
ethannicholasf789b382016-08-03 12:43:36 -0700695 case Token::FLAT:
696 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500697 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700698 break;
699 case Token::NOPERSPECTIVE:
700 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500701 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700702 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500703 case Token::READONLY:
704 this->nextToken();
705 flags |= Modifiers::kReadOnly_Flag;
706 break;
707 case Token::WRITEONLY:
708 this->nextToken();
709 flags |= Modifiers::kWriteOnly_Flag;
710 break;
711 case Token::COHERENT:
712 this->nextToken();
713 flags |= Modifiers::kCoherent_Flag;
714 break;
715 case Token::VOLATILE:
716 this->nextToken();
717 flags |= Modifiers::kVolatile_Flag;
718 break;
719 case Token::RESTRICT:
720 this->nextToken();
721 flags |= Modifiers::kRestrict_Flag;
722 break;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400723 case Token::BUFFER:
724 this->nextToken();
725 flags |= Modifiers::kBuffer_Flag;
726 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400727 case Token::HASSIDEEFFECTS:
728 this->nextToken();
729 flags |= Modifiers::kHasSideEffects_Flag;
730 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700731 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500732 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700733 }
734 }
735}
736
Ethan Nicholas11d53972016-11-28 11:23:23 -0500737Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
738 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700739 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500740 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700741 }
742 return result;
743}
744
745/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
746std::unique_ptr<ASTStatement> Parser::statement() {
747 Token start = this->peek();
748 switch (start.fKind) {
749 case Token::IF:
750 return this->ifStatement();
751 case Token::FOR:
752 return this->forStatement();
753 case Token::DO:
754 return this->doStatement();
755 case Token::WHILE:
756 return this->whileStatement();
Ethan Nicholasaf197692017-02-27 13:26:45 -0500757 case Token::SWITCH:
758 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700759 case Token::RETURN:
760 return this->returnStatement();
761 case Token::BREAK:
762 return this->breakStatement();
763 case Token::CONTINUE:
764 return this->continueStatement();
765 case Token::DISCARD:
766 return this->discardStatement();
767 case Token::LBRACE:
768 return this->block();
769 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500770 this->nextToken();
771 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
ethannicholas0730be72016-09-01 07:59:02 -0700772 std::vector<std::unique_ptr<ASTStatement>>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700773 case Token::CONST: // fall through
774 case Token::HIGHP: // fall through
775 case Token::MEDIUMP: // fall through
776 case Token::LOWP: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700777 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700778 if (!decl) {
779 return nullptr;
780 }
781 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
782 }
783 case Token::IDENTIFIER:
784 if (this->isType(start.fText)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700785 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700786 if (!decl) {
787 return nullptr;
788 }
789 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
790 std::move(decl)));
791 }
792 // fall through
793 default:
794 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500795 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700796}
797
Ethan Nicholas50afc172017-02-16 14:49:57 -0500798/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
ethannicholasb3058bd2016-07-01 08:22:01 -0700799std::unique_ptr<ASTType> Parser::type() {
800 Token type;
801 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
802 return nullptr;
803 }
804 if (!this->isType(type.fText)) {
805 this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
806 return nullptr;
807 }
Ethan Nicholas50afc172017-02-16 14:49:57 -0500808 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400809 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500810 if (this->peek().fKind != Token::RBRACKET) {
811 int64_t i;
812 if (this->intLiteral(&i)) {
813 sizes.push_back(i);
814 } else {
815 return nullptr;
816 }
817 } else {
818 sizes.push_back(-1);
819 }
820 this->expect(Token::RBRACKET, "']'");
821 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500822 return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500823 ASTType::kIdentifier_Kind, sizes));
ethannicholasb3058bd2016-07-01 08:22:01 -0700824}
825
Ethan Nicholas50afc172017-02-16 14:49:57 -0500826/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500827std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700828 Token name;
829 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
830 return nullptr;
831 }
832 if (peek().fKind != Token::LBRACE) {
833 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500834 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700835 // it's better to report it as an unknown type
836 this->error(name.fPosition, "no type named '" + name.fText + "'");
837 return nullptr;
838 }
839 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500840 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700841 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700842 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700843 if (!decl) {
844 return nullptr;
845 }
846 decls.push_back(std::move(decl));
847 }
848 this->nextToken();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500849 std::vector<std::unique_ptr<ASTExpression>> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400850 Token instanceName;
851 if (this->checkNext(Token::IDENTIFIER, &instanceName)) {
852 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500853 if (this->peek().fKind != Token::RBRACKET) {
854 std::unique_ptr<ASTExpression> size = this->expression();
855 if (!size) {
856 return nullptr;
857 }
858 sizes.push_back(std::move(size));
859 } else {
860 sizes.push_back(nullptr);
861 }
862 this->expect(Token::RBRACKET, "']'");
863 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700864 }
865 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas11d53972016-11-28 11:23:23 -0500866 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500867 name.fText, std::move(decls),
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400868 std::move(instanceName.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500869 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700870}
871
872/* IF LPAREN expression RPAREN statement (ELSE statement)? */
873std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
874 Token start;
875 if (!this->expect(Token::IF, "'if'", &start)) {
876 return nullptr;
877 }
878 if (!this->expect(Token::LPAREN, "'('")) {
879 return nullptr;
880 }
881 std::unique_ptr<ASTExpression> test(this->expression());
882 if (!test) {
883 return nullptr;
884 }
885 if (!this->expect(Token::RPAREN, "')'")) {
886 return nullptr;
887 }
888 std::unique_ptr<ASTStatement> ifTrue(this->statement());
889 if (!ifTrue) {
890 return nullptr;
891 }
892 std::unique_ptr<ASTStatement> ifFalse;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400893 if (this->checkNext(Token::ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700894 ifFalse = this->statement();
895 if (!ifFalse) {
896 return nullptr;
897 }
898 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500899 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, std::move(test),
900 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -0700901 std::move(ifFalse)));
902}
903
904/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
905std::unique_ptr<ASTDoStatement> Parser::doStatement() {
906 Token start;
907 if (!this->expect(Token::DO, "'do'", &start)) {
908 return nullptr;
909 }
910 std::unique_ptr<ASTStatement> statement(this->statement());
911 if (!statement) {
912 return nullptr;
913 }
914 if (!this->expect(Token::WHILE, "'while'")) {
915 return nullptr;
916 }
917 if (!this->expect(Token::LPAREN, "'('")) {
918 return nullptr;
919 }
920 std::unique_ptr<ASTExpression> test(this->expression());
921 if (!test) {
922 return nullptr;
923 }
924 if (!this->expect(Token::RPAREN, "')'")) {
925 return nullptr;
926 }
927 if (!this->expect(Token::SEMICOLON, "';'")) {
928 return nullptr;
929 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500930 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700931 std::move(statement),
932 std::move(test)));
933}
934
935/* WHILE LPAREN expression RPAREN STATEMENT */
936std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
937 Token start;
938 if (!this->expect(Token::WHILE, "'while'", &start)) {
939 return nullptr;
940 }
941 if (!this->expect(Token::LPAREN, "'('")) {
942 return nullptr;
943 }
944 std::unique_ptr<ASTExpression> test(this->expression());
945 if (!test) {
946 return nullptr;
947 }
948 if (!this->expect(Token::RPAREN, "')'")) {
949 return nullptr;
950 }
951 std::unique_ptr<ASTStatement> statement(this->statement());
952 if (!statement) {
953 return nullptr;
954 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500955 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
956 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -0700957 std::move(statement)));
958}
959
Ethan Nicholasaf197692017-02-27 13:26:45 -0500960/* CASE expression COLON statement* */
961std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
962 Token start;
963 if (!this->expect(Token::CASE, "'case'", &start)) {
964 return nullptr;
965 }
966 std::unique_ptr<ASTExpression> value = this->expression();
967 if (!value) {
968 return nullptr;
969 }
970 if (!this->expect(Token::COLON, "':'")) {
971 return nullptr;
972 }
973 std::vector<std::unique_ptr<ASTStatement>> statements;
974 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
975 this->peek().fKind != Token::DEFAULT) {
976 std::unique_ptr<ASTStatement> s = this->statement();
977 if (!s) {
978 return nullptr;
979 }
980 statements.push_back(std::move(s));
981 }
982 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fPosition, std::move(value),
983 std::move(statements)));
984}
985
986/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
987std::unique_ptr<ASTStatement> Parser::switchStatement() {
988 Token start;
989 if (!this->expect(Token::SWITCH, "'switch'", &start)) {
990 return nullptr;
991 }
992 if (!this->expect(Token::LPAREN, "'('")) {
993 return nullptr;
994 }
995 std::unique_ptr<ASTExpression> value(this->expression());
996 if (!value) {
997 return nullptr;
998 }
999 if (!this->expect(Token::RPAREN, "')'")) {
1000 return nullptr;
1001 }
1002 if (!this->expect(Token::LBRACE, "'{'")) {
1003 return nullptr;
1004 }
1005 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1006 while (this->peek().fKind == Token::CASE) {
1007 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1008 if (!c) {
1009 return nullptr;
1010 }
1011 cases.push_back(std::move(c));
1012 }
1013 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1014 // parts of the compiler may rely upon this assumption.
1015 if (this->peek().fKind == Token::DEFAULT) {
1016 Token defaultStart;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001017 ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001018 if (!this->expect(Token::COLON, "':'")) {
1019 return nullptr;
1020 }
1021 std::vector<std::unique_ptr<ASTStatement>> statements;
1022 while (this->peek().fKind != Token::RBRACE) {
1023 std::unique_ptr<ASTStatement> s = this->statement();
1024 if (!s) {
1025 return nullptr;
1026 }
1027 statements.push_back(std::move(s));
1028 }
1029 cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr,
1030 std::move(statements)));
1031 }
1032 if (!this->expect(Token::RBRACE, "'}'")) {
1033 return nullptr;
1034 }
1035 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition,
1036 std::move(value),
1037 std::move(cases)));
1038}
1039
Ethan Nicholas11d53972016-11-28 11:23:23 -05001040/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 STATEMENT */
1042std::unique_ptr<ASTForStatement> Parser::forStatement() {
1043 Token start;
1044 if (!this->expect(Token::FOR, "'for'", &start)) {
1045 return nullptr;
1046 }
1047 if (!this->expect(Token::LPAREN, "'('")) {
1048 return nullptr;
1049 }
1050 std::unique_ptr<ASTStatement> initializer;
1051 Token nextToken = this->peek();
1052 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001053 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001054 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001056 case Token::CONST: {
1057 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1058 if (!vd) {
1059 return nullptr;
1060 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001061 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001062 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001064 }
1065 case Token::IDENTIFIER: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 if (this->isType(nextToken.fText)) {
ethannicholasa54401d2016-10-14 08:37:32 -07001067 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1068 if (!vd) {
1069 return nullptr;
1070 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001072 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 break;
1074 }
ethannicholasa54401d2016-10-14 08:37:32 -07001075 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001076 default:
1077 initializer = this->expressionStatement();
1078 }
1079 std::unique_ptr<ASTExpression> test;
1080 if (this->peek().fKind != Token::SEMICOLON) {
1081 test = this->expression();
1082 if (!test) {
1083 return nullptr;
1084 }
1085 }
1086 if (!this->expect(Token::SEMICOLON, "';'")) {
1087 return nullptr;
1088 }
1089 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001090 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 next = this->expression();
1092 if (!next) {
1093 return nullptr;
1094 }
1095 }
1096 if (!this->expect(Token::RPAREN, "')'")) {
1097 return nullptr;
1098 }
1099 std::unique_ptr<ASTStatement> statement(this->statement());
1100 if (!statement) {
1101 return nullptr;
1102 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001103 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 std::move(initializer),
1105 std::move(test), std::move(next),
1106 std::move(statement)));
1107}
1108
1109/* RETURN expression? SEMICOLON */
1110std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1111 Token start;
1112 if (!this->expect(Token::RETURN, "'return'", &start)) {
1113 return nullptr;
1114 }
1115 std::unique_ptr<ASTExpression> expression;
1116 if (this->peek().fKind != Token::SEMICOLON) {
1117 expression = this->expression();
1118 if (!expression) {
1119 return nullptr;
1120 }
1121 }
1122 if (!this->expect(Token::SEMICOLON, "';'")) {
1123 return nullptr;
1124 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001125 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 std::move(expression)));
1127}
1128
1129/* BREAK SEMICOLON */
1130std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1131 Token start;
1132 if (!this->expect(Token::BREAK, "'break'", &start)) {
1133 return nullptr;
1134 }
1135 if (!this->expect(Token::SEMICOLON, "';'")) {
1136 return nullptr;
1137 }
1138 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
1139}
1140
1141/* CONTINUE SEMICOLON */
1142std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1143 Token start;
1144 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1145 return nullptr;
1146 }
1147 if (!this->expect(Token::SEMICOLON, "';'")) {
1148 return nullptr;
1149 }
1150 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
1151}
1152
1153/* DISCARD SEMICOLON */
1154std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1155 Token start;
1156 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1157 return nullptr;
1158 }
1159 if (!this->expect(Token::SEMICOLON, "';'")) {
1160 return nullptr;
1161 }
1162 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
1163}
1164
1165/* LBRACE statement* RBRACE */
1166std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001167 AutoDepth depth(this);
1168 if (!depth.checkValid()) {
1169 return nullptr;
1170 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001171 Token start;
1172 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1173 return nullptr;
1174 }
1175 std::vector<std::unique_ptr<ASTStatement>> statements;
1176 for (;;) {
1177 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001178 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001179 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001180 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001181 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001182 case Token::END_OF_FILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001183 this->error(this->peek().fPosition, "expected '}', but found end of file");
1184 return nullptr;
1185 default: {
1186 std::unique_ptr<ASTStatement> statement = this->statement();
1187 if (!statement) {
1188 return nullptr;
1189 }
1190 statements.push_back(std::move(statement));
1191 }
1192 }
1193 }
1194}
1195
1196/* expression SEMICOLON */
1197std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1198 std::unique_ptr<ASTExpression> expr = this->expression();
1199 if (expr) {
1200 if (this->expect(Token::SEMICOLON, "';'")) {
1201 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1202 return std::unique_ptr<ASTExpressionStatement>(result);
1203 }
1204 }
1205 return nullptr;
1206}
1207
1208/* assignmentExpression */
1209std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001210 AutoDepth depth(this);
1211 if (!depth.checkValid()) {
1212 return nullptr;
1213 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001214 return this->assignmentExpression();
1215}
1216
1217/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1218 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1219 assignmentExpression)*
1220 */
1221std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1222 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1223 if (!result) {
1224 return nullptr;
1225 }
1226 for (;;) {
1227 switch (this->peek().fKind) {
1228 case Token::EQ: // fall through
1229 case Token::STAREQ: // fall through
1230 case Token::SLASHEQ: // fall through
1231 case Token::PERCENTEQ: // fall through
1232 case Token::PLUSEQ: // fall through
1233 case Token::MINUSEQ: // fall through
1234 case Token::SHLEQ: // fall through
1235 case Token::SHREQ: // fall through
1236 case Token::BITWISEANDEQ: // fall through
1237 case Token::BITWISEXOREQ: // fall through
1238 case Token::BITWISEOREQ: // fall through
1239 case Token::LOGICALANDEQ: // fall through
1240 case Token::LOGICALXOREQ: // fall through
1241 case Token::LOGICALOREQ: {
1242 Token t = this->nextToken();
1243 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1244 if (!right) {
1245 return nullptr;
1246 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001247 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
1248 t,
ethannicholasb3058bd2016-07-01 08:22:01 -07001249 std::move(right)));
1250 }
1251 default:
1252 return result;
1253 }
1254 }
1255}
1256
1257/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1258std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1259 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1260 if (!result) {
1261 return nullptr;
1262 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001263 if (this->checkNext(Token::QUESTION)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001264 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1265 if (!trueExpr) {
1266 return nullptr;
1267 }
1268 if (this->expect(Token::COLON, "':'")) {
1269 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001270 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1271 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001272 std::move(falseExpr)));
1273 }
1274 return nullptr;
1275 }
1276 return result;
1277}
1278
1279/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1280std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1281 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1282 if (!result) {
1283 return nullptr;
1284 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001285 Token t;
1286 while (this->checkNext(Token::LOGICALOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001287 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
1288 if (!right) {
1289 return nullptr;
1290 }
1291 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1292 }
1293 return result;
1294}
1295
1296/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1297std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1298 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1299 if (!result) {
1300 return nullptr;
1301 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001302 Token t;
1303 while (this->checkNext(Token::LOGICALXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001304 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1305 if (!right) {
1306 return nullptr;
1307 }
1308 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1309 }
1310 return result;
1311}
1312
1313/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1314std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1315 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1316 if (!result) {
1317 return nullptr;
1318 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001319 Token t;
1320 while (this->checkNext(Token::LOGICALAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001321 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1322 if (!right) {
1323 return nullptr;
1324 }
1325 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1326 }
1327 return result;
1328}
1329
1330/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1331std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1332 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1333 if (!result) {
1334 return nullptr;
1335 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001336 Token t;
1337 while (this->checkNext(Token::BITWISEOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001338 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1339 if (!right) {
1340 return nullptr;
1341 }
1342 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1343 }
1344 return result;
1345}
1346
1347/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1348std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1349 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1350 if (!result) {
1351 return nullptr;
1352 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001353 Token t;
1354 while (this->checkNext(Token::BITWISEXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001355 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1356 if (!right) {
1357 return nullptr;
1358 }
1359 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1360 }
1361 return result;
1362}
1363
1364/* equalityExpression (BITWISEAND equalityExpression)* */
1365std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1366 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1367 if (!result) {
1368 return nullptr;
1369 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001370 Token t;
1371 while (this->checkNext(Token::BITWISEAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001372 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1373 if (!right) {
1374 return nullptr;
1375 }
1376 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1377 }
1378 return result;
1379}
1380
1381/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1382std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1383 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1384 if (!result) {
1385 return nullptr;
1386 }
1387 for (;;) {
1388 switch (this->peek().fKind) {
1389 case Token::EQEQ: // fall through
1390 case Token::NEQ: {
1391 Token t = this->nextToken();
1392 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1393 if (!right) {
1394 return nullptr;
1395 }
1396 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1397 break;
1398 }
1399 default:
1400 return result;
1401 }
1402 }
1403}
1404
1405/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1406std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1407 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1408 if (!result) {
1409 return nullptr;
1410 }
1411 for (;;) {
1412 switch (this->peek().fKind) {
1413 case Token::LT: // fall through
1414 case Token::GT: // fall through
1415 case Token::LTEQ: // fall through
1416 case Token::GTEQ: {
1417 Token t = this->nextToken();
1418 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1419 if (!right) {
1420 return nullptr;
1421 }
1422 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1423 break;
1424 }
1425 default:
1426 return result;
1427 }
1428 }
1429}
1430
1431/* additiveExpression ((SHL | SHR) additiveExpression)* */
1432std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1433 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1434 if (!result) {
1435 return nullptr;
1436 }
1437 for (;;) {
1438 switch (this->peek().fKind) {
1439 case Token::SHL: // fall through
1440 case Token::SHR: {
1441 Token t = this->nextToken();
1442 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1443 if (!right) {
1444 return nullptr;
1445 }
1446 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1447 break;
1448 }
1449 default:
1450 return result;
1451 }
1452 }
1453}
1454
1455/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1456std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1457 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1458 if (!result) {
1459 return nullptr;
1460 }
1461 for (;;) {
1462 switch (this->peek().fKind) {
1463 case Token::PLUS: // fall through
1464 case Token::MINUS: {
1465 Token t = this->nextToken();
1466 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1467 if (!right) {
1468 return nullptr;
1469 }
1470 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1471 break;
1472 }
1473 default:
1474 return result;
1475 }
1476 }
1477}
1478
1479/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1480std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1481 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1482 if (!result) {
1483 return nullptr;
1484 }
1485 for (;;) {
1486 switch (this->peek().fKind) {
1487 case Token::STAR: // fall through
1488 case Token::SLASH: // fall through
1489 case Token::PERCENT: {
1490 Token t = this->nextToken();
1491 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1492 if (!right) {
1493 return nullptr;
1494 }
1495 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1496 break;
1497 }
1498 default:
1499 return result;
1500 }
1501 }
1502}
1503
1504/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1505std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1506 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001507 case Token::PLUS: // fall through
1508 case Token::MINUS: // fall through
1509 case Token::LOGICALNOT: // fall through
1510 case Token::BITWISENOT: // fall through
1511 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 case Token::MINUSMINUS: {
1513 Token t = this->nextToken();
1514 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1515 if (!expr) {
1516 return nullptr;
1517 }
1518 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
1519 }
1520 default:
1521 return this->postfixExpression();
1522 }
1523}
1524
1525/* term suffix* */
1526std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1527 std::unique_ptr<ASTExpression> result = this->term();
1528 if (!result) {
1529 return nullptr;
1530 }
1531 for (;;) {
1532 switch (this->peek().fKind) {
1533 case Token::LBRACKET: // fall through
1534 case Token::DOT: // fall through
1535 case Token::LPAREN: // fall through
1536 case Token::PLUSPLUS: // fall through
1537 case Token::MINUSMINUS: {
1538 std::unique_ptr<ASTSuffix> s = this->suffix();
1539 if (!s) {
1540 return nullptr;
1541 }
1542 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1543 break;
1544 }
1545 default:
1546 return result;
1547 }
1548 }
1549}
1550
Ethan Nicholas11d53972016-11-28 11:23:23 -05001551/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
ethannicholasb3058bd2016-07-01 08:22:01 -07001552 PLUSPLUS | MINUSMINUS */
1553std::unique_ptr<ASTSuffix> Parser::suffix() {
1554 Token next = this->nextToken();
1555 switch (next.fKind) {
1556 case Token::LBRACKET: {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001557 if (this->checkNext(Token::RBRACKET)) {
ethannicholas5961bc92016-10-12 06:39:56 -07001558 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
1559 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001560 std::unique_ptr<ASTExpression> e = this->expression();
1561 if (!e) {
1562 return nullptr;
1563 }
1564 this->expect(Token::RBRACKET, "']' to complete array access expression");
1565 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1566 }
1567 case Token::DOT: {
1568 Position pos = this->peek().fPosition;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001569 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001570 if (this->identifier(&text)) {
1571 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
1572 }
1573 return nullptr;
1574 }
1575 case Token::LPAREN: {
1576 std::vector<std::unique_ptr<ASTExpression>> parameters;
1577 if (this->peek().fKind != Token::RPAREN) {
1578 for (;;) {
1579 std::unique_ptr<ASTExpression> expr = this->expression();
1580 if (!expr) {
1581 return nullptr;
1582 }
1583 parameters.push_back(std::move(expr));
1584 if (this->peek().fKind != Token::COMMA) {
1585 break;
1586 }
1587 this->nextToken();
1588 }
1589 }
1590 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas11d53972016-11-28 11:23:23 -05001591 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001592 std::move(parameters)));
1593 }
1594 case Token::PLUSPLUS:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001595 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 ASTSuffix::kPostIncrement_Kind));
1597 case Token::MINUSMINUS:
1598 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1599 ASTSuffix::kPostDecrement_Kind));
1600 default: {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001601 this->error(next.fPosition, "expected expression suffix, but found '" + next.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -07001602 "'\n");
1603 return nullptr;
1604 }
1605 }
1606}
1607
1608/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1609std::unique_ptr<ASTExpression> Parser::term() {
1610 std::unique_ptr<ASTExpression> result;
1611 Token t = this->peek();
1612 switch (t.fKind) {
1613 case Token::IDENTIFIER: {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001614 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001615 if (this->identifier(&text)) {
1616 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
1617 }
1618 break;
1619 }
1620 case Token::INT_LITERAL: {
1621 int64_t i;
1622 if (this->intLiteral(&i)) {
1623 result.reset(new ASTIntLiteral(t.fPosition, i));
1624 }
1625 break;
1626 }
1627 case Token::FLOAT_LITERAL: {
1628 double f;
1629 if (this->floatLiteral(&f)) {
1630 result.reset(new ASTFloatLiteral(t.fPosition, f));
1631 }
1632 break;
1633 }
1634 case Token::TRUE_LITERAL: // fall through
1635 case Token::FALSE_LITERAL: {
1636 bool b;
1637 if (this->boolLiteral(&b)) {
1638 result.reset(new ASTBoolLiteral(t.fPosition, b));
1639 }
1640 break;
1641 }
1642 case Token::LPAREN: {
1643 this->nextToken();
1644 result = this->expression();
1645 if (result) {
1646 this->expect(Token::RPAREN, "')' to complete expression");
1647 }
1648 break;
1649 }
1650 default:
1651 this->nextToken();
1652 this->error(t.fPosition, "expected expression, but found '" + t.fText + "'\n");
1653 result = nullptr;
1654 }
1655 return result;
1656}
1657
1658/* INT_LITERAL */
1659bool Parser::intLiteral(int64_t* dest) {
1660 Token t;
1661 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1662 *dest = SkSL::stol(t.fText);
1663 return true;
1664 }
1665 return false;
1666}
1667
1668/* FLOAT_LITERAL */
1669bool Parser::floatLiteral(double* dest) {
1670 Token t;
1671 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1672 *dest = SkSL::stod(t.fText);
1673 return true;
1674 }
1675 return false;
1676}
1677
1678/* TRUE_LITERAL | FALSE_LITERAL */
1679bool Parser::boolLiteral(bool* dest) {
1680 Token t = this->nextToken();
1681 switch (t.fKind) {
1682 case Token::TRUE_LITERAL:
1683 *dest = true;
1684 return true;
1685 case Token::FALSE_LITERAL:
1686 *dest = false;
1687 return true;
1688 default:
1689 this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1690 return false;
1691 }
1692}
1693
1694/* IDENTIFIER */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001695bool Parser::identifier(String* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001696 Token t;
1697 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001698 *dest = t.fText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001699 return true;
1700 }
1701 return false;
1702}
1703
1704} // namespace