blob: 5e8ec6398b06759aa5064caa71e345d4995af084 [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 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400170 Position p = Position(skslget_lineno(fScanner), -1);
171 if (token == Token::INVALID_TOKEN) {
172 this->error(p, "invalid token: '" + text + "'");
173 }
174 return Token(p, (Token::Kind) token, text);
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
177void Parser::pushback(Token t) {
178 ASSERT(fPushback.fKind == Token::INVALID_TOKEN);
179 fPushback = t;
180}
181
182Token Parser::peek() {
183 fPushback = this->nextToken();
184 return fPushback;
185}
186
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400187bool Parser::checkNext(Token::Kind kind, Token* result) {
188 Token next = this->nextToken();
189 if (next.fKind == kind) {
190 if (result) {
191 *result = next;
192 }
193 return true;
194 }
195 this->pushback(next);
196 return false;
197}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500198
199bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400200 return this->expect(kind, String(expected), result);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500201}
202
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400203bool Parser::expect(Token::Kind kind, String expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700204 Token next = this->nextToken();
205 if (next.fKind == kind) {
206 if (result) {
207 *result = next;
208 }
209 return true;
210 } else {
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500211 if (next.fText.size()) {
212 this->error(next.fPosition, "expected " + expected + ", but found '" + next.fText +
213 "'");
214 } else {
215 this->error(next.fPosition, "parse error, recompile in debug mode for details");
216 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700217 return false;
218 }
219}
220
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500221void Parser::error(Position p, const char* msg) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400222 this->error(p, String(msg));
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500223}
224
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400225void Parser::error(Position p, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700226 fErrors.error(p, msg);
227}
228
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400229bool Parser::isType(String name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700230 return nullptr != fTypes[name];
231}
232
233/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
ethannicholas5961bc92016-10-12 06:39:56 -0700234std::unique_ptr<ASTDeclaration> Parser::precision() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700235 if (!this->expect(Token::PRECISION, "'precision'")) {
ethannicholas5961bc92016-10-12 06:39:56 -0700236 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 }
ethannicholas5961bc92016-10-12 06:39:56 -0700238 Modifiers::Flag result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700239 Token p = this->nextToken();
240 switch (p.fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -0700241 case Token::LOWP:
242 result = Modifiers::kLowp_Flag;
243 break;
244 case Token::MEDIUMP:
245 result = Modifiers::kMediump_Flag;
246 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 case Token::HIGHP:
ethannicholas5961bc92016-10-12 06:39:56 -0700248 result = Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700249 break;
250 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500251 this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
ethannicholasb3058bd2016-07-01 08:22:01 -0700252 p.fText + "'");
ethannicholas5961bc92016-10-12 06:39:56 -0700253 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 }
ethannicholas5961bc92016-10-12 06:39:56 -0700255 // FIXME handle the type
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 if (!this->type()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700257 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700258 }
259 this->expect(Token::SEMICOLON, "';'");
ethannicholas5961bc92016-10-12 06:39:56 -0700260 return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
ethannicholasb3058bd2016-07-01 08:22:01 -0700261}
262
Ethan Nicholas11d53972016-11-28 11:23:23 -0500263/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700264 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700265std::unique_ptr<ASTDeclaration> Parser::directive() {
266 Token start;
267 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
268 return nullptr;
269 }
270 if (start.fText == "#version") {
271 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700272 Token next = this->peek();
273 if (next.fText == "es" || next.fText == "compatibility") {
274 this->nextToken();
275 }
276 // version is ignored for now; it will eventually become an error when we stop pretending
277 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700278 return nullptr;
279 } else if (start.fText == "#extension") {
280 Token name;
281 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
282 return nullptr;
283 }
284 if (!this->expect(Token::COLON, "':'")) {
285 return nullptr;
286 }
287 // FIXME: need to start paying attention to this token
288 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
289 return nullptr;
290 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500291 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700292 std::move(name.fText)));
293 } else {
294 this->error(start.fPosition, "unsupported directive '" + start.fText + "'");
295 return nullptr;
296 }
297}
298
Ethan Nicholas11d53972016-11-28 11:23:23 -0500299/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
301std::unique_ptr<ASTDeclaration> Parser::declaration() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500302 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700303 Token lookahead = this->peek();
304 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
305 // we have an identifier that's not a type, could be the start of an interface block
306 return this->interfaceBlock(modifiers);
307 }
308 if (lookahead.fKind == Token::STRUCT) {
309 return this->structVarDeclaration(modifiers);
310 }
ethannicholas5961bc92016-10-12 06:39:56 -0700311 if (lookahead.fKind == Token::SEMICOLON) {
312 this->nextToken();
313 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
314 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700315 std::unique_ptr<ASTType> type(this->type());
316 if (!type) {
317 return nullptr;
318 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400319 if (type->fKind == ASTType::kStruct_Kind && this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700320 return nullptr;
321 }
322 Token name;
323 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
324 return nullptr;
325 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400326 if (this->checkNext(Token::LPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700327 std::vector<std::unique_ptr<ASTParameter>> parameters;
328 while (this->peek().fKind != Token::RPAREN) {
329 if (parameters.size() > 0) {
330 if (!this->expect(Token::COMMA, "','")) {
331 return nullptr;
332 }
333 }
334 std::unique_ptr<ASTParameter> parameter = this->parameter();
335 if (!parameter) {
336 return nullptr;
337 }
338 parameters.push_back(std::move(parameter));
339 }
340 this->nextToken();
341 std::unique_ptr<ASTBlock> body;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400342 if (!this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700343 body = this->block();
344 if (!body) {
345 return nullptr;
346 }
347 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400348 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition,
349 modifiers,
350 std::move(type),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500351 std::move(name.fText),
352 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 std::move(body)));
354 } else {
355 return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
356 }
357}
358
359/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700360std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500361 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700362 std::unique_ptr<ASTType> type(this->type());
363 if (!type) {
364 return nullptr;
365 }
366 Token name;
367 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
368 return nullptr;
369 }
370 return this->varDeclarationEnd(modifiers, std::move(type), std::move(name.fText));
371}
372
373/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
374std::unique_ptr<ASTType> Parser::structDeclaration() {
375 if (!this->expect(Token::STRUCT, "'struct'")) {
376 return nullptr;
377 }
378 Token name;
379 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
380 return nullptr;
381 }
382 if (!this->expect(Token::LBRACE, "'{'")) {
383 return nullptr;
384 }
385 std::vector<Type::Field> fields;
386 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700387 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700388 if (!decl) {
389 return nullptr;
390 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700391 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700392 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700393 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700394 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700395 this->error(decl->fPosition, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700396 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700397 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700398 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400399 String name = type->name() + "[" + to_string(columns) + "]";
ethannicholasd598f792016-07-25 10:08:54 -0700400 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
401 fTypes.takeOwnership((Type*) type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700402 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700403 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
404 if (var.fValue) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700405 this->error(decl->fPosition, "initializers are not permitted on struct fields");
406 }
407 }
408 }
409 if (!this->expect(Token::RBRACE, "'}'")) {
410 return nullptr;
411 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500412 fTypes.add(name.fText, std::unique_ptr<Type>(new Type(name.fPosition, name.fText, fields)));
Ethan Nicholas11d53972016-11-28 11:23:23 -0500413 return std::unique_ptr<ASTType>(new ASTType(name.fPosition, name.fText,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500414 ASTType::kStruct_Kind, std::vector<int>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700415}
416
417/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500418std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700419 std::unique_ptr<ASTType> type = this->structDeclaration();
420 if (!type) {
421 return nullptr;
422 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400423 Token name;
424 if (this->checkNext(Token::IDENTIFIER, &name)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500425 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
426 std::move(type),
ethannicholas14fe8cc2016-09-07 13:37:16 -0700427 std::move(name.fText));
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700429 for (const auto& var : result->fVars) {
430 if (var.fValue) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500431 this->error(var.fValue->fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 "struct variables cannot be initialized");
433 }
434 }
435 }
436 return result;
437 }
438 this->expect(Token::SEMICOLON, "';'");
439 return nullptr;
440}
441
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400442/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
443 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500444std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700445 std::unique_ptr<ASTType> type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400446 String name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700447 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700448 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400449 while (this->checkNext(Token::LBRACKET)) {
450 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700451 currentVarSizes.push_back(nullptr);
452 } else {
453 std::unique_ptr<ASTExpression> size(this->expression());
454 if (!size) {
455 return nullptr;
456 }
457 currentVarSizes.push_back(std::move(size));
458 if (!this->expect(Token::RBRACKET, "']'")) {
459 return nullptr;
460 }
461 }
462 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700463 std::unique_ptr<ASTExpression> value;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400464 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400465 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700466 if (!value) {
467 return nullptr;
468 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700470 vars.emplace_back(std::move(name), std::move(currentVarSizes), std::move(value));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400471 while (this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700472 Token name;
473 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
474 return nullptr;
475 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700477 value.reset();
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400478 while (this->checkNext(Token::LBRACKET)) {
479 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700480 currentVarSizes.push_back(nullptr);
481 } else {
482 std::unique_ptr<ASTExpression> size(this->expression());
483 if (!size) {
484 return nullptr;
485 }
486 currentVarSizes.push_back(std::move(size));
487 if (!this->expect(Token::RBRACKET, "']'")) {
488 return nullptr;
489 }
490 }
491 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400492 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400493 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 if (!value) {
495 return nullptr;
496 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700497 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700498 vars.emplace_back(std::move(name.fText), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 }
500 if (!this->expect(Token::SEMICOLON, "';'")) {
501 return nullptr;
502 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700503 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
504 std::move(type),
505 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700506}
507
508/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
509std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400510 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 std::unique_ptr<ASTType> type = this->type();
512 if (!type) {
513 return nullptr;
514 }
515 Token name;
516 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
517 return nullptr;
518 }
519 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400520 while (this->checkNext(Token::LBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700521 Token sizeToken;
522 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
523 return nullptr;
524 }
525 sizes.push_back(SkSL::stoi(sizeToken.fText));
526 if (!this->expect(Token::RBRACKET, "']'")) {
527 return nullptr;
528 }
529 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500530 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifiers,
531 std::move(type), name.fText,
ethannicholasb3058bd2016-07-01 08:22:01 -0700532 std::move(sizes)));
533}
534
535/** (EQ INT_LITERAL)? */
536int Parser::layoutInt() {
537 if (!this->expect(Token::EQ, "'='")) {
538 return -1;
539 }
540 Token resultToken;
541 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
542 return SkSL::stoi(resultToken.fText);
543 }
544 return -1;
545}
546
ethannicholas8ac838d2016-11-22 08:39:36 -0800547/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500548Layout Parser::layout() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700549 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500550 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700551 int binding = -1;
552 int index = -1;
553 int set = -1;
554 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500555 int inputAttachmentIndex = -1;
ethannicholasf789b382016-08-03 12:43:36 -0700556 bool originUpperLeft = false;
ethannicholas5961bc92016-10-12 06:39:56 -0700557 bool overrideCoverage = false;
558 bool blendSupportAllEquations = false;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500559 Layout::Format format = Layout::Format::kUnspecified;
ethannicholas8ac838d2016-11-22 08:39:36 -0800560 bool pushConstant = false;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500561 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
562 int maxVertices = -1;
563 int invocations = -1;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400564 if (this->checkNext(Token::LAYOUT)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500566 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
Ethan Nicholas11d53972016-11-28 11:23:23 -0500567 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas52cad152017-02-16 16:37:32 -0500568 pushConstant, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700569 }
570 for (;;) {
571 Token t = this->nextToken();
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500572 YY_BUFFER_STATE buffer;
573 buffer = layout_scan_string(t.fText.c_str(), fLayoutScanner);
574 int token = layoutlex(fLayoutScanner);
575 layout_delete_buffer(buffer, fLayoutScanner);
576 if (token != Token::INVALID_TOKEN) {
577 switch (token) {
578 case Token::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500579 location = this->layoutInt();
580 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500581 case Token::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500582 offset = this->layoutInt();
583 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500584 case Token::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500585 binding = this->layoutInt();
586 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500587 case Token::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500588 index = this->layoutInt();
589 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500590 case Token::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500591 set = this->layoutInt();
592 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500593 case Token::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500594 builtin = this->layoutInt();
595 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500596 case Token::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500597 inputAttachmentIndex = this->layoutInt();
598 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500599 case Token::ORIGIN_UPPER_LEFT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500600 originUpperLeft = true;
601 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500602 case Token::OVERRIDE_COVERAGE:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500603 overrideCoverage = true;
604 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500605 case Token::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500606 blendSupportAllEquations = true;
607 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500608 case Token::PUSH_CONSTANT:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500609 pushConstant = true;
610 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500611 case Token::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500612 primitive = Layout::kPoints_Primitive;
613 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500614 case Token::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500615 primitive = Layout::kLines_Primitive;
616 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500617 case Token::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500618 primitive = Layout::kLineStrip_Primitive;
619 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500620 case Token::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500621 primitive = Layout::kLinesAdjacency_Primitive;
622 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500623 case Token::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500624 primitive = Layout::kTriangles_Primitive;
625 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500626 case Token::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500627 primitive = Layout::kTriangleStrip_Primitive;
628 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500629 case Token::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500630 primitive = Layout::kTrianglesAdjacency_Primitive;
631 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500632 case Token::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500633 maxVertices = this->layoutInt();
634 break;
Ethan Nicholasbfe15f62017-03-01 11:46:51 -0500635 case Token::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500636 invocations = this->layoutInt();
637 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500638 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500639 } else if (Layout::ReadFormat(t.fText, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500640 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 } else {
Greg Daniel64773e62016-11-22 09:44:03 -0500642 this->error(t.fPosition, ("'" + t.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 "' is not a valid layout qualifier").c_str());
644 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400645 if (this->checkNext(Token::RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 break;
647 }
648 if (!this->expect(Token::COMMA, "','")) {
649 break;
650 }
651 }
652 }
Ethan Nicholas19671772016-11-28 16:30:17 -0500653 return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
654 originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
Ethan Nicholas52cad152017-02-16 16:37:32 -0500655 pushConstant, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700656}
657
Brian Salomonf9f45122016-11-29 11:59:17 -0500658/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400659 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500660Modifiers Parser::modifiers() {
661 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700662 int flags = 0;
663 for (;;) {
664 // TODO: handle duplicate / incompatible flags
665 switch (peek().fKind) {
666 case Token::UNIFORM:
667 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500668 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700669 break;
670 case Token::CONST:
671 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500672 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700673 break;
674 case Token::IN:
675 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500676 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700677 break;
678 case Token::OUT:
679 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500680 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700681 break;
682 case Token::INOUT:
683 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500684 flags |= Modifiers::kIn_Flag;
685 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700686 break;
687 case Token::LOWP:
688 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500689 flags |= Modifiers::kLowp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700690 break;
691 case Token::MEDIUMP:
692 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500693 flags |= Modifiers::kMediump_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700694 break;
695 case Token::HIGHP:
696 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500697 flags |= Modifiers::kHighp_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700698 break;
ethannicholasf789b382016-08-03 12:43:36 -0700699 case Token::FLAT:
700 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500701 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700702 break;
703 case Token::NOPERSPECTIVE:
704 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500705 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700706 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500707 case Token::READONLY:
708 this->nextToken();
709 flags |= Modifiers::kReadOnly_Flag;
710 break;
711 case Token::WRITEONLY:
712 this->nextToken();
713 flags |= Modifiers::kWriteOnly_Flag;
714 break;
715 case Token::COHERENT:
716 this->nextToken();
717 flags |= Modifiers::kCoherent_Flag;
718 break;
719 case Token::VOLATILE:
720 this->nextToken();
721 flags |= Modifiers::kVolatile_Flag;
722 break;
723 case Token::RESTRICT:
724 this->nextToken();
725 flags |= Modifiers::kRestrict_Flag;
726 break;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400727 case Token::BUFFER:
728 this->nextToken();
729 flags |= Modifiers::kBuffer_Flag;
730 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400731 case Token::HASSIDEEFFECTS:
732 this->nextToken();
733 flags |= Modifiers::kHasSideEffects_Flag;
734 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700735 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500736 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700737 }
738 }
739}
740
Ethan Nicholas11d53972016-11-28 11:23:23 -0500741Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
742 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700743 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500744 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700745 }
746 return result;
747}
748
749/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
750std::unique_ptr<ASTStatement> Parser::statement() {
751 Token start = this->peek();
752 switch (start.fKind) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400753 case Token::IF: // fall through
754 case Token::STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -0700755 return this->ifStatement();
756 case Token::FOR:
757 return this->forStatement();
758 case Token::DO:
759 return this->doStatement();
760 case Token::WHILE:
761 return this->whileStatement();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400762 case Token::SWITCH: // fall through
763 case Token::STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500764 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700765 case Token::RETURN:
766 return this->returnStatement();
767 case Token::BREAK:
768 return this->breakStatement();
769 case Token::CONTINUE:
770 return this->continueStatement();
771 case Token::DISCARD:
772 return this->discardStatement();
773 case Token::LBRACE:
774 return this->block();
775 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500776 this->nextToken();
777 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
ethannicholas0730be72016-09-01 07:59:02 -0700778 std::vector<std::unique_ptr<ASTStatement>>()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700779 case Token::CONST: // fall through
780 case Token::HIGHP: // fall through
781 case Token::MEDIUMP: // fall through
782 case Token::LOWP: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700783 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700784 if (!decl) {
785 return nullptr;
786 }
787 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
788 }
789 case Token::IDENTIFIER:
790 if (this->isType(start.fText)) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700791 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700792 if (!decl) {
793 return nullptr;
794 }
795 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
796 std::move(decl)));
797 }
798 // fall through
799 default:
800 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500801 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700802}
803
Ethan Nicholas50afc172017-02-16 14:49:57 -0500804/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* */
ethannicholasb3058bd2016-07-01 08:22:01 -0700805std::unique_ptr<ASTType> Parser::type() {
806 Token type;
807 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
808 return nullptr;
809 }
810 if (!this->isType(type.fText)) {
811 this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str());
812 return nullptr;
813 }
Ethan Nicholas50afc172017-02-16 14:49:57 -0500814 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400815 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500816 if (this->peek().fKind != Token::RBRACKET) {
817 int64_t i;
818 if (this->intLiteral(&i)) {
819 sizes.push_back(i);
820 } else {
821 return nullptr;
822 }
823 } else {
824 sizes.push_back(-1);
825 }
826 this->expect(Token::RBRACKET, "']'");
827 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500828 return std::unique_ptr<ASTType>(new ASTType(type.fPosition, std::move(type.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500829 ASTType::kIdentifier_Kind, sizes));
ethannicholasb3058bd2016-07-01 08:22:01 -0700830}
831
Ethan Nicholas50afc172017-02-16 14:49:57 -0500832/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500833std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700834 Token name;
835 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
836 return nullptr;
837 }
838 if (peek().fKind != Token::LBRACE) {
839 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500840 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700841 // it's better to report it as an unknown type
842 this->error(name.fPosition, "no type named '" + name.fText + "'");
843 return nullptr;
844 }
845 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500846 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700847 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700848 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700849 if (!decl) {
850 return nullptr;
851 }
852 decls.push_back(std::move(decl));
853 }
854 this->nextToken();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500855 std::vector<std::unique_ptr<ASTExpression>> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400856 Token instanceName;
857 if (this->checkNext(Token::IDENTIFIER, &instanceName)) {
858 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -0500859 if (this->peek().fKind != Token::RBRACKET) {
860 std::unique_ptr<ASTExpression> size = this->expression();
861 if (!size) {
862 return nullptr;
863 }
864 sizes.push_back(std::move(size));
865 } else {
866 sizes.push_back(nullptr);
867 }
868 this->expect(Token::RBRACKET, "']'");
869 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700870 }
871 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas11d53972016-11-28 11:23:23 -0500872 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
Ethan Nicholas50afc172017-02-16 14:49:57 -0500873 name.fText, std::move(decls),
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400874 std::move(instanceName.fText),
Ethan Nicholas50afc172017-02-16 14:49:57 -0500875 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700876}
877
878/* IF LPAREN expression RPAREN statement (ELSE statement)? */
879std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
880 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400881 bool isStatic = this->checkNext(Token::STATIC_IF, &start);
882 if (!isStatic && !this->expect(Token::IF, "'if'", &start)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700883 return nullptr;
884 }
885 if (!this->expect(Token::LPAREN, "'('")) {
886 return nullptr;
887 }
888 std::unique_ptr<ASTExpression> test(this->expression());
889 if (!test) {
890 return nullptr;
891 }
892 if (!this->expect(Token::RPAREN, "')'")) {
893 return nullptr;
894 }
895 std::unique_ptr<ASTStatement> ifTrue(this->statement());
896 if (!ifTrue) {
897 return nullptr;
898 }
899 std::unique_ptr<ASTStatement> ifFalse;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400900 if (this->checkNext(Token::ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700901 ifFalse = this->statement();
902 if (!ifFalse) {
903 return nullptr;
904 }
905 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400906 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition,
907 isStatic,
908 std::move(test),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500909 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -0700910 std::move(ifFalse)));
911}
912
913/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
914std::unique_ptr<ASTDoStatement> Parser::doStatement() {
915 Token start;
916 if (!this->expect(Token::DO, "'do'", &start)) {
917 return nullptr;
918 }
919 std::unique_ptr<ASTStatement> statement(this->statement());
920 if (!statement) {
921 return nullptr;
922 }
923 if (!this->expect(Token::WHILE, "'while'")) {
924 return nullptr;
925 }
926 if (!this->expect(Token::LPAREN, "'('")) {
927 return nullptr;
928 }
929 std::unique_ptr<ASTExpression> test(this->expression());
930 if (!test) {
931 return nullptr;
932 }
933 if (!this->expect(Token::RPAREN, "')'")) {
934 return nullptr;
935 }
936 if (!this->expect(Token::SEMICOLON, "';'")) {
937 return nullptr;
938 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500939 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -0700940 std::move(statement),
941 std::move(test)));
942}
943
944/* WHILE LPAREN expression RPAREN STATEMENT */
945std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
946 Token start;
947 if (!this->expect(Token::WHILE, "'while'", &start)) {
948 return nullptr;
949 }
950 if (!this->expect(Token::LPAREN, "'('")) {
951 return nullptr;
952 }
953 std::unique_ptr<ASTExpression> test(this->expression());
954 if (!test) {
955 return nullptr;
956 }
957 if (!this->expect(Token::RPAREN, "')'")) {
958 return nullptr;
959 }
960 std::unique_ptr<ASTStatement> statement(this->statement());
961 if (!statement) {
962 return nullptr;
963 }
Ethan Nicholas11d53972016-11-28 11:23:23 -0500964 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosition,
965 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -0700966 std::move(statement)));
967}
968
Ethan Nicholasaf197692017-02-27 13:26:45 -0500969/* CASE expression COLON statement* */
970std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
971 Token start;
972 if (!this->expect(Token::CASE, "'case'", &start)) {
973 return nullptr;
974 }
975 std::unique_ptr<ASTExpression> value = this->expression();
976 if (!value) {
977 return nullptr;
978 }
979 if (!this->expect(Token::COLON, "':'")) {
980 return nullptr;
981 }
982 std::vector<std::unique_ptr<ASTStatement>> statements;
983 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
984 this->peek().fKind != Token::DEFAULT) {
985 std::unique_ptr<ASTStatement> s = this->statement();
986 if (!s) {
987 return nullptr;
988 }
989 statements.push_back(std::move(s));
990 }
991 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fPosition, std::move(value),
992 std::move(statements)));
993}
994
995/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
996std::unique_ptr<ASTStatement> Parser::switchStatement() {
997 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -0400998 bool isStatic = this->checkNext(Token::STATIC_SWITCH, &start);
999 if (!isStatic && !this->expect(Token::SWITCH, "'switch'", &start)) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001000 return nullptr;
1001 }
1002 if (!this->expect(Token::LPAREN, "'('")) {
1003 return nullptr;
1004 }
1005 std::unique_ptr<ASTExpression> value(this->expression());
1006 if (!value) {
1007 return nullptr;
1008 }
1009 if (!this->expect(Token::RPAREN, "')'")) {
1010 return nullptr;
1011 }
1012 if (!this->expect(Token::LBRACE, "'{'")) {
1013 return nullptr;
1014 }
1015 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1016 while (this->peek().fKind == Token::CASE) {
1017 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1018 if (!c) {
1019 return nullptr;
1020 }
1021 cases.push_back(std::move(c));
1022 }
1023 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1024 // parts of the compiler may rely upon this assumption.
1025 if (this->peek().fKind == Token::DEFAULT) {
1026 Token defaultStart;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001027 ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001028 if (!this->expect(Token::COLON, "':'")) {
1029 return nullptr;
1030 }
1031 std::vector<std::unique_ptr<ASTStatement>> statements;
1032 while (this->peek().fKind != Token::RBRACE) {
1033 std::unique_ptr<ASTStatement> s = this->statement();
1034 if (!s) {
1035 return nullptr;
1036 }
1037 statements.push_back(std::move(s));
1038 }
1039 cases.emplace_back(new ASTSwitchCase(defaultStart.fPosition, nullptr,
1040 std::move(statements)));
1041 }
1042 if (!this->expect(Token::RBRACE, "'}'")) {
1043 return nullptr;
1044 }
1045 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001046 isStatic,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001047 std::move(value),
1048 std::move(cases)));
1049}
1050
Ethan Nicholas11d53972016-11-28 11:23:23 -05001051/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001052 STATEMENT */
1053std::unique_ptr<ASTForStatement> Parser::forStatement() {
1054 Token start;
1055 if (!this->expect(Token::FOR, "'for'", &start)) {
1056 return nullptr;
1057 }
1058 if (!this->expect(Token::LPAREN, "'('")) {
1059 return nullptr;
1060 }
1061 std::unique_ptr<ASTStatement> initializer;
1062 Token nextToken = this->peek();
1063 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001064 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001065 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001067 case Token::CONST: {
1068 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1069 if (!vd) {
1070 return nullptr;
1071 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001072 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001073 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001074 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001075 }
1076 case Token::IDENTIFIER: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001077 if (this->isType(nextToken.fText)) {
ethannicholasa54401d2016-10-14 08:37:32 -07001078 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1079 if (!vd) {
1080 return nullptr;
1081 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001083 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001084 break;
1085 }
ethannicholasa54401d2016-10-14 08:37:32 -07001086 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 default:
1088 initializer = this->expressionStatement();
1089 }
1090 std::unique_ptr<ASTExpression> test;
1091 if (this->peek().fKind != Token::SEMICOLON) {
1092 test = this->expression();
1093 if (!test) {
1094 return nullptr;
1095 }
1096 }
1097 if (!this->expect(Token::SEMICOLON, "';'")) {
1098 return nullptr;
1099 }
1100 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001101 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001102 next = this->expression();
1103 if (!next) {
1104 return nullptr;
1105 }
1106 }
1107 if (!this->expect(Token::RPAREN, "')'")) {
1108 return nullptr;
1109 }
1110 std::unique_ptr<ASTStatement> statement(this->statement());
1111 if (!statement) {
1112 return nullptr;
1113 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001114 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001115 std::move(initializer),
1116 std::move(test), std::move(next),
1117 std::move(statement)));
1118}
1119
1120/* RETURN expression? SEMICOLON */
1121std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1122 Token start;
1123 if (!this->expect(Token::RETURN, "'return'", &start)) {
1124 return nullptr;
1125 }
1126 std::unique_ptr<ASTExpression> expression;
1127 if (this->peek().fKind != Token::SEMICOLON) {
1128 expression = this->expression();
1129 if (!expression) {
1130 return nullptr;
1131 }
1132 }
1133 if (!this->expect(Token::SEMICOLON, "';'")) {
1134 return nullptr;
1135 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001136 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001137 std::move(expression)));
1138}
1139
1140/* BREAK SEMICOLON */
1141std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1142 Token start;
1143 if (!this->expect(Token::BREAK, "'break'", &start)) {
1144 return nullptr;
1145 }
1146 if (!this->expect(Token::SEMICOLON, "';'")) {
1147 return nullptr;
1148 }
1149 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosition));
1150}
1151
1152/* CONTINUE SEMICOLON */
1153std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1154 Token start;
1155 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1156 return nullptr;
1157 }
1158 if (!this->expect(Token::SEMICOLON, "';'")) {
1159 return nullptr;
1160 }
1161 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fPosition));
1162}
1163
1164/* DISCARD SEMICOLON */
1165std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1166 Token start;
1167 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1168 return nullptr;
1169 }
1170 if (!this->expect(Token::SEMICOLON, "';'")) {
1171 return nullptr;
1172 }
1173 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fPosition));
1174}
1175
1176/* LBRACE statement* RBRACE */
1177std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001178 AutoDepth depth(this);
1179 if (!depth.checkValid()) {
1180 return nullptr;
1181 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001182 Token start;
1183 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1184 return nullptr;
1185 }
1186 std::vector<std::unique_ptr<ASTStatement>> statements;
1187 for (;;) {
1188 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001189 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001190 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001191 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001192 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001193 case Token::END_OF_FILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001194 this->error(this->peek().fPosition, "expected '}', but found end of file");
1195 return nullptr;
1196 default: {
1197 std::unique_ptr<ASTStatement> statement = this->statement();
1198 if (!statement) {
1199 return nullptr;
1200 }
1201 statements.push_back(std::move(statement));
1202 }
1203 }
1204 }
1205}
1206
1207/* expression SEMICOLON */
1208std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1209 std::unique_ptr<ASTExpression> expr = this->expression();
1210 if (expr) {
1211 if (this->expect(Token::SEMICOLON, "';'")) {
1212 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1213 return std::unique_ptr<ASTExpressionStatement>(result);
1214 }
1215 }
1216 return nullptr;
1217}
1218
1219/* assignmentExpression */
1220std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001221 AutoDepth depth(this);
1222 if (!depth.checkValid()) {
1223 return nullptr;
1224 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001225 return this->commaExpression();
1226}
1227
1228/* assignmentExpression (COMMA assignmentExpression)* */
1229std::unique_ptr<ASTExpression> Parser::commaExpression() {
1230 std::unique_ptr<ASTExpression> result = this->assignmentExpression();
1231 if (!result) {
1232 return nullptr;
1233 }
1234 Token t;
1235 while (this->checkNext(Token::COMMA, &t)) {
1236 std::unique_ptr<ASTExpression> right = this->commaExpression();
1237 if (!right) {
1238 return nullptr;
1239 }
1240 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1241 }
1242 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001243}
1244
1245/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1246 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1247 assignmentExpression)*
1248 */
1249std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1250 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1251 if (!result) {
1252 return nullptr;
1253 }
1254 for (;;) {
1255 switch (this->peek().fKind) {
1256 case Token::EQ: // fall through
1257 case Token::STAREQ: // fall through
1258 case Token::SLASHEQ: // fall through
1259 case Token::PERCENTEQ: // fall through
1260 case Token::PLUSEQ: // fall through
1261 case Token::MINUSEQ: // fall through
1262 case Token::SHLEQ: // fall through
1263 case Token::SHREQ: // fall through
1264 case Token::BITWISEANDEQ: // fall through
1265 case Token::BITWISEXOREQ: // fall through
1266 case Token::BITWISEOREQ: // fall through
1267 case Token::LOGICALANDEQ: // fall through
1268 case Token::LOGICALXOREQ: // fall through
1269 case Token::LOGICALOREQ: {
1270 Token t = this->nextToken();
1271 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1272 if (!right) {
1273 return nullptr;
1274 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001275 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
1276 t,
ethannicholasb3058bd2016-07-01 08:22:01 -07001277 std::move(right)));
1278 }
1279 default:
1280 return result;
1281 }
1282 }
1283}
1284
1285/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1286std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1287 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1288 if (!result) {
1289 return nullptr;
1290 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001291 if (this->checkNext(Token::QUESTION)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001292 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1293 if (!trueExpr) {
1294 return nullptr;
1295 }
1296 if (this->expect(Token::COLON, "':'")) {
1297 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001298 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1299 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001300 std::move(falseExpr)));
1301 }
1302 return nullptr;
1303 }
1304 return result;
1305}
1306
1307/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1308std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1309 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1310 if (!result) {
1311 return nullptr;
1312 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001313 Token t;
1314 while (this->checkNext(Token::LOGICALOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001315 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
1316 if (!right) {
1317 return nullptr;
1318 }
1319 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1320 }
1321 return result;
1322}
1323
1324/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1325std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1326 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1327 if (!result) {
1328 return nullptr;
1329 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001330 Token t;
1331 while (this->checkNext(Token::LOGICALXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001332 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1333 if (!right) {
1334 return nullptr;
1335 }
1336 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1337 }
1338 return result;
1339}
1340
1341/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1342std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1343 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1344 if (!result) {
1345 return nullptr;
1346 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001347 Token t;
1348 while (this->checkNext(Token::LOGICALAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001349 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1350 if (!right) {
1351 return nullptr;
1352 }
1353 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1354 }
1355 return result;
1356}
1357
1358/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1359std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1360 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1361 if (!result) {
1362 return nullptr;
1363 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001364 Token t;
1365 while (this->checkNext(Token::BITWISEOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001366 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1367 if (!right) {
1368 return nullptr;
1369 }
1370 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1371 }
1372 return result;
1373}
1374
1375/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1376std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1377 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1378 if (!result) {
1379 return nullptr;
1380 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001381 Token t;
1382 while (this->checkNext(Token::BITWISEXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001383 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1384 if (!right) {
1385 return nullptr;
1386 }
1387 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1388 }
1389 return result;
1390}
1391
1392/* equalityExpression (BITWISEAND equalityExpression)* */
1393std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1394 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1395 if (!result) {
1396 return nullptr;
1397 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001398 Token t;
1399 while (this->checkNext(Token::BITWISEAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001400 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1401 if (!right) {
1402 return nullptr;
1403 }
1404 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1405 }
1406 return result;
1407}
1408
1409/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1410std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1411 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1412 if (!result) {
1413 return nullptr;
1414 }
1415 for (;;) {
1416 switch (this->peek().fKind) {
1417 case Token::EQEQ: // fall through
1418 case Token::NEQ: {
1419 Token t = this->nextToken();
1420 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1421 if (!right) {
1422 return nullptr;
1423 }
1424 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1425 break;
1426 }
1427 default:
1428 return result;
1429 }
1430 }
1431}
1432
1433/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1434std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1435 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1436 if (!result) {
1437 return nullptr;
1438 }
1439 for (;;) {
1440 switch (this->peek().fKind) {
1441 case Token::LT: // fall through
1442 case Token::GT: // fall through
1443 case Token::LTEQ: // fall through
1444 case Token::GTEQ: {
1445 Token t = this->nextToken();
1446 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1447 if (!right) {
1448 return nullptr;
1449 }
1450 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1451 break;
1452 }
1453 default:
1454 return result;
1455 }
1456 }
1457}
1458
1459/* additiveExpression ((SHL | SHR) additiveExpression)* */
1460std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1461 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1462 if (!result) {
1463 return nullptr;
1464 }
1465 for (;;) {
1466 switch (this->peek().fKind) {
1467 case Token::SHL: // fall through
1468 case Token::SHR: {
1469 Token t = this->nextToken();
1470 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1471 if (!right) {
1472 return nullptr;
1473 }
1474 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1475 break;
1476 }
1477 default:
1478 return result;
1479 }
1480 }
1481}
1482
1483/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1484std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1485 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1486 if (!result) {
1487 return nullptr;
1488 }
1489 for (;;) {
1490 switch (this->peek().fKind) {
1491 case Token::PLUS: // fall through
1492 case Token::MINUS: {
1493 Token t = this->nextToken();
1494 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1495 if (!right) {
1496 return nullptr;
1497 }
1498 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1499 break;
1500 }
1501 default:
1502 return result;
1503 }
1504 }
1505}
1506
1507/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1508std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1509 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1510 if (!result) {
1511 return nullptr;
1512 }
1513 for (;;) {
1514 switch (this->peek().fKind) {
1515 case Token::STAR: // fall through
1516 case Token::SLASH: // fall through
1517 case Token::PERCENT: {
1518 Token t = this->nextToken();
1519 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1520 if (!right) {
1521 return nullptr;
1522 }
1523 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(right)));
1524 break;
1525 }
1526 default:
1527 return result;
1528 }
1529 }
1530}
1531
1532/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1533std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1534 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001535 case Token::PLUS: // fall through
1536 case Token::MINUS: // fall through
1537 case Token::LOGICALNOT: // fall through
1538 case Token::BITWISENOT: // fall through
1539 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 case Token::MINUSMINUS: {
1541 Token t = this->nextToken();
1542 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1543 if (!expr) {
1544 return nullptr;
1545 }
1546 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std::move(expr)));
1547 }
1548 default:
1549 return this->postfixExpression();
1550 }
1551}
1552
1553/* term suffix* */
1554std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1555 std::unique_ptr<ASTExpression> result = this->term();
1556 if (!result) {
1557 return nullptr;
1558 }
1559 for (;;) {
1560 switch (this->peek().fKind) {
1561 case Token::LBRACKET: // fall through
1562 case Token::DOT: // fall through
1563 case Token::LPAREN: // fall through
1564 case Token::PLUSPLUS: // fall through
1565 case Token::MINUSMINUS: {
1566 std::unique_ptr<ASTSuffix> s = this->suffix();
1567 if (!s) {
1568 return nullptr;
1569 }
1570 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1571 break;
1572 }
1573 default:
1574 return result;
1575 }
1576 }
1577}
1578
Ethan Nicholas11d53972016-11-28 11:23:23 -05001579/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
ethannicholasb3058bd2016-07-01 08:22:01 -07001580 PLUSPLUS | MINUSMINUS */
1581std::unique_ptr<ASTSuffix> Parser::suffix() {
1582 Token next = this->nextToken();
1583 switch (next.fKind) {
1584 case Token::LBRACKET: {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001585 if (this->checkNext(Token::RBRACKET)) {
ethannicholas5961bc92016-10-12 06:39:56 -07001586 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
1587 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 std::unique_ptr<ASTExpression> e = this->expression();
1589 if (!e) {
1590 return nullptr;
1591 }
1592 this->expect(Token::RBRACKET, "']' to complete array access expression");
1593 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1594 }
1595 case Token::DOT: {
1596 Position pos = this->peek().fPosition;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001597 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001598 if (this->identifier(&text)) {
1599 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
1600 }
1601 return nullptr;
1602 }
1603 case Token::LPAREN: {
1604 std::vector<std::unique_ptr<ASTExpression>> parameters;
1605 if (this->peek().fKind != Token::RPAREN) {
1606 for (;;) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001607 std::unique_ptr<ASTExpression> expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001608 if (!expr) {
1609 return nullptr;
1610 }
1611 parameters.push_back(std::move(expr));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001612 if (!this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001613 break;
1614 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001615 }
1616 }
1617 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas11d53972016-11-28 11:23:23 -05001618 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001619 std::move(parameters)));
1620 }
1621 case Token::PLUSPLUS:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001622 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 ASTSuffix::kPostIncrement_Kind));
1624 case Token::MINUSMINUS:
1625 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1626 ASTSuffix::kPostDecrement_Kind));
1627 default: {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001628 this->error(next.fPosition, "expected expression suffix, but found '" + next.fText +
ethannicholasb3058bd2016-07-01 08:22:01 -07001629 "'\n");
1630 return nullptr;
1631 }
1632 }
1633}
1634
1635/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1636std::unique_ptr<ASTExpression> Parser::term() {
1637 std::unique_ptr<ASTExpression> result;
1638 Token t = this->peek();
1639 switch (t.fKind) {
1640 case Token::IDENTIFIER: {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001641 String text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001642 if (this->identifier(&text)) {
1643 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
1644 }
1645 break;
1646 }
1647 case Token::INT_LITERAL: {
1648 int64_t i;
1649 if (this->intLiteral(&i)) {
1650 result.reset(new ASTIntLiteral(t.fPosition, i));
1651 }
1652 break;
1653 }
1654 case Token::FLOAT_LITERAL: {
1655 double f;
1656 if (this->floatLiteral(&f)) {
1657 result.reset(new ASTFloatLiteral(t.fPosition, f));
1658 }
1659 break;
1660 }
1661 case Token::TRUE_LITERAL: // fall through
1662 case Token::FALSE_LITERAL: {
1663 bool b;
1664 if (this->boolLiteral(&b)) {
1665 result.reset(new ASTBoolLiteral(t.fPosition, b));
1666 }
1667 break;
1668 }
1669 case Token::LPAREN: {
1670 this->nextToken();
1671 result = this->expression();
1672 if (result) {
1673 this->expect(Token::RPAREN, "')' to complete expression");
1674 }
1675 break;
1676 }
1677 default:
1678 this->nextToken();
1679 this->error(t.fPosition, "expected expression, but found '" + t.fText + "'\n");
1680 result = nullptr;
1681 }
1682 return result;
1683}
1684
1685/* INT_LITERAL */
1686bool Parser::intLiteral(int64_t* dest) {
1687 Token t;
1688 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1689 *dest = SkSL::stol(t.fText);
1690 return true;
1691 }
1692 return false;
1693}
1694
1695/* FLOAT_LITERAL */
1696bool Parser::floatLiteral(double* dest) {
1697 Token t;
1698 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1699 *dest = SkSL::stod(t.fText);
1700 return true;
1701 }
1702 return false;
1703}
1704
1705/* TRUE_LITERAL | FALSE_LITERAL */
1706bool Parser::boolLiteral(bool* dest) {
1707 Token t = this->nextToken();
1708 switch (t.fKind) {
1709 case Token::TRUE_LITERAL:
1710 *dest = true;
1711 return true;
1712 case Token::FALSE_LITERAL:
1713 *dest = false;
1714 return true;
1715 default:
1716 this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1717 return false;
1718 }
1719}
1720
1721/* IDENTIFIER */
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001722bool Parser::identifier(String* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001723 Token t;
1724 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001725 *dest = t.fText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 return true;
1727 }
1728 return false;
1729}
1730
1731} // namespace