blob: f76a47633e390df95e72669debfa438fb5dac558 [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
Ethan Nicholasdaed2592021-03-04 14:30:25 -050013#include "include/private/SkSLModifiers.h"
John Stilesfbd050b2020-08-03 13:21:46 -040014#include "src/sksl/SkSLASTNode.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#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
John Stiles7d5b90a2021-01-21 14:26:51 -050043static int parse_modifier_token(Token::Kind token) {
44 switch (token) {
45 case Token::Kind::TK_UNIFORM: return Modifiers::kUniform_Flag;
46 case Token::Kind::TK_CONST: return Modifiers::kConst_Flag;
47 case Token::Kind::TK_IN: return Modifiers::kIn_Flag;
48 case Token::Kind::TK_OUT: return Modifiers::kOut_Flag;
49 case Token::Kind::TK_INOUT: return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
50 case Token::Kind::TK_FLAT: return Modifiers::kFlat_Flag;
51 case Token::Kind::TK_NOPERSPECTIVE: return Modifiers::kNoPerspective_Flag;
John Stiles7d5b90a2021-01-21 14:26:51 -050052 case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
John Stiles7d5b90a2021-01-21 14:26:51 -050053 case Token::Kind::TK_INLINE: return Modifiers::kInline_Flag;
John Stiles0dd1a772021-03-09 22:14:27 -050054 case Token::Kind::TK_NOINLINE: return Modifiers::kNoInline_Flag;
John Stiles7d5b90a2021-01-21 14:26:51 -050055 default: return 0;
56 }
57}
58
ethannicholascad64162016-10-27 10:54:02 -070059class AutoDepth {
60public:
61 AutoDepth(Parser* p)
Ethan Nicholascf4deab2019-09-13 16:28:14 -040062 : fParser(p)
63 , fDepth(0) {}
ethannicholascad64162016-10-27 10:54:02 -070064
65 ~AutoDepth() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -040066 fParser->fDepth -= fDepth;
ethannicholascad64162016-10-27 10:54:02 -070067 }
68
Ethan Nicholascf4deab2019-09-13 16:28:14 -040069 bool increase() {
70 ++fDepth;
71 ++fParser->fDepth;
John Stiles8d056592020-11-10 10:03:50 -050072 if (fParser->fDepth > kMaxParseDepth) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070073 fParser->error(fParser->peek(), String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070074 return false;
75 }
76 return true;
77 }
78
79private:
80 Parser* fParser;
Ethan Nicholascf4deab2019-09-13 16:28:14 -040081 int fDepth;
ethannicholascad64162016-10-27 10:54:02 -070082};
83
Brian Salomon140f3da2018-08-23 13:51:27 +000084std::unordered_map<String, Parser::LayoutToken>* Parser::layoutTokens;
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040085
86void Parser::InitLayoutMap() {
Brian Salomon140f3da2018-08-23 13:51:27 +000087 layoutTokens = new std::unordered_map<String, LayoutToken>;
Brian Salomon23356442018-11-30 15:33:19 -050088 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040089 TOKEN(LOCATION, "location");
90 TOKEN(OFFSET, "offset");
91 TOKEN(BINDING, "binding");
92 TOKEN(INDEX, "index");
93 TOKEN(SET, "set");
94 TOKEN(BUILTIN, "builtin");
95 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
96 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040097 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040098 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");
108 TOKEN(WHEN, "when");
109 TOKEN(KEY, "key");
Brian Osmanb32d66b2020-04-30 17:12:03 -0400110 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400111 TOKEN(CTYPE, "ctype");
Brian Osmanf28e55d2018-10-03 16:35:54 -0400112 TOKEN(SKPMCOLOR4F, "SkPMColor4f");
Mike Reedb26b4e72020-01-22 14:31:21 -0500113 TOKEN(SKV4, "SkV4");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400114 #undef TOKEN
115}
116
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400117Parser::Parser(const char* text, size_t length, SymbolTable& symbols, ErrorReporter& errors)
John Stiles18a45b32021-03-29 18:07:32 -0400118: fText(text, length)
John Stiles7cbb09c22021-01-07 16:07:00 -0500119, fPushback(Token::Kind::TK_NONE, -1, -1)
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400120, fSymbols(symbols)
ethannicholasb3058bd2016-07-01 08:22:01 -0700121, fErrors(errors) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700122 fLexer.start(text, length);
Brian Salomon3b83afe2018-08-23 11:04:36 -0400123 static const bool layoutMapInitialized = []{ return (void)InitLayoutMap(), true; }();
124 (void) layoutMapInitialized;
ethannicholasb3058bd2016-07-01 08:22:01 -0700125}
126
John Stiles3b209362020-11-16 17:03:10 -0500127template <typename... Args>
128ASTNode::ID Parser::createNode(Args&&... args) {
129 ASTNode::ID result(fFile->fNodes.size());
130 fFile->fNodes.emplace_back(&fFile->fNodes, std::forward<Args>(args)...);
131 return result;
132}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400133
John Stiles3b209362020-11-16 17:03:10 -0500134ASTNode::ID Parser::addChild(ASTNode::ID target, ASTNode::ID child) {
135 fFile->fNodes[target.fValue].addChild(child);
136 return child;
137}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400138
John Stiles3b209362020-11-16 17:03:10 -0500139void Parser::createEmptyChild(ASTNode::ID target) {
140 ASTNode::ID child(fFile->fNodes.size());
141 fFile->fNodes.emplace_back();
142 fFile->fNodes[target.fValue].addChild(child);
143}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400144
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400145/* (directive | section | declaration)* END_OF_FILE */
Ethan Nicholasba9a04f2020-11-06 09:28:04 -0500146std::unique_ptr<ASTFile> Parser::compilationUnit() {
John Stilesfbd050b2020-08-03 13:21:46 -0400147 fFile = std::make_unique<ASTFile>();
John Stiles18a45b32021-03-29 18:07:32 -0400148 fFile->fNodes.reserve(fText.size() / 10); // a typical program is approx 10:1 for chars:nodes
John Stiles3b209362020-11-16 17:03:10 -0500149 ASTNode::ID result = this->createNode(/*offset=*/0, ASTNode::Kind::kFile);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400150 fFile->fRoot = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700151 for (;;) {
152 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400153 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholasfc994162019-06-06 10:04:27 -0400154 return std::move(fFile);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400155 case Token::Kind::TK_DIRECTIVE: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400156 ASTNode::ID dir = this->directive();
157 if (fErrors.errorCount()) {
158 return nullptr;
159 }
160 if (dir) {
161 getNode(result).addChild(dir);
ethannicholasb3058bd2016-07-01 08:22:01 -0700162 }
163 break;
164 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400165 case Token::Kind::TK_SECTION: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400166 ASTNode::ID section = this->section();
167 if (fErrors.errorCount()) {
168 return nullptr;
169 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400170 if (section) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400171 getNode(result).addChild(section);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400172 }
173 break;
174 }
John Stiles7cbb09c22021-01-07 16:07:00 -0500175 case Token::Kind::TK_INVALID: {
176 this->error(this->peek(), String("invalid token"));
177 return nullptr;
178 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700179 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400180 ASTNode::ID decl = this->declaration();
181 if (fErrors.errorCount()) {
182 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700183 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400184 if (decl) {
185 getNode(result).addChild(decl);
186 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700187 }
188 }
189 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400190 return std::move(fFile);
ethannicholasb3058bd2016-07-01 08:22:01 -0700191}
192
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700193Token Parser::nextRawToken() {
John Stiles7cbb09c22021-01-07 16:07:00 -0500194 if (fPushback.fKind != Token::Kind::TK_NONE) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700195 Token result = fPushback;
John Stiles7cbb09c22021-01-07 16:07:00 -0500196 fPushback.fKind = Token::Kind::TK_NONE;
ethannicholasb3058bd2016-07-01 08:22:01 -0700197 return result;
198 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700199 Token result = fLexer.next();
200 return result;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400201}
202
203Token Parser::nextToken() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700204 Token token = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400205 while (token.fKind == Token::Kind::TK_WHITESPACE ||
206 token.fKind == Token::Kind::TK_LINE_COMMENT ||
207 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700208 token = this->nextRawToken();
209 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400210 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700211}
212
213void Parser::pushback(Token t) {
John Stiles7cbb09c22021-01-07 16:07:00 -0500214 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400215 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700216}
217
218Token Parser::peek() {
John Stiles7cbb09c22021-01-07 16:07:00 -0500219 if (fPushback.fKind == Token::Kind::TK_NONE) {
Brian Osman634624a2017-08-15 11:14:30 -0400220 fPushback = this->nextToken();
221 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700222 return fPushback;
223}
224
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400225bool Parser::checkNext(Token::Kind kind, Token* result) {
John Stiles7cbb09c22021-01-07 16:07:00 -0500226 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
Brian Osman634624a2017-08-15 11:14:30 -0400227 return false;
228 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400229 Token next = this->nextToken();
230 if (next.fKind == kind) {
231 if (result) {
232 *result = next;
233 }
234 return true;
235 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400236 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400237 return false;
238}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500239
240bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 Token next = this->nextToken();
242 if (next.fKind == kind) {
243 if (result) {
Brian Osman634624a2017-08-15 11:14:30 -0400244 *result = std::move(next);
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 }
246 return true;
247 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700248 this->error(next, "expected " + String(expected) + ", but found '" +
249 this->text(next) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 return false;
251 }
252}
253
John Stiles2630ea32020-12-04 10:51:21 -0500254bool Parser::expectIdentifier(Token* result) {
255 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
256 return false;
257 }
258 if (this->isType(this->text(*result))) {
259 this->error(*result, "expected an identifier, but found type '" +
260 this->text(*result) + "'");
261 return false;
262 }
263 return true;
264}
265
Ethan Nicholas962dec42021-06-10 13:06:39 -0400266skstd::string_view Parser::text(Token token) {
267 return skstd::string_view(fText.begin() + token.fOffset, token.fLength);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500268}
269
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270void Parser::error(Token token, String msg) {
271 this->error(token.fOffset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -0700272}
273
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700274void Parser::error(int offset, String msg) {
275 fErrors.error(offset, msg);
276}
277
Ethan Nicholas962dec42021-06-10 13:06:39 -0400278bool Parser::isType(skstd::string_view name) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400279 const Symbol* s = fSymbols[name];
John Stiles2630ea32020-12-04 10:51:21 -0500280 return s && s->is<Type>();
ethannicholasb3058bd2016-07-01 08:22:01 -0700281}
282
John Stiles80b02af2021-02-12 17:07:51 -0500283bool Parser::isArrayType(ASTNode::ID type) {
284 const ASTNode& node = this->getNode(type);
285 SkASSERT(node.fKind == ASTNode::Kind::kType);
286 return node.begin() != node.end();
287}
288
Ethan Nicholas11d53972016-11-28 11:23:23 -0500289/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700290 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400291ASTNode::ID Parser::directive() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700292 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400293 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400294 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700295 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400296 skstd::string_view text = this->text(start);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400297 if (text == "#extension") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700298 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500299 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400300 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700301 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400302 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400303 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700304 }
305 // FIXME: need to start paying attention to this token
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400306 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400307 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700308 }
John Stiles3b209362020-11-16 17:03:10 -0500309 return this->createNode(start.fOffset, ASTNode::Kind::kExtension, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700311 this->error(start, "unsupported directive '" + this->text(start) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400312 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700313 }
314}
315
Ethan Nicholas762466e2017-06-29 10:03:38 -0400316/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
317 RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400318ASTNode::ID Parser::section() {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400319 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400320 if (!this->expect(Token::Kind::TK_SECTION, "a section token", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400321 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400322 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400323 skstd::string_view argument;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400324 if (this->peek().fKind == Token::Kind::TK_LPAREN) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400325 this->nextToken();
326 Token argToken;
John Stiles2630ea32020-12-04 10:51:21 -0500327 if (!this->expectIdentifier(&argToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400328 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400329 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700330 argument = this->text(argToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400331 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400332 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400333 }
334 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400335 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400336 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400337 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400338 Token codeStart = this->nextRawToken();
339 size_t startOffset = codeStart.fOffset;
340 this->pushback(codeStart);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400341 int level = 1;
Ethan Nicholas962dec42021-06-10 13:06:39 -0400342 skstd::string_view text;
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400343 Token next;
344 while (level > 0) {
345 next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400346 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400347 case Token::Kind::TK_LBRACE:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400348 ++level;
349 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400350 case Token::Kind::TK_RBRACE:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400351 --level;
352 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400353 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700354 this->error(start, "reached end of file while parsing section");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400355 return ASTNode::ID::Invalid();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400356 default:
357 break;
358 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400359 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400360 text = skstd::string_view(fText.begin() + startOffset, next.fOffset - startOffset);
361 skstd::string_view name = this->text(start);
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400362 name.remove_prefix(1);
John Stiles3b209362020-11-16 17:03:10 -0500363 return this->createNode(start.fOffset, ASTNode::Kind::kSection,
364 ASTNode::SectionData(name, argument, text));
Ethan Nicholas762466e2017-06-29 10:03:38 -0400365}
366
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500367/* ENUM CLASS IDENTIFIER LBRACE (IDENTIFIER (EQ expression)? (COMMA IDENTIFIER (EQ expression))*)?
368 RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400369ASTNode::ID Parser::enumDeclaration() {
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500370 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400371 if (!this->expect(Token::Kind::TK_ENUM, "'enum'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400372 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500373 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400374 if (!this->expect(Token::Kind::TK_CLASS, "'class'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400375 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500376 }
377 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500378 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400379 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500380 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400381 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400382 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500383 }
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400384 fSymbols.add(Type::MakeEnumType(String(this->text(name))));
John Stiles3b209362020-11-16 17:03:10 -0500385 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kEnum, this->text(name));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400386 if (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500387 Token id;
John Stiles2630ea32020-12-04 10:51:21 -0500388 if (!this->expectIdentifier(&id)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400389 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500390 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400391 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400392 ASTNode::ID value = this->assignmentExpression();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500393 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400394 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500395 }
John Stiles3b209362020-11-16 17:03:10 -0500396 ASTNode::ID child = this->addChild(
397 result, this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400398 getNode(child).addChild(value);
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500399 } else {
John Stiles3b209362020-11-16 17:03:10 -0500400 this->addChild(result,
401 this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500402 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400403 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
404 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400405 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500406 }
John Stiles2630ea32020-12-04 10:51:21 -0500407 if (!this->expectIdentifier(&id)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400408 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500409 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400410 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400411 ASTNode::ID value = this->assignmentExpression();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500412 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400413 return ASTNode::ID::Invalid();
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500414 }
John Stiles3b209362020-11-16 17:03:10 -0500415 ASTNode::ID child = this->addChild(
416 result,
417 this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400418 getNode(child).addChild(value);
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500419 } else {
John Stiles3b209362020-11-16 17:03:10 -0500420 this->addChild(
421 result,
422 this->createNode(id.fOffset, ASTNode::Kind::kEnumCase, this->text(id)));
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500423 }
424 }
425 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400426 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400427 return result;
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500428}
429
John Stiles147cfda2021-05-21 14:11:38 -0400430/* enumDeclaration | modifiers (interfaceBlock | structVarDeclaration | SEMICOLON |
431 type IDENTIFIER (varDeclarationEnd | LPAREN functionDeclarationEnd))) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400432ASTNode::ID Parser::declaration() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700433 Token lookahead = this->peek();
Ethan Nicholasda6320c2020-09-02 14:08:23 -0400434 switch (lookahead.fKind) {
435 case Token::Kind::TK_ENUM:
436 return this->enumDeclaration();
437 case Token::Kind::TK_SEMICOLON:
438 this->error(lookahead.fOffset, "expected a declaration, but found ';'");
439 return ASTNode::ID::Invalid();
440 default:
441 break;
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500442 }
443 Modifiers modifiers = this->modifiers();
444 lookahead = this->peek();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400445 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !this->isType(this->text(lookahead))) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700446 // we have an identifier that's not a type, could be the start of an interface block
447 return this->interfaceBlock(modifiers);
448 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400449 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700450 return this->structVarDeclaration(modifiers);
451 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400452 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
ethannicholas5961bc92016-10-12 06:39:56 -0700453 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -0500454 return this->createNode(lookahead.fOffset, ASTNode::Kind::kModifiers, modifiers);
ethannicholas5961bc92016-10-12 06:39:56 -0700455 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400456 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700457 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400458 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700459 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700460 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500461 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400462 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700463 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400464 if (this->checkNext(Token::Kind::TK_LPAREN)) {
John Stiles147cfda2021-05-21 14:11:38 -0400465 return this->functionDeclarationEnd(modifiers, type, name);
ethannicholasb3058bd2016-07-01 08:22:01 -0700466 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400467 return this->varDeclarationEnd(modifiers, type, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700468 }
469}
470
John Stiles147cfda2021-05-21 14:11:38 -0400471/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
472ASTNode::ID Parser::functionDeclarationEnd(Modifiers modifiers,
473 ASTNode::ID type,
474 const Token& name) {
475 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kFunction);
476 ASTNode::FunctionData fd(modifiers, this->text(name), 0);
477 getNode(result).addChild(type);
478 Token lookahead = this->peek();
479 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
480 // `()` means no parameters at all.
481 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
482 // `(void)` also means no parameters at all.
483 this->nextToken();
484 } else {
485 for (;;) {
486 ASTNode::ID parameter = this->parameter();
487 if (!parameter) {
488 return ASTNode::ID::Invalid();
489 }
490 ++fd.fParameterCount;
491 getNode(result).addChild(parameter);
492 if (!this->checkNext(Token::Kind::TK_COMMA)) {
493 break;
494 }
495 }
496 }
497 getNode(result).setFunctionData(fd);
498 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
499 return ASTNode::ID::Invalid();
500 }
501 ASTNode::ID body;
502 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
503 body = this->block();
504 if (!body) {
505 return ASTNode::ID::Invalid();
506 }
507 getNode(result).addChild(body);
508 }
509 return result;
510}
511
John Stiles76389b72021-01-25 13:49:05 -0500512/* (varDeclarations | expressionStatement) */
513ASTNode::ID Parser::varDeclarationsOrExpressionStatement() {
John Stiles89b484a2021-04-19 14:57:27 -0400514 Token nextToken = this->peek();
515 if (nextToken.fKind == Token::Kind::TK_CONST) {
516 // Statements that begin with `const` might be variable declarations, but can't be legal
517 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
518 return this->varDeclarations();
519 }
520
521 if (this->isType(this->text(nextToken))) {
John Stiles76389b72021-01-25 13:49:05 -0500522 // Statements that begin with a typename are most often variable declarations, but
523 // occasionally the type is part of a constructor, and these are actually expression-
524 // statements in disguise. First, attempt the common case: parse it as a vardecl.
525 Checkpoint checkpoint(this);
John Stiles8dabeac2021-02-12 16:05:00 -0500526 VarDeclarationsPrefix prefix;
527 if (this->varDeclarationsPrefix(&prefix)) {
528 return this->varDeclarationEnd(prefix.modifiers, prefix.type, this->text(prefix.name));
John Stiles76389b72021-01-25 13:49:05 -0500529 }
530
531 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
532 // expression-statement instead.
533 checkpoint.rewind();
534 }
535
536 return this->expressionStatement();
537}
538
John Stiles8dabeac2021-02-12 16:05:00 -0500539// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
540// statement is a variable-declaration statement, not an expression-statement.
541bool Parser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
542 prefixData->modifiers = this->modifiers();
543 prefixData->type = this->type();
544 if (!prefixData->type) {
545 return false;
546 }
547 return this->expectIdentifier(&prefixData->name);
548}
549
ethannicholasb3058bd2016-07-01 08:22:01 -0700550/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400551ASTNode::ID Parser::varDeclarations() {
John Stiles8dabeac2021-02-12 16:05:00 -0500552 VarDeclarationsPrefix prefix;
553 if (!this->varDeclarationsPrefix(&prefix)) {
John Stiles76389b72021-01-25 13:49:05 -0500554 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700555 }
John Stiles8dabeac2021-02-12 16:05:00 -0500556 return this->varDeclarationEnd(prefix.modifiers, prefix.type, this->text(prefix.name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700557}
558
559/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400560ASTNode::ID Parser::structDeclaration() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400561 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400562 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700563 }
564 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500565 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400566 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400568 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400569 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700570 }
571 std::vector<Type::Field> fields;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400572 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400573 ASTNode::ID decls = this->varDeclarations();
574 if (!decls) {
575 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700576 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400577 ASTNode& declsNode = getNode(decls);
John Stilesece1bf02021-03-08 11:15:55 -0500578 const Modifiers& modifiers = declsNode.begin()->getModifiers();
John Stiles13fc2602020-10-09 17:42:31 -0400579 if (modifiers.fFlags != Modifiers::kNo_Flag) {
580 String desc = modifiers.description();
581 desc.pop_back(); // remove trailing space
582 this->error(declsNode.fOffset,
583 "modifier '" + desc + "' is not permitted on a struct field");
584 }
585
Ethan Nicholas962dec42021-06-10 13:06:39 -0400586 const Symbol* symbol = fSymbols[(declsNode.begin() + 1)->getStringView()];
John Stiles13fc2602020-10-09 17:42:31 -0400587 SkASSERT(symbol);
588 const Type* type = &symbol->as<Type>();
John Stiles1d757782020-11-17 09:43:22 -0500589 if (type->isOpaque()) {
590 this->error(declsNode.fOffset,
591 "opaque type '" + type->name() + "' is not permitted in a struct");
592 }
John Stiles13fc2602020-10-09 17:42:31 -0400593
Ethan Nicholasfc994162019-06-06 10:04:27 -0400594 for (auto iter = declsNode.begin() + 2; iter != declsNode.end(); ++iter) {
595 ASTNode& var = *iter;
John Stilesece1bf02021-03-08 11:15:55 -0500596 const ASTNode::VarData& vd = var.getVarData();
John Stiles6bef6a72020-12-02 14:26:04 -0500597
John Stilesd39aec92020-12-03 14:37:16 -0500598 // Read array size if one is present.
599 if (vd.fIsArray) {
600 const ASTNode& size = *var.begin();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400601 if (!size || size.fKind != ASTNode::Kind::kInt) {
602 this->error(declsNode.fOffset, "array size in struct field must be a constant");
603 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 }
John Stiles6bef6a72020-12-02 14:26:04 -0500605 if (size.getInt() <= 0 || size.getInt() > INT_MAX) {
606 this->error(declsNode.fOffset, "array size is invalid");
607 return ASTNode::ID::Invalid();
608 }
John Stilesd39aec92020-12-03 14:37:16 -0500609 // Add the array dimensions to our type.
610 int arraySize = size.getInt();
John Stilesa2179502020-12-03 14:37:57 -0500611 type = fSymbols.addArrayDimension(type, arraySize);
ethannicholasb3058bd2016-07-01 08:22:01 -0700612 }
John Stiles13fc2602020-10-09 17:42:31 -0400613
614 fields.push_back(Type::Field(modifiers, vd.fName, type));
John Stilesd39aec92020-12-03 14:37:16 -0500615 if (vd.fIsArray ? var.begin()->fNext : var.fFirstChild) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400616 this->error(declsNode.fOffset, "initializers are not permitted on struct fields");
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 }
618 }
619 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400620 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400621 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700622 }
Brian Osman6c3b23f2021-02-12 13:09:58 -0500623 if (fields.empty()) {
624 this->error(name.fOffset,
625 "struct '" + this->text(name) + "' must contain at least one field");
626 return ASTNode::ID::Invalid();
627 }
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400628 std::unique_ptr<Type> newType = Type::MakeStructType(name.fOffset, String(this->text(name)),
629 fields);
John Stilesa695d622020-11-10 10:04:26 -0500630 if (struct_is_too_deeply_nested(*newType, kMaxStructDepth)) {
631 this->error(name.fOffset, "struct '" + this->text(name) + "' is too deeply nested");
632 return ASTNode::ID::Invalid();
633 }
634 fSymbols.add(std::move(newType));
Brian Osman00fea5b2021-01-28 09:46:30 -0500635 return this->createNode(name.fOffset, ASTNode::Kind::kType, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700636}
637
638/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400639ASTNode::ID Parser::structVarDeclaration(Modifiers modifiers) {
640 ASTNode::ID type = this->structDeclaration();
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400642 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400644 Token name;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400645 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400646 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700647 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400648 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesdc75a972020-11-25 16:24:55 -0500649 return type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700650}
651
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400652/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
653 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400654ASTNode::ID Parser::varDeclarationEnd(Modifiers mods, ASTNode::ID type, skstd::string_view name) {
John Stiles08070f62020-11-17 10:45:49 -0500655 int offset = this->peek().fOffset;
656 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kVarDeclarations);
657 this->addChild(result, this->createNode(offset, ASTNode::Kind::kModifiers, mods));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400658 getNode(result).addChild(type);
John Stilesd39aec92020-12-03 14:37:16 -0500659
John Stiles80b02af2021-02-12 17:07:51 -0500660 auto parseArrayDimensions = [&](ASTNode::ID currentVar, ASTNode::VarData* vd) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400661 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stiles80b02af2021-02-12 17:07:51 -0500662 if (vd->fIsArray || this->isArrayType(type)) {
John Stilesd39aec92020-12-03 14:37:16 -0500663 this->error(this->peek(), "multi-dimensional arrays are not supported");
664 return false;
665 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400666 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -0500667 this->createEmptyChild(currentVar);
ethannicholasb3058bd2016-07-01 08:22:01 -0700668 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400669 ASTNode::ID size = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700670 if (!size) {
John Stilesd39aec92020-12-03 14:37:16 -0500671 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700672 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400673 getNode(currentVar).addChild(size);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400674 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
John Stilesd39aec92020-12-03 14:37:16 -0500675 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700676 }
677 }
John Stilesd39aec92020-12-03 14:37:16 -0500678 vd->fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700679 }
John Stilesd39aec92020-12-03 14:37:16 -0500680 return true;
681 };
682
683 auto parseInitializer = [this](ASTNode::ID currentVar) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400684 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400685 ASTNode::ID value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700686 if (!value) {
John Stilesd39aec92020-12-03 14:37:16 -0500687 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700688 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400689 getNode(currentVar).addChild(value);
ethannicholasb3058bd2016-07-01 08:22:01 -0700690 }
John Stilesd39aec92020-12-03 14:37:16 -0500691 return true;
692 };
693
694 ASTNode::ID currentVar = this->createNode(offset, ASTNode::Kind::kVarDeclaration);
695 ASTNode::VarData vd{name, /*isArray=*/false};
696
697 getNode(result).addChild(currentVar);
698 if (!parseArrayDimensions(currentVar, &vd)) {
699 return ASTNode::ID::Invalid();
700 }
701 getNode(currentVar).setVarData(vd);
702 if (!parseInitializer(currentVar)) {
703 return ASTNode::ID::Invalid();
704 }
705
706 while (this->checkNext(Token::Kind::TK_COMMA)) {
707 Token identifierName;
John Stiles2630ea32020-12-04 10:51:21 -0500708 if (!this->expectIdentifier(&identifierName)) {
John Stilesd39aec92020-12-03 14:37:16 -0500709 return ASTNode::ID::Invalid();
710 }
711
712 currentVar = ASTNode::ID(fFile->fNodes.size());
713 vd = ASTNode::VarData{this->text(identifierName), /*isArray=*/false};
714 fFile->fNodes.emplace_back(&fFile->fNodes, offset, ASTNode::Kind::kVarDeclaration);
715
716 getNode(result).addChild(currentVar);
717 if (!parseArrayDimensions(currentVar, &vd)) {
718 return ASTNode::ID::Invalid();
719 }
720 getNode(currentVar).setVarData(vd);
721 if (!parseInitializer(currentVar)) {
722 return ASTNode::ID::Invalid();
723 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700724 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400725 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400726 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700727 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400728 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700729}
730
731/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400732ASTNode::ID Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400733 Modifiers modifiers = this->modifiersWithDefaults(0);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400734 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700735 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400736 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700737 }
738 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500739 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400740 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700741 }
John Stiles3b209362020-11-16 17:03:10 -0500742 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kParameter);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400743 ASTNode::ParameterData pd(modifiers, this->text(name), 0);
744 getNode(result).addChild(type);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400745 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stiles80b02af2021-02-12 17:07:51 -0500746 if (pd.fIsArray || this->isArrayType(type)) {
John Stilesd39aec92020-12-03 14:37:16 -0500747 this->error(this->peek(), "multi-dimensional arrays are not supported");
748 return ASTNode::ID::Invalid();
749 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700750 Token sizeToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400751 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400752 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700753 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400754 skstd::string_view arraySizeFrag = this->text(sizeToken);
John Stilesf94348f2020-12-23 18:58:43 -0500755 SKSL_INT arraySize;
756 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
757 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
758 return ASTNode::ID::Invalid();
759 }
760 this->addChild(result, this->createNode(sizeToken.fOffset, ASTNode::Kind::kInt, arraySize));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400761 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400762 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700763 }
John Stilesd39aec92020-12-03 14:37:16 -0500764 pd.fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700765 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400766 getNode(result).setParameterData(pd);
767 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700768}
769
Ethan Nicholasd608c092017-10-26 09:30:08 -0400770/** EQ INT_LITERAL */
ethannicholasb3058bd2016-07-01 08:22:01 -0700771int Parser::layoutInt() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400772 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700773 return -1;
774 }
775 Token resultToken;
John Stilesf94348f2020-12-23 18:58:43 -0500776 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
777 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700778 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400779 skstd::string_view resultFrag = this->text(resultToken);
John Stilesf94348f2020-12-23 18:58:43 -0500780 SKSL_INT resultValue;
781 if (!SkSL::stoi(resultFrag, &resultValue)) {
782 this->error(resultToken, "value in layout is too large: " + resultFrag);
783 return -1;
784 }
785 return resultValue;
ethannicholasb3058bd2016-07-01 08:22:01 -0700786}
787
Ethan Nicholasd608c092017-10-26 09:30:08 -0400788/** EQ IDENTIFIER */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400789skstd::string_view Parser::layoutIdentifier() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400790 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400791 return skstd::string_view();
Ethan Nicholasd608c092017-10-26 09:30:08 -0400792 }
793 Token resultToken;
John Stiles2630ea32020-12-04 10:51:21 -0500794 if (!this->expectIdentifier(&resultToken)) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400795 return skstd::string_view();
Ethan Nicholasd608c092017-10-26 09:30:08 -0400796 }
797 return this->text(resultToken);
798}
799
800
Ethan Nicholas762466e2017-06-29 10:03:38 -0400801/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400802skstd::string_view Parser::layoutCode() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400803 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400804 return "";
805 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700806 Token start = this->nextRawToken();
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400807 this->pushback(start);
Ethan Nicholas962dec42021-06-10 13:06:39 -0400808 skstd::string_view code;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400809 int level = 1;
810 bool done = false;
811 while (!done) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700812 Token next = this->nextRawToken();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400813 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400814 case Token::Kind::TK_LPAREN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400815 ++level;
816 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400817 case Token::Kind::TK_RPAREN:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400818 --level;
819 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400820 case Token::Kind::TK_COMMA:
Ethan Nicholas762466e2017-06-29 10:03:38 -0400821 if (level == 1) {
822 done = true;
823 }
824 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400825 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700826 this->error(start, "reached end of file while parsing layout");
Ethan Nicholas6d71f492019-06-10 16:58:37 -0400827 return "";
Ethan Nicholas762466e2017-06-29 10:03:38 -0400828 default:
829 break;
830 }
831 if (!level) {
832 done = true;
833 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400834 if (done) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400835 code = skstd::string_view(fText.begin() + start.fOffset, next.fOffset - start.fOffset);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400836 this->pushback(std::move(next));
837 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400838 }
839 return code;
840}
841
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400842Layout::CType Parser::layoutCType() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400843 if (this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400844 Token t = this->nextToken();
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400845 String text(this->text(t));
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400846 auto found = layoutTokens->find(text);
847 if (found != layoutTokens->end()) {
848 switch (found->second) {
Brian Osmanf28e55d2018-10-03 16:35:54 -0400849 case LayoutToken::SKPMCOLOR4F:
850 return Layout::CType::kSkPMColor4f;
Mike Reedb26b4e72020-01-22 14:31:21 -0500851 case LayoutToken::SKV4:
852 return Layout::CType::kSkV4;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400853 default:
854 break;
855 }
856 }
857 this->error(t, "unsupported ctype");
858 }
859 return Layout::CType::kDefault;
860}
861
ethannicholas8ac838d2016-11-22 08:39:36 -0800862/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500863Layout Parser::layout() {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500864 int flags = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700865 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500866 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700867 int binding = -1;
868 int index = -1;
869 int set = -1;
870 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500871 int inputAttachmentIndex = -1;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500872 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
873 int maxVertices = -1;
874 int invocations = -1;
Ethan Nicholas962dec42021-06-10 13:06:39 -0400875 skstd::string_view when;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400876 Layout::CType ctype = Layout::CType::kDefault;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400877 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
878 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500879 return Layout(flags, location, offset, binding, index, set, builtin,
Brian Osman8f1dff62021-04-19 13:50:58 -0400880 inputAttachmentIndex, primitive, maxVertices, invocations, when, ctype);
ethannicholasb3058bd2016-07-01 08:22:01 -0700881 }
882 for (;;) {
883 Token t = this->nextToken();
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400884 String text(this->text(t));
Brian Osmana77ed8b2021-02-23 12:54:22 -0500885 auto setFlag = [&](Layout::Flag f) {
886 if (flags & f) {
887 this->error(t, "layout qualifier '" + text + "' appears more than once");
888 }
889 flags |= f;
890 };
891 auto setPrimitive = [&](Layout::Primitive p) {
892 if (flags & Layout::kPrimitive_Flag) {
893 this->error(t, "only one primitive-type layout qualifier is allowed");
894 }
895 flags |= Layout::kPrimitive_Flag;
896 primitive = p;
897 };
898
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400899 auto found = layoutTokens->find(text);
900 if (found != layoutTokens->end()) {
901 switch (found->second) {
Brian Osmana77ed8b2021-02-23 12:54:22 -0500902 case LayoutToken::ORIGIN_UPPER_LEFT:
903 setFlag(Layout::kOriginUpperLeft_Flag);
904 break;
Brian Osmana77ed8b2021-02-23 12:54:22 -0500905 case LayoutToken::PUSH_CONSTANT:
906 setFlag(Layout::kPushConstant_Flag);
907 break;
908 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
909 setFlag(Layout::kBlendSupportAllEquations_Flag);
910 break;
Brian Osmana77ed8b2021-02-23 12:54:22 -0500911 case LayoutToken::SRGB_UNPREMUL:
912 setFlag(Layout::kSRGBUnpremul_Flag);
913 break;
914 case LayoutToken::KEY:
915 setFlag(Layout::kKey_Flag);
916 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700917 case LayoutToken::LOCATION:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500918 setFlag(Layout::kLocation_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500919 location = this->layoutInt();
920 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700921 case LayoutToken::OFFSET:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500922 setFlag(Layout::kOffset_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500923 offset = this->layoutInt();
924 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700925 case LayoutToken::BINDING:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500926 setFlag(Layout::kBinding_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500927 binding = this->layoutInt();
928 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700929 case LayoutToken::INDEX:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500930 setFlag(Layout::kIndex_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500931 index = this->layoutInt();
932 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700933 case LayoutToken::SET:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500934 setFlag(Layout::kSet_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500935 set = this->layoutInt();
936 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700937 case LayoutToken::BUILTIN:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500938 setFlag(Layout::kBuiltin_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500939 builtin = this->layoutInt();
940 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700941 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500942 setFlag(Layout::kInputAttachmentIndex_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500943 inputAttachmentIndex = this->layoutInt();
944 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700945 case LayoutToken::POINTS:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500946 setPrimitive(Layout::kPoints_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500947 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700948 case LayoutToken::LINES:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500949 setPrimitive(Layout::kLines_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500950 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700951 case LayoutToken::LINE_STRIP:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500952 setPrimitive(Layout::kLineStrip_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500953 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700954 case LayoutToken::LINES_ADJACENCY:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500955 setPrimitive(Layout::kLinesAdjacency_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500956 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700957 case LayoutToken::TRIANGLES:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500958 setPrimitive(Layout::kTriangles_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500959 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700960 case LayoutToken::TRIANGLE_STRIP:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500961 setPrimitive(Layout::kTriangleStrip_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500962 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700963 case LayoutToken::TRIANGLES_ADJACENCY:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500964 setPrimitive(Layout::kTrianglesAdjacency_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500965 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700966 case LayoutToken::MAX_VERTICES:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500967 setFlag(Layout::kMaxVertices_Flag);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500968 maxVertices = this->layoutInt();
969 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700970 case LayoutToken::INVOCATIONS:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500971 setFlag(Layout::kInvocations_Flag);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500972 invocations = this->layoutInt();
973 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700974 case LayoutToken::WHEN:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500975 setFlag(Layout::kWhen_Flag);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400976 when = this->layoutCode();
977 break;
Ethan Nicholasd608c092017-10-26 09:30:08 -0400978 case LayoutToken::CTYPE:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500979 setFlag(Layout::kCType_Flag);
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400980 ctype = this->layoutCType();
981 break;
982 default:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500983 this->error(t, "'" + text + "' is not a valid layout qualifier");
Ethan Nicholasd608c092017-10-26 09:30:08 -0400984 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500985 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700986 } else {
Brian Osmana77ed8b2021-02-23 12:54:22 -0500987 this->error(t, "'" + text + "' is not a valid layout qualifier");
ethannicholasb3058bd2016-07-01 08:22:01 -0700988 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400989 if (this->checkNext(Token::Kind::TK_RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700990 break;
991 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400992 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700993 break;
994 }
995 }
996 }
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500997 return Layout(flags, location, offset, binding, index, set, builtin, inputAttachmentIndex,
Brian Osman8f1dff62021-04-19 13:50:58 -0400998 primitive, maxVertices, invocations, when, ctype);
ethannicholasb3058bd2016-07-01 08:22:01 -0700999}
1000
Brian Osmane49703f2021-04-19 11:15:24 -04001001/* layout? (UNIFORM | CONST | IN | OUT | INOUT | FLAT | NOPERSPECTIVE | INLINE)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -05001002Modifiers Parser::modifiers() {
1003 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 int flags = 0;
1005 for (;;) {
1006 // TODO: handle duplicate / incompatible flags
John Stiles7d5b90a2021-01-21 14:26:51 -05001007 int tokenFlag = parse_modifier_token(peek().fKind);
1008 if (!tokenFlag) {
1009 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001010 }
John Stiles7d5b90a2021-01-21 14:26:51 -05001011 flags |= tokenFlag;
1012 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -07001013 }
John Stiles7d5b90a2021-01-21 14:26:51 -05001014 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -07001015}
1016
Ethan Nicholas11d53972016-11-28 11:23:23 -05001017Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
1018 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001020 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 }
1022 return result;
1023}
1024
1025/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001026ASTNode::ID Parser::statement() {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001027 Token start = this->nextToken();
1028 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001029 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001030 return ASTNode::ID::Invalid();
1031 }
1032 this->pushback(start);
ethannicholasb3058bd2016-07-01 08:22:01 -07001033 switch (start.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001034 case Token::Kind::TK_IF: // fall through
1035 case Token::Kind::TK_STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -07001036 return this->ifStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001037 case Token::Kind::TK_FOR:
ethannicholasb3058bd2016-07-01 08:22:01 -07001038 return this->forStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001039 case Token::Kind::TK_DO:
ethannicholasb3058bd2016-07-01 08:22:01 -07001040 return this->doStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001041 case Token::Kind::TK_WHILE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 return this->whileStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001043 case Token::Kind::TK_SWITCH: // fall through
1044 case Token::Kind::TK_STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -05001045 return this->switchStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001046 case Token::Kind::TK_RETURN:
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 return this->returnStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001048 case Token::Kind::TK_BREAK:
ethannicholasb3058bd2016-07-01 08:22:01 -07001049 return this->breakStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001050 case Token::Kind::TK_CONTINUE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 return this->continueStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001052 case Token::Kind::TK_DISCARD:
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 return this->discardStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001054 case Token::Kind::TK_LBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 return this->block();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001056 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -05001057 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -05001058 return this->createNode(start.fOffset, ASTNode::Kind::kBlock);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001059 case Token::Kind::TK_CONST:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001060 case Token::Kind::TK_IDENTIFIER:
John Stiles76389b72021-01-25 13:49:05 -05001061 return this->varDeclarationsOrExpressionStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001062 default:
1063 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -05001064 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001065}
1066
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001067/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001068ASTNode::ID Parser::type() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 Token type;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001070 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001071 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001072 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001073 if (!this->isType(this->text(type))) {
1074 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
Ethan Nicholasfc994162019-06-06 10:04:27 -04001075 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001076 }
Brian Osman00fea5b2021-01-28 09:46:30 -05001077 ASTNode::ID result = this->createNode(type.fOffset, ASTNode::Kind::kType, this->text(type));
John Stilesd39aec92020-12-03 14:37:16 -05001078 bool isArray = false;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001079 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -05001080 if (isArray) {
1081 this->error(this->peek(), "multi-dimensional arrays are not supported");
1082 return ASTNode::ID::Invalid();
1083 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001084 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001085 SKSL_INT i;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001086 if (this->intLiteral(&i)) {
John Stiles08070f62020-11-17 10:45:49 -05001087 this->addChild(result, this->createNode(this->peek().fOffset,
1088 ASTNode::Kind::kInt, i));
Ethan Nicholas50afc172017-02-16 14:49:57 -05001089 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001090 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001091 }
1092 } else {
John Stiles3b209362020-11-16 17:03:10 -05001093 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001094 }
John Stilesd39aec92020-12-03 14:37:16 -05001095 isArray = true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001096 this->expect(Token::Kind::TK_RBRACKET, "']'");
Ethan Nicholas50afc172017-02-16 14:49:57 -05001097 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001098 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001099}
1100
John Stiles57a996b2020-04-19 19:05:12 -07001101/* IDENTIFIER LBRACE
1102 varDeclaration+
1103 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001104ASTNode::ID Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001105 Token name;
John Stiles2630ea32020-12-04 10:51:21 -05001106 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001107 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001109 if (peek().fKind != Token::Kind::TK_LBRACE) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001110 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -05001111 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -07001112 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001113 this->error(name, "no type named '" + this->text(name) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001114 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001115 }
John Stiles3b209362020-11-16 17:03:10 -05001116 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kInterfaceBlock);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001117 ASTNode::InterfaceBlockData id(mods, this->text(name), 0, "", 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001118 this->nextToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001119 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001120 ASTNode::ID decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 if (!decl) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001122 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001123 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001124 getNode(result).addChild(decl);
1125 ++id.fDeclarationCount;
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 }
John Stiles57a996b2020-04-19 19:05:12 -07001127 if (id.fDeclarationCount == 0) {
1128 this->error(name, "interface block '" + this->text(name) +
1129 "' must contain at least one member");
1130 return ASTNode::ID::Invalid();
1131 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001132 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001133 std::vector<ASTNode> sizes;
Ethan Nicholas962dec42021-06-10 13:06:39 -04001134 skstd::string_view instanceName;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001135 Token instanceNameToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001136 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001137 id.fInstanceName = this->text(instanceNameToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001138 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -05001139 if (id.fIsArray) {
1140 this->error(this->peek(), "multi-dimensional arrays are not supported");
1141 return false;
1142 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001143 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001144 ASTNode::ID size = this->expression();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001145 if (!size) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001146 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001147 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001148 getNode(result).addChild(size);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001149 } else {
John Stiles3b209362020-11-16 17:03:10 -05001150 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001151 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001152 this->expect(Token::Kind::TK_RBRACKET, "']'");
John Stilesd39aec92020-12-03 14:37:16 -05001153 id.fIsArray = true;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001154 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001155 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -07001156 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001157 getNode(result).setInterfaceBlockData(id);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001158 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001159 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001160}
1161
1162/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001163ASTNode::ID Parser::ifStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001164 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001165 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
1166 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001167 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001168 }
John Stiles3b209362020-11-16 17:03:10 -05001169 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kIf, isStatic);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001170 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001171 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001172 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001173 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001174 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001175 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001176 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001177 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001178 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001179 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001180 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001181 ASTNode::ID ifTrue = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001182 if (!ifTrue) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001183 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001184 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001185 getNode(result).addChild(ifTrue);
1186 ASTNode::ID ifFalse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001187 if (this->checkNext(Token::Kind::TK_ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001188 ifFalse = this->statement();
1189 if (!ifFalse) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001190 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001191 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001192 getNode(result).addChild(ifFalse);
ethannicholasb3058bd2016-07-01 08:22:01 -07001193 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001194 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001195}
1196
1197/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001198ASTNode::ID Parser::doStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001200 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001201 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001202 }
John Stiles3b209362020-11-16 17:03:10 -05001203 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kDo);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001204 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001205 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001206 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001207 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001208 getNode(result).addChild(statement);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001209 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001210 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001211 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001212 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001213 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001214 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001215 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001216 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001217 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001218 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001219 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001220 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001221 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001222 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001223 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001224 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001225 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001226 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001227}
1228
1229/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001230ASTNode::ID Parser::whileStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001231 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001232 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001233 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001234 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001235 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001236 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001237 }
John Stiles3b209362020-11-16 17:03:10 -05001238 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kWhile);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001239 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001240 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001241 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001242 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001243 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001244 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001245 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001246 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001247 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001248 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001249 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001250 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001251 getNode(result).addChild(statement);
1252 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001253}
1254
Ethan Nicholasaf197692017-02-27 13:26:45 -05001255/* CASE expression COLON statement* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001256ASTNode::ID Parser::switchCase() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001257 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001258 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001259 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001260 }
John Stiles3b209362020-11-16 17:03:10 -05001261 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitchCase);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001262 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001263 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001264 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001265 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001266 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001267 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001268 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001269 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001270 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1271 this->peek().fKind != Token::Kind::TK_CASE &&
1272 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001273 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001274 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001275 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001276 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001277 getNode(result).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001278 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001279 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001280}
1281
1282/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001283ASTNode::ID Parser::switchStatement() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001284 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001285 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1286 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001287 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001288 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001289 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001290 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001291 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001292 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001293 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001294 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001295 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001296 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001297 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001298 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001299 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001300 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001301 }
John Stiles3b209362020-11-16 17:03:10 -05001302 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitch, isStatic);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001303 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001304 while (this->peek().fKind == Token::Kind::TK_CASE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001305 ASTNode::ID c = this->switchCase();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001306 if (!c) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001307 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001308 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001309 getNode(result).addChild(c);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001310 }
1311 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1312 // parts of the compiler may rely upon this assumption.
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001313 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001314 Token defaultStart;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001315 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1316 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001317 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001318 }
John Stiles3b209362020-11-16 17:03:10 -05001319 ASTNode::ID defaultCase = this->addChild(
1320 result, this->createNode(defaultStart.fOffset, ASTNode::Kind::kSwitchCase));
1321 this->createEmptyChild(defaultCase); // empty test to signify default case
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001322 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001323 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001324 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001325 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001326 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001327 getNode(defaultCase).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001328 }
Ethan Nicholasaf197692017-02-27 13:26:45 -05001329 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001330 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001331 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001332 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001333 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001334}
1335
Ethan Nicholas11d53972016-11-28 11:23:23 -05001336/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001337 STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001338ASTNode::ID Parser::forStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001339 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001340 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001341 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001342 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001343 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001344 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001345 }
John Stiles3b209362020-11-16 17:03:10 -05001346 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kFor);
ethannicholasb3058bd2016-07-01 08:22:01 -07001347 Token nextToken = this->peek();
John Stiles89b484a2021-04-19 14:57:27 -04001348 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1349 // An empty init-statement.
1350 this->nextToken();
1351 this->createEmptyChild(result);
1352 } else {
1353 // The init-statement must be an expression or variable declaration.
1354 ASTNode::ID initializer = this->varDeclarationsOrExpressionStatement();
1355 if (!initializer) {
1356 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001357 }
John Stiles89b484a2021-04-19 14:57:27 -04001358 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001359 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001360 ASTNode::ID test;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001361 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001362 test = this->expression();
1363 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001364 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001365 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001366 getNode(result).addChild(test);
1367 } else {
John Stiles3b209362020-11-16 17:03:10 -05001368 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001369 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001370 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001371 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001372 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001373 ASTNode::ID next;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001374 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001375 next = this->expression();
1376 if (!next) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001377 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001378 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001379 getNode(result).addChild(next);
1380 } else {
John Stiles3b209362020-11-16 17:03:10 -05001381 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001382 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001383 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001384 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001385 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001386 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001387 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001388 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001389 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001390 getNode(result).addChild(statement);
1391 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001392}
1393
1394/* RETURN expression? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001395ASTNode::ID Parser::returnStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001396 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001397 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001398 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001399 }
John Stiles3b209362020-11-16 17:03:10 -05001400 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kReturn);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001401 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001402 ASTNode::ID expression = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001403 if (!expression) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001404 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001405 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001406 getNode(result).addChild(expression);
ethannicholasb3058bd2016-07-01 08:22:01 -07001407 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001408 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001409 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001410 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001411 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001412}
1413
1414/* BREAK SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001415ASTNode::ID Parser::breakStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001416 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001417 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001418 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001420 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001421 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 }
John Stiles3b209362020-11-16 17:03:10 -05001423 return this->createNode(start.fOffset, ASTNode::Kind::kBreak);
ethannicholasb3058bd2016-07-01 08:22:01 -07001424}
1425
1426/* CONTINUE SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001427ASTNode::ID Parser::continueStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001429 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001430 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001431 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001432 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001433 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001434 }
John Stiles3b209362020-11-16 17:03:10 -05001435 return this->createNode(start.fOffset, ASTNode::Kind::kContinue);
ethannicholasb3058bd2016-07-01 08:22:01 -07001436}
1437
1438/* DISCARD SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001439ASTNode::ID Parser::discardStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001440 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001441 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001442 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001443 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001444 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001445 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001446 }
John Stiles3b209362020-11-16 17:03:10 -05001447 return this->createNode(start.fOffset, ASTNode::Kind::kDiscard);
ethannicholasb3058bd2016-07-01 08:22:01 -07001448}
1449
1450/* LBRACE statement* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001451ASTNode::ID Parser::block() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001453 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001454 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001455 }
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001456 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001457 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001458 return ASTNode::ID::Invalid();
1459 }
John Stiles3b209362020-11-16 17:03:10 -05001460 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -07001461 for (;;) {
1462 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001463 case Token::Kind::TK_RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001464 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001465 return result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001466 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001467 this->error(this->peek(), "expected '}', but found end of file");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001468 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001469 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001470 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001471 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001472 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001473 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001474 getNode(result).addChild(statement);
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 }
1476 }
1477 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001478 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001479}
1480
1481/* expression SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001482ASTNode::ID Parser::expressionStatement() {
1483 ASTNode::ID expr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001484 if (expr) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001485 if (this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001486 return expr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001487 }
1488 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001489 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001490}
1491
1492/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001493ASTNode::ID Parser::expression() {
1494 ASTNode::ID result = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001495 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001496 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001497 }
1498 Token t;
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001499 AutoDepth depth(this);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001500 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001501 if (!depth.increase()) {
1502 return ASTNode::ID::Invalid();
1503 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001504 ASTNode::ID right = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001505 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001506 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001507 }
John Stiles45990502021-02-16 10:55:27 -05001508 ASTNode::ID newResult = this->createNode(t.fOffset, ASTNode::Kind::kBinary,
1509 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001510 getNode(newResult).addChild(result);
1511 getNode(newResult).addChild(right);
1512 result = newResult;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001513 }
1514 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001515}
1516
1517/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1518 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1519 assignmentExpression)*
1520 */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001521ASTNode::ID Parser::assignmentExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001522 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001523 ASTNode::ID result = this->ternaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001524 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001525 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 }
1527 for (;;) {
1528 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001529 case Token::Kind::TK_EQ: // fall through
1530 case Token::Kind::TK_STAREQ: // fall through
1531 case Token::Kind::TK_SLASHEQ: // fall through
1532 case Token::Kind::TK_PERCENTEQ: // fall through
1533 case Token::Kind::TK_PLUSEQ: // fall through
1534 case Token::Kind::TK_MINUSEQ: // fall through
1535 case Token::Kind::TK_SHLEQ: // fall through
1536 case Token::Kind::TK_SHREQ: // fall through
1537 case Token::Kind::TK_BITWISEANDEQ: // fall through
1538 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05001539 case Token::Kind::TK_BITWISEOREQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001540 if (!depth.increase()) {
1541 return ASTNode::ID::Invalid();
1542 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001543 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001544 ASTNode::ID right = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001545 if (!right) {
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 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001549 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001550 getNode(newResult).addChild(result);
1551 getNode(newResult).addChild(right);
1552 result = newResult;
1553 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001554 }
1555 default:
1556 return result;
1557 }
1558 }
1559}
1560
1561/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001562ASTNode::ID Parser::ternaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001563 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001564 ASTNode::ID base = this->logicalOrExpression();
1565 if (!base) {
1566 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001567 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001568 if (this->checkNext(Token::Kind::TK_QUESTION)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001569 if (!depth.increase()) {
1570 return ASTNode::ID::Invalid();
1571 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001572 ASTNode::ID trueExpr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 if (!trueExpr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001574 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001576 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001577 ASTNode::ID falseExpr = this->assignmentExpression();
1578 if (!falseExpr) {
1579 return ASTNode::ID::Invalid();
1580 }
John Stiles3b209362020-11-16 17:03:10 -05001581 ASTNode::ID ternary = this->createNode(getNode(base).fOffset, ASTNode::Kind::kTernary);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001582 getNode(ternary).addChild(base);
1583 getNode(ternary).addChild(trueExpr);
1584 getNode(ternary).addChild(falseExpr);
1585 return ternary;
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001587 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001589 return base;
ethannicholasb3058bd2016-07-01 08:22:01 -07001590}
1591
1592/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001593ASTNode::ID Parser::logicalOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001594 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001595 ASTNode::ID result = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001597 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001598 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001599 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001600 while (this->checkNext(Token::Kind::TK_LOGICALOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001601 if (!depth.increase()) {
1602 return ASTNode::ID::Invalid();
1603 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001604 ASTNode::ID right = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001605 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001606 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001607 }
John Stiles3b209362020-11-16 17:03:10 -05001608 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001609 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001610 getNode(newResult).addChild(result);
1611 getNode(newResult).addChild(right);
1612 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001613 }
1614 return result;
1615}
1616
1617/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001618ASTNode::ID Parser::logicalXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001619 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001620 ASTNode::ID result = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001621 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001622 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001624 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001625 while (this->checkNext(Token::Kind::TK_LOGICALXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001626 if (!depth.increase()) {
1627 return ASTNode::ID::Invalid();
1628 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001629 ASTNode::ID right = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001630 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001631 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 }
John Stiles3b209362020-11-16 17:03:10 -05001633 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001634 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001635 getNode(newResult).addChild(result);
1636 getNode(newResult).addChild(right);
1637 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 }
1639 return result;
1640}
1641
1642/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001643ASTNode::ID Parser::logicalAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001644 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001645 ASTNode::ID result = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001646 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001647 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001649 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001650 while (this->checkNext(Token::Kind::TK_LOGICALAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001651 if (!depth.increase()) {
1652 return ASTNode::ID::Invalid();
1653 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001654 ASTNode::ID right = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001655 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001656 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 }
John Stiles3b209362020-11-16 17:03:10 -05001658 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001659 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001660 getNode(newResult).addChild(result);
1661 getNode(newResult).addChild(right);
1662 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001663 }
1664 return result;
1665}
1666
1667/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001668ASTNode::ID Parser::bitwiseOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001669 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001670 ASTNode::ID result = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001671 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001672 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001673 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001674 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001675 while (this->checkNext(Token::Kind::TK_BITWISEOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001676 if (!depth.increase()) {
1677 return ASTNode::ID::Invalid();
1678 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001679 ASTNode::ID right = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001680 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001681 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001682 }
John Stiles45990502021-02-16 10:55:27 -05001683 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1684 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001685 getNode(newResult).addChild(result);
1686 getNode(newResult).addChild(right);
1687 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001688 }
1689 return result;
1690}
1691
1692/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001693ASTNode::ID Parser::bitwiseXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001694 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001695 ASTNode::ID result = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001696 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001697 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001699 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001700 while (this->checkNext(Token::Kind::TK_BITWISEXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001701 if (!depth.increase()) {
1702 return ASTNode::ID::Invalid();
1703 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001704 ASTNode::ID right = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001706 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001707 }
John Stiles45990502021-02-16 10:55:27 -05001708 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1709 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001710 getNode(newResult).addChild(result);
1711 getNode(newResult).addChild(right);
1712 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001713 }
1714 return result;
1715}
1716
1717/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001718ASTNode::ID Parser::bitwiseAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001719 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001720 ASTNode::ID result = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001721 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001722 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001723 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001724 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001725 while (this->checkNext(Token::Kind::TK_BITWISEAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001726 if (!depth.increase()) {
1727 return ASTNode::ID::Invalid();
1728 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001729 ASTNode::ID right = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001731 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001732 }
John Stiles3b209362020-11-16 17:03:10 -05001733 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001734 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001735 getNode(newResult).addChild(result);
1736 getNode(newResult).addChild(right);
1737 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001738 }
1739 return result;
1740}
1741
1742/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001743ASTNode::ID Parser::equalityExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001744 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001745 ASTNode::ID result = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001746 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001747 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001748 }
1749 for (;;) {
1750 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001751 case Token::Kind::TK_EQEQ: // fall through
1752 case Token::Kind::TK_NEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001753 if (!depth.increase()) {
1754 return ASTNode::ID::Invalid();
1755 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001756 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001757 ASTNode::ID right = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001758 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001759 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001760 }
John Stiles3b209362020-11-16 17:03:10 -05001761 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001762 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001763 getNode(newResult).addChild(result);
1764 getNode(newResult).addChild(right);
1765 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001766 break;
1767 }
1768 default:
1769 return result;
1770 }
1771 }
1772}
1773
1774/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001775ASTNode::ID Parser::relationalExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001776 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001777 ASTNode::ID result = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001778 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001779 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001780 }
1781 for (;;) {
1782 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001783 case Token::Kind::TK_LT: // fall through
1784 case Token::Kind::TK_GT: // fall through
1785 case Token::Kind::TK_LTEQ: // fall through
1786 case Token::Kind::TK_GTEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001787 if (!depth.increase()) {
1788 return ASTNode::ID::Invalid();
1789 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001791 ASTNode::ID right = this->shiftExpression();
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 = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001796 ASTNode::Kind::kBinary, Operator(t.fKind));
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 break;
1801 }
1802 default:
1803 return result;
1804 }
1805 }
1806}
1807
1808/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001809ASTNode::ID Parser::shiftExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001810 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001811 ASTNode::ID result = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001812 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001813 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001814 }
1815 for (;;) {
1816 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001817 case Token::Kind::TK_SHL: // fall through
1818 case Token::Kind::TK_SHR: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001819 if (!depth.increase()) {
1820 return ASTNode::ID::Invalid();
1821 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001823 ASTNode::ID right = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001825 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001826 }
John Stiles3b209362020-11-16 17:03:10 -05001827 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001828 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001829 getNode(newResult).addChild(result);
1830 getNode(newResult).addChild(right);
1831 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001832 break;
1833 }
1834 default:
1835 return result;
1836 }
1837 }
1838}
1839
1840/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001841ASTNode::ID Parser::additiveExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001842 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001843 ASTNode::ID result = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001844 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001845 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001846 }
1847 for (;;) {
1848 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001849 case Token::Kind::TK_PLUS: // fall through
1850 case Token::Kind::TK_MINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001851 if (!depth.increase()) {
1852 return ASTNode::ID::Invalid();
1853 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001854 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001855 ASTNode::ID right = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001856 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001857 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 }
John Stiles3b209362020-11-16 17:03:10 -05001859 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001860 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001861 getNode(newResult).addChild(result);
1862 getNode(newResult).addChild(right);
1863 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001864 break;
1865 }
1866 default:
1867 return result;
1868 }
1869 }
1870}
1871
1872/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001873ASTNode::ID Parser::multiplicativeExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001874 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001875 ASTNode::ID result = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001876 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001877 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001878 }
1879 for (;;) {
1880 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001881 case Token::Kind::TK_STAR: // fall through
1882 case Token::Kind::TK_SLASH: // fall through
1883 case Token::Kind::TK_PERCENT: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001884 if (!depth.increase()) {
1885 return ASTNode::ID::Invalid();
1886 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001887 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001888 ASTNode::ID right = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001889 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001890 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001891 }
John Stiles3b209362020-11-16 17:03:10 -05001892 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001893 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001894 getNode(newResult).addChild(result);
1895 getNode(newResult).addChild(right);
1896 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001897 break;
1898 }
1899 default:
1900 return result;
1901 }
1902 }
1903}
1904
1905/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001906ASTNode::ID Parser::unaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001907 AutoDepth depth(this);
ethannicholasb3058bd2016-07-01 08:22:01 -07001908 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001909 case Token::Kind::TK_PLUS: // fall through
1910 case Token::Kind::TK_MINUS: // fall through
1911 case Token::Kind::TK_LOGICALNOT: // fall through
1912 case Token::Kind::TK_BITWISENOT: // fall through
1913 case Token::Kind::TK_PLUSPLUS: // fall through
1914 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001915 if (!depth.increase()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001916 return ASTNode::ID::Invalid();
Ethan Nicholas6dcc3252019-02-20 15:18:36 -05001917 }
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001918 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001919 ASTNode::ID expr = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001920 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001921 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001922 }
John Stiles45990502021-02-16 10:55:27 -05001923 ASTNode::ID result = this->createNode(t.fOffset, ASTNode::Kind::kPrefix,
1924 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001925 getNode(result).addChild(expr);
1926 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001927 }
1928 default:
1929 return this->postfixExpression();
1930 }
1931}
1932
1933/* term suffix* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001934ASTNode::ID Parser::postfixExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001935 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001936 ASTNode::ID result = this->term();
ethannicholasb3058bd2016-07-01 08:22:01 -07001937 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001938 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001939 }
1940 for (;;) {
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04001941 Token t = this->peek();
1942 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001943 case Token::Kind::TK_FLOAT_LITERAL:
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04001944 if (this->text(t)[0] != '.') {
1945 return result;
1946 }
John Stiles30212b72020-06-11 17:55:07 -04001947 [[fallthrough]];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001948 case Token::Kind::TK_LBRACKET:
1949 case Token::Kind::TK_DOT:
1950 case Token::Kind::TK_LPAREN:
1951 case Token::Kind::TK_PLUSPLUS:
1952 case Token::Kind::TK_MINUSMINUS:
1953 case Token::Kind::TK_COLONCOLON:
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001954 if (!depth.increase()) {
1955 return ASTNode::ID::Invalid();
1956 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001957 result = this->suffix(result);
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001958 if (!result) {
1959 return ASTNode::ID::Invalid();
1960 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001961 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001962 default:
1963 return result;
1964 }
1965 }
1966}
1967
Ethan Nicholas11d53972016-11-28 11:23:23 -05001968/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
Ethan Nicholase455f652019-09-13 12:52:55 -04001969 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001970ASTNode::ID Parser::suffix(ASTNode::ID base) {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001971 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001972 Token next = this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001973 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001974 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001975 return ASTNode::ID::Invalid();
1976 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001977 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001978 case Token::Kind::TK_LBRACKET: {
1979 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -05001980 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001981 getNode(result).addChild(base);
1982 return result;
ethannicholas5961bc92016-10-12 06:39:56 -07001983 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001984 ASTNode::ID e = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001985 if (!e) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001986 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001987 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001988 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
John Stiles3b209362020-11-16 17:03:10 -05001989 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001990 getNode(result).addChild(base);
1991 getNode(result).addChild(e);
1992 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001994 case Token::Kind::TK_COLONCOLON: {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001995 int offset = this->peek().fOffset;
Ethan Nicholas962dec42021-06-10 13:06:39 -04001996 skstd::string_view text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001997 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05001998 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kScope,
1999 std::move(text));
Brian Osman6518d772020-09-10 16:50:06 -04002000 getNode(result).addChild(base);
2001 return result;
2002 }
2003 return ASTNode::ID::Invalid();
2004 }
2005 case Token::Kind::TK_DOT: {
2006 int offset = this->peek().fOffset;
Ethan Nicholas962dec42021-06-10 13:06:39 -04002007 skstd::string_view text;
Brian Osman6518d772020-09-10 16:50:06 -04002008 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002009 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kField,
2010 std::move(text));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002011 getNode(result).addChild(base);
2012 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002013 }
Brian Osman6518d772020-09-10 16:50:06 -04002014 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04002015 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002016 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholase455f652019-09-13 12:52:55 -04002017 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
2018 // floating point literals, possibly followed by an identifier. Handle that here.
Ethan Nicholas962dec42021-06-10 13:06:39 -04002019 skstd::string_view field = this->text(next);
Ethan Nicholasd2e09602021-06-10 11:21:59 -04002020 SkASSERT(field[0] == '.');
2021 field.remove_prefix(1);
2022 for (auto iter = field.begin(); iter != field.end(); ++iter) {
2023 if (*iter != '0' && *iter != '1') {
Ethan Nicholase455f652019-09-13 12:52:55 -04002024 this->error(next, "invalid swizzle");
2025 return ASTNode::ID::Invalid();
2026 }
2027 }
2028 // use the next *raw* token so we don't ignore whitespace - we only care about
2029 // identifiers that directly follow the float
2030 Token id = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002031 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas962dec42021-06-10 13:06:39 -04002032 field = skstd::string_view(field.data(), field.length() + id.fLength);
Ethan Nicholase455f652019-09-13 12:52:55 -04002033 } else {
2034 this->pushback(id);
2035 }
John Stiles3b209362020-11-16 17:03:10 -05002036 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kField, field);
Ethan Nicholase455f652019-09-13 12:52:55 -04002037 getNode(result).addChild(base);
2038 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002039 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002040 case Token::Kind::TK_LPAREN: {
John Stiles3b209362020-11-16 17:03:10 -05002041 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kCall);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002042 getNode(result).addChild(base);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002043 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002044 for (;;) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002045 ASTNode::ID expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002046 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002047 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002048 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002049 getNode(result).addChild(expr);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002050 if (!this->checkNext(Token::Kind::TK_COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002051 break;
2052 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002053 }
2054 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002055 this->expect(Token::Kind::TK_RPAREN, "')' to complete function parameters");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002056 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002057 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002058 case Token::Kind::TK_PLUSPLUS: // fall through
2059 case Token::Kind::TK_MINUSMINUS: {
John Stiles45990502021-02-16 10:55:27 -05002060 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kPostfix,
2061 Operator(next.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04002062 getNode(result).addChild(base);
2063 return result;
2064 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002065 default: {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002066 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002067 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002068 }
2069 }
2070}
2071
Brian Osman33c64a42020-12-23 10:26:38 -05002072/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002073ASTNode::ID Parser::term() {
ethannicholasb3058bd2016-07-01 08:22:01 -07002074 Token t = this->peek();
2075 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002076 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas962dec42021-06-10 13:06:39 -04002077 skstd::string_view text;
ethannicholasb3058bd2016-07-01 08:22:01 -07002078 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05002079 return this->createNode(t.fOffset, ASTNode::Kind::kIdentifier, std::move(text));
ethannicholasb3058bd2016-07-01 08:22:01 -07002080 }
John Stiles30212b72020-06-11 17:55:07 -04002081 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002082 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002083 case Token::Kind::TK_INT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002084 SKSL_INT i;
ethannicholasb3058bd2016-07-01 08:22:01 -07002085 if (this->intLiteral(&i)) {
John Stiles3b209362020-11-16 17:03:10 -05002086 return this->createNode(t.fOffset, ASTNode::Kind::kInt, i);
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 }
2088 break;
2089 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002090 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002091 SKSL_FLOAT f;
ethannicholasb3058bd2016-07-01 08:22:01 -07002092 if (this->floatLiteral(&f)) {
John Stiles3b209362020-11-16 17:03:10 -05002093 return this->createNode(t.fOffset, ASTNode::Kind::kFloat, f);
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 }
2095 break;
2096 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002097 case Token::Kind::TK_TRUE_LITERAL: // fall through
2098 case Token::Kind::TK_FALSE_LITERAL: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002099 bool b;
2100 if (this->boolLiteral(&b)) {
John Stiles3b209362020-11-16 17:03:10 -05002101 return this->createNode(t.fOffset, ASTNode::Kind::kBool, b);
ethannicholasb3058bd2016-07-01 08:22:01 -07002102 }
2103 break;
2104 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002105 case Token::Kind::TK_LPAREN: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002106 this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002107 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04002108 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04002109 return ASTNode::ID::Invalid();
2110 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002111 ASTNode::ID result = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07002112 if (result) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002113 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002114 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002115 }
2116 break;
2117 }
2118 default:
2119 this->nextToken();
John Stilesf94348f2020-12-23 18:58:43 -05002120 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002122 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07002123}
2124
2125/* INT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002126bool Parser::intLiteral(SKSL_INT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 Token t;
John Stilesf94348f2020-12-23 18:58:43 -05002128 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
2129 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -07002130 }
Ethan Nicholas962dec42021-06-10 13:06:39 -04002131 skstd::string_view s = this->text(t);
John Stilesf94348f2020-12-23 18:58:43 -05002132 if (!SkSL::stoi(s, dest)) {
2133 this->error(t, "integer is too large: " + s);
2134 return false;
2135 }
2136 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07002137}
2138
John Stilesf94348f2020-12-23 18:58:43 -05002139
ethannicholasb3058bd2016-07-01 08:22:01 -07002140/* FLOAT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04002141bool Parser::floatLiteral(SKSL_FLOAT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002142 Token t;
John Stilesf94348f2020-12-23 18:58:43 -05002143 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
2144 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -07002145 }
Ethan Nicholas962dec42021-06-10 13:06:39 -04002146 skstd::string_view s = this->text(t);
John Stilesf94348f2020-12-23 18:58:43 -05002147 if (!SkSL::stod(s, dest)) {
2148 this->error(t, "floating-point value is too large: " + s);
2149 return false;
2150 }
2151 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07002152}
2153
2154/* TRUE_LITERAL | FALSE_LITERAL */
2155bool Parser::boolLiteral(bool* dest) {
2156 Token t = this->nextToken();
2157 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002158 case Token::Kind::TK_TRUE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07002159 *dest = true;
2160 return true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002161 case Token::Kind::TK_FALSE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07002162 *dest = false;
2163 return true;
2164 default:
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04002165 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002166 return false;
2167 }
2168}
2169
2170/* IDENTIFIER */
Ethan Nicholas962dec42021-06-10 13:06:39 -04002171bool Parser::identifier(skstd::string_view* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002172 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002173 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002174 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07002175 return true;
2176 }
2177 return false;
2178}
2179
John Stilesa6841be2020-08-06 14:11:56 -04002180} // namespace SkSL