blob: 31be95921adc1c1dd0add4c028c5d3f4933cf94b [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "src/sksl/SkSLParser.h"
10#include "src/sksl/ast/SkSLASTBinaryExpression.h"
11#include "src/sksl/ast/SkSLASTBlock.h"
12#include "src/sksl/ast/SkSLASTBoolLiteral.h"
13#include "src/sksl/ast/SkSLASTBreakStatement.h"
14#include "src/sksl/ast/SkSLASTCallSuffix.h"
15#include "src/sksl/ast/SkSLASTContinueStatement.h"
16#include "src/sksl/ast/SkSLASTDiscardStatement.h"
17#include "src/sksl/ast/SkSLASTDoStatement.h"
18#include "src/sksl/ast/SkSLASTEnum.h"
19#include "src/sksl/ast/SkSLASTExpression.h"
20#include "src/sksl/ast/SkSLASTExpressionStatement.h"
21#include "src/sksl/ast/SkSLASTExtension.h"
22#include "src/sksl/ast/SkSLASTFieldSuffix.h"
23#include "src/sksl/ast/SkSLASTFloatLiteral.h"
24#include "src/sksl/ast/SkSLASTForStatement.h"
25#include "src/sksl/ast/SkSLASTFunction.h"
26#include "src/sksl/ast/SkSLASTIdentifier.h"
27#include "src/sksl/ast/SkSLASTIfStatement.h"
28#include "src/sksl/ast/SkSLASTIndexSuffix.h"
29#include "src/sksl/ast/SkSLASTIntLiteral.h"
30#include "src/sksl/ast/SkSLASTInterfaceBlock.h"
31#include "src/sksl/ast/SkSLASTModifiersDeclaration.h"
32#include "src/sksl/ast/SkSLASTNullLiteral.h"
33#include "src/sksl/ast/SkSLASTParameter.h"
34#include "src/sksl/ast/SkSLASTPrefixExpression.h"
35#include "src/sksl/ast/SkSLASTReturnStatement.h"
36#include "src/sksl/ast/SkSLASTSection.h"
37#include "src/sksl/ast/SkSLASTStatement.h"
38#include "src/sksl/ast/SkSLASTSuffixExpression.h"
39#include "src/sksl/ast/SkSLASTSwitchCase.h"
40#include "src/sksl/ast/SkSLASTSwitchStatement.h"
41#include "src/sksl/ast/SkSLASTTernaryExpression.h"
42#include "src/sksl/ast/SkSLASTType.h"
43#include "src/sksl/ast/SkSLASTVarDeclaration.h"
44#include "src/sksl/ast/SkSLASTVarDeclarationStatement.h"
45#include "src/sksl/ast/SkSLASTWhileStatement.h"
46#include "src/sksl/ir/SkSLModifiers.h"
47#include "src/sksl/ir/SkSLSymbolTable.h"
48#include "src/sksl/ir/SkSLType.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070049
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040050#ifndef SKSL_STANDALONE
Mike Kleinc0bd9f92019-04-23 12:05:21 -050051#include "include/private/SkOnce.h"
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040052#endif
53
ethannicholasb3058bd2016-07-01 08:22:01 -070054namespace SkSL {
55
ethannicholascad64162016-10-27 10:54:02 -070056#define MAX_PARSE_DEPTH 50
57
58class AutoDepth {
59public:
60 AutoDepth(Parser* p)
61 : fParser(p) {
62 fParser->fDepth++;
63 }
64
65 ~AutoDepth() {
66 fParser->fDepth--;
67 }
68
69 bool checkValid() {
70 if (fParser->fDepth > MAX_PARSE_DEPTH) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070071 fParser->error(fParser->peek(), String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070072 return false;
73 }
74 return true;
75 }
76
77private:
78 Parser* fParser;
79};
80
Brian Salomon140f3da2018-08-23 13:51:27 +000081std::unordered_map<String, Parser::LayoutToken>* Parser::layoutTokens;
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040082
83void Parser::InitLayoutMap() {
Brian Salomon140f3da2018-08-23 13:51:27 +000084 layoutTokens = new std::unordered_map<String, LayoutToken>;
Brian Salomon23356442018-11-30 15:33:19 -050085 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040086 TOKEN(LOCATION, "location");
87 TOKEN(OFFSET, "offset");
88 TOKEN(BINDING, "binding");
89 TOKEN(INDEX, "index");
90 TOKEN(SET, "set");
91 TOKEN(BUILTIN, "builtin");
92 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
93 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
94 TOKEN(OVERRIDE_COVERAGE, "override_coverage");
95 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
96 TOKEN(BLEND_SUPPORT_MULTIPLY, "blend_support_multiply");
97 TOKEN(BLEND_SUPPORT_SCREEN, "blend_support_screen");
98 TOKEN(BLEND_SUPPORT_OVERLAY, "blend_support_overlay");
99 TOKEN(BLEND_SUPPORT_DARKEN, "blend_support_darken");
100 TOKEN(BLEND_SUPPORT_LIGHTEN, "blend_support_lighten");
101 TOKEN(BLEND_SUPPORT_COLORDODGE, "blend_support_colordodge");
102 TOKEN(BLEND_SUPPORT_COLORBURN, "blend_support_colorburn");
103 TOKEN(BLEND_SUPPORT_HARDLIGHT, "blend_support_hardlight");
104 TOKEN(BLEND_SUPPORT_SOFTLIGHT, "blend_support_softlight");
105 TOKEN(BLEND_SUPPORT_DIFFERENCE, "blend_support_difference");
106 TOKEN(BLEND_SUPPORT_EXCLUSION, "blend_support_exclusion");
107 TOKEN(BLEND_SUPPORT_HSL_HUE, "blend_support_hsl_hue");
108 TOKEN(BLEND_SUPPORT_HSL_SATURATION, "blend_support_hsl_saturation");
109 TOKEN(BLEND_SUPPORT_HSL_COLOR, "blend_support_hsl_color");
110 TOKEN(BLEND_SUPPORT_HSL_LUMINOSITY, "blend_support_hsl_luminosity");
111 TOKEN(PUSH_CONSTANT, "push_constant");
112 TOKEN(POINTS, "points");
113 TOKEN(LINES, "lines");
114 TOKEN(LINE_STRIP, "line_strip");
115 TOKEN(LINES_ADJACENCY, "lines_adjacency");
116 TOKEN(TRIANGLES, "triangles");
117 TOKEN(TRIANGLE_STRIP, "triangle_strip");
118 TOKEN(TRIANGLES_ADJACENCY, "triangles_adjacency");
119 TOKEN(MAX_VERTICES, "max_vertices");
120 TOKEN(INVOCATIONS, "invocations");
121 TOKEN(WHEN, "when");
122 TOKEN(KEY, "key");
Michael Ludwiga4275592018-08-31 10:52:47 -0400123 TOKEN(TRACKED, "tracked");
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400124 TOKEN(CTYPE, "ctype");
Brian Osmanf28e55d2018-10-03 16:35:54 -0400125 TOKEN(SKPMCOLOR4F, "SkPMColor4f");
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400126 TOKEN(SKRECT, "SkRect");
127 TOKEN(SKIRECT, "SkIRect");
128 TOKEN(SKPMCOLOR, "SkPMColor");
Ethan Nicholas65e49ba2019-05-30 14:50:08 -0400129 TOKEN(SKMATRIX44, "SkMatrix44");
Ethan Nicholasc1c686b2019-04-02 17:30:23 -0400130 TOKEN(BOOL, "bool");
131 TOKEN(INT, "int");
132 TOKEN(FLOAT, "float");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400133 #undef TOKEN
134}
135
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700136Parser::Parser(const char* text, size_t length, SymbolTable& types, ErrorReporter& errors)
137: fText(text)
138, fPushback(Token::INVALID, -1, -1)
ethannicholasb3058bd2016-07-01 08:22:01 -0700139, fTypes(types)
140, fErrors(errors) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700141 fLexer.start(text, length);
Brian Salomon3b83afe2018-08-23 11:04:36 -0400142 static const bool layoutMapInitialized = []{ return (void)InitLayoutMap(), true; }();
143 (void) layoutMapInitialized;
ethannicholasb3058bd2016-07-01 08:22:01 -0700144}
145
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400146/* (directive | section | declaration)* END_OF_FILE */
ethannicholasb3058bd2016-07-01 08:22:01 -0700147std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
148 std::vector<std::unique_ptr<ASTDeclaration>> result;
149 for (;;) {
150 switch (this->peek().fKind) {
151 case Token::END_OF_FILE:
152 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700153 case Token::DIRECTIVE: {
154 std::unique_ptr<ASTDeclaration> decl = this->directive();
155 if (decl) {
156 result.push_back(std::move(decl));
157 }
158 break;
159 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400160 case Token::SECTION: {
161 std::unique_ptr<ASTDeclaration> section = this->section();
162 if (section) {
163 result.push_back(std::move(section));
164 }
165 break;
166 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 default: {
168 std::unique_ptr<ASTDeclaration> decl = this->declaration();
169 if (!decl) {
170 continue;
171 }
172 result.push_back(std::move(decl));
173 }
174 }
175 }
176}
177
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700178Token Parser::nextRawToken() {
179 if (fPushback.fKind != Token::INVALID) {
180 Token result = fPushback;
181 fPushback.fKind = Token::INVALID;
ethannicholasb3058bd2016-07-01 08:22:01 -0700182 return result;
183 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700184 Token result = fLexer.next();
185 return result;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400186}
187
188Token Parser::nextToken() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700189 Token token = this->nextRawToken();
190 while (token.fKind == Token::WHITESPACE || token.fKind == Token::LINE_COMMENT ||
191 token.fKind == Token::BLOCK_COMMENT) {
192 token = this->nextRawToken();
193 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400194 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700195}
196
197void Parser::pushback(Token t) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400198 SkASSERT(fPushback.fKind == Token::INVALID);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400199 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700200}
201
202Token Parser::peek() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700203 if (fPushback.fKind == Token::INVALID) {
Brian Osman634624a2017-08-15 11:14:30 -0400204 fPushback = this->nextToken();
205 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700206 return fPushback;
207}
208
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400209bool Parser::checkNext(Token::Kind kind, Token* result) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700210 if (fPushback.fKind != Token::INVALID && fPushback.fKind != kind) {
Brian Osman634624a2017-08-15 11:14:30 -0400211 return false;
212 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400213 Token next = this->nextToken();
214 if (next.fKind == kind) {
215 if (result) {
216 *result = next;
217 }
218 return true;
219 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400220 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400221 return false;
222}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500223
224bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700225 Token next = this->nextToken();
226 if (next.fKind == kind) {
227 if (result) {
Brian Osman634624a2017-08-15 11:14:30 -0400228 *result = std::move(next);
ethannicholasb3058bd2016-07-01 08:22:01 -0700229 }
230 return true;
231 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700232 this->error(next, "expected " + String(expected) + ", but found '" +
233 this->text(next) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700234 return false;
235 }
236}
237
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700238StringFragment Parser::text(Token token) {
239 return StringFragment(fText + token.fOffset, token.fLength);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500240}
241
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700242void Parser::error(Token token, String msg) {
243 this->error(token.fOffset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -0700244}
245
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700246void Parser::error(int offset, String msg) {
247 fErrors.error(offset, msg);
248}
249
250bool Parser::isType(StringFragment name) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700251 return nullptr != fTypes[name];
252}
253
Ethan Nicholas11d53972016-11-28 11:23:23 -0500254/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700255 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -0700256std::unique_ptr<ASTDeclaration> Parser::directive() {
257 Token start;
258 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
259 return nullptr;
260 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700261 StringFragment text = this->text(start);
262 if (text == "#version") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 this->expect(Token::INT_LITERAL, "a version number");
ethannicholas5961bc92016-10-12 06:39:56 -0700264 Token next = this->peek();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700265 StringFragment nextText = this->text(next);
266 if (nextText == "es" || nextText == "compatibility") {
ethannicholas5961bc92016-10-12 06:39:56 -0700267 this->nextToken();
268 }
269 // version is ignored for now; it will eventually become an error when we stop pretending
270 // to be GLSL
ethannicholasb3058bd2016-07-01 08:22:01 -0700271 return nullptr;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700272 } else if (text == "#extension") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700273 Token name;
274 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
275 return nullptr;
276 }
277 if (!this->expect(Token::COLON, "':'")) {
278 return nullptr;
279 }
280 // FIXME: need to start paying attention to this token
281 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
282 return nullptr;
283 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700284 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fOffset,
285 String(this->text(name))));
ethannicholasb3058bd2016-07-01 08:22:01 -0700286 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700287 this->error(start, "unsupported directive '" + this->text(start) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700288 return nullptr;
289 }
290}
291
Ethan Nicholas762466e2017-06-29 10:03:38 -0400292/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
293 RBRACE */
294std::unique_ptr<ASTDeclaration> Parser::section() {
295 Token start;
296 if (!this->expect(Token::SECTION, "a section token", &start)) {
297 return nullptr;
298 }
299 String argument;
300 if (this->peek().fKind == Token::LPAREN) {
301 this->nextToken();
302 Token argToken;
303 if (!this->expect(Token::IDENTIFIER, "an identifier", &argToken)) {
304 return nullptr;
305 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700306 argument = this->text(argToken);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400307 if (!this->expect(Token::RPAREN, "')'")) {
308 return nullptr;
309 }
310 }
311 if (!this->expect(Token::LBRACE, "'{'")) {
312 return nullptr;
313 }
314 String text;
315 int level = 1;
316 for (;;) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700317 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400318 switch (next.fKind) {
319 case Token::LBRACE:
320 ++level;
321 break;
322 case Token::RBRACE:
323 --level;
324 break;
325 case Token::END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700326 this->error(start, "reached end of file while parsing section");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400327 return nullptr;
328 default:
329 break;
330 }
331 if (!level) {
332 break;
333 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700334 text += this->text(next);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400335 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700336 StringFragment name = this->text(start);
337 ++name.fChars;
338 --name.fLength;
339 return std::unique_ptr<ASTDeclaration>(new ASTSection(start.fOffset,
340 String(name),
Ethan Nicholas762466e2017-06-29 10:03:38 -0400341 argument,
342 text));
343}
344
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500345/* ENUM CLASS IDENTIFIER LBRACE (IDENTIFIER (EQ expression)? (COMMA IDENTIFIER (EQ expression))*)?
346 RBRACE */
347std::unique_ptr<ASTDeclaration> Parser::enumDeclaration() {
348 Token start;
349 if (!this->expect(Token::ENUM, "'enum'", &start)) {
350 return nullptr;
351 }
352 if (!this->expect(Token::CLASS, "'class'")) {
353 return nullptr;
354 }
355 Token name;
356 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
357 return nullptr;
358 }
359 if (!this->expect(Token::LBRACE, "'{'")) {
360 return nullptr;
361 }
362 fTypes.add(this->text(name), std::unique_ptr<Symbol>(new Type(this->text(name),
363 Type::kEnum_Kind)));
364 std::vector<StringFragment> names;
365 std::vector<std::unique_ptr<ASTExpression>> values;
366 if (!this->checkNext(Token::RBRACE)) {
367 Token id;
368 if (!this->expect(Token::IDENTIFIER, "an identifier", &id)) {
369 return nullptr;
370 }
371 names.push_back(this->text(id));
372 if (this->checkNext(Token::EQ)) {
373 std::unique_ptr<ASTExpression> value = this->assignmentExpression();
374 if (!value) {
375 return nullptr;
376 }
377 values.push_back(std::move(value));
378 } else {
379 values.push_back(nullptr);
380 }
381 while (!this->checkNext(Token::RBRACE)) {
382 if (!this->expect(Token::COMMA, "','")) {
383 return nullptr;
384 }
385 if (!this->expect(Token::IDENTIFIER, "an identifier", &id)) {
386 return nullptr;
387 }
388 names.push_back(this->text(id));
389 if (this->checkNext(Token::EQ)) {
390 std::unique_ptr<ASTExpression> value = this->assignmentExpression();
391 if (!value) {
392 return nullptr;
393 }
394 values.push_back(std::move(value));
395 } else {
396 values.push_back(nullptr);
397 }
398 }
399 }
400 this->expect(Token::SEMICOLON, "';'");
401 return std::unique_ptr<ASTDeclaration>(new ASTEnum(name.fOffset, this->text(name), names,
402 std::move(values)));
403}
404
405/* enumDeclaration | modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700406 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
407std::unique_ptr<ASTDeclaration> Parser::declaration() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700408 Token lookahead = this->peek();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500409 if (lookahead.fKind == Token::ENUM) {
410 return this->enumDeclaration();
411 }
412 Modifiers modifiers = this->modifiers();
413 lookahead = this->peek();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700414 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(this->text(lookahead))) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700415 // we have an identifier that's not a type, could be the start of an interface block
416 return this->interfaceBlock(modifiers);
417 }
418 if (lookahead.fKind == Token::STRUCT) {
419 return this->structVarDeclaration(modifiers);
420 }
ethannicholas5961bc92016-10-12 06:39:56 -0700421 if (lookahead.fKind == Token::SEMICOLON) {
422 this->nextToken();
423 return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
424 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700425 std::unique_ptr<ASTType> type(this->type());
426 if (!type) {
427 return nullptr;
428 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400429 if (type->fKind == ASTType::kStruct_Kind && this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700430 return nullptr;
431 }
432 Token name;
433 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
434 return nullptr;
435 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400436 if (this->checkNext(Token::LPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 std::vector<std::unique_ptr<ASTParameter>> parameters;
438 while (this->peek().fKind != Token::RPAREN) {
439 if (parameters.size() > 0) {
440 if (!this->expect(Token::COMMA, "','")) {
441 return nullptr;
442 }
443 }
444 std::unique_ptr<ASTParameter> parameter = this->parameter();
445 if (!parameter) {
446 return nullptr;
447 }
448 parameters.push_back(std::move(parameter));
449 }
450 this->nextToken();
451 std::unique_ptr<ASTBlock> body;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400452 if (!this->checkNext(Token::SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700453 body = this->block();
454 if (!body) {
455 return nullptr;
456 }
457 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700458 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fOffset,
Ethan Nicholascb670962017-04-20 19:31:52 -0400459 modifiers,
460 std::move(type),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700461 this->text(name),
Ethan Nicholas11d53972016-11-28 11:23:23 -0500462 std::move(parameters),
ethannicholasb3058bd2016-07-01 08:22:01 -0700463 std::move(body)));
464 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700465 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700466 }
467}
468
469/* modifiers type IDENTIFIER varDeclarationEnd */
ethannicholas14fe8cc2016-09-07 13:37:16 -0700470std::unique_ptr<ASTVarDeclarations> Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500471 Modifiers modifiers = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700472 std::unique_ptr<ASTType> type(this->type());
473 if (!type) {
474 return nullptr;
475 }
476 Token name;
477 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
478 return nullptr;
479 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700480 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700481}
482
483/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
484std::unique_ptr<ASTType> Parser::structDeclaration() {
485 if (!this->expect(Token::STRUCT, "'struct'")) {
486 return nullptr;
487 }
488 Token name;
489 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
490 return nullptr;
491 }
492 if (!this->expect(Token::LBRACE, "'{'")) {
493 return nullptr;
494 }
495 std::vector<Type::Field> fields;
496 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700497 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 if (!decl) {
499 return nullptr;
500 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700501 for (const auto& var : decl->fVars) {
ethannicholasd598f792016-07-25 10:08:54 -0700502 auto type = (const Type*) fTypes[decl->fType->fName];
ethannicholas14fe8cc2016-09-07 13:37:16 -0700503 for (int i = (int) var.fSizes.size() - 1; i >= 0; i--) {
ethannicholasdd4645b2016-10-14 12:14:46 -0700504 if (!var.fSizes[i] || var.fSizes[i]->fKind != ASTExpression::kInt_Kind) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700505 this->error(decl->fOffset, "array size in struct field must be a constant");
ethannicholasdd4645b2016-10-14 12:14:46 -0700506 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700508 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400509 String name = type->name() + "[" + to_string(columns) + "]";
Ethan Nicholas91164d12019-05-15 15:29:54 -0400510 type = (Type*) fTypes.takeOwnership(std::unique_ptr<Symbol>(
511 new Type(name,
512 Type::kArray_Kind,
513 *type,
514 (int) columns)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700516 fields.push_back(Type::Field(decl->fModifiers, var.fName, type));
517 if (var.fValue) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700518 this->error(decl->fOffset, "initializers are not permitted on struct fields");
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 }
520 }
521 }
522 if (!this->expect(Token::RBRACE, "'}'")) {
523 return nullptr;
524 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700525 fTypes.add(this->text(name), std::unique_ptr<Type>(new Type(name.fOffset, this->text(name),
526 fields)));
527 return std::unique_ptr<ASTType>(new ASTType(name.fOffset, this->text(name),
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500528 ASTType::kStruct_Kind, std::vector<int>(), false));
ethannicholasb3058bd2016-07-01 08:22:01 -0700529}
530
531/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500532std::unique_ptr<ASTVarDeclarations> Parser::structVarDeclaration(Modifiers modifiers) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 std::unique_ptr<ASTType> type = this->structDeclaration();
534 if (!type) {
535 return nullptr;
536 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400537 Token name;
538 if (this->checkNext(Token::IDENTIFIER, &name)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500539 std::unique_ptr<ASTVarDeclarations> result = this->varDeclarationEnd(modifiers,
540 std::move(type),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700541 this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700542 if (result) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700543 for (const auto& var : result->fVars) {
544 if (var.fValue) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700545 this->error(var.fValue->fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700546 "struct variables cannot be initialized");
547 }
548 }
549 }
550 return result;
551 }
552 this->expect(Token::SEMICOLON, "';'");
553 return nullptr;
554}
555
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400556/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
557 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500558std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
ethannicholas14fe8cc2016-09-07 13:37:16 -0700559 std::unique_ptr<ASTType> type,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700560 StringFragment name) {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700561 std::vector<ASTVarDeclaration> vars;
ethannicholasb3058bd2016-07-01 08:22:01 -0700562 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400563 while (this->checkNext(Token::LBRACKET)) {
564 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 currentVarSizes.push_back(nullptr);
566 } else {
567 std::unique_ptr<ASTExpression> size(this->expression());
568 if (!size) {
569 return nullptr;
570 }
571 currentVarSizes.push_back(std::move(size));
572 if (!this->expect(Token::RBRACKET, "']'")) {
573 return nullptr;
574 }
575 }
576 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700577 std::unique_ptr<ASTExpression> value;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400578 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400579 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 if (!value) {
581 return nullptr;
582 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700584 vars.emplace_back(name, std::move(currentVarSizes), std::move(value));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400585 while (this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700586 Token name;
587 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
588 return nullptr;
589 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700590 currentVarSizes.clear();
ethannicholas14fe8cc2016-09-07 13:37:16 -0700591 value.reset();
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400592 while (this->checkNext(Token::LBRACKET)) {
593 if (this->checkNext(Token::RBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700594 currentVarSizes.push_back(nullptr);
595 } else {
596 std::unique_ptr<ASTExpression> size(this->expression());
597 if (!size) {
598 return nullptr;
599 }
600 currentVarSizes.push_back(std::move(size));
601 if (!this->expect(Token::RBRACKET, "']'")) {
602 return nullptr;
603 }
604 }
605 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400606 if (this->checkNext(Token::EQ)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400607 value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700608 if (!value) {
609 return nullptr;
610 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700611 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700612 vars.emplace_back(this->text(name), std::move(currentVarSizes), std::move(value));
ethannicholasb3058bd2016-07-01 08:22:01 -0700613 }
614 if (!this->expect(Token::SEMICOLON, "';'")) {
615 return nullptr;
616 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700617 return std::unique_ptr<ASTVarDeclarations>(new ASTVarDeclarations(std::move(mods),
618 std::move(type),
619 std::move(vars)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700620}
621
622/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
623std::unique_ptr<ASTParameter> Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400624 Modifiers modifiers = this->modifiersWithDefaults(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 std::unique_ptr<ASTType> type = this->type();
626 if (!type) {
627 return nullptr;
628 }
629 Token name;
630 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
631 return nullptr;
632 }
633 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400634 while (this->checkNext(Token::LBRACKET)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700635 Token sizeToken;
636 if (!this->expect(Token::INT_LITERAL, "a positive integer", &sizeToken)) {
637 return nullptr;
638 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700639 sizes.push_back(SkSL::stoi(this->text(sizeToken)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700640 if (!this->expect(Token::RBRACKET, "']'")) {
641 return nullptr;
642 }
643 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700644 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fOffset, modifiers, std::move(type),
645 this->text(name), std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700646}
647
Ethan Nicholasd608c092017-10-26 09:30:08 -0400648/** EQ INT_LITERAL */
ethannicholasb3058bd2016-07-01 08:22:01 -0700649int Parser::layoutInt() {
650 if (!this->expect(Token::EQ, "'='")) {
651 return -1;
652 }
653 Token resultToken;
654 if (this->expect(Token::INT_LITERAL, "a non-negative integer", &resultToken)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700655 return SkSL::stoi(this->text(resultToken));
ethannicholasb3058bd2016-07-01 08:22:01 -0700656 }
657 return -1;
658}
659
Ethan Nicholasd608c092017-10-26 09:30:08 -0400660/** EQ IDENTIFIER */
661StringFragment Parser::layoutIdentifier() {
662 if (!this->expect(Token::EQ, "'='")) {
663 return StringFragment();
664 }
665 Token resultToken;
666 if (!this->expect(Token::IDENTIFIER, "an identifier", &resultToken)) {
667 return StringFragment();
668 }
669 return this->text(resultToken);
670}
671
672
Ethan Nicholas762466e2017-06-29 10:03:38 -0400673/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
674String Parser::layoutCode() {
675 if (!this->expect(Token::EQ, "'='")) {
676 return "";
677 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700678 Token start = this->nextRawToken();
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400679 this->pushback(start);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400680 String code;
681 int level = 1;
682 bool done = false;
683 while (!done) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700684 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400685 switch (next.fKind) {
686 case Token::LPAREN:
687 ++level;
688 break;
689 case Token::RPAREN:
690 --level;
691 break;
692 case Token::COMMA:
693 if (level == 1) {
694 done = true;
695 }
696 break;
697 case Token::END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700698 this->error(start, "reached end of file while parsing layout");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400699 return nullptr;
700 default:
701 break;
702 }
703 if (!level) {
704 done = true;
705 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400706 if (done) {
707 this->pushback(std::move(next));
708 }
709 else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700710 code += this->text(next);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400711 }
712 }
713 return code;
714}
715
716/** (EQ IDENTIFIER('identity'))? */
717Layout::Key Parser::layoutKey() {
718 if (this->peek().fKind == Token::EQ) {
719 this->expect(Token::EQ, "'='");
720 Token key;
721 if (this->expect(Token::IDENTIFIER, "an identifer", &key)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700722 if (this->text(key) == "identity") {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400723 return Layout::kIdentity_Key;
724 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700725 this->error(key, "unsupported layout key");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400726 }
727 }
728 }
729 return Layout::kKey_Key;
730}
731
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400732Layout::CType Parser::layoutCType() {
733 if (this->expect(Token::EQ, "'='")) {
734 Token t = this->nextToken();
735 String text = this->text(t);
736 auto found = layoutTokens->find(text);
737 if (found != layoutTokens->end()) {
738 switch (found->second) {
Brian Osmanf28e55d2018-10-03 16:35:54 -0400739 case LayoutToken::SKPMCOLOR4F:
740 return Layout::CType::kSkPMColor4f;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400741 case LayoutToken::SKRECT:
742 return Layout::CType::kSkRect;
743 case LayoutToken::SKIRECT:
744 return Layout::CType::kSkIRect;
745 case LayoutToken::SKPMCOLOR:
746 return Layout::CType::kSkPMColor;
Ethan Nicholasc1c686b2019-04-02 17:30:23 -0400747 case LayoutToken::BOOL:
748 return Layout::CType::kBool;
749 case LayoutToken::INT:
750 return Layout::CType::kInt32;
751 case LayoutToken::FLOAT:
752 return Layout::CType::kFloat;
Ethan Nicholas65e49ba2019-05-30 14:50:08 -0400753 case LayoutToken::SKMATRIX44:
754 return Layout::CType::kSkMatrix44;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400755 default:
756 break;
757 }
758 }
759 this->error(t, "unsupported ctype");
760 }
761 return Layout::CType::kDefault;
762}
763
ethannicholas8ac838d2016-11-22 08:39:36 -0800764/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500765Layout Parser::layout() {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500766 int flags = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700767 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500768 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700769 int binding = -1;
770 int index = -1;
771 int set = -1;
772 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500773 int inputAttachmentIndex = -1;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500774 Layout::Format format = Layout::Format::kUnspecified;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500775 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
776 int maxVertices = -1;
777 int invocations = -1;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400778 String when;
779 Layout::Key key = Layout::kNo_Key;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400780 Layout::CType ctype = Layout::CType::kDefault;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400781 if (this->checkNext(Token::LAYOUT)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700782 if (!this->expect(Token::LPAREN, "'('")) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500783 return Layout(flags, location, offset, binding, index, set, builtin,
784 inputAttachmentIndex, format, primitive, maxVertices, invocations, when,
785 key, ctype);
ethannicholasb3058bd2016-07-01 08:22:01 -0700786 }
787 for (;;) {
788 Token t = this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700789 String text = this->text(t);
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400790 auto found = layoutTokens->find(text);
791 if (found != layoutTokens->end()) {
792 switch (found->second) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700793 case LayoutToken::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500794 location = this->layoutInt();
795 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700796 case LayoutToken::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500797 offset = this->layoutInt();
798 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700799 case LayoutToken::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500800 binding = this->layoutInt();
801 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700802 case LayoutToken::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500803 index = this->layoutInt();
804 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700805 case LayoutToken::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500806 set = this->layoutInt();
807 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700808 case LayoutToken::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500809 builtin = this->layoutInt();
810 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700811 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500812 inputAttachmentIndex = this->layoutInt();
813 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700814 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500815 flags |= Layout::kOriginUpperLeft_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500816 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700817 case LayoutToken::OVERRIDE_COVERAGE:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500818 flags |= Layout::kOverrideCoverage_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500819 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700820 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500821 flags |= Layout::kBlendSupportAllEquations_Flag;
822 break;
823 case LayoutToken::BLEND_SUPPORT_MULTIPLY:
824 flags |= Layout::kBlendSupportMultiply_Flag;
825 break;
826 case LayoutToken::BLEND_SUPPORT_SCREEN:
827 flags |= Layout::kBlendSupportScreen_Flag;
828 break;
829 case LayoutToken::BLEND_SUPPORT_OVERLAY:
830 flags |= Layout::kBlendSupportOverlay_Flag;
831 break;
832 case LayoutToken::BLEND_SUPPORT_DARKEN:
833 flags |= Layout::kBlendSupportDarken_Flag;
834 break;
835 case LayoutToken::BLEND_SUPPORT_LIGHTEN:
836 flags |= Layout::kBlendSupportLighten_Flag;
837 break;
838 case LayoutToken::BLEND_SUPPORT_COLORDODGE:
839 flags |= Layout::kBlendSupportColorDodge_Flag;
840 break;
841 case LayoutToken::BLEND_SUPPORT_COLORBURN:
842 flags |= Layout::kBlendSupportColorBurn_Flag;
843 break;
844 case LayoutToken::BLEND_SUPPORT_HARDLIGHT:
845 flags |= Layout::kBlendSupportHardLight_Flag;
846 break;
847 case LayoutToken::BLEND_SUPPORT_SOFTLIGHT:
848 flags |= Layout::kBlendSupportSoftLight_Flag;
849 break;
850 case LayoutToken::BLEND_SUPPORT_DIFFERENCE:
851 flags |= Layout::kBlendSupportDifference_Flag;
852 break;
853 case LayoutToken::BLEND_SUPPORT_EXCLUSION:
854 flags |= Layout::kBlendSupportExclusion_Flag;
855 break;
856 case LayoutToken::BLEND_SUPPORT_HSL_HUE:
857 flags |= Layout::kBlendSupportHSLHue_Flag;
858 break;
859 case LayoutToken::BLEND_SUPPORT_HSL_SATURATION:
860 flags |= Layout::kBlendSupportHSLSaturation_Flag;
861 break;
862 case LayoutToken::BLEND_SUPPORT_HSL_COLOR:
863 flags |= Layout::kBlendSupportHSLColor_Flag;
864 break;
865 case LayoutToken::BLEND_SUPPORT_HSL_LUMINOSITY:
866 flags |= Layout::kBlendSupportHSLLuminosity_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500867 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700868 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500869 flags |= Layout::kPushConstant_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500870 break;
Michael Ludwiga4275592018-08-31 10:52:47 -0400871 case LayoutToken::TRACKED:
872 flags |= Layout::kTracked_Flag;
873 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700874 case LayoutToken::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500875 primitive = Layout::kPoints_Primitive;
876 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700877 case LayoutToken::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500878 primitive = Layout::kLines_Primitive;
879 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700880 case LayoutToken::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500881 primitive = Layout::kLineStrip_Primitive;
882 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700883 case LayoutToken::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500884 primitive = Layout::kLinesAdjacency_Primitive;
885 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700886 case LayoutToken::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500887 primitive = Layout::kTriangles_Primitive;
888 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700889 case LayoutToken::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500890 primitive = Layout::kTriangleStrip_Primitive;
891 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700892 case LayoutToken::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500893 primitive = Layout::kTrianglesAdjacency_Primitive;
894 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700895 case LayoutToken::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500896 maxVertices = this->layoutInt();
897 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700898 case LayoutToken::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500899 invocations = this->layoutInt();
900 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700901 case LayoutToken::WHEN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400902 when = this->layoutCode();
903 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700904 case LayoutToken::KEY:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400905 key = this->layoutKey();
906 break;
Ethan Nicholasd608c092017-10-26 09:30:08 -0400907 case LayoutToken::CTYPE:
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400908 ctype = this->layoutCType();
909 break;
910 default:
911 this->error(t, ("'" + text + "' is not a valid layout qualifier").c_str());
Ethan Nicholasd608c092017-10-26 09:30:08 -0400912 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500913 }
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400914 } else if (Layout::ReadFormat(text, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500915 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700916 } else {
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400917 this->error(t, ("'" + text + "' is not a valid layout qualifier").c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -0700918 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400919 if (this->checkNext(Token::RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700920 break;
921 }
922 if (!this->expect(Token::COMMA, "','")) {
923 break;
924 }
925 }
926 }
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500927 return Layout(flags, location, offset, binding, index, set, builtin, inputAttachmentIndex,
928 format, primitive, maxVertices, invocations, when, key, ctype);
ethannicholasb3058bd2016-07-01 08:22:01 -0700929}
930
Brian Salomonf9f45122016-11-29 11:59:17 -0500931/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholasa7ceb502019-01-11 10:31:48 -0500932 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER | PLS | PLSIN |
933 PLSOUT)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500934Modifiers Parser::modifiers() {
935 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700936 int flags = 0;
937 for (;;) {
938 // TODO: handle duplicate / incompatible flags
939 switch (peek().fKind) {
940 case Token::UNIFORM:
941 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500942 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700943 break;
944 case Token::CONST:
945 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500946 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700947 break;
948 case Token::IN:
949 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500950 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700951 break;
952 case Token::OUT:
953 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500954 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700955 break;
956 case Token::INOUT:
957 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500958 flags |= Modifiers::kIn_Flag;
959 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -0700960 break;
ethannicholasf789b382016-08-03 12:43:36 -0700961 case Token::FLAT:
962 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500963 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700964 break;
965 case Token::NOPERSPECTIVE:
966 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500967 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -0700968 break;
Brian Salomonf9f45122016-11-29 11:59:17 -0500969 case Token::READONLY:
970 this->nextToken();
971 flags |= Modifiers::kReadOnly_Flag;
972 break;
973 case Token::WRITEONLY:
974 this->nextToken();
975 flags |= Modifiers::kWriteOnly_Flag;
976 break;
977 case Token::COHERENT:
978 this->nextToken();
979 flags |= Modifiers::kCoherent_Flag;
980 break;
981 case Token::VOLATILE:
982 this->nextToken();
983 flags |= Modifiers::kVolatile_Flag;
984 break;
985 case Token::RESTRICT:
986 this->nextToken();
987 flags |= Modifiers::kRestrict_Flag;
988 break;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400989 case Token::BUFFER:
990 this->nextToken();
991 flags |= Modifiers::kBuffer_Flag;
992 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400993 case Token::HASSIDEEFFECTS:
994 this->nextToken();
995 flags |= Modifiers::kHasSideEffects_Flag;
996 break;
Ethan Nicholasa7ceb502019-01-11 10:31:48 -0500997 case Token::PLS:
998 this->nextToken();
999 flags |= Modifiers::kPLS_Flag;
1000 break;
1001 case Token::PLSIN:
1002 this->nextToken();
1003 flags |= Modifiers::kPLSIn_Flag;
1004 break;
1005 case Token::PLSOUT:
1006 this->nextToken();
1007 flags |= Modifiers::kPLSOut_Flag;
1008 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001009 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001010 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -07001011 }
1012 }
1013}
1014
Ethan Nicholas11d53972016-11-28 11:23:23 -05001015Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
1016 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -07001017 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001018 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 }
1020 return result;
1021}
1022
1023/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
1024std::unique_ptr<ASTStatement> Parser::statement() {
1025 Token start = this->peek();
1026 switch (start.fKind) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001027 case Token::IF: // fall through
1028 case Token::STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -07001029 return this->ifStatement();
1030 case Token::FOR:
1031 return this->forStatement();
1032 case Token::DO:
1033 return this->doStatement();
1034 case Token::WHILE:
1035 return this->whileStatement();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001036 case Token::SWITCH: // fall through
1037 case Token::STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -05001038 return this->switchStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001039 case Token::RETURN:
1040 return this->returnStatement();
1041 case Token::BREAK:
1042 return this->breakStatement();
1043 case Token::CONTINUE:
1044 return this->continueStatement();
1045 case Token::DISCARD:
1046 return this->discardStatement();
1047 case Token::LBRACE:
1048 return this->block();
1049 case Token::SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001050 this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001051 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fOffset,
ethannicholas0730be72016-09-01 07:59:02 -07001052 std::vector<std::unique_ptr<ASTStatement>>()));
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001053 case Token::CONST: {
ethannicholas14fe8cc2016-09-07 13:37:16 -07001054 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 if (!decl) {
1056 return nullptr;
1057 }
1058 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(std::move(decl)));
1059 }
1060 case Token::IDENTIFIER:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001061 if (this->isType(this->text(start))) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07001062 auto decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 if (!decl) {
1064 return nullptr;
1065 }
1066 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
1067 std::move(decl)));
1068 }
1069 // fall through
1070 default:
1071 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001072 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001073}
1074
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001075/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
ethannicholasb3058bd2016-07-01 08:22:01 -07001076std::unique_ptr<ASTType> Parser::type() {
1077 Token type;
1078 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
1079 return nullptr;
1080 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001081 if (!this->isType(this->text(type))) {
1082 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07001083 return nullptr;
1084 }
Ethan Nicholas50afc172017-02-16 14:49:57 -05001085 std::vector<int> sizes;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001086 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -05001087 if (this->peek().fKind != Token::RBRACKET) {
1088 int64_t i;
1089 if (this->intLiteral(&i)) {
1090 sizes.push_back(i);
1091 } else {
1092 return nullptr;
1093 }
1094 } else {
1095 sizes.push_back(-1);
1096 }
1097 this->expect(Token::RBRACKET, "']'");
1098 }
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001099 bool nullable = this->checkNext(Token::QUESTION);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001100 return std::unique_ptr<ASTType>(new ASTType(type.fOffset, this->text(type),
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001101 ASTType::kIdentifier_Kind, sizes, nullable));
ethannicholasb3058bd2016-07-01 08:22:01 -07001102}
1103
Ethan Nicholas50afc172017-02-16 14:49:57 -05001104/* IDENTIFIER LBRACE varDeclaration* RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? */
Ethan Nicholas11d53972016-11-28 11:23:23 -05001105std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 Token name;
1107 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
1108 return nullptr;
1109 }
1110 if (peek().fKind != Token::LBRACE) {
1111 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -05001112 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -07001113 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001114 this->error(name, "no type named '" + this->text(name) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001115 return nullptr;
1116 }
1117 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001118 std::vector<std::unique_ptr<ASTVarDeclarations>> decls;
ethannicholasb3058bd2016-07-01 08:22:01 -07001119 while (this->peek().fKind != Token::RBRACE) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07001120 std::unique_ptr<ASTVarDeclarations> decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 if (!decl) {
1122 return nullptr;
1123 }
1124 decls.push_back(std::move(decl));
1125 }
1126 this->nextToken();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001127 std::vector<std::unique_ptr<ASTExpression>> sizes;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001128 StringFragment instanceName;
1129 Token instanceNameToken;
1130 if (this->checkNext(Token::IDENTIFIER, &instanceNameToken)) {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001131 while (this->checkNext(Token::LBRACKET)) {
Ethan Nicholas50afc172017-02-16 14:49:57 -05001132 if (this->peek().fKind != Token::RBRACKET) {
1133 std::unique_ptr<ASTExpression> size = this->expression();
1134 if (!size) {
1135 return nullptr;
1136 }
1137 sizes.push_back(std::move(size));
1138 } else {
1139 sizes.push_back(nullptr);
1140 }
1141 this->expect(Token::RBRACKET, "']'");
1142 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001143 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 }
1145 this->expect(Token::SEMICOLON, "';'");
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001146 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fOffset, mods,
1147 this->text(name),
Brian Osman634624a2017-08-15 11:14:30 -04001148 std::move(decls),
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001149 instanceName,
Ethan Nicholas50afc172017-02-16 14:49:57 -05001150 std::move(sizes)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001151}
1152
1153/* IF LPAREN expression RPAREN statement (ELSE statement)? */
1154std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
1155 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001156 bool isStatic = this->checkNext(Token::STATIC_IF, &start);
1157 if (!isStatic && !this->expect(Token::IF, "'if'", &start)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001158 return nullptr;
1159 }
1160 if (!this->expect(Token::LPAREN, "'('")) {
1161 return nullptr;
1162 }
1163 std::unique_ptr<ASTExpression> test(this->expression());
1164 if (!test) {
1165 return nullptr;
1166 }
1167 if (!this->expect(Token::RPAREN, "')'")) {
1168 return nullptr;
1169 }
1170 std::unique_ptr<ASTStatement> ifTrue(this->statement());
1171 if (!ifTrue) {
1172 return nullptr;
1173 }
1174 std::unique_ptr<ASTStatement> ifFalse;
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001175 if (this->checkNext(Token::ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001176 ifFalse = this->statement();
1177 if (!ifFalse) {
1178 return nullptr;
1179 }
1180 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001181 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001182 isStatic,
1183 std::move(test),
Ethan Nicholas11d53972016-11-28 11:23:23 -05001184 std::move(ifTrue),
ethannicholasb3058bd2016-07-01 08:22:01 -07001185 std::move(ifFalse)));
1186}
1187
1188/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
1189std::unique_ptr<ASTDoStatement> Parser::doStatement() {
1190 Token start;
1191 if (!this->expect(Token::DO, "'do'", &start)) {
1192 return nullptr;
1193 }
1194 std::unique_ptr<ASTStatement> statement(this->statement());
1195 if (!statement) {
1196 return nullptr;
1197 }
1198 if (!this->expect(Token::WHILE, "'while'")) {
1199 return nullptr;
1200 }
1201 if (!this->expect(Token::LPAREN, "'('")) {
1202 return nullptr;
1203 }
1204 std::unique_ptr<ASTExpression> test(this->expression());
1205 if (!test) {
1206 return nullptr;
1207 }
1208 if (!this->expect(Token::RPAREN, "')'")) {
1209 return nullptr;
1210 }
1211 if (!this->expect(Token::SEMICOLON, "';'")) {
1212 return nullptr;
1213 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001214 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001215 std::move(statement),
1216 std::move(test)));
1217}
1218
1219/* WHILE LPAREN expression RPAREN STATEMENT */
1220std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
1221 Token start;
1222 if (!this->expect(Token::WHILE, "'while'", &start)) {
1223 return nullptr;
1224 }
1225 if (!this->expect(Token::LPAREN, "'('")) {
1226 return nullptr;
1227 }
1228 std::unique_ptr<ASTExpression> test(this->expression());
1229 if (!test) {
1230 return nullptr;
1231 }
1232 if (!this->expect(Token::RPAREN, "')'")) {
1233 return nullptr;
1234 }
1235 std::unique_ptr<ASTStatement> statement(this->statement());
1236 if (!statement) {
1237 return nullptr;
1238 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001239 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fOffset,
Ethan Nicholas11d53972016-11-28 11:23:23 -05001240 std::move(test),
ethannicholasb3058bd2016-07-01 08:22:01 -07001241 std::move(statement)));
1242}
1243
Ethan Nicholasaf197692017-02-27 13:26:45 -05001244/* CASE expression COLON statement* */
1245std::unique_ptr<ASTSwitchCase> Parser::switchCase() {
1246 Token start;
1247 if (!this->expect(Token::CASE, "'case'", &start)) {
1248 return nullptr;
1249 }
1250 std::unique_ptr<ASTExpression> value = this->expression();
1251 if (!value) {
1252 return nullptr;
1253 }
1254 if (!this->expect(Token::COLON, "':'")) {
1255 return nullptr;
1256 }
1257 std::vector<std::unique_ptr<ASTStatement>> statements;
1258 while (this->peek().fKind != Token::RBRACE && this->peek().fKind != Token::CASE &&
1259 this->peek().fKind != Token::DEFAULT) {
1260 std::unique_ptr<ASTStatement> s = this->statement();
1261 if (!s) {
1262 return nullptr;
1263 }
1264 statements.push_back(std::move(s));
1265 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001266 return std::unique_ptr<ASTSwitchCase>(new ASTSwitchCase(start.fOffset, std::move(value),
Ethan Nicholasaf197692017-02-27 13:26:45 -05001267 std::move(statements)));
1268}
1269
1270/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
1271std::unique_ptr<ASTStatement> Parser::switchStatement() {
1272 Token start;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001273 bool isStatic = this->checkNext(Token::STATIC_SWITCH, &start);
1274 if (!isStatic && !this->expect(Token::SWITCH, "'switch'", &start)) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001275 return nullptr;
1276 }
1277 if (!this->expect(Token::LPAREN, "'('")) {
1278 return nullptr;
1279 }
1280 std::unique_ptr<ASTExpression> value(this->expression());
1281 if (!value) {
1282 return nullptr;
1283 }
1284 if (!this->expect(Token::RPAREN, "')'")) {
1285 return nullptr;
1286 }
1287 if (!this->expect(Token::LBRACE, "'{'")) {
1288 return nullptr;
1289 }
1290 std::vector<std::unique_ptr<ASTSwitchCase>> cases;
1291 while (this->peek().fKind == Token::CASE) {
1292 std::unique_ptr<ASTSwitchCase> c = this->switchCase();
1293 if (!c) {
1294 return nullptr;
1295 }
1296 cases.push_back(std::move(c));
1297 }
1298 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1299 // parts of the compiler may rely upon this assumption.
1300 if (this->peek().fKind == Token::DEFAULT) {
1301 Token defaultStart;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001302 SkAssertResult(this->expect(Token::DEFAULT, "'default'", &defaultStart));
Ethan Nicholasaf197692017-02-27 13:26:45 -05001303 if (!this->expect(Token::COLON, "':'")) {
1304 return nullptr;
1305 }
1306 std::vector<std::unique_ptr<ASTStatement>> statements;
1307 while (this->peek().fKind != Token::RBRACE) {
1308 std::unique_ptr<ASTStatement> s = this->statement();
1309 if (!s) {
1310 return nullptr;
1311 }
1312 statements.push_back(std::move(s));
1313 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001314 cases.emplace_back(new ASTSwitchCase(defaultStart.fOffset, nullptr,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001315 std::move(statements)));
1316 }
1317 if (!this->expect(Token::RBRACE, "'}'")) {
1318 return nullptr;
1319 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001320 return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001321 isStatic,
Ethan Nicholasaf197692017-02-27 13:26:45 -05001322 std::move(value),
1323 std::move(cases)));
1324}
1325
Ethan Nicholas11d53972016-11-28 11:23:23 -05001326/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001327 STATEMENT */
1328std::unique_ptr<ASTForStatement> Parser::forStatement() {
1329 Token start;
1330 if (!this->expect(Token::FOR, "'for'", &start)) {
1331 return nullptr;
1332 }
1333 if (!this->expect(Token::LPAREN, "'('")) {
1334 return nullptr;
1335 }
1336 std::unique_ptr<ASTStatement> initializer;
1337 Token nextToken = this->peek();
1338 switch (nextToken.fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001339 case Token::SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001340 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001341 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001342 case Token::CONST: {
1343 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1344 if (!vd) {
1345 return nullptr;
1346 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001347 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001348 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001349 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001350 }
1351 case Token::IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001352 if (this->isType(this->text(nextToken))) {
ethannicholasa54401d2016-10-14 08:37:32 -07001353 std::unique_ptr<ASTVarDeclarations> vd = this->varDeclarations();
1354 if (!vd) {
1355 return nullptr;
1356 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001357 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
ethannicholasa54401d2016-10-14 08:37:32 -07001358 std::move(vd)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001359 break;
1360 }
ethannicholasa54401d2016-10-14 08:37:32 -07001361 } // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001362 default:
1363 initializer = this->expressionStatement();
1364 }
1365 std::unique_ptr<ASTExpression> test;
1366 if (this->peek().fKind != Token::SEMICOLON) {
1367 test = this->expression();
1368 if (!test) {
1369 return nullptr;
1370 }
1371 }
1372 if (!this->expect(Token::SEMICOLON, "';'")) {
1373 return nullptr;
1374 }
1375 std::unique_ptr<ASTExpression> next;
ethannicholas22f939e2016-10-13 13:25:34 -07001376 if (this->peek().fKind != Token::RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001377 next = this->expression();
1378 if (!next) {
1379 return nullptr;
1380 }
1381 }
1382 if (!this->expect(Token::RPAREN, "')'")) {
1383 return nullptr;
1384 }
1385 std::unique_ptr<ASTStatement> statement(this->statement());
1386 if (!statement) {
1387 return nullptr;
1388 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001389 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001390 std::move(initializer),
1391 std::move(test), std::move(next),
1392 std::move(statement)));
1393}
1394
1395/* RETURN expression? SEMICOLON */
1396std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
1397 Token start;
1398 if (!this->expect(Token::RETURN, "'return'", &start)) {
1399 return nullptr;
1400 }
1401 std::unique_ptr<ASTExpression> expression;
1402 if (this->peek().fKind != Token::SEMICOLON) {
1403 expression = this->expression();
1404 if (!expression) {
1405 return nullptr;
1406 }
1407 }
1408 if (!this->expect(Token::SEMICOLON, "';'")) {
1409 return nullptr;
1410 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001411 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001412 std::move(expression)));
1413}
1414
1415/* BREAK SEMICOLON */
1416std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
1417 Token start;
1418 if (!this->expect(Token::BREAK, "'break'", &start)) {
1419 return nullptr;
1420 }
1421 if (!this->expect(Token::SEMICOLON, "';'")) {
1422 return nullptr;
1423 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001424 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -07001425}
1426
1427/* CONTINUE SEMICOLON */
1428std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
1429 Token start;
1430 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
1431 return nullptr;
1432 }
1433 if (!this->expect(Token::SEMICOLON, "';'")) {
1434 return nullptr;
1435 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001436 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -07001437}
1438
1439/* DISCARD SEMICOLON */
1440std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
1441 Token start;
1442 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
1443 return nullptr;
1444 }
1445 if (!this->expect(Token::SEMICOLON, "';'")) {
1446 return nullptr;
1447 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001448 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -07001449}
1450
1451/* LBRACE statement* RBRACE */
1452std::unique_ptr<ASTBlock> Parser::block() {
ethannicholascad64162016-10-27 10:54:02 -07001453 AutoDepth depth(this);
1454 if (!depth.checkValid()) {
1455 return nullptr;
1456 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001457 Token start;
1458 if (!this->expect(Token::LBRACE, "'{'", &start)) {
1459 return nullptr;
1460 }
1461 std::vector<std::unique_ptr<ASTStatement>> statements;
1462 for (;;) {
1463 switch (this->peek().fKind) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001464 case Token::RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001465 this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001466 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001467 std::move(statements)));
Ethan Nicholas11d53972016-11-28 11:23:23 -05001468 case Token::END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001469 this->error(this->peek(), "expected '}', but found end of file");
ethannicholasb3058bd2016-07-01 08:22:01 -07001470 return nullptr;
1471 default: {
1472 std::unique_ptr<ASTStatement> statement = this->statement();
1473 if (!statement) {
1474 return nullptr;
1475 }
1476 statements.push_back(std::move(statement));
1477 }
1478 }
1479 }
1480}
1481
1482/* expression SEMICOLON */
1483std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
1484 std::unique_ptr<ASTExpression> expr = this->expression();
1485 if (expr) {
1486 if (this->expect(Token::SEMICOLON, "';'")) {
1487 ASTExpressionStatement* result = new ASTExpressionStatement(std::move(expr));
1488 return std::unique_ptr<ASTExpressionStatement>(result);
1489 }
1490 }
1491 return nullptr;
1492}
1493
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001494/* commaExpression */
ethannicholasb3058bd2016-07-01 08:22:01 -07001495std::unique_ptr<ASTExpression> Parser::expression() {
ethannicholascad64162016-10-27 10:54:02 -07001496 AutoDepth depth(this);
1497 if (!depth.checkValid()) {
1498 return nullptr;
1499 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001500 return this->commaExpression();
1501}
1502
1503/* assignmentExpression (COMMA assignmentExpression)* */
1504std::unique_ptr<ASTExpression> Parser::commaExpression() {
1505 std::unique_ptr<ASTExpression> result = this->assignmentExpression();
1506 if (!result) {
1507 return nullptr;
1508 }
1509 Token t;
1510 while (this->checkNext(Token::COMMA, &t)) {
1511 std::unique_ptr<ASTExpression> right = this->commaExpression();
1512 if (!right) {
1513 return nullptr;
1514 }
Brian Osman634624a2017-08-15 11:14:30 -04001515 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001516 }
1517 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001518}
1519
1520/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1521 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1522 assignmentExpression)*
1523 */
1524std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
1525 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
1526 if (!result) {
1527 return nullptr;
1528 }
1529 for (;;) {
1530 switch (this->peek().fKind) {
1531 case Token::EQ: // fall through
1532 case Token::STAREQ: // fall through
1533 case Token::SLASHEQ: // fall through
1534 case Token::PERCENTEQ: // fall through
1535 case Token::PLUSEQ: // fall through
1536 case Token::MINUSEQ: // fall through
1537 case Token::SHLEQ: // fall through
1538 case Token::SHREQ: // fall through
1539 case Token::BITWISEANDEQ: // fall through
1540 case Token::BITWISEXOREQ: // fall through
1541 case Token::BITWISEOREQ: // fall through
1542 case Token::LOGICALANDEQ: // fall through
1543 case Token::LOGICALXOREQ: // fall through
1544 case Token::LOGICALOREQ: {
1545 Token t = this->nextToken();
1546 std::unique_ptr<ASTExpression> right = this->assignmentExpression();
1547 if (!right) {
1548 return nullptr;
1549 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001550 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression(std::move(result),
Brian Osman634624a2017-08-15 11:14:30 -04001551 std::move(t),
ethannicholasb3058bd2016-07-01 08:22:01 -07001552 std::move(right)));
Ethan Nicholas371e29c2018-03-19 13:40:37 -04001553 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001554 }
1555 default:
1556 return result;
1557 }
1558 }
1559}
1560
1561/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1562std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
1563 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
1564 if (!result) {
1565 return nullptr;
1566 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001567 if (this->checkNext(Token::QUESTION)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 std::unique_ptr<ASTExpression> trueExpr = this->expression();
1569 if (!trueExpr) {
1570 return nullptr;
1571 }
1572 if (this->expect(Token::COLON, "':'")) {
1573 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpression();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001574 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std::move(result),
1575 std::move(trueExpr),
ethannicholasb3058bd2016-07-01 08:22:01 -07001576 std::move(falseExpr)));
1577 }
1578 return nullptr;
1579 }
1580 return result;
1581}
1582
1583/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1584std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
1585 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
1586 if (!result) {
1587 return nullptr;
1588 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001589 Token t;
1590 while (this->checkNext(Token::LOGICALOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
1592 if (!right) {
1593 return nullptr;
1594 }
Brian Osman634624a2017-08-15 11:14:30 -04001595 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 }
1597 return result;
1598}
1599
1600/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1601std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
1602 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
1603 if (!result) {
1604 return nullptr;
1605 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001606 Token t;
1607 while (this->checkNext(Token::LOGICALXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001608 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
1609 if (!right) {
1610 return nullptr;
1611 }
Brian Osman634624a2017-08-15 11:14:30 -04001612 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001613 }
1614 return result;
1615}
1616
1617/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1618std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
1619 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
1620 if (!result) {
1621 return nullptr;
1622 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001623 Token t;
1624 while (this->checkNext(Token::LOGICALAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001625 std::unique_ptr<ASTExpression> right = this->bitwiseOrExpression();
1626 if (!right) {
1627 return nullptr;
1628 }
Brian Osman634624a2017-08-15 11:14:30 -04001629 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001630 }
1631 return result;
1632}
1633
1634/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1635std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
1636 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
1637 if (!result) {
1638 return nullptr;
1639 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001640 Token t;
1641 while (this->checkNext(Token::BITWISEOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001642 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
1643 if (!right) {
1644 return nullptr;
1645 }
Brian Osman634624a2017-08-15 11:14:30 -04001646 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 }
1648 return result;
1649}
1650
1651/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1652std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
1653 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1654 if (!result) {
1655 return nullptr;
1656 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001657 Token t;
1658 while (this->checkNext(Token::BITWISEXOR, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001659 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1660 if (!right) {
1661 return nullptr;
1662 }
Brian Osman634624a2017-08-15 11:14:30 -04001663 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001664 }
1665 return result;
1666}
1667
1668/* equalityExpression (BITWISEAND equalityExpression)* */
1669std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1670 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1671 if (!result) {
1672 return nullptr;
1673 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001674 Token t;
1675 while (this->checkNext(Token::BITWISEAND, &t)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1677 if (!right) {
1678 return nullptr;
1679 }
Brian Osman634624a2017-08-15 11:14:30 -04001680 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001681 }
1682 return result;
1683}
1684
1685/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1686std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1687 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1688 if (!result) {
1689 return nullptr;
1690 }
1691 for (;;) {
1692 switch (this->peek().fKind) {
1693 case Token::EQEQ: // fall through
1694 case Token::NEQ: {
1695 Token t = this->nextToken();
1696 std::unique_ptr<ASTExpression> right = this->relationalExpression();
1697 if (!right) {
1698 return nullptr;
1699 }
Brian Osman634624a2017-08-15 11:14:30 -04001700 result.reset(new ASTBinaryExpression(std::move(result), std::move(t), std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 break;
1702 }
1703 default:
1704 return result;
1705 }
1706 }
1707}
1708
1709/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1710std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1711 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1712 if (!result) {
1713 return nullptr;
1714 }
1715 for (;;) {
1716 switch (this->peek().fKind) {
1717 case Token::LT: // fall through
1718 case Token::GT: // fall through
1719 case Token::LTEQ: // fall through
1720 case Token::GTEQ: {
1721 Token t = this->nextToken();
1722 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1723 if (!right) {
1724 return nullptr;
1725 }
Brian Osman634624a2017-08-15 11:14:30 -04001726 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1727 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001728 break;
1729 }
1730 default:
1731 return result;
1732 }
1733 }
1734}
1735
1736/* additiveExpression ((SHL | SHR) additiveExpression)* */
1737std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1738 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1739 if (!result) {
1740 return nullptr;
1741 }
1742 for (;;) {
1743 switch (this->peek().fKind) {
1744 case Token::SHL: // fall through
1745 case Token::SHR: {
1746 Token t = this->nextToken();
1747 std::unique_ptr<ASTExpression> right = this->additiveExpression();
1748 if (!right) {
1749 return nullptr;
1750 }
Brian Osman634624a2017-08-15 11:14:30 -04001751 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1752 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001753 break;
1754 }
1755 default:
1756 return result;
1757 }
1758 }
1759}
1760
1761/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1762std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1763 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1764 if (!result) {
1765 return nullptr;
1766 }
1767 for (;;) {
1768 switch (this->peek().fKind) {
1769 case Token::PLUS: // fall through
1770 case Token::MINUS: {
1771 Token t = this->nextToken();
1772 std::unique_ptr<ASTExpression> right = this->multiplicativeExpression();
1773 if (!right) {
1774 return nullptr;
1775 }
Brian Osman634624a2017-08-15 11:14:30 -04001776 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1777 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001778 break;
1779 }
1780 default:
1781 return result;
1782 }
1783 }
1784}
1785
1786/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1787std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1788 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1789 if (!result) {
1790 return nullptr;
1791 }
1792 for (;;) {
1793 switch (this->peek().fKind) {
1794 case Token::STAR: // fall through
1795 case Token::SLASH: // fall through
1796 case Token::PERCENT: {
1797 Token t = this->nextToken();
1798 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1799 if (!right) {
1800 return nullptr;
1801 }
Brian Osman634624a2017-08-15 11:14:30 -04001802 result.reset(new ASTBinaryExpression(std::move(result), std::move(t),
1803 std::move(right)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001804 break;
1805 }
1806 default:
1807 return result;
1808 }
1809 }
1810}
1811
1812/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1813std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1814 switch (this->peek().fKind) {
ethannicholas5961bc92016-10-12 06:39:56 -07001815 case Token::PLUS: // fall through
1816 case Token::MINUS: // fall through
1817 case Token::LOGICALNOT: // fall through
1818 case Token::BITWISENOT: // fall through
1819 case Token::PLUSPLUS: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 case Token::MINUSMINUS: {
Ethan Nicholas6dcc3252019-02-20 15:18:36 -05001821 AutoDepth depth(this);
1822 if (!depth.checkValid()) {
1823 return nullptr;
1824 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001825 Token t = this->nextToken();
1826 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1827 if (!expr) {
1828 return nullptr;
1829 }
Brian Osman634624a2017-08-15 11:14:30 -04001830 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(std::move(t),
1831 std::move(expr)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001832 }
1833 default:
1834 return this->postfixExpression();
1835 }
1836}
1837
1838/* term suffix* */
1839std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1840 std::unique_ptr<ASTExpression> result = this->term();
1841 if (!result) {
1842 return nullptr;
1843 }
1844 for (;;) {
1845 switch (this->peek().fKind) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001846 case Token::LBRACKET: // fall through
1847 case Token::DOT: // fall through
1848 case Token::LPAREN: // fall through
1849 case Token::PLUSPLUS: // fall through
1850 case Token::MINUSMINUS: // fall through
1851 case Token::COLONCOLON: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001852 std::unique_ptr<ASTSuffix> s = this->suffix();
1853 if (!s) {
1854 return nullptr;
1855 }
1856 result.reset(new ASTSuffixExpression(std::move(result), std::move(s)));
1857 break;
1858 }
1859 default:
1860 return result;
1861 }
1862 }
1863}
1864
Ethan Nicholas11d53972016-11-28 11:23:23 -05001865/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001866 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER */
ethannicholasb3058bd2016-07-01 08:22:01 -07001867std::unique_ptr<ASTSuffix> Parser::suffix() {
1868 Token next = this->nextToken();
1869 switch (next.fKind) {
1870 case Token::LBRACKET: {
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001871 if (this->checkNext(Token::RBRACKET)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001872 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fOffset));
ethannicholas5961bc92016-10-12 06:39:56 -07001873 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001874 std::unique_ptr<ASTExpression> e = this->expression();
1875 if (!e) {
1876 return nullptr;
1877 }
1878 this->expect(Token::RBRACKET, "']' to complete array access expression");
1879 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1880 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001881 case Token::DOT: // fall through
1882 case Token::COLONCOLON: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001883 int offset = this->peek().fOffset;
1884 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001885 if (this->identifier(&text)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001886 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(offset, std::move(text)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001887 }
1888 return nullptr;
1889 }
1890 case Token::LPAREN: {
1891 std::vector<std::unique_ptr<ASTExpression>> parameters;
1892 if (this->peek().fKind != Token::RPAREN) {
1893 for (;;) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001894 std::unique_ptr<ASTExpression> expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001895 if (!expr) {
1896 return nullptr;
1897 }
1898 parameters.push_back(std::move(expr));
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001899 if (!this->checkNext(Token::COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001900 break;
1901 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001902 }
1903 }
1904 this->expect(Token::RPAREN, "')' to complete function parameters");
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001905 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001906 std::move(parameters)));
1907 }
1908 case Token::PLUSPLUS:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001909 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001910 ASTSuffix::kPostIncrement_Kind));
1911 case Token::MINUSMINUS:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001912 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001913 ASTSuffix::kPostDecrement_Kind));
1914 default: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001915 this->error(next, "expected expression suffix, but found '" + this->text(next) +
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 "'\n");
1917 return nullptr;
1918 }
1919 }
1920}
1921
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001922/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | NULL_LITERAL | '(' expression ')' */
ethannicholasb3058bd2016-07-01 08:22:01 -07001923std::unique_ptr<ASTExpression> Parser::term() {
1924 std::unique_ptr<ASTExpression> result;
1925 Token t = this->peek();
1926 switch (t.fKind) {
1927 case Token::IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001928 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001929 if (this->identifier(&text)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001930 result.reset(new ASTIdentifier(t.fOffset, std::move(text)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001931 }
1932 break;
1933 }
1934 case Token::INT_LITERAL: {
1935 int64_t i;
1936 if (this->intLiteral(&i)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001937 result.reset(new ASTIntLiteral(t.fOffset, i));
ethannicholasb3058bd2016-07-01 08:22:01 -07001938 }
1939 break;
1940 }
1941 case Token::FLOAT_LITERAL: {
1942 double f;
1943 if (this->floatLiteral(&f)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001944 result.reset(new ASTFloatLiteral(t.fOffset, f));
ethannicholasb3058bd2016-07-01 08:22:01 -07001945 }
1946 break;
1947 }
1948 case Token::TRUE_LITERAL: // fall through
1949 case Token::FALSE_LITERAL: {
1950 bool b;
1951 if (this->boolLiteral(&b)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001952 result.reset(new ASTBoolLiteral(t.fOffset, b));
ethannicholasb3058bd2016-07-01 08:22:01 -07001953 }
1954 break;
1955 }
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001956 case Token::NULL_LITERAL:
1957 this->nextToken();
1958 result.reset(new ASTNullLiteral(t.fOffset));
1959 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001960 case Token::LPAREN: {
1961 this->nextToken();
1962 result = this->expression();
1963 if (result) {
1964 this->expect(Token::RPAREN, "')' to complete expression");
1965 }
1966 break;
1967 }
1968 default:
1969 this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001970 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07001971 result = nullptr;
1972 }
1973 return result;
1974}
1975
1976/* INT_LITERAL */
1977bool Parser::intLiteral(int64_t* dest) {
1978 Token t;
1979 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001980 *dest = SkSL::stol(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07001981 return true;
1982 }
1983 return false;
1984}
1985
1986/* FLOAT_LITERAL */
1987bool Parser::floatLiteral(double* dest) {
1988 Token t;
1989 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001990 *dest = SkSL::stod(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07001991 return true;
1992 }
1993 return false;
1994}
1995
1996/* TRUE_LITERAL | FALSE_LITERAL */
1997bool Parser::boolLiteral(bool* dest) {
1998 Token t = this->nextToken();
1999 switch (t.fKind) {
2000 case Token::TRUE_LITERAL:
2001 *dest = true;
2002 return true;
2003 case Token::FALSE_LITERAL:
2004 *dest = false;
2005 return true;
2006 default:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002007 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 return false;
2009 }
2010}
2011
2012/* IDENTIFIER */
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002013bool Parser::identifier(StringFragment* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 Token t;
2015 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002016 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07002017 return true;
2018 }
2019 return false;
2020}
2021
2022} // namespace