blob: fd07afa05ba05d1be1295e7526076cbe2918b4ec [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
Mike Klein4b432fa2019-06-06 11:44:05 -05008#include "src/sksl/SkSLParser.h"
John Stilesfbd050b2020-08-03 13:21:46 -04009
10#include <memory>
11#include "stdio.h"
12
13#include "src/sksl/SkSLASTNode.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/ir/SkSLModifiers.h"
15#include "src/sksl/ir/SkSLSymbolTable.h"
16#include "src/sksl/ir/SkSLType.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040018#ifndef SKSL_STANDALONE
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/private/SkOnce.h"
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040020#endif
21
ethannicholasb3058bd2016-07-01 08:22:01 -070022namespace SkSL {
23
John Stiles8d056592020-11-10 10:03:50 -050024static constexpr int kMaxParseDepth = 50;
John Stilesd39aec92020-12-03 14:37:16 -050025static constexpr int kMaxStructDepth = 8;
John Stilesa695d622020-11-10 10:04:26 -050026
27static bool struct_is_too_deeply_nested(const Type& type, int limit) {
28 if (limit < 0) {
29 return true;
30 }
31
John Stilesc0c51062020-12-03 17:16:29 -050032 if (type.isStruct()) {
John Stilesa695d622020-11-10 10:04:26 -050033 for (const Type::Field& f : type.fields()) {
34 if (struct_is_too_deeply_nested(*f.fType, limit - 1)) {
35 return true;
36 }
37 }
38 }
39
40 return false;
41}
ethannicholascad64162016-10-27 10:54:02 -070042
43class AutoDepth {
44public:
45 AutoDepth(Parser* p)
Ethan Nicholascf4deab2019-09-13 16:28:14 -040046 : fParser(p)
47 , fDepth(0) {}
ethannicholascad64162016-10-27 10:54:02 -070048
49 ~AutoDepth() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -040050 fParser->fDepth -= fDepth;
ethannicholascad64162016-10-27 10:54:02 -070051 }
52
Ethan Nicholascf4deab2019-09-13 16:28:14 -040053 bool increase() {
54 ++fDepth;
55 ++fParser->fDepth;
John Stiles8d056592020-11-10 10:03:50 -050056 if (fParser->fDepth > kMaxParseDepth) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070057 fParser->error(fParser->peek(), String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070058 return false;
59 }
60 return true;
61 }
62
63private:
64 Parser* fParser;
Ethan Nicholascf4deab2019-09-13 16:28:14 -040065 int fDepth;
ethannicholascad64162016-10-27 10:54:02 -070066};
67
Brian Salomon140f3da2018-08-23 13:51:27 +000068std::unordered_map<String, Parser::LayoutToken>* Parser::layoutTokens;
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040069
70void Parser::InitLayoutMap() {
Brian Salomon140f3da2018-08-23 13:51:27 +000071 layoutTokens = new std::unordered_map<String, LayoutToken>;
Brian Salomon23356442018-11-30 15:33:19 -050072 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040073 TOKEN(LOCATION, "location");
74 TOKEN(OFFSET, "offset");
75 TOKEN(BINDING, "binding");
76 TOKEN(INDEX, "index");
77 TOKEN(SET, "set");
78 TOKEN(BUILTIN, "builtin");
79 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
80 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
81 TOKEN(OVERRIDE_COVERAGE, "override_coverage");
82 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
83 TOKEN(BLEND_SUPPORT_MULTIPLY, "blend_support_multiply");
84 TOKEN(BLEND_SUPPORT_SCREEN, "blend_support_screen");
85 TOKEN(BLEND_SUPPORT_OVERLAY, "blend_support_overlay");
86 TOKEN(BLEND_SUPPORT_DARKEN, "blend_support_darken");
87 TOKEN(BLEND_SUPPORT_LIGHTEN, "blend_support_lighten");
88 TOKEN(BLEND_SUPPORT_COLORDODGE, "blend_support_colordodge");
89 TOKEN(BLEND_SUPPORT_COLORBURN, "blend_support_colorburn");
90 TOKEN(BLEND_SUPPORT_HARDLIGHT, "blend_support_hardlight");
91 TOKEN(BLEND_SUPPORT_SOFTLIGHT, "blend_support_softlight");
92 TOKEN(BLEND_SUPPORT_DIFFERENCE, "blend_support_difference");
93 TOKEN(BLEND_SUPPORT_EXCLUSION, "blend_support_exclusion");
94 TOKEN(BLEND_SUPPORT_HSL_HUE, "blend_support_hsl_hue");
95 TOKEN(BLEND_SUPPORT_HSL_SATURATION, "blend_support_hsl_saturation");
96 TOKEN(BLEND_SUPPORT_HSL_COLOR, "blend_support_hsl_color");
97 TOKEN(BLEND_SUPPORT_HSL_LUMINOSITY, "blend_support_hsl_luminosity");
98 TOKEN(PUSH_CONSTANT, "push_constant");
99 TOKEN(POINTS, "points");
100 TOKEN(LINES, "lines");
101 TOKEN(LINE_STRIP, "line_strip");
102 TOKEN(LINES_ADJACENCY, "lines_adjacency");
103 TOKEN(TRIANGLES, "triangles");
104 TOKEN(TRIANGLE_STRIP, "triangle_strip");
105 TOKEN(TRIANGLES_ADJACENCY, "triangles_adjacency");
106 TOKEN(MAX_VERTICES, "max_vertices");
107 TOKEN(INVOCATIONS, "invocations");
Brian Osmanf59a9612020-04-15 14:18:13 -0400108 TOKEN(MARKER, "marker");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400109 TOKEN(WHEN, "when");
110 TOKEN(KEY, "key");
Michael Ludwiga4275592018-08-31 10:52:47 -0400111 TOKEN(TRACKED, "tracked");
Brian Osmanb32d66b2020-04-30 17:12:03 -0400112 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400113 TOKEN(CTYPE, "ctype");
Brian Osmanf28e55d2018-10-03 16:35:54 -0400114 TOKEN(SKPMCOLOR4F, "SkPMColor4f");
Mike Reedb26b4e72020-01-22 14:31:21 -0500115 TOKEN(SKV4, "SkV4");
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400116 TOKEN(SKRECT, "SkRect");
117 TOKEN(SKIRECT, "SkIRect");
118 TOKEN(SKPMCOLOR, "SkPMColor");
Mike Reedb26b4e72020-01-22 14:31:21 -0500119 TOKEN(SKM44, "SkM44");
Ethan Nicholasc1c686b2019-04-02 17:30:23 -0400120 TOKEN(BOOL, "bool");
121 TOKEN(INT, "int");
122 TOKEN(FLOAT, "float");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400123 #undef TOKEN
124}
125
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400126Parser::Parser(const char* text, size_t length, SymbolTable& symbols, ErrorReporter& errors)
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700127: fText(text)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400128, fPushback(Token::Kind::TK_INVALID, -1, -1)
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400129, fSymbols(symbols)
ethannicholasb3058bd2016-07-01 08:22:01 -0700130, fErrors(errors) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700131 fLexer.start(text, length);
Brian Salomon3b83afe2018-08-23 11:04:36 -0400132 static const bool layoutMapInitialized = []{ return (void)InitLayoutMap(), true; }();
133 (void) layoutMapInitialized;
ethannicholasb3058bd2016-07-01 08:22:01 -0700134}
135
John Stiles3b209362020-11-16 17:03:10 -0500136template <typename... Args>
137ASTNode::ID Parser::createNode(Args&&... args) {
138 ASTNode::ID result(fFile->fNodes.size());
139 fFile->fNodes.emplace_back(&fFile->fNodes, std::forward<Args>(args)...);
140 return result;
141}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400142
John Stiles3b209362020-11-16 17:03:10 -0500143ASTNode::ID Parser::addChild(ASTNode::ID target, ASTNode::ID child) {
144 fFile->fNodes[target.fValue].addChild(child);
145 return child;
146}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400147
John Stiles3b209362020-11-16 17:03:10 -0500148void Parser::createEmptyChild(ASTNode::ID target) {
149 ASTNode::ID child(fFile->fNodes.size());
150 fFile->fNodes.emplace_back();
151 fFile->fNodes[target.fValue].addChild(child);
152}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400153
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400154/* (directive | section | declaration)* END_OF_FILE */
Ethan Nicholasba9a04f2020-11-06 09:28:04 -0500155std::unique_ptr<ASTFile> Parser::compilationUnit() {
John Stilesfbd050b2020-08-03 13:21:46 -0400156 fFile = std::make_unique<ASTFile>();
John Stiles3b209362020-11-16 17:03:10 -0500157 ASTNode::ID result = this->createNode(/*offset=*/0, ASTNode::Kind::kFile);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400158 fFile->fRoot = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700159 for (;;) {
160 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400161 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholasfc994162019-06-06 10:04:27 -0400162 return std::move(fFile);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400163 case Token::Kind::TK_DIRECTIVE: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400164 ASTNode::ID dir = this->directive();
165 if (fErrors.errorCount()) {
166 return nullptr;
167 }
168 if (dir) {
169 getNode(result).addChild(dir);
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 }
171 break;
172 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400173 case Token::Kind::TK_SECTION: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400174 ASTNode::ID section = this->section();
175 if (fErrors.errorCount()) {
176 return nullptr;
177 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400178 if (section) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400179 getNode(result).addChild(section);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400180 }
181 break;
182 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700183 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400184 ASTNode::ID decl = this->declaration();
185 if (fErrors.errorCount()) {
186 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700187 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400188 if (decl) {
189 getNode(result).addChild(decl);
190 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700191 }
192 }
193 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400194 return std::move(fFile);
ethannicholasb3058bd2016-07-01 08:22:01 -0700195}
196
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700197Token Parser::nextRawToken() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400198 if (fPushback.fKind != Token::Kind::TK_INVALID) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700199 Token result = fPushback;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400200 fPushback.fKind = Token::Kind::TK_INVALID;
ethannicholasb3058bd2016-07-01 08:22:01 -0700201 return result;
202 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700203 Token result = fLexer.next();
204 return result;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400205}
206
207Token Parser::nextToken() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700208 Token token = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400209 while (token.fKind == Token::Kind::TK_WHITESPACE ||
210 token.fKind == Token::Kind::TK_LINE_COMMENT ||
211 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700212 token = this->nextRawToken();
213 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400214 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700215}
216
217void Parser::pushback(Token t) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400218 SkASSERT(fPushback.fKind == Token::Kind::TK_INVALID);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400219 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700220}
221
222Token Parser::peek() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400223 if (fPushback.fKind == Token::Kind::TK_INVALID) {
Brian Osman634624a2017-08-15 11:14:30 -0400224 fPushback = this->nextToken();
225 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700226 return fPushback;
227}
228
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400229bool Parser::checkNext(Token::Kind kind, Token* result) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400230 if (fPushback.fKind != Token::Kind::TK_INVALID && fPushback.fKind != kind) {
Brian Osman634624a2017-08-15 11:14:30 -0400231 return false;
232 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400233 Token next = this->nextToken();
234 if (next.fKind == kind) {
235 if (result) {
236 *result = next;
237 }
238 return true;
239 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400240 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400241 return false;
242}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500243
244bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 Token next = this->nextToken();
246 if (next.fKind == kind) {
247 if (result) {
Brian Osman634624a2017-08-15 11:14:30 -0400248 *result = std::move(next);
ethannicholasb3058bd2016-07-01 08:22:01 -0700249 }
250 return true;
251 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700252 this->error(next, "expected " + String(expected) + ", but found '" +
253 this->text(next) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 return false;
255 }
256}
257
John Stiles2630ea32020-12-04 10:51:21 -0500258bool Parser::expectIdentifier(Token* result) {
259 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
260 return false;
261 }
262 if (this->isType(this->text(*result))) {
263 this->error(*result, "expected an identifier, but found type '" +
264 this->text(*result) + "'");
265 return false;
266 }
267 return true;
268}
269
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270StringFragment Parser::text(Token token) {
271 return StringFragment(fText + token.fOffset, token.fLength);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500272}
273
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700274void Parser::error(Token token, String msg) {
275 this->error(token.fOffset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -0700276}
277
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700278void Parser::error(int offset, String msg) {
279 fErrors.error(offset, msg);
280}
281
282bool Parser::isType(StringFragment name) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400283 const Symbol* s = fSymbols[name];
John Stiles2630ea32020-12-04 10:51:21 -0500284 return s && s->is<Type>();
ethannicholasb3058bd2016-07-01 08:22:01 -0700285}
286
Ethan Nicholas11d53972016-11-28 11:23:23 -0500287/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700288 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400289ASTNode::ID Parser::directive() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700290 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400291 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400292 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700294 StringFragment text = this->text(start);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400295 if (text == "#extension") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700296 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500297 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400298 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400300 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400301 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700302 }
303 // FIXME: need to start paying attention to this token
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400304 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400305 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700306 }
John Stiles3b209362020-11-16 17:03:10 -0500307 return this->createNode(start.fOffset, ASTNode::Kind::kExtension, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700308 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700309 this->error(start, "unsupported directive '" + this->text(start) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400310 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700311 }
312}
313
Ethan Nicholas762466e2017-06-29 10:03:38 -0400314/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
315 RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400316ASTNode::ID Parser::section() {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400317 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400318 if (!this->expect(Token::Kind::TK_SECTION, "a section token", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400319 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400320 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400321 StringFragment argument;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400322 if (this->peek().fKind == Token::Kind::TK_LPAREN) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400323 this->nextToken();
324 Token argToken;
John Stiles2630ea32020-12-04 10:51:21 -0500325 if (!this->expectIdentifier(&argToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400326 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400327 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700328 argument = this->text(argToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400329 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400330 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400331 }
332 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400333 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400334 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400335 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400336 StringFragment text;
337 Token codeStart = this->nextRawToken();
338 size_t startOffset = codeStart.fOffset;
339 this->pushback(codeStart);
340 text.fChars = fText + startOffset;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400341 int level = 1;
342 for (;;) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700343 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400344 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400345 case Token::Kind::TK_LBRACE:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400346 ++level;
347 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400348 case Token::Kind::TK_RBRACE:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400349 --level;
350 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400351 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700352 this->error(start, "reached end of file while parsing section");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400353 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400354 default:
355 break;
356 }
357 if (!level) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400358 text.fLength = next.fOffset - startOffset;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400359 break;
360 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400361 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700362 StringFragment name = this->text(start);
363 ++name.fChars;
364 --name.fLength;
John Stiles3b209362020-11-16 17:03:10 -0500365 return this->createNode(start.fOffset, ASTNode::Kind::kSection,
366 ASTNode::SectionData(name, argument, text));
Ethan Nicholas762466e2017-06-29 10:03:38 -0400367}
368
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500369/* ENUM CLASS IDENTIFIER LBRACE (IDENTIFIER (EQ expression)? (COMMA IDENTIFIER (EQ expression))*)?
370 RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400371ASTNode::ID Parser::enumDeclaration() {
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500372 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400373 if (!this->expect(Token::Kind::TK_ENUM, "'enum'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400374 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500375 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400376 if (!this->expect(Token::Kind::TK_CLASS, "'class'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400377 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500378 }
379 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500380 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400381 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500382 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400383 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400384 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500385 }
John Stilesad2d4942020-12-11 16:55:58 -0500386 fSymbols.add(Type::MakeSimpleType(this->text(name), Type::TypeKind::kEnum));
John Stiles3b209362020-11-16 17:03:10 -0500387 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kEnum, this->text(name));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400388 if (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500389 Token id;
John Stiles2630ea32020-12-04 10:51:21 -0500390 if (!this->expectIdentifier(&id)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400391 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500392 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400393 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400394 ASTNode::ID value = this->assignmentExpression();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500395 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400396 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500397 }
John Stiles3b209362020-11-16 17:03:10 -0500398 ASTNode::ID child = this->addChild(
399 result, this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400400 getNode(child).addChild(value);
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500401 } else {
John Stiles3b209362020-11-16 17:03:10 -0500402 this->addChild(result,
403 this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500404 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400405 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
406 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400407 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500408 }
John Stiles2630ea32020-12-04 10:51:21 -0500409 if (!this->expectIdentifier(&id)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400410 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500411 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400412 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400413 ASTNode::ID value = this->assignmentExpression();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500414 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400415 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500416 }
John Stiles3b209362020-11-16 17:03:10 -0500417 ASTNode::ID child = this->addChild(
418 result,
419 this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400420 getNode(child).addChild(value);
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500421 } else {
John Stiles3b209362020-11-16 17:03:10 -0500422 this->addChild(
423 result,
424 this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500425 }
426 }
427 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400428 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400429 return result;
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500430}
431
432/* enumDeclaration | modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
ethannicholasb3058bd2016-07-01 08:22:01 -0700433 (COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400434ASTNode::ID Parser::declaration() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700435 Token lookahead = this->peek();
Ethan Nicholasda6320c2020-09-02 14:08:23 -0400436 switch (lookahead.fKind) {
437 case Token::Kind::TK_ENUM:
438 return this->enumDeclaration();
439 case Token::Kind::TK_SEMICOLON:
440 this->error(lookahead.fOffset, "expected a declaration, but found ';'");
441 return ASTNode::ID::Invalid();
442 default:
443 break;
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500444 }
445 Modifiers modifiers = this->modifiers();
446 lookahead = this->peek();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400447 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !this->isType(this->text(lookahead))) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700448 // we have an identifier that's not a type, could be the start of an interface block
449 return this->interfaceBlock(modifiers);
450 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400451 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700452 return this->structVarDeclaration(modifiers);
453 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400454 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
ethannicholas5961bc92016-10-12 06:39:56 -0700455 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -0500456 return this->createNode(lookahead.fOffset, ASTNode::Kind::kModifiers, modifiers);
ethannicholas5961bc92016-10-12 06:39:56 -0700457 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400458 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700459 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400460 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700461 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400462 if (getNode(type).getTypeData().fIsStructDeclaration &&
463 this->checkNext(Token::Kind::TK_SEMICOLON)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400464 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700465 }
466 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500467 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400468 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400470 if (this->checkNext(Token::Kind::TK_LPAREN)) {
John Stiles3b209362020-11-16 17:03:10 -0500471 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kFunction);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400472 ASTNode::FunctionData fd(modifiers, this->text(name), 0);
473 getNode(result).addChild(type);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400474 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400475 for (;;) {
476 ASTNode::ID parameter = this->parameter();
477 if (!parameter) {
478 return ASTNode::ID::Invalid();
479 }
480 ++fd.fParameterCount;
481 getNode(result).addChild(parameter);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400482 if (!this->checkNext(Token::Kind::TK_COMMA)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400483 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700484 }
485 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700486 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400487 getNode(result).setFunctionData(fd);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400488 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400489 return ASTNode::ID::Invalid();
490 }
491 ASTNode::ID body;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400492 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 body = this->block();
494 if (!body) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400495 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400497 getNode(result).addChild(body);
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400499 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700500 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400501 return this->varDeclarationEnd(modifiers, type, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 }
503}
504
505/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400506ASTNode::ID Parser::varDeclarations() {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500507 Modifiers modifiers = this->modifiers();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400508 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400510 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 }
512 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500513 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400514 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400516 return this->varDeclarationEnd(modifiers, type, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700517}
518
519/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400520ASTNode::ID Parser::structDeclaration() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400521 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400522 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 }
524 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500525 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400526 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400528 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400529 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700530 }
531 std::vector<Type::Field> fields;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400532 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400533 ASTNode::ID decls = this->varDeclarations();
534 if (!decls) {
535 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400537 ASTNode& declsNode = getNode(decls);
John Stiles13fc2602020-10-09 17:42:31 -0400538 Modifiers modifiers = declsNode.begin()->getModifiers();
539 if (modifiers.fFlags != Modifiers::kNo_Flag) {
540 String desc = modifiers.description();
541 desc.pop_back(); // remove trailing space
542 this->error(declsNode.fOffset,
543 "modifier '" + desc + "' is not permitted on a struct field");
544 }
545
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400546 const Symbol* symbol = fSymbols[(declsNode.begin() + 1)->getTypeData().fName];
John Stiles13fc2602020-10-09 17:42:31 -0400547 SkASSERT(symbol);
548 const Type* type = &symbol->as<Type>();
John Stiles1d757782020-11-17 09:43:22 -0500549 if (type->isOpaque()) {
550 this->error(declsNode.fOffset,
551 "opaque type '" + type->name() + "' is not permitted in a struct");
552 }
John Stiles13fc2602020-10-09 17:42:31 -0400553
Ethan Nicholasfc994162019-06-06 10:04:27 -0400554 for (auto iter = declsNode.begin() + 2; iter != declsNode.end(); ++iter) {
555 ASTNode& var = *iter;
556 ASTNode::VarData vd = var.getVarData();
John Stiles6bef6a72020-12-02 14:26:04 -0500557
John Stilesd39aec92020-12-03 14:37:16 -0500558 // Read array size if one is present.
559 if (vd.fIsArray) {
560 const ASTNode& size = *var.begin();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400561 if (!size || size.fKind != ASTNode::Kind::kInt) {
562 this->error(declsNode.fOffset, "array size in struct field must be a constant");
563 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 }
John Stiles6bef6a72020-12-02 14:26:04 -0500565 if (size.getInt() <= 0 || size.getInt() > INT_MAX) {
566 this->error(declsNode.fOffset, "array size is invalid");
567 return ASTNode::ID::Invalid();
568 }
John Stilesd39aec92020-12-03 14:37:16 -0500569 // Add the array dimensions to our type.
570 int arraySize = size.getInt();
John Stilesa2179502020-12-03 14:37:57 -0500571 type = fSymbols.addArrayDimension(type, arraySize);
ethannicholasb3058bd2016-07-01 08:22:01 -0700572 }
John Stiles13fc2602020-10-09 17:42:31 -0400573
574 fields.push_back(Type::Field(modifiers, vd.fName, type));
John Stilesd39aec92020-12-03 14:37:16 -0500575 if (vd.fIsArray ? var.begin()->fNext : var.fFirstChild) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400576 this->error(declsNode.fOffset, "initializers are not permitted on struct fields");
ethannicholasb3058bd2016-07-01 08:22:01 -0700577 }
578 }
579 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400580 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400581 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700582 }
John Stilesad2d4942020-12-11 16:55:58 -0500583 std::unique_ptr<Type> newType = Type::MakeStructType(name.fOffset, this->text(name), fields);
John Stilesa695d622020-11-10 10:04:26 -0500584 if (struct_is_too_deeply_nested(*newType, kMaxStructDepth)) {
585 this->error(name.fOffset, "struct '" + this->text(name) + "' is too deeply nested");
586 return ASTNode::ID::Invalid();
587 }
588 fSymbols.add(std::move(newType));
John Stiles3b209362020-11-16 17:03:10 -0500589 return this->createNode(name.fOffset, ASTNode::Kind::kType,
John Stilesdc75a972020-11-25 16:24:55 -0500590 ASTNode::TypeData(this->text(name),
591 /*isStructDeclaration=*/true, /*isNullable=*/false));
ethannicholasb3058bd2016-07-01 08:22:01 -0700592}
593
594/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400595ASTNode::ID Parser::structVarDeclaration(Modifiers modifiers) {
596 ASTNode::ID type = this->structDeclaration();
ethannicholasb3058bd2016-07-01 08:22:01 -0700597 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400598 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700599 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400600 Token name;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400601 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400602 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400604 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesdc75a972020-11-25 16:24:55 -0500605 return type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700606}
607
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400608/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
609 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400610ASTNode::ID Parser::varDeclarationEnd(Modifiers mods, ASTNode::ID type, StringFragment name) {
John Stiles08070f62020-11-17 10:45:49 -0500611 int offset = this->peek().fOffset;
612 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kVarDeclarations);
613 this->addChild(result, this->createNode(offset, ASTNode::Kind::kModifiers, mods));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400614 getNode(result).addChild(type);
John Stilesd39aec92020-12-03 14:37:16 -0500615
616 auto parseArrayDimensions = [this](ASTNode::ID currentVar, ASTNode::VarData* vd) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400617 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -0500618 if (vd->fIsArray) {
619 this->error(this->peek(), "multi-dimensional arrays are not supported");
620 return false;
621 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400622 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -0500623 this->createEmptyChild(currentVar);
ethannicholasb3058bd2016-07-01 08:22:01 -0700624 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400625 ASTNode::ID size = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700626 if (!size) {
John Stilesd39aec92020-12-03 14:37:16 -0500627 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700628 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400629 getNode(currentVar).addChild(size);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400630 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
John Stilesd39aec92020-12-03 14:37:16 -0500631 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700632 }
633 }
John Stilesd39aec92020-12-03 14:37:16 -0500634 vd->fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700635 }
John Stilesd39aec92020-12-03 14:37:16 -0500636 return true;
637 };
638
639 auto parseInitializer = [this](ASTNode::ID currentVar) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400640 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400641 ASTNode::ID value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700642 if (!value) {
John Stilesd39aec92020-12-03 14:37:16 -0500643 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700644 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400645 getNode(currentVar).addChild(value);
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 }
John Stilesd39aec92020-12-03 14:37:16 -0500647 return true;
648 };
649
650 ASTNode::ID currentVar = this->createNode(offset, ASTNode::Kind::kVarDeclaration);
651 ASTNode::VarData vd{name, /*isArray=*/false};
652
653 getNode(result).addChild(currentVar);
654 if (!parseArrayDimensions(currentVar, &vd)) {
655 return ASTNode::ID::Invalid();
656 }
657 getNode(currentVar).setVarData(vd);
658 if (!parseInitializer(currentVar)) {
659 return ASTNode::ID::Invalid();
660 }
661
662 while (this->checkNext(Token::Kind::TK_COMMA)) {
663 Token identifierName;
John Stiles2630ea32020-12-04 10:51:21 -0500664 if (!this->expectIdentifier(&identifierName)) {
John Stilesd39aec92020-12-03 14:37:16 -0500665 return ASTNode::ID::Invalid();
666 }
667
668 currentVar = ASTNode::ID(fFile->fNodes.size());
669 vd = ASTNode::VarData{this->text(identifierName), /*isArray=*/false};
670 fFile->fNodes.emplace_back(&fFile->fNodes, offset, ASTNode::Kind::kVarDeclaration);
671
672 getNode(result).addChild(currentVar);
673 if (!parseArrayDimensions(currentVar, &vd)) {
674 return ASTNode::ID::Invalid();
675 }
676 getNode(currentVar).setVarData(vd);
677 if (!parseInitializer(currentVar)) {
678 return ASTNode::ID::Invalid();
679 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700680 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400681 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400682 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700683 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400684 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700685}
686
687/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400688ASTNode::ID Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400689 Modifiers modifiers = this->modifiersWithDefaults(0);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400690 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700691 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400692 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700693 }
694 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500695 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400696 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700697 }
John Stiles3b209362020-11-16 17:03:10 -0500698 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kParameter);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400699 ASTNode::ParameterData pd(modifiers, this->text(name), 0);
700 getNode(result).addChild(type);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400701 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -0500702 if (pd.fIsArray) {
703 this->error(this->peek(), "multi-dimensional arrays are not supported");
704 return ASTNode::ID::Invalid();
705 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700706 Token sizeToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400707 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400708 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 }
John Stiles3b209362020-11-16 17:03:10 -0500710 this->addChild(result, this->createNode(sizeToken.fOffset, ASTNode::Kind::kInt,
711 SkSL::stoi(this->text(sizeToken))));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400712 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400713 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700714 }
John Stilesd39aec92020-12-03 14:37:16 -0500715 pd.fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700716 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400717 getNode(result).setParameterData(pd);
718 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700719}
720
Ethan Nicholasd608c092017-10-26 09:30:08 -0400721/** EQ INT_LITERAL */
ethannicholasb3058bd2016-07-01 08:22:01 -0700722int Parser::layoutInt() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400723 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700724 return -1;
725 }
726 Token resultToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400727 if (this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700728 return SkSL::stoi(this->text(resultToken));
ethannicholasb3058bd2016-07-01 08:22:01 -0700729 }
730 return -1;
731}
732
Ethan Nicholasd608c092017-10-26 09:30:08 -0400733/** EQ IDENTIFIER */
734StringFragment Parser::layoutIdentifier() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400735 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholasd608c092017-10-26 09:30:08 -0400736 return StringFragment();
737 }
738 Token resultToken;
John Stiles2630ea32020-12-04 10:51:21 -0500739 if (!this->expectIdentifier(&resultToken)) {
Ethan Nicholasd608c092017-10-26 09:30:08 -0400740 return StringFragment();
741 }
742 return this->text(resultToken);
743}
744
745
Ethan Nicholas762466e2017-06-29 10:03:38 -0400746/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400747StringFragment Parser::layoutCode() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400748 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400749 return "";
750 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700751 Token start = this->nextRawToken();
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400752 this->pushback(start);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400753 StringFragment code;
754 code.fChars = fText + start.fOffset;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400755 int level = 1;
756 bool done = false;
757 while (!done) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700758 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400759 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400760 case Token::Kind::TK_LPAREN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400761 ++level;
762 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400763 case Token::Kind::TK_RPAREN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400764 --level;
765 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400766 case Token::Kind::TK_COMMA:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400767 if (level == 1) {
768 done = true;
769 }
770 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400771 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700772 this->error(start, "reached end of file while parsing layout");
Ethan Nicholas6d71f492019-06-10 16:58:37 -0400773 return "";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400774 default:
775 break;
776 }
777 if (!level) {
778 done = true;
779 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400780 if (done) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400781 code.fLength = next.fOffset - start.fOffset;
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400782 this->pushback(std::move(next));
783 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400784 }
785 return code;
786}
787
788/** (EQ IDENTIFIER('identity'))? */
789Layout::Key Parser::layoutKey() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400790 if (this->peek().fKind == Token::Kind::TK_EQ) {
791 this->expect(Token::Kind::TK_EQ, "'='");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400792 Token key;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400793 if (this->expect(Token::Kind::TK_IDENTIFIER, "an identifer", &key)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700794 if (this->text(key) == "identity") {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400795 return Layout::kIdentity_Key;
796 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700797 this->error(key, "unsupported layout key");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400798 }
799 }
800 }
801 return Layout::kKey_Key;
802}
803
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400804Layout::CType Parser::layoutCType() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400805 if (this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400806 Token t = this->nextToken();
807 String text = this->text(t);
808 auto found = layoutTokens->find(text);
809 if (found != layoutTokens->end()) {
810 switch (found->second) {
Brian Osmanf28e55d2018-10-03 16:35:54 -0400811 case LayoutToken::SKPMCOLOR4F:
812 return Layout::CType::kSkPMColor4f;
Mike Reedb26b4e72020-01-22 14:31:21 -0500813 case LayoutToken::SKV4:
814 return Layout::CType::kSkV4;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400815 case LayoutToken::SKRECT:
816 return Layout::CType::kSkRect;
817 case LayoutToken::SKIRECT:
818 return Layout::CType::kSkIRect;
819 case LayoutToken::SKPMCOLOR:
820 return Layout::CType::kSkPMColor;
Ethan Nicholasc1c686b2019-04-02 17:30:23 -0400821 case LayoutToken::BOOL:
822 return Layout::CType::kBool;
823 case LayoutToken::INT:
824 return Layout::CType::kInt32;
825 case LayoutToken::FLOAT:
826 return Layout::CType::kFloat;
Mike Reedb26b4e72020-01-22 14:31:21 -0500827 case LayoutToken::SKM44:
828 return Layout::CType::kSkM44;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400829 default:
830 break;
831 }
832 }
833 this->error(t, "unsupported ctype");
834 }
835 return Layout::CType::kDefault;
836}
837
ethannicholas8ac838d2016-11-22 08:39:36 -0800838/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500839Layout Parser::layout() {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500840 int flags = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700841 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500842 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700843 int binding = -1;
844 int index = -1;
845 int set = -1;
846 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500847 int inputAttachmentIndex = -1;
Ethan Nicholas11d53972016-11-28 11:23:23 -0500848 Layout::Format format = Layout::Format::kUnspecified;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500849 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
850 int maxVertices = -1;
851 int invocations = -1;
Brian Osmanf59a9612020-04-15 14:18:13 -0400852 StringFragment marker;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400853 StringFragment when;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400854 Layout::Key key = Layout::kNo_Key;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400855 Layout::CType ctype = Layout::CType::kDefault;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400856 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
857 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500858 return Layout(flags, location, offset, binding, index, set, builtin,
Brian Osmanf59a9612020-04-15 14:18:13 -0400859 inputAttachmentIndex, format, primitive, maxVertices, invocations, marker,
860 when, key, ctype);
ethannicholasb3058bd2016-07-01 08:22:01 -0700861 }
862 for (;;) {
863 Token t = this->nextToken();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700864 String text = this->text(t);
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400865 auto found = layoutTokens->find(text);
866 if (found != layoutTokens->end()) {
867 switch (found->second) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700868 case LayoutToken::LOCATION:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500869 location = this->layoutInt();
870 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700871 case LayoutToken::OFFSET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500872 offset = this->layoutInt();
873 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700874 case LayoutToken::BINDING:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500875 binding = this->layoutInt();
876 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700877 case LayoutToken::INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500878 index = this->layoutInt();
879 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700880 case LayoutToken::SET:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500881 set = this->layoutInt();
882 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700883 case LayoutToken::BUILTIN:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500884 builtin = this->layoutInt();
885 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700886 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500887 inputAttachmentIndex = this->layoutInt();
888 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700889 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500890 flags |= Layout::kOriginUpperLeft_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500891 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700892 case LayoutToken::OVERRIDE_COVERAGE:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500893 flags |= Layout::kOverrideCoverage_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500894 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700895 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500896 flags |= Layout::kBlendSupportAllEquations_Flag;
897 break;
898 case LayoutToken::BLEND_SUPPORT_MULTIPLY:
899 flags |= Layout::kBlendSupportMultiply_Flag;
900 break;
901 case LayoutToken::BLEND_SUPPORT_SCREEN:
902 flags |= Layout::kBlendSupportScreen_Flag;
903 break;
904 case LayoutToken::BLEND_SUPPORT_OVERLAY:
905 flags |= Layout::kBlendSupportOverlay_Flag;
906 break;
907 case LayoutToken::BLEND_SUPPORT_DARKEN:
908 flags |= Layout::kBlendSupportDarken_Flag;
909 break;
910 case LayoutToken::BLEND_SUPPORT_LIGHTEN:
911 flags |= Layout::kBlendSupportLighten_Flag;
912 break;
913 case LayoutToken::BLEND_SUPPORT_COLORDODGE:
914 flags |= Layout::kBlendSupportColorDodge_Flag;
915 break;
916 case LayoutToken::BLEND_SUPPORT_COLORBURN:
917 flags |= Layout::kBlendSupportColorBurn_Flag;
918 break;
919 case LayoutToken::BLEND_SUPPORT_HARDLIGHT:
920 flags |= Layout::kBlendSupportHardLight_Flag;
921 break;
922 case LayoutToken::BLEND_SUPPORT_SOFTLIGHT:
923 flags |= Layout::kBlendSupportSoftLight_Flag;
924 break;
925 case LayoutToken::BLEND_SUPPORT_DIFFERENCE:
926 flags |= Layout::kBlendSupportDifference_Flag;
927 break;
928 case LayoutToken::BLEND_SUPPORT_EXCLUSION:
929 flags |= Layout::kBlendSupportExclusion_Flag;
930 break;
931 case LayoutToken::BLEND_SUPPORT_HSL_HUE:
932 flags |= Layout::kBlendSupportHSLHue_Flag;
933 break;
934 case LayoutToken::BLEND_SUPPORT_HSL_SATURATION:
935 flags |= Layout::kBlendSupportHSLSaturation_Flag;
936 break;
937 case LayoutToken::BLEND_SUPPORT_HSL_COLOR:
938 flags |= Layout::kBlendSupportHSLColor_Flag;
939 break;
940 case LayoutToken::BLEND_SUPPORT_HSL_LUMINOSITY:
941 flags |= Layout::kBlendSupportHSLLuminosity_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500942 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700943 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500944 flags |= Layout::kPushConstant_Flag;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500945 break;
Michael Ludwiga4275592018-08-31 10:52:47 -0400946 case LayoutToken::TRACKED:
947 flags |= Layout::kTracked_Flag;
948 break;
Brian Osmanb32d66b2020-04-30 17:12:03 -0400949 case LayoutToken::SRGB_UNPREMUL:
950 flags |= Layout::kSRGBUnpremul_Flag;
951 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700952 case LayoutToken::POINTS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500953 primitive = Layout::kPoints_Primitive;
954 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700955 case LayoutToken::LINES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500956 primitive = Layout::kLines_Primitive;
957 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700958 case LayoutToken::LINE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500959 primitive = Layout::kLineStrip_Primitive;
960 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700961 case LayoutToken::LINES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500962 primitive = Layout::kLinesAdjacency_Primitive;
963 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700964 case LayoutToken::TRIANGLES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500965 primitive = Layout::kTriangles_Primitive;
966 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700967 case LayoutToken::TRIANGLE_STRIP:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500968 primitive = Layout::kTriangleStrip_Primitive;
969 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700970 case LayoutToken::TRIANGLES_ADJACENCY:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500971 primitive = Layout::kTrianglesAdjacency_Primitive;
972 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700973 case LayoutToken::MAX_VERTICES:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500974 maxVertices = this->layoutInt();
975 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700976 case LayoutToken::INVOCATIONS:
Ethan Nicholas52cad152017-02-16 16:37:32 -0500977 invocations = this->layoutInt();
978 break;
Brian Osmanf59a9612020-04-15 14:18:13 -0400979 case LayoutToken::MARKER:
980 marker = this->layoutCode();
981 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700982 case LayoutToken::WHEN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400983 when = this->layoutCode();
984 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700985 case LayoutToken::KEY:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400986 key = this->layoutKey();
987 break;
Ethan Nicholasd608c092017-10-26 09:30:08 -0400988 case LayoutToken::CTYPE:
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400989 ctype = this->layoutCType();
990 break;
991 default:
992 this->error(t, ("'" + text + "' is not a valid layout qualifier").c_str());
Ethan Nicholasd608c092017-10-26 09:30:08 -0400993 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500994 }
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400995 } else if (Layout::ReadFormat(text, &format)) {
Brian Salomon2a51de82016-11-16 12:06:01 -0500996 // AST::ReadFormat stored the result in 'format'.
ethannicholasb3058bd2016-07-01 08:22:01 -0700997 } else {
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400998 this->error(t, ("'" + text + "' is not a valid layout qualifier").c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -0700999 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001000 if (this->checkNext(Token::Kind::TK_RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001001 break;
1002 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001003 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 break;
1005 }
1006 }
1007 }
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001008 return Layout(flags, location, offset, binding, index, set, builtin, inputAttachmentIndex,
Brian Osmanf59a9612020-04-15 14:18:13 -04001009 format, primitive, maxVertices, invocations, marker, when, key, ctype);
ethannicholasb3058bd2016-07-01 08:22:01 -07001010}
1011
Brian Salomonf9f45122016-11-29 11:59:17 -05001012/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001013 READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT | BUFFER | PLS | PLSIN |
Ethan Nicholasf3c8f5d2020-08-20 13:09:14 +00001014 PLSOUT | VARYING | INLINE)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -05001015Modifiers Parser::modifiers() {
1016 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -07001017 int flags = 0;
1018 for (;;) {
1019 // TODO: handle duplicate / incompatible flags
1020 switch (peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001021 case Token::Kind::TK_UNIFORM:
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001023 flags |= Modifiers::kUniform_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -07001024 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001025 case Token::Kind::TK_CONST:
ethannicholasb3058bd2016-07-01 08:22:01 -07001026 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001027 flags |= Modifiers::kConst_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -07001028 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001029 case Token::Kind::TK_IN:
ethannicholasb3058bd2016-07-01 08:22:01 -07001030 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001031 flags |= Modifiers::kIn_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -07001032 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001033 case Token::Kind::TK_OUT:
ethannicholasb3058bd2016-07-01 08:22:01 -07001034 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001035 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -07001036 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001037 case Token::Kind::TK_INOUT:
ethannicholasb3058bd2016-07-01 08:22:01 -07001038 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001039 flags |= Modifiers::kIn_Flag;
1040 flags |= Modifiers::kOut_Flag;
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001042 case Token::Kind::TK_FLAT:
ethannicholasf789b382016-08-03 12:43:36 -07001043 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001044 flags |= Modifiers::kFlat_Flag;
ethannicholasf789b382016-08-03 12:43:36 -07001045 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001046 case Token::Kind::TK_NOPERSPECTIVE:
ethannicholasf789b382016-08-03 12:43:36 -07001047 this->nextToken();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001048 flags |= Modifiers::kNoPerspective_Flag;
ethannicholasf789b382016-08-03 12:43:36 -07001049 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001050 case Token::Kind::TK_READONLY:
Brian Salomonf9f45122016-11-29 11:59:17 -05001051 this->nextToken();
1052 flags |= Modifiers::kReadOnly_Flag;
1053 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001054 case Token::Kind::TK_WRITEONLY:
Brian Salomonf9f45122016-11-29 11:59:17 -05001055 this->nextToken();
1056 flags |= Modifiers::kWriteOnly_Flag;
1057 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001058 case Token::Kind::TK_COHERENT:
Brian Salomonf9f45122016-11-29 11:59:17 -05001059 this->nextToken();
1060 flags |= Modifiers::kCoherent_Flag;
1061 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001062 case Token::Kind::TK_VOLATILE:
Brian Salomonf9f45122016-11-29 11:59:17 -05001063 this->nextToken();
1064 flags |= Modifiers::kVolatile_Flag;
1065 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001066 case Token::Kind::TK_RESTRICT:
Brian Salomonf9f45122016-11-29 11:59:17 -05001067 this->nextToken();
1068 flags |= Modifiers::kRestrict_Flag;
1069 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001070 case Token::Kind::TK_BUFFER:
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04001071 this->nextToken();
1072 flags |= Modifiers::kBuffer_Flag;
1073 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001074 case Token::Kind::TK_HASSIDEEFFECTS:
Ethan Nicholascb670962017-04-20 19:31:52 -04001075 this->nextToken();
1076 flags |= Modifiers::kHasSideEffects_Flag;
1077 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001078 case Token::Kind::TK_PLS:
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001079 this->nextToken();
1080 flags |= Modifiers::kPLS_Flag;
1081 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001082 case Token::Kind::TK_PLSIN:
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001083 this->nextToken();
1084 flags |= Modifiers::kPLSIn_Flag;
1085 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001086 case Token::Kind::TK_PLSOUT:
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001087 this->nextToken();
1088 flags |= Modifiers::kPLSOut_Flag;
1089 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001090 case Token::Kind::TK_VARYING:
Brian Osman3c358422020-03-23 10:44:12 -04001091 this->nextToken();
1092 flags |= Modifiers::kVarying_Flag;
1093 break;
Ethan Nicholasf3c8f5d2020-08-20 13:09:14 +00001094 case Token::Kind::TK_INLINE:
1095 this->nextToken();
1096 flags |= Modifiers::kInline_Flag;
1097 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 default:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001099 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 }
1101 }
1102}
1103
Ethan Nicholas11d53972016-11-28 11:23:23 -05001104Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
1105 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001107 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 }
1109 return result;
1110}
1111
1112/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001113ASTNode::ID Parser::statement() {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001114 Token start = this->nextToken();
1115 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001116 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001117 return ASTNode::ID::Invalid();
1118 }
1119 this->pushback(start);
ethannicholasb3058bd2016-07-01 08:22:01 -07001120 switch (start.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001121 case Token::Kind::TK_IF: // fall through
1122 case Token::Kind::TK_STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -07001123 return this->ifStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001124 case Token::Kind::TK_FOR:
ethannicholasb3058bd2016-07-01 08:22:01 -07001125 return this->forStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001126 case Token::Kind::TK_DO:
ethannicholasb3058bd2016-07-01 08:22:01 -07001127 return this->doStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001128 case Token::Kind::TK_WHILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 return this->whileStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001130 case Token::Kind::TK_SWITCH: // fall through
1131 case Token::Kind::TK_STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -05001132 return this->switchStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001133 case Token::Kind::TK_RETURN:
ethannicholasb3058bd2016-07-01 08:22:01 -07001134 return this->returnStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001135 case Token::Kind::TK_BREAK:
ethannicholasb3058bd2016-07-01 08:22:01 -07001136 return this->breakStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001137 case Token::Kind::TK_CONTINUE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 return this->continueStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001139 case Token::Kind::TK_DISCARD:
ethannicholasb3058bd2016-07-01 08:22:01 -07001140 return this->discardStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001141 case Token::Kind::TK_LBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001142 return this->block();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001143 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001144 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -05001145 return this->createNode(start.fOffset, ASTNode::Kind::kBlock);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001146 case Token::Kind::TK_CONST:
Ethan Nicholasfc994162019-06-06 10:04:27 -04001147 return this->varDeclarations();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001148 case Token::Kind::TK_IDENTIFIER:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001149 if (this->isType(this->text(start))) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001150 return this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001151 }
John Stiles30212b72020-06-11 17:55:07 -04001152 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -07001153 default:
1154 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001155 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001156}
1157
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001158/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001159ASTNode::ID Parser::type() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001160 Token type;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001161 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001162 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001163 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001164 if (!this->isType(this->text(type))) {
1165 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
Ethan Nicholasfc994162019-06-06 10:04:27 -04001166 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001167 }
John Stiles3b209362020-11-16 17:03:10 -05001168 ASTNode::ID result = this->createNode(type.fOffset, ASTNode::Kind::kType);
John Stilesdc75a972020-11-25 16:24:55 -05001169 ASTNode::TypeData td(this->text(type), /*isStructDeclaration=*/false, /*isNullable=*/false);
John Stilesd39aec92020-12-03 14:37:16 -05001170 bool isArray = false;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001171 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -05001172 if (isArray) {
1173 this->error(this->peek(), "multi-dimensional arrays are not supported");
1174 return ASTNode::ID::Invalid();
1175 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001176 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001177 SKSL_INT i;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001178 if (this->intLiteral(&i)) {
John Stiles08070f62020-11-17 10:45:49 -05001179 this->addChild(result, this->createNode(this->peek().fOffset,
1180 ASTNode::Kind::kInt, i));
Ethan Nicholas50afc172017-02-16 14:49:57 -05001181 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001182 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001183 }
1184 } else {
John Stiles3b209362020-11-16 17:03:10 -05001185 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001186 }
John Stilesd39aec92020-12-03 14:37:16 -05001187 isArray = true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001188 this->expect(Token::Kind::TK_RBRACKET, "']'");
Ethan Nicholas50afc172017-02-16 14:49:57 -05001189 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001190 td.fIsNullable = this->checkNext(Token::Kind::TK_QUESTION);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001191 getNode(result).setTypeData(td);
1192 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001193}
1194
John Stiles57a996b2020-04-19 19:05:12 -07001195/* IDENTIFIER LBRACE
1196 varDeclaration+
1197 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001198ASTNode::ID Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 Token name;
John Stiles2630ea32020-12-04 10:51:21 -05001200 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001201 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001202 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001203 if (peek().fKind != Token::Kind::TK_LBRACE) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001204 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -05001205 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -07001206 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001207 this->error(name, "no type named '" + this->text(name) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001208 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001209 }
John Stiles3b209362020-11-16 17:03:10 -05001210 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kInterfaceBlock);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001211 ASTNode::InterfaceBlockData id(mods, this->text(name), 0, "", 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001212 this->nextToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001213 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001214 ASTNode::ID decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001215 if (!decl) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001216 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001217 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001218 getNode(result).addChild(decl);
1219 ++id.fDeclarationCount;
ethannicholasb3058bd2016-07-01 08:22:01 -07001220 }
John Stiles57a996b2020-04-19 19:05:12 -07001221 if (id.fDeclarationCount == 0) {
1222 this->error(name, "interface block '" + this->text(name) +
1223 "' must contain at least one member");
1224 return ASTNode::ID::Invalid();
1225 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001226 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001227 std::vector<ASTNode> sizes;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001228 StringFragment instanceName;
1229 Token instanceNameToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001230 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001231 id.fInstanceName = this->text(instanceNameToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001232 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -05001233 if (id.fIsArray) {
1234 this->error(this->peek(), "multi-dimensional arrays are not supported");
1235 return false;
1236 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001237 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001238 ASTNode::ID size = this->expression();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001239 if (!size) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001240 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001241 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001242 getNode(result).addChild(size);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001243 } else {
John Stiles3b209362020-11-16 17:03:10 -05001244 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001245 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001246 this->expect(Token::Kind::TK_RBRACKET, "']'");
John Stilesd39aec92020-12-03 14:37:16 -05001247 id.fIsArray = true;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001248 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001249 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -07001250 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001251 getNode(result).setInterfaceBlockData(id);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001252 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001253 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001254}
1255
1256/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001257ASTNode::ID Parser::ifStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001258 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001259 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
1260 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001261 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001262 }
John Stiles3b209362020-11-16 17:03:10 -05001263 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kIf, isStatic);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001264 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001265 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001266 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001267 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001268 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001269 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001270 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001271 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001272 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001273 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001274 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001275 ASTNode::ID ifTrue = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001276 if (!ifTrue) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001277 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001278 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001279 getNode(result).addChild(ifTrue);
1280 ASTNode::ID ifFalse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001281 if (this->checkNext(Token::Kind::TK_ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001282 ifFalse = this->statement();
1283 if (!ifFalse) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001284 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001285 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001286 getNode(result).addChild(ifFalse);
ethannicholasb3058bd2016-07-01 08:22:01 -07001287 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001288 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001289}
1290
1291/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001292ASTNode::ID Parser::doStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001293 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001294 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001295 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001296 }
John Stiles3b209362020-11-16 17:03:10 -05001297 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kDo);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001298 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001299 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001300 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001301 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001302 getNode(result).addChild(statement);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001303 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001304 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001305 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001306 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001307 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001308 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001309 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001310 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001311 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001312 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001313 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001314 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001315 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001316 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001317 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001318 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001319 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001320 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001321}
1322
1323/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001324ASTNode::ID Parser::whileStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001325 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001326 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001327 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001328 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001329 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001330 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001331 }
John Stiles3b209362020-11-16 17:03:10 -05001332 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kWhile);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001333 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001334 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001335 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001336 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001337 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001338 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001339 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001340 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001341 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001342 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001343 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001344 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001345 getNode(result).addChild(statement);
1346 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001347}
1348
Ethan Nicholasaf197692017-02-27 13:26:45 -05001349/* CASE expression COLON statement* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001350ASTNode::ID Parser::switchCase() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001351 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001352 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001353 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001354 }
John Stiles3b209362020-11-16 17:03:10 -05001355 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitchCase);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001356 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001357 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001358 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001359 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001360 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001361 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001362 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001363 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001364 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1365 this->peek().fKind != Token::Kind::TK_CASE &&
1366 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001367 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001368 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001369 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001370 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001371 getNode(result).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001372 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001373 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001374}
1375
1376/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001377ASTNode::ID Parser::switchStatement() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001378 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001379 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1380 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001381 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001382 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001383 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001384 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001385 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001386 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001387 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001388 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001389 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001390 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001391 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001392 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001393 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001394 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001395 }
John Stiles3b209362020-11-16 17:03:10 -05001396 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitch, isStatic);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001397 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001398 while (this->peek().fKind == Token::Kind::TK_CASE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001399 ASTNode::ID c = this->switchCase();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001400 if (!c) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001401 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001402 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001403 getNode(result).addChild(c);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001404 }
1405 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1406 // parts of the compiler may rely upon this assumption.
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001407 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001408 Token defaultStart;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001409 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1410 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001411 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001412 }
John Stiles3b209362020-11-16 17:03:10 -05001413 ASTNode::ID defaultCase = this->addChild(
1414 result, this->createNode(defaultStart.fOffset, ASTNode::Kind::kSwitchCase));
1415 this->createEmptyChild(defaultCase); // empty test to signify default case
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001416 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001417 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001418 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001419 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001420 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001421 getNode(defaultCase).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001422 }
Ethan Nicholasaf197692017-02-27 13:26:45 -05001423 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001424 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001425 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001426 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001427 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001428}
1429
Ethan Nicholas11d53972016-11-28 11:23:23 -05001430/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001431 STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001432ASTNode::ID Parser::forStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001433 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001434 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001435 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001436 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001437 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001438 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001439 }
John Stiles3b209362020-11-16 17:03:10 -05001440 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kFor);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001441 ASTNode::ID initializer;
ethannicholasb3058bd2016-07-01 08:22:01 -07001442 Token nextToken = this->peek();
1443 switch (nextToken.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001444 case Token::Kind::TK_SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001445 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -05001446 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001447 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001448 case Token::Kind::TK_CONST: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001449 initializer = this->varDeclarations();
1450 if (!initializer) {
1451 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001452 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001453 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001455 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001456 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001457 if (this->isType(this->text(nextToken))) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001458 initializer = this->varDeclarations();
1459 if (!initializer) {
1460 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001461 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001462 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001463 break;
1464 }
John Stiles30212b72020-06-11 17:55:07 -04001465 [[fallthrough]];
1466 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001467 default:
1468 initializer = this->expressionStatement();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001469 if (!initializer) {
1470 return ASTNode::ID::Invalid();
1471 }
1472 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001473 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001474 ASTNode::ID test;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001475 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001476 test = this->expression();
1477 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001478 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001479 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001480 getNode(result).addChild(test);
1481 } else {
John Stiles3b209362020-11-16 17:03:10 -05001482 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001483 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001484 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001485 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001486 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001487 ASTNode::ID next;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001488 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001489 next = this->expression();
1490 if (!next) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001491 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001492 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001493 getNode(result).addChild(next);
1494 } else {
John Stiles3b209362020-11-16 17:03:10 -05001495 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001496 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001497 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001498 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001499 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001500 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001502 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001503 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001504 getNode(result).addChild(statement);
1505 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001506}
1507
1508/* RETURN expression? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001509ASTNode::ID Parser::returnStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001510 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001511 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001512 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001513 }
John Stiles3b209362020-11-16 17:03:10 -05001514 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kReturn);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001515 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001516 ASTNode::ID expression = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 if (!expression) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001518 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001519 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001520 getNode(result).addChild(expression);
ethannicholasb3058bd2016-07-01 08:22:01 -07001521 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001522 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001523 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001524 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001525 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001526}
1527
1528/* BREAK SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001529ASTNode::ID Parser::breakStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001530 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001531 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001532 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001533 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001534 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001535 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001536 }
John Stiles3b209362020-11-16 17:03:10 -05001537 return this->createNode(start.fOffset, ASTNode::Kind::kBreak);
ethannicholasb3058bd2016-07-01 08:22:01 -07001538}
1539
1540/* CONTINUE SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001541ASTNode::ID Parser::continueStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001543 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001544 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001545 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001546 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001547 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001548 }
John Stiles3b209362020-11-16 17:03:10 -05001549 return this->createNode(start.fOffset, ASTNode::Kind::kContinue);
ethannicholasb3058bd2016-07-01 08:22:01 -07001550}
1551
1552/* DISCARD SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001553ASTNode::ID Parser::discardStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001554 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001555 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001556 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001557 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001558 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001559 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001560 }
John Stiles3b209362020-11-16 17:03:10 -05001561 return this->createNode(start.fOffset, ASTNode::Kind::kDiscard);
ethannicholasb3058bd2016-07-01 08:22:01 -07001562}
1563
1564/* LBRACE statement* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001565ASTNode::ID Parser::block() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001566 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001567 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001568 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001569 }
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001570 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001571 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001572 return ASTNode::ID::Invalid();
1573 }
John Stiles3b209362020-11-16 17:03:10 -05001574 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 for (;;) {
1576 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001577 case Token::Kind::TK_RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001579 return result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001580 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001581 this->error(this->peek(), "expected '}', but found end of file");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001582 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001584 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001585 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001586 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001587 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001588 getNode(result).addChild(statement);
ethannicholasb3058bd2016-07-01 08:22:01 -07001589 }
1590 }
1591 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001592 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001593}
1594
1595/* expression SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001596ASTNode::ID Parser::expressionStatement() {
1597 ASTNode::ID expr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001598 if (expr) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001599 if (this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001600 return expr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001601 }
1602 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001603 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001604}
1605
1606/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001607ASTNode::ID Parser::expression() {
1608 ASTNode::ID result = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001609 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001610 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001611 }
1612 Token t;
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001613 AutoDepth depth(this);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001614 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001615 if (!depth.increase()) {
1616 return ASTNode::ID::Invalid();
1617 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001618 ASTNode::ID right = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001619 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001620 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001621 }
John Stiles3b209362020-11-16 17:03:10 -05001622 ASTNode::ID newResult = this->createNode(t.fOffset, ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001623 getNode(newResult).addChild(result);
1624 getNode(newResult).addChild(right);
1625 result = newResult;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001626 }
1627 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001628}
1629
1630/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1631 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1632 assignmentExpression)*
1633 */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001634ASTNode::ID Parser::assignmentExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001635 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001636 ASTNode::ID result = this->ternaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001638 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001639 }
1640 for (;;) {
1641 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001642 case Token::Kind::TK_EQ: // fall through
1643 case Token::Kind::TK_STAREQ: // fall through
1644 case Token::Kind::TK_SLASHEQ: // fall through
1645 case Token::Kind::TK_PERCENTEQ: // fall through
1646 case Token::Kind::TK_PLUSEQ: // fall through
1647 case Token::Kind::TK_MINUSEQ: // fall through
1648 case Token::Kind::TK_SHLEQ: // fall through
1649 case Token::Kind::TK_SHREQ: // fall through
1650 case Token::Kind::TK_BITWISEANDEQ: // fall through
1651 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05001652 case Token::Kind::TK_BITWISEOREQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001653 if (!depth.increase()) {
1654 return ASTNode::ID::Invalid();
1655 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001656 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001657 ASTNode::ID right = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001659 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001660 }
John Stiles3b209362020-11-16 17:03:10 -05001661 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1662 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001663 getNode(newResult).addChild(result);
1664 getNode(newResult).addChild(right);
1665 result = newResult;
1666 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 }
1668 default:
1669 return result;
1670 }
1671 }
1672}
1673
1674/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001675ASTNode::ID Parser::ternaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001676 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001677 ASTNode::ID base = this->logicalOrExpression();
1678 if (!base) {
1679 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001680 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001681 if (this->checkNext(Token::Kind::TK_QUESTION)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001682 if (!depth.increase()) {
1683 return ASTNode::ID::Invalid();
1684 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001685 ASTNode::ID trueExpr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001686 if (!trueExpr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001687 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001688 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001689 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001690 ASTNode::ID falseExpr = this->assignmentExpression();
1691 if (!falseExpr) {
1692 return ASTNode::ID::Invalid();
1693 }
John Stiles3b209362020-11-16 17:03:10 -05001694 ASTNode::ID ternary = this->createNode(getNode(base).fOffset, ASTNode::Kind::kTernary);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001695 getNode(ternary).addChild(base);
1696 getNode(ternary).addChild(trueExpr);
1697 getNode(ternary).addChild(falseExpr);
1698 return ternary;
ethannicholasb3058bd2016-07-01 08:22:01 -07001699 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001700 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001702 return base;
ethannicholasb3058bd2016-07-01 08:22:01 -07001703}
1704
1705/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001706ASTNode::ID Parser::logicalOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001707 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001708 ASTNode::ID result = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001709 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001710 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001711 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001712 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001713 while (this->checkNext(Token::Kind::TK_LOGICALOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001714 if (!depth.increase()) {
1715 return ASTNode::ID::Invalid();
1716 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001717 ASTNode::ID right = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001718 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001719 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001720 }
John Stiles3b209362020-11-16 17:03:10 -05001721 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1722 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001723 getNode(newResult).addChild(result);
1724 getNode(newResult).addChild(right);
1725 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 }
1727 return result;
1728}
1729
1730/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001731ASTNode::ID Parser::logicalXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001732 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001733 ASTNode::ID result = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001734 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001735 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001737 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001738 while (this->checkNext(Token::Kind::TK_LOGICALXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001739 if (!depth.increase()) {
1740 return ASTNode::ID::Invalid();
1741 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001742 ASTNode::ID right = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001743 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001744 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001745 }
John Stiles3b209362020-11-16 17:03:10 -05001746 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1747 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001748 getNode(newResult).addChild(result);
1749 getNode(newResult).addChild(right);
1750 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001751 }
1752 return result;
1753}
1754
1755/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001756ASTNode::ID Parser::logicalAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001757 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001758 ASTNode::ID result = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001760 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001761 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001762 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001763 while (this->checkNext(Token::Kind::TK_LOGICALAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001764 if (!depth.increase()) {
1765 return ASTNode::ID::Invalid();
1766 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001767 ASTNode::ID right = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001768 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001769 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001770 }
John Stiles3b209362020-11-16 17:03:10 -05001771 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1772 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001773 getNode(newResult).addChild(result);
1774 getNode(newResult).addChild(right);
1775 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 }
1777 return result;
1778}
1779
1780/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001781ASTNode::ID Parser::bitwiseOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001782 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001783 ASTNode::ID result = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001785 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001787 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001788 while (this->checkNext(Token::Kind::TK_BITWISEOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001789 if (!depth.increase()) {
1790 return ASTNode::ID::Invalid();
1791 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001792 ASTNode::ID right = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001794 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001795 }
John Stiles3b209362020-11-16 17:03:10 -05001796 ASTNode::ID newResult =
1797 this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001798 getNode(newResult).addChild(result);
1799 getNode(newResult).addChild(right);
1800 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 }
1802 return result;
1803}
1804
1805/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001806ASTNode::ID Parser::bitwiseXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001807 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001808 ASTNode::ID result = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001809 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001810 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001811 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001812 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001813 while (this->checkNext(Token::Kind::TK_BITWISEXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001814 if (!depth.increase()) {
1815 return ASTNode::ID::Invalid();
1816 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001817 ASTNode::ID right = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001818 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001819 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 }
John Stiles3b209362020-11-16 17:03:10 -05001821 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001822 getNode(newResult).addChild(result);
1823 getNode(newResult).addChild(right);
1824 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001825 }
1826 return result;
1827}
1828
1829/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001830ASTNode::ID Parser::bitwiseAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001831 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001832 ASTNode::ID result = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001833 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001834 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001835 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001836 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001837 while (this->checkNext(Token::Kind::TK_BITWISEAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001838 if (!depth.increase()) {
1839 return ASTNode::ID::Invalid();
1840 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001841 ASTNode::ID right = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001842 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001843 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001844 }
John Stiles3b209362020-11-16 17:03:10 -05001845 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1846 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001847 getNode(newResult).addChild(result);
1848 getNode(newResult).addChild(right);
1849 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 }
1851 return result;
1852}
1853
1854/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001855ASTNode::ID Parser::equalityExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001856 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001857 ASTNode::ID result = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001859 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001860 }
1861 for (;;) {
1862 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001863 case Token::Kind::TK_EQEQ: // fall through
1864 case Token::Kind::TK_NEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001865 if (!depth.increase()) {
1866 return ASTNode::ID::Invalid();
1867 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001868 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001869 ASTNode::ID right = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001870 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001871 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001872 }
John Stiles3b209362020-11-16 17:03:10 -05001873 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1874 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001875 getNode(newResult).addChild(result);
1876 getNode(newResult).addChild(right);
1877 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001878 break;
1879 }
1880 default:
1881 return result;
1882 }
1883 }
1884}
1885
1886/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001887ASTNode::ID Parser::relationalExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001888 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001889 ASTNode::ID result = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001890 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001891 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001892 }
1893 for (;;) {
1894 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001895 case Token::Kind::TK_LT: // fall through
1896 case Token::Kind::TK_GT: // fall through
1897 case Token::Kind::TK_LTEQ: // fall through
1898 case Token::Kind::TK_GTEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001899 if (!depth.increase()) {
1900 return ASTNode::ID::Invalid();
1901 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001902 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001903 ASTNode::ID right = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001904 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001905 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001906 }
John Stiles3b209362020-11-16 17:03:10 -05001907 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1908 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001909 getNode(newResult).addChild(result);
1910 getNode(newResult).addChild(right);
1911 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001912 break;
1913 }
1914 default:
1915 return result;
1916 }
1917 }
1918}
1919
1920/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001921ASTNode::ID Parser::shiftExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001922 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001923 ASTNode::ID result = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001925 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001926 }
1927 for (;;) {
1928 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001929 case Token::Kind::TK_SHL: // fall through
1930 case Token::Kind::TK_SHR: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001931 if (!depth.increase()) {
1932 return ASTNode::ID::Invalid();
1933 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001934 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001935 ASTNode::ID right = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001936 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001937 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001938 }
John Stiles3b209362020-11-16 17:03:10 -05001939 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1940 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001941 getNode(newResult).addChild(result);
1942 getNode(newResult).addChild(right);
1943 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001944 break;
1945 }
1946 default:
1947 return result;
1948 }
1949 }
1950}
1951
1952/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001953ASTNode::ID Parser::additiveExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001954 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001955 ASTNode::ID result = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001956 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001957 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001958 }
1959 for (;;) {
1960 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001961 case Token::Kind::TK_PLUS: // fall through
1962 case Token::Kind::TK_MINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001963 if (!depth.increase()) {
1964 return ASTNode::ID::Invalid();
1965 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001966 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001967 ASTNode::ID right = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001968 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001969 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001970 }
John Stiles3b209362020-11-16 17:03:10 -05001971 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1972 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001973 getNode(newResult).addChild(result);
1974 getNode(newResult).addChild(right);
1975 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001976 break;
1977 }
1978 default:
1979 return result;
1980 }
1981 }
1982}
1983
1984/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001985ASTNode::ID Parser::multiplicativeExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001986 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001987 ASTNode::ID result = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001988 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001989 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001990 }
1991 for (;;) {
1992 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001993 case Token::Kind::TK_STAR: // fall through
1994 case Token::Kind::TK_SLASH: // fall through
1995 case Token::Kind::TK_PERCENT: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001996 if (!depth.increase()) {
1997 return ASTNode::ID::Invalid();
1998 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04002000 ASTNode::ID right = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002001 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002002 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002003 }
John Stiles3b209362020-11-16 17:03:10 -05002004 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
2005 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002006 getNode(newResult).addChild(result);
2007 getNode(newResult).addChild(right);
2008 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 break;
2010 }
2011 default:
2012 return result;
2013 }
2014 }
2015}
2016
2017/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002018ASTNode::ID Parser::unaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002019 AutoDepth depth(this);
ethannicholasb3058bd2016-07-01 08:22:01 -07002020 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002021 case Token::Kind::TK_PLUS: // fall through
2022 case Token::Kind::TK_MINUS: // fall through
2023 case Token::Kind::TK_LOGICALNOT: // fall through
2024 case Token::Kind::TK_BITWISENOT: // fall through
2025 case Token::Kind::TK_PLUSPLUS: // fall through
2026 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002027 if (!depth.increase()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002028 return ASTNode::ID::Invalid();
Ethan Nicholas6dcc3252019-02-20 15:18:36 -05002029 }
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002030 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04002031 ASTNode::ID expr = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002032 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002033 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002034 }
John Stiles3b209362020-11-16 17:03:10 -05002035 ASTNode::ID result = this->createNode(t.fOffset, ASTNode::Kind::kPrefix, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002036 getNode(result).addChild(expr);
2037 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002038 }
2039 default:
2040 return this->postfixExpression();
2041 }
2042}
2043
2044/* term suffix* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002045ASTNode::ID Parser::postfixExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002046 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002047 ASTNode::ID result = this->term();
ethannicholasb3058bd2016-07-01 08:22:01 -07002048 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002049 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002050 }
2051 for (;;) {
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04002052 Token t = this->peek();
2053 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002054 case Token::Kind::TK_FLOAT_LITERAL:
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04002055 if (this->text(t)[0] != '.') {
2056 return result;
2057 }
John Stiles30212b72020-06-11 17:55:07 -04002058 [[fallthrough]];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002059 case Token::Kind::TK_LBRACKET:
2060 case Token::Kind::TK_DOT:
2061 case Token::Kind::TK_LPAREN:
2062 case Token::Kind::TK_PLUSPLUS:
2063 case Token::Kind::TK_MINUSMINUS:
2064 case Token::Kind::TK_COLONCOLON:
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002065 if (!depth.increase()) {
2066 return ASTNode::ID::Invalid();
2067 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002068 result = this->suffix(result);
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002069 if (!result) {
2070 return ASTNode::ID::Invalid();
2071 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002072 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002073 default:
2074 return result;
2075 }
2076 }
2077}
2078
Ethan Nicholas11d53972016-11-28 11:23:23 -05002079/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
Ethan Nicholase455f652019-09-13 12:52:55 -04002080 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002081ASTNode::ID Parser::suffix(ASTNode::ID base) {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002082 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07002083 Token next = this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002084 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002085 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002086 return ASTNode::ID::Invalid();
2087 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002088 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002089 case Token::Kind::TK_LBRACKET: {
2090 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -05002091 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002092 getNode(result).addChild(base);
2093 return result;
ethannicholas5961bc92016-10-12 06:39:56 -07002094 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002095 ASTNode::ID e = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002096 if (!e) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002097 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002098 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002099 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
John Stiles3b209362020-11-16 17:03:10 -05002100 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002101 getNode(result).addChild(base);
2102 getNode(result).addChild(e);
2103 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002105 case Token::Kind::TK_COLONCOLON: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002106 int offset = this->peek().fOffset;
2107 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07002108 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002109 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kScope,
2110 std::move(text));
Brian Osman6518d772020-09-10 16:50:06 -04002111 getNode(result).addChild(base);
2112 return result;
2113 }
2114 return ASTNode::ID::Invalid();
2115 }
2116 case Token::Kind::TK_DOT: {
2117 int offset = this->peek().fOffset;
2118 StringFragment text;
2119 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002120 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kField,
2121 std::move(text));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002122 getNode(result).addChild(base);
2123 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002124 }
Brian Osman6518d772020-09-10 16:50:06 -04002125 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04002126 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002127 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholase455f652019-09-13 12:52:55 -04002128 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
2129 // floating point literals, possibly followed by an identifier. Handle that here.
2130 StringFragment field = this->text(next);
2131 SkASSERT(field.fChars[0] == '.');
2132 ++field.fChars;
2133 --field.fLength;
2134 for (size_t i = 0; i < field.fLength; ++i) {
2135 if (field.fChars[i] != '0' && field.fChars[i] != '1') {
2136 this->error(next, "invalid swizzle");
2137 return ASTNode::ID::Invalid();
2138 }
2139 }
2140 // use the next *raw* token so we don't ignore whitespace - we only care about
2141 // identifiers that directly follow the float
2142 Token id = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002143 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholase455f652019-09-13 12:52:55 -04002144 field.fLength += id.fLength;
2145 } else {
2146 this->pushback(id);
2147 }
John Stiles3b209362020-11-16 17:03:10 -05002148 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kField, field);
Ethan Nicholase455f652019-09-13 12:52:55 -04002149 getNode(result).addChild(base);
2150 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002151 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002152 case Token::Kind::TK_LPAREN: {
John Stiles3b209362020-11-16 17:03:10 -05002153 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kCall);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002154 getNode(result).addChild(base);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002155 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002156 for (;;) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002157 ASTNode::ID expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002158 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002159 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002160 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002161 getNode(result).addChild(expr);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002162 if (!this->checkNext(Token::Kind::TK_COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 break;
2164 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 }
2166 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002167 this->expect(Token::Kind::TK_RPAREN, "')' to complete function parameters");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002168 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002170 case Token::Kind::TK_PLUSPLUS: // fall through
2171 case Token::Kind::TK_MINUSMINUS: {
John Stiles3b209362020-11-16 17:03:10 -05002172 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kPostfix, next);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002173 getNode(result).addChild(base);
2174 return result;
2175 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 default: {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002177 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002178 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 }
2180 }
2181}
2182
Brian Osman33c64a42020-12-23 10:26:38 -05002183/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002184ASTNode::ID Parser::term() {
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 Token t = this->peek();
2186 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002187 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002188 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07002189 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002190 return this->createNode(t.fOffset, ASTNode::Kind::kIdentifier, std::move(text));
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 }
John Stiles30212b72020-06-11 17:55:07 -04002192 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002193 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002194 case Token::Kind::TK_INT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002195 SKSL_INT i;
ethannicholasb3058bd2016-07-01 08:22:01 -07002196 if (this->intLiteral(&i)) {
John Stiles3b209362020-11-16 17:03:10 -05002197 return this->createNode(t.fOffset, ASTNode::Kind::kInt, i);
ethannicholasb3058bd2016-07-01 08:22:01 -07002198 }
2199 break;
2200 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002201 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002202 SKSL_FLOAT f;
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 if (this->floatLiteral(&f)) {
John Stiles3b209362020-11-16 17:03:10 -05002204 return this->createNode(t.fOffset, ASTNode::Kind::kFloat, f);
ethannicholasb3058bd2016-07-01 08:22:01 -07002205 }
2206 break;
2207 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002208 case Token::Kind::TK_TRUE_LITERAL: // fall through
2209 case Token::Kind::TK_FALSE_LITERAL: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002210 bool b;
2211 if (this->boolLiteral(&b)) {
John Stiles3b209362020-11-16 17:03:10 -05002212 return this->createNode(t.fOffset, ASTNode::Kind::kBool, b);
ethannicholasb3058bd2016-07-01 08:22:01 -07002213 }
2214 break;
2215 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002216 case Token::Kind::TK_LPAREN: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002217 this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002218 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002219 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002220 return ASTNode::ID::Invalid();
2221 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002222 ASTNode::ID result = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002223 if (result) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002224 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002225 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002226 }
2227 break;
2228 }
2229 default:
2230 this->nextToken();
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002231 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002233 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002234}
2235
2236/* INT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002237bool Parser::intLiteral(SKSL_INT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002238 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002239 if (this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002240 *dest = SkSL::stol(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07002241 return true;
2242 }
2243 return false;
2244}
2245
2246/* FLOAT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002247bool Parser::floatLiteral(SKSL_FLOAT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002248 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002249 if (this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002250 *dest = SkSL::stod(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07002251 return true;
2252 }
2253 return false;
2254}
2255
2256/* TRUE_LITERAL | FALSE_LITERAL */
2257bool Parser::boolLiteral(bool* dest) {
2258 Token t = this->nextToken();
2259 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002260 case Token::Kind::TK_TRUE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07002261 *dest = true;
2262 return true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002263 case Token::Kind::TK_FALSE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07002264 *dest = false;
2265 return true;
2266 default:
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002267 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 return false;
2269 }
2270}
2271
2272/* IDENTIFIER */
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002273bool Parser::identifier(StringFragment* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002274 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002275 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002276 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07002277 return true;
2278 }
2279 return false;
2280}
2281
John Stilesa6841be2020-08-06 14:11:56 -04002282} // namespace SkSL