blob: 3a3ae6a9715a46af55395c9391b6c7681000ec37 [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 Stiles02014312021-08-04 16:03:12 -040055 case Token::Kind::TK_HIGHP: return Modifiers::kHighp_Flag;
56 case Token::Kind::TK_MEDIUMP: return Modifiers::kMediump_Flag;
57 case Token::Kind::TK_LOWP: return Modifiers::kLowp_Flag;
John Stilesefde90d2021-08-12 23:06:24 -040058 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
John Stiles7d5b90a2021-01-21 14:26:51 -050059 default: return 0;
60 }
61}
62
ethannicholascad64162016-10-27 10:54:02 -070063class AutoDepth {
64public:
65 AutoDepth(Parser* p)
Ethan Nicholascf4deab2019-09-13 16:28:14 -040066 : fParser(p)
67 , fDepth(0) {}
ethannicholascad64162016-10-27 10:54:02 -070068
69 ~AutoDepth() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -040070 fParser->fDepth -= fDepth;
ethannicholascad64162016-10-27 10:54:02 -070071 }
72
Ethan Nicholascf4deab2019-09-13 16:28:14 -040073 bool increase() {
74 ++fDepth;
75 ++fParser->fDepth;
John Stiles8d056592020-11-10 10:03:50 -050076 if (fParser->fDepth > kMaxParseDepth) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070077 fParser->error(fParser->peek(), String("exceeded max parse depth"));
ethannicholascad64162016-10-27 10:54:02 -070078 return false;
79 }
80 return true;
81 }
82
83private:
84 Parser* fParser;
Ethan Nicholascf4deab2019-09-13 16:28:14 -040085 int fDepth;
ethannicholascad64162016-10-27 10:54:02 -070086};
87
Brian Salomon140f3da2018-08-23 13:51:27 +000088std::unordered_map<String, Parser::LayoutToken>* Parser::layoutTokens;
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040089
90void Parser::InitLayoutMap() {
Brian Salomon140f3da2018-08-23 13:51:27 +000091 layoutTokens = new std::unordered_map<String, LayoutToken>;
Brian Salomon23356442018-11-30 15:33:19 -050092 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
Ethan Nicholasb93af7e2018-07-24 11:28:52 -040093 TOKEN(LOCATION, "location");
94 TOKEN(OFFSET, "offset");
95 TOKEN(BINDING, "binding");
96 TOKEN(INDEX, "index");
97 TOKEN(SET, "set");
98 TOKEN(BUILTIN, "builtin");
99 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
100 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400101 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400102 TOKEN(PUSH_CONSTANT, "push_constant");
103 TOKEN(POINTS, "points");
104 TOKEN(LINES, "lines");
105 TOKEN(LINE_STRIP, "line_strip");
106 TOKEN(LINES_ADJACENCY, "lines_adjacency");
107 TOKEN(TRIANGLES, "triangles");
108 TOKEN(TRIANGLE_STRIP, "triangle_strip");
109 TOKEN(TRIANGLES_ADJACENCY, "triangles_adjacency");
110 TOKEN(MAX_VERTICES, "max_vertices");
111 TOKEN(INVOCATIONS, "invocations");
Brian Osmanb32d66b2020-04-30 17:12:03 -0400112 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400113 #undef TOKEN
114}
115
Ethan Nicholas6823b502021-06-15 11:42:07 -0400116Parser::Parser(skstd::string_view text, SymbolTable& symbols, ErrorReporter& errors)
117: fText(text)
John Stiles7cbb09c22021-01-07 16:07:00 -0500118, fPushback(Token::Kind::TK_NONE, -1, -1)
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400119, fSymbols(symbols)
Ethan Nicholas55478662021-08-10 17:14:26 -0400120, fErrors(&errors) {
Ethan Nicholas6823b502021-06-15 11:42:07 -0400121 fLexer.start(text);
Brian Salomon3b83afe2018-08-23 11:04:36 -0400122 static const bool layoutMapInitialized = []{ return (void)InitLayoutMap(), true; }();
123 (void) layoutMapInitialized;
ethannicholasb3058bd2016-07-01 08:22:01 -0700124}
125
John Stiles3b209362020-11-16 17:03:10 -0500126template <typename... Args>
127ASTNode::ID Parser::createNode(Args&&... args) {
128 ASTNode::ID result(fFile->fNodes.size());
129 fFile->fNodes.emplace_back(&fFile->fNodes, std::forward<Args>(args)...);
130 return result;
131}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400132
John Stiles3b209362020-11-16 17:03:10 -0500133ASTNode::ID Parser::addChild(ASTNode::ID target, ASTNode::ID child) {
134 fFile->fNodes[target.fValue].addChild(child);
135 return child;
136}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400137
John Stiles3b209362020-11-16 17:03:10 -0500138void Parser::createEmptyChild(ASTNode::ID target) {
139 ASTNode::ID child(fFile->fNodes.size());
140 fFile->fNodes.emplace_back();
141 fFile->fNodes[target.fValue].addChild(child);
142}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400143
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400144/* (directive | section | declaration)* END_OF_FILE */
Ethan Nicholasba9a04f2020-11-06 09:28:04 -0500145std::unique_ptr<ASTFile> Parser::compilationUnit() {
John Stilesfbd050b2020-08-03 13:21:46 -0400146 fFile = std::make_unique<ASTFile>();
John Stiles18a45b32021-03-29 18:07:32 -0400147 fFile->fNodes.reserve(fText.size() / 10); // a typical program is approx 10:1 for chars:nodes
John Stiles3b209362020-11-16 17:03:10 -0500148 ASTNode::ID result = this->createNode(/*offset=*/0, ASTNode::Kind::kFile);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400149 fFile->fRoot = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700150 for (;;) {
151 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400152 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholasfc994162019-06-06 10:04:27 -0400153 return std::move(fFile);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400154 case Token::Kind::TK_DIRECTIVE: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400155 ASTNode::ID dir = this->directive();
Ethan Nicholas55478662021-08-10 17:14:26 -0400156 if (fErrors->errorCount()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400157 return nullptr;
158 }
159 if (dir) {
160 getNode(result).addChild(dir);
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 }
162 break;
163 }
John Stiles7cbb09c22021-01-07 16:07:00 -0500164 case Token::Kind::TK_INVALID: {
165 this->error(this->peek(), String("invalid token"));
166 return nullptr;
167 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700168 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400169 ASTNode::ID decl = this->declaration();
Ethan Nicholas55478662021-08-10 17:14:26 -0400170 if (fErrors->errorCount()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400171 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400173 if (decl) {
174 getNode(result).addChild(decl);
175 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700176 }
177 }
178 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400179 return std::move(fFile);
ethannicholasb3058bd2016-07-01 08:22:01 -0700180}
181
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700182Token Parser::nextRawToken() {
John Stiles7cbb09c22021-01-07 16:07:00 -0500183 if (fPushback.fKind != Token::Kind::TK_NONE) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700184 Token result = fPushback;
John Stiles7cbb09c22021-01-07 16:07:00 -0500185 fPushback.fKind = Token::Kind::TK_NONE;
ethannicholasb3058bd2016-07-01 08:22:01 -0700186 return result;
187 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700188 Token result = fLexer.next();
189 return result;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400190}
191
192Token Parser::nextToken() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700193 Token token = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400194 while (token.fKind == Token::Kind::TK_WHITESPACE ||
195 token.fKind == Token::Kind::TK_LINE_COMMENT ||
196 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700197 token = this->nextRawToken();
198 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400199 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700200}
201
202void Parser::pushback(Token t) {
John Stiles7cbb09c22021-01-07 16:07:00 -0500203 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400204 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700205}
206
207Token Parser::peek() {
John Stiles7cbb09c22021-01-07 16:07:00 -0500208 if (fPushback.fKind == Token::Kind::TK_NONE) {
Brian Osman634624a2017-08-15 11:14:30 -0400209 fPushback = this->nextToken();
210 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700211 return fPushback;
212}
213
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400214bool Parser::checkNext(Token::Kind kind, Token* result) {
John Stiles7cbb09c22021-01-07 16:07:00 -0500215 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
Brian Osman634624a2017-08-15 11:14:30 -0400216 return false;
217 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400218 Token next = this->nextToken();
219 if (next.fKind == kind) {
220 if (result) {
221 *result = next;
222 }
223 return true;
224 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400225 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400226 return false;
227}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500228
229bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700230 Token next = this->nextToken();
231 if (next.fKind == kind) {
232 if (result) {
Brian Osman634624a2017-08-15 11:14:30 -0400233 *result = std::move(next);
ethannicholasb3058bd2016-07-01 08:22:01 -0700234 }
235 return true;
236 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700237 this->error(next, "expected " + String(expected) + ", but found '" +
238 this->text(next) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700239 return false;
240 }
241}
242
John Stiles2630ea32020-12-04 10:51:21 -0500243bool Parser::expectIdentifier(Token* result) {
244 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
245 return false;
246 }
247 if (this->isType(this->text(*result))) {
248 this->error(*result, "expected an identifier, but found type '" +
249 this->text(*result) + "'");
250 return false;
251 }
252 return true;
253}
254
Ethan Nicholas962dec42021-06-10 13:06:39 -0400255skstd::string_view Parser::text(Token token) {
256 return skstd::string_view(fText.begin() + token.fOffset, token.fLength);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500257}
258
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700259void Parser::error(Token token, String msg) {
260 this->error(token.fOffset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -0700261}
262
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700263void Parser::error(int offset, String msg) {
Ethan Nicholas55478662021-08-10 17:14:26 -0400264 fErrors->error(offset, msg);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700265}
266
Ethan Nicholas962dec42021-06-10 13:06:39 -0400267bool Parser::isType(skstd::string_view name) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400268 const Symbol* s = fSymbols[name];
John Stiles2630ea32020-12-04 10:51:21 -0500269 return s && s->is<Type>();
ethannicholasb3058bd2016-07-01 08:22:01 -0700270}
271
John Stiles80b02af2021-02-12 17:07:51 -0500272bool Parser::isArrayType(ASTNode::ID type) {
273 const ASTNode& node = this->getNode(type);
274 SkASSERT(node.fKind == ASTNode::Kind::kType);
275 return node.begin() != node.end();
276}
277
Ethan Nicholas11d53972016-11-28 11:23:23 -0500278/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700279 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400280ASTNode::ID Parser::directive() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700281 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400282 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400283 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700284 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400285 skstd::string_view text = this->text(start);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400286 if (text == "#extension") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700287 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500288 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400289 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700290 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400291 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400292 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 }
294 // FIXME: need to start paying attention to this token
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400295 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400296 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700297 }
John Stiles3b209362020-11-16 17:03:10 -0500298 return this->createNode(start.fOffset, ASTNode::Kind::kExtension, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700300 this->error(start, "unsupported directive '" + this->text(start) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400301 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700302 }
303}
304
Brian Osmanc9145f32021-07-08 13:40:10 -0400305/* modifiers (interfaceBlock | structVarDeclaration | SEMICOLON |
John Stiles147cfda2021-05-21 14:11:38 -0400306 type IDENTIFIER (varDeclarationEnd | LPAREN functionDeclarationEnd))) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400307ASTNode::ID Parser::declaration() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700308 Token lookahead = this->peek();
Ethan Nicholasda6320c2020-09-02 14:08:23 -0400309 switch (lookahead.fKind) {
Ethan Nicholasda6320c2020-09-02 14:08:23 -0400310 case Token::Kind::TK_SEMICOLON:
311 this->error(lookahead.fOffset, "expected a declaration, but found ';'");
312 return ASTNode::ID::Invalid();
313 default:
314 break;
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500315 }
316 Modifiers modifiers = this->modifiers();
317 lookahead = this->peek();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400318 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !this->isType(this->text(lookahead))) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 // we have an identifier that's not a type, could be the start of an interface block
320 return this->interfaceBlock(modifiers);
321 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400322 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700323 return this->structVarDeclaration(modifiers);
324 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400325 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
ethannicholas5961bc92016-10-12 06:39:56 -0700326 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -0500327 return this->createNode(lookahead.fOffset, ASTNode::Kind::kModifiers, modifiers);
ethannicholas5961bc92016-10-12 06:39:56 -0700328 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400329 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700330 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400331 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700332 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700333 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500334 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400335 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700336 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400337 if (this->checkNext(Token::Kind::TK_LPAREN)) {
John Stiles147cfda2021-05-21 14:11:38 -0400338 return this->functionDeclarationEnd(modifiers, type, name);
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400340 return this->varDeclarationEnd(modifiers, type, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700341 }
342}
343
John Stiles147cfda2021-05-21 14:11:38 -0400344/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
345ASTNode::ID Parser::functionDeclarationEnd(Modifiers modifiers,
346 ASTNode::ID type,
347 const Token& name) {
348 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kFunction);
349 ASTNode::FunctionData fd(modifiers, this->text(name), 0);
350 getNode(result).addChild(type);
351 Token lookahead = this->peek();
352 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
353 // `()` means no parameters at all.
354 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
355 // `(void)` also means no parameters at all.
356 this->nextToken();
357 } else {
358 for (;;) {
359 ASTNode::ID parameter = this->parameter();
360 if (!parameter) {
361 return ASTNode::ID::Invalid();
362 }
363 ++fd.fParameterCount;
364 getNode(result).addChild(parameter);
365 if (!this->checkNext(Token::Kind::TK_COMMA)) {
366 break;
367 }
368 }
369 }
370 getNode(result).setFunctionData(fd);
371 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
372 return ASTNode::ID::Invalid();
373 }
374 ASTNode::ID body;
375 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
376 body = this->block();
377 if (!body) {
378 return ASTNode::ID::Invalid();
379 }
380 getNode(result).addChild(body);
381 }
382 return result;
383}
384
John Stiles76389b72021-01-25 13:49:05 -0500385/* (varDeclarations | expressionStatement) */
386ASTNode::ID Parser::varDeclarationsOrExpressionStatement() {
John Stiles89b484a2021-04-19 14:57:27 -0400387 Token nextToken = this->peek();
388 if (nextToken.fKind == Token::Kind::TK_CONST) {
389 // Statements that begin with `const` might be variable declarations, but can't be legal
390 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
391 return this->varDeclarations();
392 }
393
John Stiles02014312021-08-04 16:03:12 -0400394 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
395 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
396 nextToken.fKind == Token::Kind::TK_LOWP ||
397 this->isType(this->text(nextToken))) {
John Stiles76389b72021-01-25 13:49:05 -0500398 // Statements that begin with a typename are most often variable declarations, but
399 // occasionally the type is part of a constructor, and these are actually expression-
400 // statements in disguise. First, attempt the common case: parse it as a vardecl.
401 Checkpoint checkpoint(this);
John Stiles8dabeac2021-02-12 16:05:00 -0500402 VarDeclarationsPrefix prefix;
403 if (this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholas55478662021-08-10 17:14:26 -0400404 checkpoint.accept();
John Stiles8dabeac2021-02-12 16:05:00 -0500405 return this->varDeclarationEnd(prefix.modifiers, prefix.type, this->text(prefix.name));
John Stiles76389b72021-01-25 13:49:05 -0500406 }
407
408 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
409 // expression-statement instead.
410 checkpoint.rewind();
411 }
412
413 return this->expressionStatement();
414}
415
John Stiles8dabeac2021-02-12 16:05:00 -0500416// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
417// statement is a variable-declaration statement, not an expression-statement.
418bool Parser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
419 prefixData->modifiers = this->modifiers();
420 prefixData->type = this->type();
421 if (!prefixData->type) {
422 return false;
423 }
424 return this->expectIdentifier(&prefixData->name);
425}
426
ethannicholasb3058bd2016-07-01 08:22:01 -0700427/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400428ASTNode::ID Parser::varDeclarations() {
John Stiles8dabeac2021-02-12 16:05:00 -0500429 VarDeclarationsPrefix prefix;
430 if (!this->varDeclarationsPrefix(&prefix)) {
John Stiles76389b72021-01-25 13:49:05 -0500431 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 }
John Stiles8dabeac2021-02-12 16:05:00 -0500433 return this->varDeclarationEnd(prefix.modifiers, prefix.type, this->text(prefix.name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700434}
435
436/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400437ASTNode::ID Parser::structDeclaration() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400438 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400439 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700440 }
441 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500442 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400443 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400445 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400446 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700447 }
448 std::vector<Type::Field> fields;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400449 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400450 ASTNode::ID decls = this->varDeclarations();
451 if (!decls) {
452 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700453 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400454 ASTNode& declsNode = getNode(decls);
John Stilesece1bf02021-03-08 11:15:55 -0500455 const Modifiers& modifiers = declsNode.begin()->getModifiers();
John Stiles13fc2602020-10-09 17:42:31 -0400456 if (modifiers.fFlags != Modifiers::kNo_Flag) {
457 String desc = modifiers.description();
458 desc.pop_back(); // remove trailing space
459 this->error(declsNode.fOffset,
460 "modifier '" + desc + "' is not permitted on a struct field");
461 }
462
Ethan Nicholas962dec42021-06-10 13:06:39 -0400463 const Symbol* symbol = fSymbols[(declsNode.begin() + 1)->getStringView()];
John Stiles13fc2602020-10-09 17:42:31 -0400464 SkASSERT(symbol);
465 const Type* type = &symbol->as<Type>();
John Stiles1d757782020-11-17 09:43:22 -0500466 if (type->isOpaque()) {
467 this->error(declsNode.fOffset,
468 "opaque type '" + type->name() + "' is not permitted in a struct");
469 }
John Stiles13fc2602020-10-09 17:42:31 -0400470
Ethan Nicholasfc994162019-06-06 10:04:27 -0400471 for (auto iter = declsNode.begin() + 2; iter != declsNode.end(); ++iter) {
472 ASTNode& var = *iter;
John Stilesece1bf02021-03-08 11:15:55 -0500473 const ASTNode::VarData& vd = var.getVarData();
John Stiles6bef6a72020-12-02 14:26:04 -0500474
John Stilesd39aec92020-12-03 14:37:16 -0500475 // Read array size if one is present.
John Stiles31c87102021-08-25 12:01:21 -0400476 const Type* fieldType = type;
John Stilesd39aec92020-12-03 14:37:16 -0500477 if (vd.fIsArray) {
478 const ASTNode& size = *var.begin();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400479 if (!size || size.fKind != ASTNode::Kind::kInt) {
480 this->error(declsNode.fOffset, "array size in struct field must be a constant");
481 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700482 }
John Stiles6bef6a72020-12-02 14:26:04 -0500483 if (size.getInt() <= 0 || size.getInt() > INT_MAX) {
484 this->error(declsNode.fOffset, "array size is invalid");
485 return ASTNode::ID::Invalid();
486 }
John Stilesd39aec92020-12-03 14:37:16 -0500487 // Add the array dimensions to our type.
488 int arraySize = size.getInt();
John Stiles31c87102021-08-25 12:01:21 -0400489 fieldType = fSymbols.addArrayDimension(fieldType, arraySize);
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 }
John Stiles13fc2602020-10-09 17:42:31 -0400491
John Stiles31c87102021-08-25 12:01:21 -0400492 fields.push_back(Type::Field(modifiers, vd.fName, fieldType));
John Stilesd39aec92020-12-03 14:37:16 -0500493 if (vd.fIsArray ? var.begin()->fNext : var.fFirstChild) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400494 this->error(declsNode.fOffset, "initializers are not permitted on struct fields");
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 }
496 }
497 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400498 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400499 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700500 }
Brian Osman6c3b23f2021-02-12 13:09:58 -0500501 if (fields.empty()) {
502 this->error(name.fOffset,
503 "struct '" + this->text(name) + "' must contain at least one field");
504 return ASTNode::ID::Invalid();
505 }
Ethan Nicholas27f06eb2021-07-26 16:39:40 -0400506 std::unique_ptr<Type> newType = Type::MakeStructType(name.fOffset, this->text(name), fields);
John Stilesa695d622020-11-10 10:04:26 -0500507 if (struct_is_too_deeply_nested(*newType, kMaxStructDepth)) {
508 this->error(name.fOffset, "struct '" + this->text(name) + "' is too deeply nested");
509 return ASTNode::ID::Invalid();
510 }
511 fSymbols.add(std::move(newType));
Brian Osman00fea5b2021-01-28 09:46:30 -0500512 return this->createNode(name.fOffset, ASTNode::Kind::kType, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700513}
514
515/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400516ASTNode::ID Parser::structVarDeclaration(Modifiers modifiers) {
517 ASTNode::ID type = this->structDeclaration();
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400519 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700520 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400521 Token name;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400522 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400523 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700524 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400525 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesdc75a972020-11-25 16:24:55 -0500526 return type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700527}
528
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400529/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
530 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400531ASTNode::ID Parser::varDeclarationEnd(Modifiers mods, ASTNode::ID type, skstd::string_view name) {
John Stiles08070f62020-11-17 10:45:49 -0500532 int offset = this->peek().fOffset;
533 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kVarDeclarations);
534 this->addChild(result, this->createNode(offset, ASTNode::Kind::kModifiers, mods));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400535 getNode(result).addChild(type);
John Stilesd39aec92020-12-03 14:37:16 -0500536
John Stiles80b02af2021-02-12 17:07:51 -0500537 auto parseArrayDimensions = [&](ASTNode::ID currentVar, ASTNode::VarData* vd) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400538 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stiles80b02af2021-02-12 17:07:51 -0500539 if (vd->fIsArray || this->isArrayType(type)) {
John Stilesd39aec92020-12-03 14:37:16 -0500540 this->error(this->peek(), "multi-dimensional arrays are not supported");
541 return false;
542 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400543 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -0500544 this->createEmptyChild(currentVar);
ethannicholasb3058bd2016-07-01 08:22:01 -0700545 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400546 ASTNode::ID size = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700547 if (!size) {
John Stilesd39aec92020-12-03 14:37:16 -0500548 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700549 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400550 getNode(currentVar).addChild(size);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400551 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
John Stilesd39aec92020-12-03 14:37:16 -0500552 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700553 }
554 }
John Stilesd39aec92020-12-03 14:37:16 -0500555 vd->fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700556 }
John Stilesd39aec92020-12-03 14:37:16 -0500557 return true;
558 };
559
560 auto parseInitializer = [this](ASTNode::ID currentVar) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400561 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400562 ASTNode::ID value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700563 if (!value) {
John Stilesd39aec92020-12-03 14:37:16 -0500564 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400566 getNode(currentVar).addChild(value);
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 }
John Stilesd39aec92020-12-03 14:37:16 -0500568 return true;
569 };
570
571 ASTNode::ID currentVar = this->createNode(offset, ASTNode::Kind::kVarDeclaration);
572 ASTNode::VarData vd{name, /*isArray=*/false};
573
574 getNode(result).addChild(currentVar);
575 if (!parseArrayDimensions(currentVar, &vd)) {
576 return ASTNode::ID::Invalid();
577 }
578 getNode(currentVar).setVarData(vd);
579 if (!parseInitializer(currentVar)) {
580 return ASTNode::ID::Invalid();
581 }
582
583 while (this->checkNext(Token::Kind::TK_COMMA)) {
584 Token identifierName;
John Stiles2630ea32020-12-04 10:51:21 -0500585 if (!this->expectIdentifier(&identifierName)) {
John Stilesd39aec92020-12-03 14:37:16 -0500586 return ASTNode::ID::Invalid();
587 }
588
589 currentVar = ASTNode::ID(fFile->fNodes.size());
590 vd = ASTNode::VarData{this->text(identifierName), /*isArray=*/false};
591 fFile->fNodes.emplace_back(&fFile->fNodes, offset, ASTNode::Kind::kVarDeclaration);
592
593 getNode(result).addChild(currentVar);
594 if (!parseArrayDimensions(currentVar, &vd)) {
595 return ASTNode::ID::Invalid();
596 }
597 getNode(currentVar).setVarData(vd);
598 if (!parseInitializer(currentVar)) {
599 return ASTNode::ID::Invalid();
600 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700601 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400602 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400603 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400605 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700606}
607
608/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400609ASTNode::ID Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400610 Modifiers modifiers = this->modifiersWithDefaults(0);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400611 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700612 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400613 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700614 }
615 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500616 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400617 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700618 }
John Stiles3b209362020-11-16 17:03:10 -0500619 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kParameter);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400620 ASTNode::ParameterData pd(modifiers, this->text(name), 0);
621 getNode(result).addChild(type);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400622 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stiles80b02af2021-02-12 17:07:51 -0500623 if (pd.fIsArray || this->isArrayType(type)) {
John Stilesd39aec92020-12-03 14:37:16 -0500624 this->error(this->peek(), "multi-dimensional arrays are not supported");
625 return ASTNode::ID::Invalid();
626 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700627 Token sizeToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400628 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400629 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700630 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400631 skstd::string_view arraySizeFrag = this->text(sizeToken);
John Stilesf94348f2020-12-23 18:58:43 -0500632 SKSL_INT arraySize;
633 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
634 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
635 return ASTNode::ID::Invalid();
636 }
637 this->addChild(result, this->createNode(sizeToken.fOffset, ASTNode::Kind::kInt, arraySize));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400638 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400639 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700640 }
John Stilesd39aec92020-12-03 14:37:16 -0500641 pd.fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700642 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400643 getNode(result).setParameterData(pd);
644 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700645}
646
Ethan Nicholasd608c092017-10-26 09:30:08 -0400647/** EQ INT_LITERAL */
ethannicholasb3058bd2016-07-01 08:22:01 -0700648int Parser::layoutInt() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400649 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700650 return -1;
651 }
652 Token resultToken;
John Stilesf94348f2020-12-23 18:58:43 -0500653 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
654 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700655 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400656 skstd::string_view resultFrag = this->text(resultToken);
John Stilesf94348f2020-12-23 18:58:43 -0500657 SKSL_INT resultValue;
658 if (!SkSL::stoi(resultFrag, &resultValue)) {
659 this->error(resultToken, "value in layout is too large: " + resultFrag);
660 return -1;
661 }
662 return resultValue;
ethannicholasb3058bd2016-07-01 08:22:01 -0700663}
664
Ethan Nicholasd608c092017-10-26 09:30:08 -0400665/** EQ IDENTIFIER */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400666skstd::string_view Parser::layoutIdentifier() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400667 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400668 return skstd::string_view();
Ethan Nicholasd608c092017-10-26 09:30:08 -0400669 }
670 Token resultToken;
John Stiles2630ea32020-12-04 10:51:21 -0500671 if (!this->expectIdentifier(&resultToken)) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400672 return skstd::string_view();
Ethan Nicholasd608c092017-10-26 09:30:08 -0400673 }
674 return this->text(resultToken);
675}
676
ethannicholas8ac838d2016-11-22 08:39:36 -0800677/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500678Layout Parser::layout() {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500679 int flags = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700680 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500681 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700682 int binding = -1;
683 int index = -1;
684 int set = -1;
685 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500686 int inputAttachmentIndex = -1;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500687 Layout::Primitive primitive = Layout::kUnspecified_Primitive;
688 int maxVertices = -1;
689 int invocations = -1;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400690 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
691 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500692 return Layout(flags, location, offset, binding, index, set, builtin,
Brian Osman8c264792021-07-01 16:41:27 -0400693 inputAttachmentIndex, primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700694 }
695 for (;;) {
696 Token t = this->nextToken();
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400697 String text(this->text(t));
Brian Osmana77ed8b2021-02-23 12:54:22 -0500698 auto setFlag = [&](Layout::Flag f) {
699 if (flags & f) {
700 this->error(t, "layout qualifier '" + text + "' appears more than once");
701 }
702 flags |= f;
703 };
704 auto setPrimitive = [&](Layout::Primitive p) {
705 if (flags & Layout::kPrimitive_Flag) {
706 this->error(t, "only one primitive-type layout qualifier is allowed");
707 }
708 flags |= Layout::kPrimitive_Flag;
709 primitive = p;
710 };
711
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400712 auto found = layoutTokens->find(text);
713 if (found != layoutTokens->end()) {
714 switch (found->second) {
Brian Osmana77ed8b2021-02-23 12:54:22 -0500715 case LayoutToken::ORIGIN_UPPER_LEFT:
716 setFlag(Layout::kOriginUpperLeft_Flag);
717 break;
Brian Osmana77ed8b2021-02-23 12:54:22 -0500718 case LayoutToken::PUSH_CONSTANT:
719 setFlag(Layout::kPushConstant_Flag);
720 break;
721 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
722 setFlag(Layout::kBlendSupportAllEquations_Flag);
723 break;
Brian Osmana77ed8b2021-02-23 12:54:22 -0500724 case LayoutToken::SRGB_UNPREMUL:
725 setFlag(Layout::kSRGBUnpremul_Flag);
726 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700727 case LayoutToken::LOCATION:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500728 setFlag(Layout::kLocation_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500729 location = this->layoutInt();
730 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700731 case LayoutToken::OFFSET:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500732 setFlag(Layout::kOffset_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500733 offset = this->layoutInt();
734 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700735 case LayoutToken::BINDING:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500736 setFlag(Layout::kBinding_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500737 binding = this->layoutInt();
738 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700739 case LayoutToken::INDEX:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500740 setFlag(Layout::kIndex_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500741 index = this->layoutInt();
742 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700743 case LayoutToken::SET:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500744 setFlag(Layout::kSet_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500745 set = this->layoutInt();
746 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700747 case LayoutToken::BUILTIN:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500748 setFlag(Layout::kBuiltin_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500749 builtin = this->layoutInt();
750 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700751 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500752 setFlag(Layout::kInputAttachmentIndex_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500753 inputAttachmentIndex = this->layoutInt();
754 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700755 case LayoutToken::POINTS:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500756 setPrimitive(Layout::kPoints_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500757 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700758 case LayoutToken::LINES:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500759 setPrimitive(Layout::kLines_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500760 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700761 case LayoutToken::LINE_STRIP:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500762 setPrimitive(Layout::kLineStrip_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500763 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700764 case LayoutToken::LINES_ADJACENCY:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500765 setPrimitive(Layout::kLinesAdjacency_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500766 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700767 case LayoutToken::TRIANGLES:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500768 setPrimitive(Layout::kTriangles_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500769 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700770 case LayoutToken::TRIANGLE_STRIP:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500771 setPrimitive(Layout::kTriangleStrip_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500772 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700773 case LayoutToken::TRIANGLES_ADJACENCY:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500774 setPrimitive(Layout::kTrianglesAdjacency_Primitive);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500775 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700776 case LayoutToken::MAX_VERTICES:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500777 setFlag(Layout::kMaxVertices_Flag);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500778 maxVertices = this->layoutInt();
779 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700780 case LayoutToken::INVOCATIONS:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500781 setFlag(Layout::kInvocations_Flag);
Ethan Nicholas52cad152017-02-16 16:37:32 -0500782 invocations = this->layoutInt();
783 break;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400784 default:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500785 this->error(t, "'" + text + "' is not a valid layout qualifier");
Ethan Nicholasd608c092017-10-26 09:30:08 -0400786 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500787 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700788 } else {
Brian Osmana77ed8b2021-02-23 12:54:22 -0500789 this->error(t, "'" + text + "' is not a valid layout qualifier");
ethannicholasb3058bd2016-07-01 08:22:01 -0700790 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400791 if (this->checkNext(Token::Kind::TK_RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700792 break;
793 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400794 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700795 break;
796 }
797 }
798 }
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500799 return Layout(flags, location, offset, binding, index, set, builtin, inputAttachmentIndex,
Brian Osman8c264792021-07-01 16:41:27 -0400800 primitive, maxVertices, invocations);
ethannicholasb3058bd2016-07-01 08:22:01 -0700801}
802
Brian Osmane49703f2021-04-19 11:15:24 -0400803/* layout? (UNIFORM | CONST | IN | OUT | INOUT | FLAT | NOPERSPECTIVE | INLINE)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500804Modifiers Parser::modifiers() {
805 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700806 int flags = 0;
807 for (;;) {
808 // TODO: handle duplicate / incompatible flags
John Stiles7d5b90a2021-01-21 14:26:51 -0500809 int tokenFlag = parse_modifier_token(peek().fKind);
810 if (!tokenFlag) {
811 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700812 }
John Stiles7d5b90a2021-01-21 14:26:51 -0500813 flags |= tokenFlag;
814 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -0700815 }
John Stiles7d5b90a2021-01-21 14:26:51 -0500816 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700817}
818
Ethan Nicholas11d53972016-11-28 11:23:23 -0500819Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
820 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700821 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500822 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700823 }
824 return result;
825}
826
827/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400828ASTNode::ID Parser::statement() {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -0400829 Token start = this->nextToken();
830 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -0400831 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -0400832 return ASTNode::ID::Invalid();
833 }
834 this->pushback(start);
ethannicholasb3058bd2016-07-01 08:22:01 -0700835 switch (start.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400836 case Token::Kind::TK_IF: // fall through
837 case Token::Kind::TK_STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -0700838 return this->ifStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400839 case Token::Kind::TK_FOR:
ethannicholasb3058bd2016-07-01 08:22:01 -0700840 return this->forStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400841 case Token::Kind::TK_DO:
ethannicholasb3058bd2016-07-01 08:22:01 -0700842 return this->doStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400843 case Token::Kind::TK_WHILE:
ethannicholasb3058bd2016-07-01 08:22:01 -0700844 return this->whileStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400845 case Token::Kind::TK_SWITCH: // fall through
846 case Token::Kind::TK_STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500847 return this->switchStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400848 case Token::Kind::TK_RETURN:
ethannicholasb3058bd2016-07-01 08:22:01 -0700849 return this->returnStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400850 case Token::Kind::TK_BREAK:
ethannicholasb3058bd2016-07-01 08:22:01 -0700851 return this->breakStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400852 case Token::Kind::TK_CONTINUE:
ethannicholasb3058bd2016-07-01 08:22:01 -0700853 return this->continueStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400854 case Token::Kind::TK_DISCARD:
ethannicholasb3058bd2016-07-01 08:22:01 -0700855 return this->discardStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400856 case Token::Kind::TK_LBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -0700857 return this->block();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400858 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500859 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -0500860 return this->createNode(start.fOffset, ASTNode::Kind::kBlock);
John Stiles02014312021-08-04 16:03:12 -0400861 case Token::Kind::TK_HIGHP:
862 case Token::Kind::TK_MEDIUMP:
863 case Token::Kind::TK_LOWP:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400864 case Token::Kind::TK_CONST:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400865 case Token::Kind::TK_IDENTIFIER:
John Stiles76389b72021-01-25 13:49:05 -0500866 return this->varDeclarationsOrExpressionStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700867 default:
868 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500869 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700870}
871
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500872/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400873ASTNode::ID Parser::type() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700874 Token type;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400875 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400876 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700877 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700878 if (!this->isType(this->text(type))) {
879 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
Ethan Nicholasfc994162019-06-06 10:04:27 -0400880 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700881 }
Brian Osman00fea5b2021-01-28 09:46:30 -0500882 ASTNode::ID result = this->createNode(type.fOffset, ASTNode::Kind::kType, this->text(type));
John Stilesd39aec92020-12-03 14:37:16 -0500883 bool isArray = false;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400884 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -0500885 if (isArray) {
886 this->error(this->peek(), "multi-dimensional arrays are not supported");
887 return ASTNode::ID::Invalid();
888 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400889 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400890 SKSL_INT i;
Ethan Nicholas50afc172017-02-16 14:49:57 -0500891 if (this->intLiteral(&i)) {
John Stiles08070f62020-11-17 10:45:49 -0500892 this->addChild(result, this->createNode(this->peek().fOffset,
893 ASTNode::Kind::kInt, i));
Ethan Nicholas50afc172017-02-16 14:49:57 -0500894 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400895 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500896 }
897 } else {
John Stiles3b209362020-11-16 17:03:10 -0500898 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500899 }
John Stilesd39aec92020-12-03 14:37:16 -0500900 isArray = true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 this->expect(Token::Kind::TK_RBRACKET, "']'");
Ethan Nicholas50afc172017-02-16 14:49:57 -0500902 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400903 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700904}
905
John Stiles57a996b2020-04-19 19:05:12 -0700906/* IDENTIFIER LBRACE
907 varDeclaration+
908 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400909ASTNode::ID Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700910 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500911 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400912 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700913 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400914 if (peek().fKind != Token::Kind::TK_LBRACE) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700915 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500916 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700917 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700918 this->error(name, "no type named '" + this->text(name) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400919 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700920 }
John Stiles3b209362020-11-16 17:03:10 -0500921 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kInterfaceBlock);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400922 ASTNode::InterfaceBlockData id(mods, this->text(name), 0, "", 0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700923 this->nextToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400924 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400925 ASTNode::ID decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700926 if (!decl) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400927 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700928 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400929 getNode(result).addChild(decl);
930 ++id.fDeclarationCount;
ethannicholasb3058bd2016-07-01 08:22:01 -0700931 }
John Stiles57a996b2020-04-19 19:05:12 -0700932 if (id.fDeclarationCount == 0) {
933 this->error(name, "interface block '" + this->text(name) +
934 "' must contain at least one member");
935 return ASTNode::ID::Invalid();
936 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700937 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400938 std::vector<ASTNode> sizes;
Ethan Nicholas962dec42021-06-10 13:06:39 -0400939 skstd::string_view instanceName;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700940 Token instanceNameToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400941 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400942 id.fInstanceName = this->text(instanceNameToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400943 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -0500944 if (id.fIsArray) {
945 this->error(this->peek(), "multi-dimensional arrays are not supported");
946 return false;
947 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400948 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400949 ASTNode::ID size = this->expression();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500950 if (!size) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400951 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500952 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400953 getNode(result).addChild(size);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500954 } else {
John Stiles3b209362020-11-16 17:03:10 -0500955 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500956 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400957 this->expect(Token::Kind::TK_RBRACKET, "']'");
John Stilesd39aec92020-12-03 14:37:16 -0500958 id.fIsArray = true;
Ethan Nicholas50afc172017-02-16 14:49:57 -0500959 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700960 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -0700961 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400962 getNode(result).setInterfaceBlockData(id);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400963 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400964 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700965}
966
967/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400968ASTNode::ID Parser::ifStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700969 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400970 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
971 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400972 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700973 }
John Stiles3b209362020-11-16 17:03:10 -0500974 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kIf, isStatic);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400975 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400976 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700977 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400978 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700979 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400980 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700981 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400982 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400983 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400984 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700985 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400986 ASTNode::ID ifTrue = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700987 if (!ifTrue) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400988 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700989 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400990 getNode(result).addChild(ifTrue);
991 ASTNode::ID ifFalse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400992 if (this->checkNext(Token::Kind::TK_ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700993 ifFalse = this->statement();
994 if (!ifFalse) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400995 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700996 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400997 getNode(result).addChild(ifFalse);
ethannicholasb3058bd2016-07-01 08:22:01 -0700998 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400999 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001000}
1001
1002/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001003ASTNode::ID Parser::doStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001005 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001006 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001007 }
John Stiles3b209362020-11-16 17:03:10 -05001008 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kDo);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001009 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001010 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001011 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001012 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001013 getNode(result).addChild(statement);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001014 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001015 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001016 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001017 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001018 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001020 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001022 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001023 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001024 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001025 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001026 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001028 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001029 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001030 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001031 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001032}
1033
1034/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001035ASTNode::ID Parser::whileStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001036 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001037 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001038 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001039 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001040 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001041 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 }
John Stiles3b209362020-11-16 17:03:10 -05001043 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kWhile);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001044 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001045 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001046 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001048 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001049 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001050 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001052 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001054 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001056 getNode(result).addChild(statement);
1057 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001058}
1059
Ethan Nicholasaf197692017-02-27 13:26:45 -05001060/* CASE expression COLON statement* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001061ASTNode::ID Parser::switchCase() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001062 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001063 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001064 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001065 }
John Stiles3b209362020-11-16 17:03:10 -05001066 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitchCase);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001067 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001068 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001069 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001070 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001071 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001072 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001073 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001074 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001075 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1076 this->peek().fKind != Token::Kind::TK_CASE &&
1077 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001078 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001079 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001080 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001081 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001082 getNode(result).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001083 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001084 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001085}
1086
1087/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001088ASTNode::ID Parser::switchStatement() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001089 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001090 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1091 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001092 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001093 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001094 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001095 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001096 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001097 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001098 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001099 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001100 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001101 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001102 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001103 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001104 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001105 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001106 }
John Stiles3b209362020-11-16 17:03:10 -05001107 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitch, isStatic);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001108 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001109 while (this->peek().fKind == Token::Kind::TK_CASE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001110 ASTNode::ID c = this->switchCase();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001111 if (!c) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001112 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001113 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001114 getNode(result).addChild(c);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001115 }
1116 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1117 // parts of the compiler may rely upon this assumption.
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001118 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001119 Token defaultStart;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001120 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1121 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001122 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001123 }
John Stiles3b209362020-11-16 17:03:10 -05001124 ASTNode::ID defaultCase = this->addChild(
1125 result, this->createNode(defaultStart.fOffset, ASTNode::Kind::kSwitchCase));
1126 this->createEmptyChild(defaultCase); // empty test to signify default case
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001127 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001128 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001129 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001130 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001131 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001132 getNode(defaultCase).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001133 }
Ethan Nicholasaf197692017-02-27 13:26:45 -05001134 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001135 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001136 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001137 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001138 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001139}
1140
Ethan Nicholas11d53972016-11-28 11:23:23 -05001141/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001142 STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001143ASTNode::ID Parser::forStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001145 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001146 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001147 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001148 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001149 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001150 }
John Stiles3b209362020-11-16 17:03:10 -05001151 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kFor);
ethannicholasb3058bd2016-07-01 08:22:01 -07001152 Token nextToken = this->peek();
John Stiles89b484a2021-04-19 14:57:27 -04001153 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1154 // An empty init-statement.
1155 this->nextToken();
1156 this->createEmptyChild(result);
1157 } else {
1158 // The init-statement must be an expression or variable declaration.
1159 ASTNode::ID initializer = this->varDeclarationsOrExpressionStatement();
1160 if (!initializer) {
1161 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001162 }
John Stiles89b484a2021-04-19 14:57:27 -04001163 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001164 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001165 ASTNode::ID test;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001166 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001167 test = this->expression();
1168 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001169 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001170 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001171 getNode(result).addChild(test);
1172 } else {
John Stiles3b209362020-11-16 17:03:10 -05001173 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001174 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001175 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001176 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001177 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001178 ASTNode::ID next;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001179 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001180 next = this->expression();
1181 if (!next) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001182 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001183 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001184 getNode(result).addChild(next);
1185 } else {
John Stiles3b209362020-11-16 17:03:10 -05001186 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001187 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001188 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001189 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001190 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001191 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001192 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001193 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001194 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001195 getNode(result).addChild(statement);
1196 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001197}
1198
1199/* RETURN expression? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001200ASTNode::ID Parser::returnStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001201 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001202 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001203 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001204 }
John Stiles3b209362020-11-16 17:03:10 -05001205 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kReturn);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001206 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001207 ASTNode::ID expression = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001208 if (!expression) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001209 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001210 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001211 getNode(result).addChild(expression);
ethannicholasb3058bd2016-07-01 08:22:01 -07001212 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001213 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001214 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001215 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001216 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001217}
1218
1219/* BREAK SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001220ASTNode::ID Parser::breakStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001221 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001222 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001223 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001224 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001225 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001226 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001227 }
John Stiles3b209362020-11-16 17:03:10 -05001228 return this->createNode(start.fOffset, ASTNode::Kind::kBreak);
ethannicholasb3058bd2016-07-01 08:22:01 -07001229}
1230
1231/* CONTINUE SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001232ASTNode::ID Parser::continueStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001233 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001234 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001235 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001236 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001237 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001238 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001239 }
John Stiles3b209362020-11-16 17:03:10 -05001240 return this->createNode(start.fOffset, ASTNode::Kind::kContinue);
ethannicholasb3058bd2016-07-01 08:22:01 -07001241}
1242
1243/* DISCARD SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001244ASTNode::ID Parser::discardStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001245 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001246 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001247 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001248 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001249 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001250 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001251 }
John Stiles3b209362020-11-16 17:03:10 -05001252 return this->createNode(start.fOffset, ASTNode::Kind::kDiscard);
ethannicholasb3058bd2016-07-01 08:22:01 -07001253}
1254
1255/* LBRACE statement* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001256ASTNode::ID Parser::block() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001257 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001258 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001259 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001260 }
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001261 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001262 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001263 return ASTNode::ID::Invalid();
1264 }
John Stiles3b209362020-11-16 17:03:10 -05001265 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -07001266 for (;;) {
1267 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001268 case Token::Kind::TK_RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001269 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001270 return result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001271 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001272 this->error(this->peek(), "expected '}', but found end of file");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001273 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001274 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001275 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001276 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001277 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001278 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001279 getNode(result).addChild(statement);
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 }
1281 }
1282 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001283 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001284}
1285
1286/* expression SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001287ASTNode::ID Parser::expressionStatement() {
1288 ASTNode::ID expr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001289 if (expr) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001290 if (this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001291 return expr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001292 }
1293 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001294 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001295}
1296
1297/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001298ASTNode::ID Parser::expression() {
1299 ASTNode::ID result = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001300 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001301 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001302 }
1303 Token t;
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001304 AutoDepth depth(this);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001305 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001306 if (!depth.increase()) {
1307 return ASTNode::ID::Invalid();
1308 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001309 ASTNode::ID right = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001310 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001311 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001312 }
John Stiles45990502021-02-16 10:55:27 -05001313 ASTNode::ID newResult = this->createNode(t.fOffset, ASTNode::Kind::kBinary,
1314 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001315 getNode(newResult).addChild(result);
1316 getNode(newResult).addChild(right);
1317 result = newResult;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001318 }
1319 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001320}
1321
1322/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1323 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1324 assignmentExpression)*
1325 */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001326ASTNode::ID Parser::assignmentExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001327 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001328 ASTNode::ID result = this->ternaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001329 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001330 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001331 }
1332 for (;;) {
1333 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001334 case Token::Kind::TK_EQ: // fall through
1335 case Token::Kind::TK_STAREQ: // fall through
1336 case Token::Kind::TK_SLASHEQ: // fall through
1337 case Token::Kind::TK_PERCENTEQ: // fall through
1338 case Token::Kind::TK_PLUSEQ: // fall through
1339 case Token::Kind::TK_MINUSEQ: // fall through
1340 case Token::Kind::TK_SHLEQ: // fall through
1341 case Token::Kind::TK_SHREQ: // fall through
1342 case Token::Kind::TK_BITWISEANDEQ: // fall through
1343 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05001344 case Token::Kind::TK_BITWISEOREQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001345 if (!depth.increase()) {
1346 return ASTNode::ID::Invalid();
1347 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001348 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001349 ASTNode::ID right = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001350 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001351 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001352 }
John Stiles3b209362020-11-16 17:03:10 -05001353 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001354 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001355 getNode(newResult).addChild(result);
1356 getNode(newResult).addChild(right);
1357 result = newResult;
1358 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001359 }
1360 default:
1361 return result;
1362 }
1363 }
1364}
1365
1366/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001367ASTNode::ID Parser::ternaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001368 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001369 ASTNode::ID base = this->logicalOrExpression();
1370 if (!base) {
1371 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001372 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001373 if (this->checkNext(Token::Kind::TK_QUESTION)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001374 if (!depth.increase()) {
1375 return ASTNode::ID::Invalid();
1376 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001377 ASTNode::ID trueExpr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001378 if (!trueExpr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001379 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001380 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001381 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001382 ASTNode::ID falseExpr = this->assignmentExpression();
1383 if (!falseExpr) {
1384 return ASTNode::ID::Invalid();
1385 }
John Stiles3b209362020-11-16 17:03:10 -05001386 ASTNode::ID ternary = this->createNode(getNode(base).fOffset, ASTNode::Kind::kTernary);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001387 getNode(ternary).addChild(base);
1388 getNode(ternary).addChild(trueExpr);
1389 getNode(ternary).addChild(falseExpr);
1390 return ternary;
ethannicholasb3058bd2016-07-01 08:22:01 -07001391 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001392 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001393 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001394 return base;
ethannicholasb3058bd2016-07-01 08:22:01 -07001395}
1396
1397/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001398ASTNode::ID Parser::logicalOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001399 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001400 ASTNode::ID result = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001401 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001402 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001403 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001404 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001405 while (this->checkNext(Token::Kind::TK_LOGICALOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001406 if (!depth.increase()) {
1407 return ASTNode::ID::Invalid();
1408 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001409 ASTNode::ID right = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001410 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001411 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001412 }
John Stiles3b209362020-11-16 17:03:10 -05001413 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001414 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001415 getNode(newResult).addChild(result);
1416 getNode(newResult).addChild(right);
1417 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001418 }
1419 return result;
1420}
1421
1422/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001423ASTNode::ID Parser::logicalXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001424 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001425 ASTNode::ID result = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001426 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001427 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001429 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001430 while (this->checkNext(Token::Kind::TK_LOGICALXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001431 if (!depth.increase()) {
1432 return ASTNode::ID::Invalid();
1433 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001434 ASTNode::ID right = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001435 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001436 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001437 }
John Stiles3b209362020-11-16 17:03:10 -05001438 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001439 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001440 getNode(newResult).addChild(result);
1441 getNode(newResult).addChild(right);
1442 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001443 }
1444 return result;
1445}
1446
1447/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001448ASTNode::ID Parser::logicalAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001449 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001450 ASTNode::ID result = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001451 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001452 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001454 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001455 while (this->checkNext(Token::Kind::TK_LOGICALAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001456 if (!depth.increase()) {
1457 return ASTNode::ID::Invalid();
1458 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001459 ASTNode::ID right = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001460 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001461 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001462 }
John Stiles3b209362020-11-16 17:03:10 -05001463 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001464 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001465 getNode(newResult).addChild(result);
1466 getNode(newResult).addChild(right);
1467 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001468 }
1469 return result;
1470}
1471
1472/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001473ASTNode::ID Parser::bitwiseOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001474 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001475 ASTNode::ID result = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001476 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001477 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001479 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001480 while (this->checkNext(Token::Kind::TK_BITWISEOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001481 if (!depth.increase()) {
1482 return ASTNode::ID::Invalid();
1483 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001484 ASTNode::ID right = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001485 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001486 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001487 }
John Stiles45990502021-02-16 10:55:27 -05001488 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1489 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001490 getNode(newResult).addChild(result);
1491 getNode(newResult).addChild(right);
1492 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001493 }
1494 return result;
1495}
1496
1497/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001498ASTNode::ID Parser::bitwiseXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001499 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001500 ASTNode::ID result = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001502 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001503 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001504 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001505 while (this->checkNext(Token::Kind::TK_BITWISEXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001506 if (!depth.increase()) {
1507 return ASTNode::ID::Invalid();
1508 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001509 ASTNode::ID right = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001510 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001511 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 }
John Stiles45990502021-02-16 10:55:27 -05001513 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1514 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001515 getNode(newResult).addChild(result);
1516 getNode(newResult).addChild(right);
1517 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001518 }
1519 return result;
1520}
1521
1522/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001523ASTNode::ID Parser::bitwiseAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001524 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001525 ASTNode::ID result = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001527 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001528 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001529 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001530 while (this->checkNext(Token::Kind::TK_BITWISEAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001531 if (!depth.increase()) {
1532 return ASTNode::ID::Invalid();
1533 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001534 ASTNode::ID right = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001535 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001536 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001537 }
John Stiles3b209362020-11-16 17:03:10 -05001538 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001539 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001540 getNode(newResult).addChild(result);
1541 getNode(newResult).addChild(right);
1542 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001543 }
1544 return result;
1545}
1546
1547/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001548ASTNode::ID Parser::equalityExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001549 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001550 ASTNode::ID result = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001551 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001552 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 }
1554 for (;;) {
1555 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001556 case Token::Kind::TK_EQEQ: // fall through
1557 case Token::Kind::TK_NEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001558 if (!depth.increase()) {
1559 return ASTNode::ID::Invalid();
1560 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001561 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001562 ASTNode::ID right = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001563 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001564 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 }
John Stiles3b209362020-11-16 17:03:10 -05001566 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001567 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001568 getNode(newResult).addChild(result);
1569 getNode(newResult).addChild(right);
1570 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 break;
1572 }
1573 default:
1574 return result;
1575 }
1576 }
1577}
1578
1579/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001580ASTNode::ID Parser::relationalExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001581 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001582 ASTNode::ID result = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001584 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001585 }
1586 for (;;) {
1587 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001588 case Token::Kind::TK_LT: // fall through
1589 case Token::Kind::TK_GT: // fall through
1590 case Token::Kind::TK_LTEQ: // fall through
1591 case Token::Kind::TK_GTEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001592 if (!depth.increase()) {
1593 return ASTNode::ID::Invalid();
1594 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001596 ASTNode::ID right = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001598 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001599 }
John Stiles3b209362020-11-16 17:03:10 -05001600 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001601 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001602 getNode(newResult).addChild(result);
1603 getNode(newResult).addChild(right);
1604 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001605 break;
1606 }
1607 default:
1608 return result;
1609 }
1610 }
1611}
1612
1613/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001614ASTNode::ID Parser::shiftExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001615 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001616 ASTNode::ID result = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001617 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001618 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001619 }
1620 for (;;) {
1621 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001622 case Token::Kind::TK_SHL: // fall through
1623 case Token::Kind::TK_SHR: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001624 if (!depth.increase()) {
1625 return ASTNode::ID::Invalid();
1626 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001627 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001628 ASTNode::ID right = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001629 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001630 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 }
John Stiles3b209362020-11-16 17:03:10 -05001632 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001633 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001634 getNode(newResult).addChild(result);
1635 getNode(newResult).addChild(right);
1636 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 break;
1638 }
1639 default:
1640 return result;
1641 }
1642 }
1643}
1644
1645/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001646ASTNode::ID Parser::additiveExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001647 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001648 ASTNode::ID result = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001649 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001650 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001651 }
1652 for (;;) {
1653 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001654 case Token::Kind::TK_PLUS: // fall through
1655 case Token::Kind::TK_MINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001656 if (!depth.increase()) {
1657 return ASTNode::ID::Invalid();
1658 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001659 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001660 ASTNode::ID right = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001661 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001662 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001663 }
John Stiles3b209362020-11-16 17:03:10 -05001664 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001665 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001666 getNode(newResult).addChild(result);
1667 getNode(newResult).addChild(right);
1668 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001669 break;
1670 }
1671 default:
1672 return result;
1673 }
1674 }
1675}
1676
1677/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001678ASTNode::ID Parser::multiplicativeExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001679 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001680 ASTNode::ID result = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001681 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001682 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001683 }
1684 for (;;) {
1685 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001686 case Token::Kind::TK_STAR: // fall through
1687 case Token::Kind::TK_SLASH: // fall through
1688 case Token::Kind::TK_PERCENT: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001689 if (!depth.increase()) {
1690 return ASTNode::ID::Invalid();
1691 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001692 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001693 ASTNode::ID right = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001694 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001695 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001696 }
John Stiles3b209362020-11-16 17:03:10 -05001697 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001698 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001699 getNode(newResult).addChild(result);
1700 getNode(newResult).addChild(right);
1701 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001702 break;
1703 }
1704 default:
1705 return result;
1706 }
1707 }
1708}
1709
1710/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001711ASTNode::ID Parser::unaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001712 AutoDepth depth(this);
ethannicholasb3058bd2016-07-01 08:22:01 -07001713 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001714 case Token::Kind::TK_PLUS: // fall through
1715 case Token::Kind::TK_MINUS: // fall through
1716 case Token::Kind::TK_LOGICALNOT: // fall through
1717 case Token::Kind::TK_BITWISENOT: // fall through
1718 case Token::Kind::TK_PLUSPLUS: // fall through
1719 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001720 if (!depth.increase()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001721 return ASTNode::ID::Invalid();
Ethan Nicholas6dcc3252019-02-20 15:18:36 -05001722 }
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001723 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001724 ASTNode::ID expr = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001726 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001727 }
John Stiles45990502021-02-16 10:55:27 -05001728 ASTNode::ID result = this->createNode(t.fOffset, ASTNode::Kind::kPrefix,
1729 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001730 getNode(result).addChild(expr);
1731 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001732 }
1733 default:
1734 return this->postfixExpression();
1735 }
1736}
1737
1738/* term suffix* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001739ASTNode::ID Parser::postfixExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001740 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001741 ASTNode::ID result = this->term();
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001743 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001744 }
1745 for (;;) {
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04001746 Token t = this->peek();
1747 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001748 case Token::Kind::TK_FLOAT_LITERAL:
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04001749 if (this->text(t)[0] != '.') {
1750 return result;
1751 }
John Stiles30212b72020-06-11 17:55:07 -04001752 [[fallthrough]];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001753 case Token::Kind::TK_LBRACKET:
1754 case Token::Kind::TK_DOT:
1755 case Token::Kind::TK_LPAREN:
1756 case Token::Kind::TK_PLUSPLUS:
1757 case Token::Kind::TK_MINUSMINUS:
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001758 if (!depth.increase()) {
1759 return ASTNode::ID::Invalid();
1760 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001761 result = this->suffix(result);
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001762 if (!result) {
1763 return ASTNode::ID::Invalid();
1764 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001765 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001766 default:
1767 return result;
1768 }
1769 }
1770}
1771
Ethan Nicholas11d53972016-11-28 11:23:23 -05001772/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
Brian Osmanc9145f32021-07-08 13:40:10 -04001773 PLUSPLUS | MINUSMINUS | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001774ASTNode::ID Parser::suffix(ASTNode::ID base) {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001775 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 Token next = this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001777 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001778 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001779 return ASTNode::ID::Invalid();
1780 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001781 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001782 case Token::Kind::TK_LBRACKET: {
1783 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -05001784 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001785 getNode(result).addChild(base);
1786 return result;
ethannicholas5961bc92016-10-12 06:39:56 -07001787 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001788 ASTNode::ID e = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001789 if (!e) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001790 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001792 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
John Stiles3b209362020-11-16 17:03:10 -05001793 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001794 getNode(result).addChild(base);
1795 getNode(result).addChild(e);
1796 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 }
Brian Osman6518d772020-09-10 16:50:06 -04001798 case Token::Kind::TK_DOT: {
1799 int offset = this->peek().fOffset;
Ethan Nicholas962dec42021-06-10 13:06:39 -04001800 skstd::string_view text;
Brian Osman6518d772020-09-10 16:50:06 -04001801 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05001802 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kField,
1803 std::move(text));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001804 getNode(result).addChild(base);
1805 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001806 }
Brian Osman6518d772020-09-10 16:50:06 -04001807 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04001808 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001809 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholase455f652019-09-13 12:52:55 -04001810 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1811 // floating point literals, possibly followed by an identifier. Handle that here.
Ethan Nicholas962dec42021-06-10 13:06:39 -04001812 skstd::string_view field = this->text(next);
Ethan Nicholasd2e09602021-06-10 11:21:59 -04001813 SkASSERT(field[0] == '.');
1814 field.remove_prefix(1);
1815 for (auto iter = field.begin(); iter != field.end(); ++iter) {
1816 if (*iter != '0' && *iter != '1') {
Ethan Nicholase455f652019-09-13 12:52:55 -04001817 this->error(next, "invalid swizzle");
1818 return ASTNode::ID::Invalid();
1819 }
1820 }
1821 // use the next *raw* token so we don't ignore whitespace - we only care about
1822 // identifiers that directly follow the float
1823 Token id = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001824 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas962dec42021-06-10 13:06:39 -04001825 field = skstd::string_view(field.data(), field.length() + id.fLength);
Ethan Nicholase455f652019-09-13 12:52:55 -04001826 } else {
1827 this->pushback(id);
1828 }
John Stiles3b209362020-11-16 17:03:10 -05001829 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kField, field);
Ethan Nicholase455f652019-09-13 12:52:55 -04001830 getNode(result).addChild(base);
1831 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001832 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001833 case Token::Kind::TK_LPAREN: {
John Stiles3b209362020-11-16 17:03:10 -05001834 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kCall);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001835 getNode(result).addChild(base);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001836 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001837 for (;;) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001838 ASTNode::ID expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001839 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001840 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001842 getNode(result).addChild(expr);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001843 if (!this->checkNext(Token::Kind::TK_COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001844 break;
1845 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001846 }
1847 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001848 this->expect(Token::Kind::TK_RPAREN, "')' to complete function parameters");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001849 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001851 case Token::Kind::TK_PLUSPLUS: // fall through
1852 case Token::Kind::TK_MINUSMINUS: {
John Stiles45990502021-02-16 10:55:27 -05001853 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kPostfix,
1854 Operator(next.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001855 getNode(result).addChild(base);
1856 return result;
1857 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 default: {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001859 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001860 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001861 }
1862 }
1863}
1864
Brian Osman33c64a42020-12-23 10:26:38 -05001865/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001866ASTNode::ID Parser::term() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001867 Token t = this->peek();
1868 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001869 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas962dec42021-06-10 13:06:39 -04001870 skstd::string_view text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001871 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05001872 return this->createNode(t.fOffset, ASTNode::Kind::kIdentifier, std::move(text));
ethannicholasb3058bd2016-07-01 08:22:01 -07001873 }
John Stiles30212b72020-06-11 17:55:07 -04001874 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001875 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001876 case Token::Kind::TK_INT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001877 SKSL_INT i;
ethannicholasb3058bd2016-07-01 08:22:01 -07001878 if (this->intLiteral(&i)) {
John Stiles3b209362020-11-16 17:03:10 -05001879 return this->createNode(t.fOffset, ASTNode::Kind::kInt, i);
ethannicholasb3058bd2016-07-01 08:22:01 -07001880 }
1881 break;
1882 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001883 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001884 SKSL_FLOAT f;
ethannicholasb3058bd2016-07-01 08:22:01 -07001885 if (this->floatLiteral(&f)) {
John Stiles3b209362020-11-16 17:03:10 -05001886 return this->createNode(t.fOffset, ASTNode::Kind::kFloat, f);
ethannicholasb3058bd2016-07-01 08:22:01 -07001887 }
1888 break;
1889 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001890 case Token::Kind::TK_TRUE_LITERAL: // fall through
1891 case Token::Kind::TK_FALSE_LITERAL: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001892 bool b;
1893 if (this->boolLiteral(&b)) {
John Stiles3b209362020-11-16 17:03:10 -05001894 return this->createNode(t.fOffset, ASTNode::Kind::kBool, b);
ethannicholasb3058bd2016-07-01 08:22:01 -07001895 }
1896 break;
1897 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001898 case Token::Kind::TK_LPAREN: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001899 this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001900 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001901 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001902 return ASTNode::ID::Invalid();
1903 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001904 ASTNode::ID result = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001905 if (result) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001906 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001907 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001908 }
1909 break;
1910 }
1911 default:
1912 this->nextToken();
John Stilesf94348f2020-12-23 18:58:43 -05001913 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001914 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001915 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001916}
1917
1918/* INT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001919bool Parser::intLiteral(SKSL_INT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001920 Token t;
John Stilesf94348f2020-12-23 18:58:43 -05001921 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1922 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -07001923 }
Ethan Nicholas962dec42021-06-10 13:06:39 -04001924 skstd::string_view s = this->text(t);
John Stilesf94348f2020-12-23 18:58:43 -05001925 if (!SkSL::stoi(s, dest)) {
1926 this->error(t, "integer is too large: " + s);
1927 return false;
1928 }
1929 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001930}
1931
John Stilesf94348f2020-12-23 18:58:43 -05001932
ethannicholasb3058bd2016-07-01 08:22:01 -07001933/* FLOAT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001934bool Parser::floatLiteral(SKSL_FLOAT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001935 Token t;
John Stilesf94348f2020-12-23 18:58:43 -05001936 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1937 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -07001938 }
Ethan Nicholas962dec42021-06-10 13:06:39 -04001939 skstd::string_view s = this->text(t);
John Stilesf94348f2020-12-23 18:58:43 -05001940 if (!SkSL::stod(s, dest)) {
1941 this->error(t, "floating-point value is too large: " + s);
1942 return false;
1943 }
1944 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001945}
1946
1947/* TRUE_LITERAL | FALSE_LITERAL */
1948bool Parser::boolLiteral(bool* dest) {
1949 Token t = this->nextToken();
1950 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001951 case Token::Kind::TK_TRUE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07001952 *dest = true;
1953 return true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001954 case Token::Kind::TK_FALSE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 *dest = false;
1956 return true;
1957 default:
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001958 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001959 return false;
1960 }
1961}
1962
1963/* IDENTIFIER */
Ethan Nicholas962dec42021-06-10 13:06:39 -04001964bool Parser::identifier(skstd::string_view* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001965 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001966 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001967 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07001968 return true;
1969 }
1970 return false;
1971}
1972
John Stilesa6841be2020-08-06 14:11:56 -04001973} // namespace SkSL