blob: 1742f1cdd6e11b9c1cfb072e9b79786aefeb6ea2 [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),
Brian Osmancaca7bf2020-12-23 14:30:04 -0500591 /*isStructDeclaration=*/true));
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);
Brian Osmancaca7bf2020-12-23 14:30:04 -05001169 ASTNode::TypeData td(this->text(type), /*isStructDeclaration=*/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 Nicholasfc994162019-06-06 10:04:27 -04001190 getNode(result).setTypeData(td);
1191 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001192}
1193
John Stiles57a996b2020-04-19 19:05:12 -07001194/* IDENTIFIER LBRACE
1195 varDeclaration+
1196 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001197ASTNode::ID Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001198 Token name;
John Stiles2630ea32020-12-04 10:51:21 -05001199 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001200 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001201 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001202 if (peek().fKind != Token::Kind::TK_LBRACE) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001203 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -05001204 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -07001205 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001206 this->error(name, "no type named '" + this->text(name) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001207 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001208 }
John Stiles3b209362020-11-16 17:03:10 -05001209 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kInterfaceBlock);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001210 ASTNode::InterfaceBlockData id(mods, this->text(name), 0, "", 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001211 this->nextToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001212 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001213 ASTNode::ID decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001214 if (!decl) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001215 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001216 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001217 getNode(result).addChild(decl);
1218 ++id.fDeclarationCount;
ethannicholasb3058bd2016-07-01 08:22:01 -07001219 }
John Stiles57a996b2020-04-19 19:05:12 -07001220 if (id.fDeclarationCount == 0) {
1221 this->error(name, "interface block '" + this->text(name) +
1222 "' must contain at least one member");
1223 return ASTNode::ID::Invalid();
1224 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001225 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001226 std::vector<ASTNode> sizes;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001227 StringFragment instanceName;
1228 Token instanceNameToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001229 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001230 id.fInstanceName = this->text(instanceNameToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001231 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -05001232 if (id.fIsArray) {
1233 this->error(this->peek(), "multi-dimensional arrays are not supported");
1234 return false;
1235 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001236 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001237 ASTNode::ID size = this->expression();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001238 if (!size) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001239 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001240 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001241 getNode(result).addChild(size);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001242 } else {
John Stiles3b209362020-11-16 17:03:10 -05001243 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001244 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001245 this->expect(Token::Kind::TK_RBRACKET, "']'");
John Stilesd39aec92020-12-03 14:37:16 -05001246 id.fIsArray = true;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001247 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001248 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -07001249 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001250 getNode(result).setInterfaceBlockData(id);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001251 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001252 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001253}
1254
1255/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001256ASTNode::ID Parser::ifStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001257 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001258 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
1259 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001260 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001261 }
John Stiles3b209362020-11-16 17:03:10 -05001262 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kIf, isStatic);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001263 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001264 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001265 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001266 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001267 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001268 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001269 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001270 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001271 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001272 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001273 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001274 ASTNode::ID ifTrue = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001275 if (!ifTrue) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001276 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001277 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001278 getNode(result).addChild(ifTrue);
1279 ASTNode::ID ifFalse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001280 if (this->checkNext(Token::Kind::TK_ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001281 ifFalse = this->statement();
1282 if (!ifFalse) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001283 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001284 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001285 getNode(result).addChild(ifFalse);
ethannicholasb3058bd2016-07-01 08:22:01 -07001286 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001287 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001288}
1289
1290/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001291ASTNode::ID Parser::doStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001292 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001293 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001294 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001295 }
John Stiles3b209362020-11-16 17:03:10 -05001296 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kDo);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001297 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001298 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001299 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001300 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001301 getNode(result).addChild(statement);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001302 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001303 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001304 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001305 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001306 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001307 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001308 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001309 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001310 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001311 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001312 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001313 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001314 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001315 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001316 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001317 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001318 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001319 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001320}
1321
1322/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001323ASTNode::ID Parser::whileStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001324 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001325 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001326 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001327 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001328 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001329 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001330 }
John Stiles3b209362020-11-16 17:03:10 -05001331 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kWhile);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001332 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001333 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001334 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001335 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001336 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001337 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001338 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001339 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001340 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001341 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001342 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001343 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001344 getNode(result).addChild(statement);
1345 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001346}
1347
Ethan Nicholasaf197692017-02-27 13:26:45 -05001348/* CASE expression COLON statement* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001349ASTNode::ID Parser::switchCase() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001350 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001351 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001352 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001353 }
John Stiles3b209362020-11-16 17:03:10 -05001354 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitchCase);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001355 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001356 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001357 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001358 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001359 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001360 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001361 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001362 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001363 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1364 this->peek().fKind != Token::Kind::TK_CASE &&
1365 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001366 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001367 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001368 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001369 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001370 getNode(result).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001371 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001372 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001373}
1374
1375/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001376ASTNode::ID Parser::switchStatement() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001377 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001378 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1379 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001380 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001381 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001382 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001383 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001384 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001385 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001386 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001387 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001388 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001389 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001390 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001391 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001392 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001393 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001394 }
John Stiles3b209362020-11-16 17:03:10 -05001395 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitch, isStatic);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001396 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001397 while (this->peek().fKind == Token::Kind::TK_CASE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001398 ASTNode::ID c = this->switchCase();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001399 if (!c) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001400 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001401 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001402 getNode(result).addChild(c);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001403 }
1404 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1405 // parts of the compiler may rely upon this assumption.
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001406 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001407 Token defaultStart;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001408 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1409 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001410 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001411 }
John Stiles3b209362020-11-16 17:03:10 -05001412 ASTNode::ID defaultCase = this->addChild(
1413 result, this->createNode(defaultStart.fOffset, ASTNode::Kind::kSwitchCase));
1414 this->createEmptyChild(defaultCase); // empty test to signify default case
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001415 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001416 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001417 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001418 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001419 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001420 getNode(defaultCase).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001421 }
Ethan Nicholasaf197692017-02-27 13:26:45 -05001422 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001423 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001424 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001425 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001426 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001427}
1428
Ethan Nicholas11d53972016-11-28 11:23:23 -05001429/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001430 STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001431ASTNode::ID Parser::forStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001432 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001433 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001434 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001435 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001436 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001437 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001438 }
John Stiles3b209362020-11-16 17:03:10 -05001439 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kFor);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001440 ASTNode::ID initializer;
ethannicholasb3058bd2016-07-01 08:22:01 -07001441 Token nextToken = this->peek();
1442 switch (nextToken.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001443 case Token::Kind::TK_SEMICOLON:
ethannicholas22f939e2016-10-13 13:25:34 -07001444 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -05001445 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001446 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001447 case Token::Kind::TK_CONST: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001448 initializer = this->varDeclarations();
1449 if (!initializer) {
1450 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001451 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001452 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 break;
ethannicholasa54401d2016-10-14 08:37:32 -07001454 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001455 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001456 if (this->isType(this->text(nextToken))) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001457 initializer = this->varDeclarations();
1458 if (!initializer) {
1459 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001460 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001461 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001462 break;
1463 }
John Stiles30212b72020-06-11 17:55:07 -04001464 [[fallthrough]];
1465 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001466 default:
1467 initializer = this->expressionStatement();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001468 if (!initializer) {
1469 return ASTNode::ID::Invalid();
1470 }
1471 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001472 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001473 ASTNode::ID test;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001474 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 test = this->expression();
1476 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001477 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001479 getNode(result).addChild(test);
1480 } else {
John Stiles3b209362020-11-16 17:03:10 -05001481 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001482 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001483 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001484 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001485 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001486 ASTNode::ID next;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001487 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001488 next = this->expression();
1489 if (!next) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001490 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001491 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001492 getNode(result).addChild(next);
1493 } else {
John Stiles3b209362020-11-16 17:03:10 -05001494 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001495 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001496 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001497 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001498 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001499 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001500 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001501 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001502 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001503 getNode(result).addChild(statement);
1504 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001505}
1506
1507/* RETURN expression? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001508ASTNode::ID Parser::returnStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001509 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001510 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001511 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 }
John Stiles3b209362020-11-16 17:03:10 -05001513 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kReturn);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001514 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001515 ASTNode::ID expression = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 if (!expression) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001517 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001518 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001519 getNode(result).addChild(expression);
ethannicholasb3058bd2016-07-01 08:22:01 -07001520 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001521 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001522 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001523 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001524 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001525}
1526
1527/* BREAK SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001528ASTNode::ID Parser::breakStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001530 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001531 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001532 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001533 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001534 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001535 }
John Stiles3b209362020-11-16 17:03:10 -05001536 return this->createNode(start.fOffset, ASTNode::Kind::kBreak);
ethannicholasb3058bd2016-07-01 08:22:01 -07001537}
1538
1539/* CONTINUE SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001540ASTNode::ID Parser::continueStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001541 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001542 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001543 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001544 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001545 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001546 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001547 }
John Stiles3b209362020-11-16 17:03:10 -05001548 return this->createNode(start.fOffset, ASTNode::Kind::kContinue);
ethannicholasb3058bd2016-07-01 08:22:01 -07001549}
1550
1551/* DISCARD SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001552ASTNode::ID Parser::discardStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001554 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001555 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001557 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001558 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001559 }
John Stiles3b209362020-11-16 17:03:10 -05001560 return this->createNode(start.fOffset, ASTNode::Kind::kDiscard);
ethannicholasb3058bd2016-07-01 08:22:01 -07001561}
1562
1563/* LBRACE statement* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001564ASTNode::ID Parser::block() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001566 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001567 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 }
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001569 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001570 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001571 return ASTNode::ID::Invalid();
1572 }
John Stiles3b209362020-11-16 17:03:10 -05001573 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -07001574 for (;;) {
1575 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001576 case Token::Kind::TK_RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001577 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001578 return result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001579 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001580 this->error(this->peek(), "expected '}', but found end of file");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001581 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001583 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001584 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001585 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001587 getNode(result).addChild(statement);
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 }
1589 }
1590 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001591 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001592}
1593
1594/* expression SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001595ASTNode::ID Parser::expressionStatement() {
1596 ASTNode::ID expr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 if (expr) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001598 if (this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001599 return expr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 }
1601 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001602 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001603}
1604
1605/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001606ASTNode::ID Parser::expression() {
1607 ASTNode::ID result = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001608 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001609 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001610 }
1611 Token t;
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001612 AutoDepth depth(this);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001613 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001614 if (!depth.increase()) {
1615 return ASTNode::ID::Invalid();
1616 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001617 ASTNode::ID right = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001618 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001619 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001620 }
John Stiles3b209362020-11-16 17:03:10 -05001621 ASTNode::ID newResult = this->createNode(t.fOffset, ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001622 getNode(newResult).addChild(result);
1623 getNode(newResult).addChild(right);
1624 result = newResult;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001625 }
1626 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001627}
1628
1629/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1630 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1631 assignmentExpression)*
1632 */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001633ASTNode::ID Parser::assignmentExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001634 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001635 ASTNode::ID result = this->ternaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001636 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001637 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 }
1639 for (;;) {
1640 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001641 case Token::Kind::TK_EQ: // fall through
1642 case Token::Kind::TK_STAREQ: // fall through
1643 case Token::Kind::TK_SLASHEQ: // fall through
1644 case Token::Kind::TK_PERCENTEQ: // fall through
1645 case Token::Kind::TK_PLUSEQ: // fall through
1646 case Token::Kind::TK_MINUSEQ: // fall through
1647 case Token::Kind::TK_SHLEQ: // fall through
1648 case Token::Kind::TK_SHREQ: // fall through
1649 case Token::Kind::TK_BITWISEANDEQ: // fall through
1650 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05001651 case Token::Kind::TK_BITWISEOREQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001652 if (!depth.increase()) {
1653 return ASTNode::ID::Invalid();
1654 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001655 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001656 ASTNode::ID right = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001658 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001659 }
John Stiles3b209362020-11-16 17:03:10 -05001660 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1661 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001662 getNode(newResult).addChild(result);
1663 getNode(newResult).addChild(right);
1664 result = newResult;
1665 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001666 }
1667 default:
1668 return result;
1669 }
1670 }
1671}
1672
1673/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001674ASTNode::ID Parser::ternaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001675 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001676 ASTNode::ID base = this->logicalOrExpression();
1677 if (!base) {
1678 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001679 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001680 if (this->checkNext(Token::Kind::TK_QUESTION)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001681 if (!depth.increase()) {
1682 return ASTNode::ID::Invalid();
1683 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001684 ASTNode::ID trueExpr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001685 if (!trueExpr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001686 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001688 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001689 ASTNode::ID falseExpr = this->assignmentExpression();
1690 if (!falseExpr) {
1691 return ASTNode::ID::Invalid();
1692 }
John Stiles3b209362020-11-16 17:03:10 -05001693 ASTNode::ID ternary = this->createNode(getNode(base).fOffset, ASTNode::Kind::kTernary);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001694 getNode(ternary).addChild(base);
1695 getNode(ternary).addChild(trueExpr);
1696 getNode(ternary).addChild(falseExpr);
1697 return ternary;
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001699 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001700 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001701 return base;
ethannicholasb3058bd2016-07-01 08:22:01 -07001702}
1703
1704/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001705ASTNode::ID Parser::logicalOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001706 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001707 ASTNode::ID result = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001708 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001709 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001710 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001711 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001712 while (this->checkNext(Token::Kind::TK_LOGICALOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001713 if (!depth.increase()) {
1714 return ASTNode::ID::Invalid();
1715 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001716 ASTNode::ID right = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001717 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001718 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001719 }
John Stiles3b209362020-11-16 17:03:10 -05001720 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1721 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001722 getNode(newResult).addChild(result);
1723 getNode(newResult).addChild(right);
1724 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 }
1726 return result;
1727}
1728
1729/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001730ASTNode::ID Parser::logicalXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001731 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001732 ASTNode::ID result = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001734 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001735 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001736 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001737 while (this->checkNext(Token::Kind::TK_LOGICALXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001738 if (!depth.increase()) {
1739 return ASTNode::ID::Invalid();
1740 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001741 ASTNode::ID right = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001743 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001744 }
John Stiles3b209362020-11-16 17:03:10 -05001745 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1746 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001747 getNode(newResult).addChild(result);
1748 getNode(newResult).addChild(right);
1749 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001750 }
1751 return result;
1752}
1753
1754/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001755ASTNode::ID Parser::logicalAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001756 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001757 ASTNode::ID result = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001758 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001759 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001760 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001761 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001762 while (this->checkNext(Token::Kind::TK_LOGICALAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001763 if (!depth.increase()) {
1764 return ASTNode::ID::Invalid();
1765 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001766 ASTNode::ID right = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001767 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001768 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001769 }
John Stiles3b209362020-11-16 17:03:10 -05001770 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1771 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001772 getNode(newResult).addChild(result);
1773 getNode(newResult).addChild(right);
1774 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001775 }
1776 return result;
1777}
1778
1779/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001780ASTNode::ID Parser::bitwiseOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001781 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001782 ASTNode::ID result = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001783 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001784 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001786 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001787 while (this->checkNext(Token::Kind::TK_BITWISEOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001788 if (!depth.increase()) {
1789 return ASTNode::ID::Invalid();
1790 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001791 ASTNode::ID right = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001793 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 }
John Stiles3b209362020-11-16 17:03:10 -05001795 ASTNode::ID newResult =
1796 this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001797 getNode(newResult).addChild(result);
1798 getNode(newResult).addChild(right);
1799 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001800 }
1801 return result;
1802}
1803
1804/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001805ASTNode::ID Parser::bitwiseXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001806 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001807 ASTNode::ID result = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001808 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001809 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001810 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001811 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001812 while (this->checkNext(Token::Kind::TK_BITWISEXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001813 if (!depth.increase()) {
1814 return ASTNode::ID::Invalid();
1815 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001816 ASTNode::ID right = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001817 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001818 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001819 }
John Stiles3b209362020-11-16 17:03:10 -05001820 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001821 getNode(newResult).addChild(result);
1822 getNode(newResult).addChild(right);
1823 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 }
1825 return result;
1826}
1827
1828/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001829ASTNode::ID Parser::bitwiseAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001830 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001831 ASTNode::ID result = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001832 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001833 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001834 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001835 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001836 while (this->checkNext(Token::Kind::TK_BITWISEAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001837 if (!depth.increase()) {
1838 return ASTNode::ID::Invalid();
1839 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001840 ASTNode::ID right = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001842 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001843 }
John Stiles3b209362020-11-16 17:03:10 -05001844 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1845 std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001846 getNode(newResult).addChild(result);
1847 getNode(newResult).addChild(right);
1848 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001849 }
1850 return result;
1851}
1852
1853/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001854ASTNode::ID Parser::equalityExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001855 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001856 ASTNode::ID result = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001857 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001858 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001859 }
1860 for (;;) {
1861 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001862 case Token::Kind::TK_EQEQ: // fall through
1863 case Token::Kind::TK_NEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001864 if (!depth.increase()) {
1865 return ASTNode::ID::Invalid();
1866 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001867 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001868 ASTNode::ID right = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001869 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001870 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001871 }
John Stiles3b209362020-11-16 17:03:10 -05001872 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1873 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001874 getNode(newResult).addChild(result);
1875 getNode(newResult).addChild(right);
1876 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001877 break;
1878 }
1879 default:
1880 return result;
1881 }
1882 }
1883}
1884
1885/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001886ASTNode::ID Parser::relationalExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001887 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001888 ASTNode::ID result = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001889 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001890 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001891 }
1892 for (;;) {
1893 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001894 case Token::Kind::TK_LT: // fall through
1895 case Token::Kind::TK_GT: // fall through
1896 case Token::Kind::TK_LTEQ: // fall through
1897 case Token::Kind::TK_GTEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001898 if (!depth.increase()) {
1899 return ASTNode::ID::Invalid();
1900 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001901 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001902 ASTNode::ID right = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001903 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001904 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001905 }
John Stiles3b209362020-11-16 17:03:10 -05001906 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1907 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001908 getNode(newResult).addChild(result);
1909 getNode(newResult).addChild(right);
1910 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001911 break;
1912 }
1913 default:
1914 return result;
1915 }
1916 }
1917}
1918
1919/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001920ASTNode::ID Parser::shiftExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001921 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001922 ASTNode::ID result = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001923 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001924 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001925 }
1926 for (;;) {
1927 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001928 case Token::Kind::TK_SHL: // fall through
1929 case Token::Kind::TK_SHR: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001930 if (!depth.increase()) {
1931 return ASTNode::ID::Invalid();
1932 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001933 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001934 ASTNode::ID right = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001935 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001936 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001937 }
John Stiles3b209362020-11-16 17:03:10 -05001938 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1939 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001940 getNode(newResult).addChild(result);
1941 getNode(newResult).addChild(right);
1942 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001943 break;
1944 }
1945 default:
1946 return result;
1947 }
1948 }
1949}
1950
1951/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001952ASTNode::ID Parser::additiveExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001953 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001954 ASTNode::ID result = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001956 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001957 }
1958 for (;;) {
1959 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001960 case Token::Kind::TK_PLUS: // fall through
1961 case Token::Kind::TK_MINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001962 if (!depth.increase()) {
1963 return ASTNode::ID::Invalid();
1964 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001965 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001966 ASTNode::ID right = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001967 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001968 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001969 }
John Stiles3b209362020-11-16 17:03:10 -05001970 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
1971 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001972 getNode(newResult).addChild(result);
1973 getNode(newResult).addChild(right);
1974 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001975 break;
1976 }
1977 default:
1978 return result;
1979 }
1980 }
1981}
1982
1983/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001984ASTNode::ID Parser::multiplicativeExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001985 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001986 ASTNode::ID result = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001987 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001988 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001989 }
1990 for (;;) {
1991 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001992 case Token::Kind::TK_STAR: // fall through
1993 case Token::Kind::TK_SLASH: // fall through
1994 case Token::Kind::TK_PERCENT: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001995 if (!depth.increase()) {
1996 return ASTNode::ID::Invalid();
1997 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001998 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001999 ASTNode::ID right = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002000 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002001 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002002 }
John Stiles3b209362020-11-16 17:03:10 -05002003 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
2004 ASTNode::Kind::kBinary, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002005 getNode(newResult).addChild(result);
2006 getNode(newResult).addChild(right);
2007 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 break;
2009 }
2010 default:
2011 return result;
2012 }
2013 }
2014}
2015
2016/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002017ASTNode::ID Parser::unaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002018 AutoDepth depth(this);
ethannicholasb3058bd2016-07-01 08:22:01 -07002019 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002020 case Token::Kind::TK_PLUS: // fall through
2021 case Token::Kind::TK_MINUS: // fall through
2022 case Token::Kind::TK_LOGICALNOT: // fall through
2023 case Token::Kind::TK_BITWISENOT: // fall through
2024 case Token::Kind::TK_PLUSPLUS: // fall through
2025 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002026 if (!depth.increase()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002027 return ASTNode::ID::Invalid();
Ethan Nicholas6dcc3252019-02-20 15:18:36 -05002028 }
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002029 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04002030 ASTNode::ID expr = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002031 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002032 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 }
John Stiles3b209362020-11-16 17:03:10 -05002034 ASTNode::ID result = this->createNode(t.fOffset, ASTNode::Kind::kPrefix, std::move(t));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002035 getNode(result).addChild(expr);
2036 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002037 }
2038 default:
2039 return this->postfixExpression();
2040 }
2041}
2042
2043/* term suffix* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002044ASTNode::ID Parser::postfixExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002045 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002046 ASTNode::ID result = this->term();
ethannicholasb3058bd2016-07-01 08:22:01 -07002047 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002048 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002049 }
2050 for (;;) {
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04002051 Token t = this->peek();
2052 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002053 case Token::Kind::TK_FLOAT_LITERAL:
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04002054 if (this->text(t)[0] != '.') {
2055 return result;
2056 }
John Stiles30212b72020-06-11 17:55:07 -04002057 [[fallthrough]];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002058 case Token::Kind::TK_LBRACKET:
2059 case Token::Kind::TK_DOT:
2060 case Token::Kind::TK_LPAREN:
2061 case Token::Kind::TK_PLUSPLUS:
2062 case Token::Kind::TK_MINUSMINUS:
2063 case Token::Kind::TK_COLONCOLON:
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002064 if (!depth.increase()) {
2065 return ASTNode::ID::Invalid();
2066 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002067 result = this->suffix(result);
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002068 if (!result) {
2069 return ASTNode::ID::Invalid();
2070 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002071 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002072 default:
2073 return result;
2074 }
2075 }
2076}
2077
Ethan Nicholas11d53972016-11-28 11:23:23 -05002078/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
Ethan Nicholase455f652019-09-13 12:52:55 -04002079 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002080ASTNode::ID Parser::suffix(ASTNode::ID base) {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002081 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07002082 Token next = this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002083 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002084 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002085 return ASTNode::ID::Invalid();
2086 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002088 case Token::Kind::TK_LBRACKET: {
2089 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -05002090 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002091 getNode(result).addChild(base);
2092 return result;
ethannicholas5961bc92016-10-12 06:39:56 -07002093 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002094 ASTNode::ID e = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002095 if (!e) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002096 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002097 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002098 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
John Stiles3b209362020-11-16 17:03:10 -05002099 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002100 getNode(result).addChild(base);
2101 getNode(result).addChild(e);
2102 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002103 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002104 case Token::Kind::TK_COLONCOLON: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002105 int offset = this->peek().fOffset;
2106 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07002107 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002108 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kScope,
2109 std::move(text));
Brian Osman6518d772020-09-10 16:50:06 -04002110 getNode(result).addChild(base);
2111 return result;
2112 }
2113 return ASTNode::ID::Invalid();
2114 }
2115 case Token::Kind::TK_DOT: {
2116 int offset = this->peek().fOffset;
2117 StringFragment text;
2118 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002119 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kField,
2120 std::move(text));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002121 getNode(result).addChild(base);
2122 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002123 }
Brian Osman6518d772020-09-10 16:50:06 -04002124 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04002125 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002126 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholase455f652019-09-13 12:52:55 -04002127 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
2128 // floating point literals, possibly followed by an identifier. Handle that here.
2129 StringFragment field = this->text(next);
2130 SkASSERT(field.fChars[0] == '.');
2131 ++field.fChars;
2132 --field.fLength;
2133 for (size_t i = 0; i < field.fLength; ++i) {
2134 if (field.fChars[i] != '0' && field.fChars[i] != '1') {
2135 this->error(next, "invalid swizzle");
2136 return ASTNode::ID::Invalid();
2137 }
2138 }
2139 // use the next *raw* token so we don't ignore whitespace - we only care about
2140 // identifiers that directly follow the float
2141 Token id = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002142 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholase455f652019-09-13 12:52:55 -04002143 field.fLength += id.fLength;
2144 } else {
2145 this->pushback(id);
2146 }
John Stiles3b209362020-11-16 17:03:10 -05002147 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kField, field);
Ethan Nicholase455f652019-09-13 12:52:55 -04002148 getNode(result).addChild(base);
2149 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002150 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002151 case Token::Kind::TK_LPAREN: {
John Stiles3b209362020-11-16 17:03:10 -05002152 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kCall);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002153 getNode(result).addChild(base);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002154 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002155 for (;;) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002156 ASTNode::ID expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002158 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002159 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002160 getNode(result).addChild(expr);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002161 if (!this->checkNext(Token::Kind::TK_COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002162 break;
2163 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 }
2165 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002166 this->expect(Token::Kind::TK_RPAREN, "')' to complete function parameters");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002167 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002169 case Token::Kind::TK_PLUSPLUS: // fall through
2170 case Token::Kind::TK_MINUSMINUS: {
John Stiles3b209362020-11-16 17:03:10 -05002171 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kPostfix, next);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002172 getNode(result).addChild(base);
2173 return result;
2174 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002175 default: {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002176 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002177 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002178 }
2179 }
2180}
2181
Brian Osman33c64a42020-12-23 10:26:38 -05002182/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002183ASTNode::ID Parser::term() {
ethannicholasb3058bd2016-07-01 08:22:01 -07002184 Token t = this->peek();
2185 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002186 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002187 StringFragment text;
ethannicholasb3058bd2016-07-01 08:22:01 -07002188 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002189 return this->createNode(t.fOffset, ASTNode::Kind::kIdentifier, std::move(text));
ethannicholasb3058bd2016-07-01 08:22:01 -07002190 }
John Stiles30212b72020-06-11 17:55:07 -04002191 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002192 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002193 case Token::Kind::TK_INT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002194 SKSL_INT i;
ethannicholasb3058bd2016-07-01 08:22:01 -07002195 if (this->intLiteral(&i)) {
John Stiles3b209362020-11-16 17:03:10 -05002196 return this->createNode(t.fOffset, ASTNode::Kind::kInt, i);
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 }
2198 break;
2199 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002200 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002201 SKSL_FLOAT f;
ethannicholasb3058bd2016-07-01 08:22:01 -07002202 if (this->floatLiteral(&f)) {
John Stiles3b209362020-11-16 17:03:10 -05002203 return this->createNode(t.fOffset, ASTNode::Kind::kFloat, f);
ethannicholasb3058bd2016-07-01 08:22:01 -07002204 }
2205 break;
2206 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002207 case Token::Kind::TK_TRUE_LITERAL: // fall through
2208 case Token::Kind::TK_FALSE_LITERAL: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002209 bool b;
2210 if (this->boolLiteral(&b)) {
John Stiles3b209362020-11-16 17:03:10 -05002211 return this->createNode(t.fOffset, ASTNode::Kind::kBool, b);
ethannicholasb3058bd2016-07-01 08:22:01 -07002212 }
2213 break;
2214 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002215 case Token::Kind::TK_LPAREN: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002216 this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002217 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002218 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002219 return ASTNode::ID::Invalid();
2220 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002221 ASTNode::ID result = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002222 if (result) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002223 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002224 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002225 }
2226 break;
2227 }
2228 default:
2229 this->nextToken();
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002230 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002231 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002232 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002233}
2234
2235/* INT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002236bool Parser::intLiteral(SKSL_INT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002237 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002238 if (this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002239 *dest = SkSL::stol(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07002240 return true;
2241 }
2242 return false;
2243}
2244
2245/* FLOAT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002246bool Parser::floatLiteral(SKSL_FLOAT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002247 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002248 if (this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002249 *dest = SkSL::stod(this->text(t));
ethannicholasb3058bd2016-07-01 08:22:01 -07002250 return true;
2251 }
2252 return false;
2253}
2254
2255/* TRUE_LITERAL | FALSE_LITERAL */
2256bool Parser::boolLiteral(bool* dest) {
2257 Token t = this->nextToken();
2258 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002259 case Token::Kind::TK_TRUE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07002260 *dest = true;
2261 return true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002262 case Token::Kind::TK_FALSE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07002263 *dest = false;
2264 return true;
2265 default:
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002266 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002267 return false;
2268 }
2269}
2270
2271/* IDENTIFIER */
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002272bool Parser::identifier(StringFragment* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002273 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002274 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002275 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 return true;
2277 }
2278 return false;
2279}
2280
John Stilesa6841be2020-08-06 14:11:56 -04002281} // namespace SkSL