blob: 9d7de5d47ac51854166f0ca63b0252a852c79716 [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");
Brian Osmanb32d66b2020-04-30 17:12:03 -0400103 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400104 #undef TOKEN
105}
106
Ethan Nicholas6823b502021-06-15 11:42:07 -0400107Parser::Parser(skstd::string_view text, SymbolTable& symbols, ErrorReporter& errors)
108: fText(text)
John Stiles7cbb09c22021-01-07 16:07:00 -0500109, fPushback(Token::Kind::TK_NONE, -1, -1)
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400110, fSymbols(symbols)
Ethan Nicholas55478662021-08-10 17:14:26 -0400111, fErrors(&errors) {
Ethan Nicholas6823b502021-06-15 11:42:07 -0400112 fLexer.start(text);
Brian Salomon3b83afe2018-08-23 11:04:36 -0400113 static const bool layoutMapInitialized = []{ return (void)InitLayoutMap(), true; }();
114 (void) layoutMapInitialized;
ethannicholasb3058bd2016-07-01 08:22:01 -0700115}
116
John Stiles3b209362020-11-16 17:03:10 -0500117template <typename... Args>
118ASTNode::ID Parser::createNode(Args&&... args) {
119 ASTNode::ID result(fFile->fNodes.size());
120 fFile->fNodes.emplace_back(&fFile->fNodes, std::forward<Args>(args)...);
121 return result;
122}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400123
John Stiles3b209362020-11-16 17:03:10 -0500124ASTNode::ID Parser::addChild(ASTNode::ID target, ASTNode::ID child) {
125 fFile->fNodes[target.fValue].addChild(child);
126 return child;
127}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400128
John Stiles3b209362020-11-16 17:03:10 -0500129void Parser::createEmptyChild(ASTNode::ID target) {
130 ASTNode::ID child(fFile->fNodes.size());
131 fFile->fNodes.emplace_back();
132 fFile->fNodes[target.fValue].addChild(child);
133}
Ethan Nicholasfc994162019-06-06 10:04:27 -0400134
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400135/* (directive | section | declaration)* END_OF_FILE */
Ethan Nicholasba9a04f2020-11-06 09:28:04 -0500136std::unique_ptr<ASTFile> Parser::compilationUnit() {
John Stilesfbd050b2020-08-03 13:21:46 -0400137 fFile = std::make_unique<ASTFile>();
John Stiles18a45b32021-03-29 18:07:32 -0400138 fFile->fNodes.reserve(fText.size() / 10); // a typical program is approx 10:1 for chars:nodes
John Stiles3b209362020-11-16 17:03:10 -0500139 ASTNode::ID result = this->createNode(/*offset=*/0, ASTNode::Kind::kFile);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400140 fFile->fRoot = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700141 for (;;) {
142 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400143 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholasfc994162019-06-06 10:04:27 -0400144 return std::move(fFile);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400145 case Token::Kind::TK_DIRECTIVE: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400146 ASTNode::ID dir = this->directive();
Ethan Nicholas55478662021-08-10 17:14:26 -0400147 if (fErrors->errorCount()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400148 return nullptr;
149 }
150 if (dir) {
151 getNode(result).addChild(dir);
ethannicholasb3058bd2016-07-01 08:22:01 -0700152 }
153 break;
154 }
John Stiles7cbb09c22021-01-07 16:07:00 -0500155 case Token::Kind::TK_INVALID: {
156 this->error(this->peek(), String("invalid token"));
157 return nullptr;
158 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700159 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400160 ASTNode::ID decl = this->declaration();
Ethan Nicholas55478662021-08-10 17:14:26 -0400161 if (fErrors->errorCount()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400162 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700163 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400164 if (decl) {
165 getNode(result).addChild(decl);
166 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 }
168 }
169 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400170 return std::move(fFile);
ethannicholasb3058bd2016-07-01 08:22:01 -0700171}
172
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700173Token Parser::nextRawToken() {
John Stiles7cbb09c22021-01-07 16:07:00 -0500174 if (fPushback.fKind != Token::Kind::TK_NONE) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700175 Token result = fPushback;
John Stiles7cbb09c22021-01-07 16:07:00 -0500176 fPushback.fKind = Token::Kind::TK_NONE;
ethannicholasb3058bd2016-07-01 08:22:01 -0700177 return result;
178 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700179 Token result = fLexer.next();
180 return result;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400181}
182
183Token Parser::nextToken() {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700184 Token token = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400185 while (token.fKind == Token::Kind::TK_WHITESPACE ||
186 token.fKind == Token::Kind::TK_LINE_COMMENT ||
187 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700188 token = this->nextRawToken();
189 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400190 return token;
ethannicholasb3058bd2016-07-01 08:22:01 -0700191}
192
193void Parser::pushback(Token t) {
John Stiles7cbb09c22021-01-07 16:07:00 -0500194 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400195 fPushback = std::move(t);
ethannicholasb3058bd2016-07-01 08:22:01 -0700196}
197
198Token Parser::peek() {
John Stiles7cbb09c22021-01-07 16:07:00 -0500199 if (fPushback.fKind == Token::Kind::TK_NONE) {
Brian Osman634624a2017-08-15 11:14:30 -0400200 fPushback = this->nextToken();
201 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700202 return fPushback;
203}
204
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400205bool Parser::checkNext(Token::Kind kind, Token* result) {
John Stiles7cbb09c22021-01-07 16:07:00 -0500206 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
Brian Osman634624a2017-08-15 11:14:30 -0400207 return false;
208 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400209 Token next = this->nextToken();
210 if (next.fKind == kind) {
211 if (result) {
212 *result = next;
213 }
214 return true;
215 }
Ethan Nicholas08b79b72017-08-14 10:35:37 -0400216 this->pushback(std::move(next));
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400217 return false;
218}
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500219
220bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700221 Token next = this->nextToken();
222 if (next.fKind == kind) {
223 if (result) {
Brian Osman634624a2017-08-15 11:14:30 -0400224 *result = std::move(next);
ethannicholasb3058bd2016-07-01 08:22:01 -0700225 }
226 return true;
227 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700228 this->error(next, "expected " + String(expected) + ", but found '" +
229 this->text(next) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700230 return false;
231 }
232}
233
John Stiles2630ea32020-12-04 10:51:21 -0500234bool Parser::expectIdentifier(Token* result) {
235 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
236 return false;
237 }
238 if (this->isType(this->text(*result))) {
239 this->error(*result, "expected an identifier, but found type '" +
240 this->text(*result) + "'");
241 return false;
242 }
243 return true;
244}
245
Ethan Nicholas962dec42021-06-10 13:06:39 -0400246skstd::string_view Parser::text(Token token) {
247 return skstd::string_view(fText.begin() + token.fOffset, token.fLength);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500248}
249
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700250void Parser::error(Token token, String msg) {
251 this->error(token.fOffset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -0700252}
253
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700254void Parser::error(int offset, String msg) {
Ethan Nicholas55478662021-08-10 17:14:26 -0400255 fErrors->error(offset, msg);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700256}
257
Ethan Nicholas962dec42021-06-10 13:06:39 -0400258bool Parser::isType(skstd::string_view name) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400259 const Symbol* s = fSymbols[name];
John Stiles2630ea32020-12-04 10:51:21 -0500260 return s && s->is<Type>();
ethannicholasb3058bd2016-07-01 08:22:01 -0700261}
262
John Stiles80b02af2021-02-12 17:07:51 -0500263bool Parser::isArrayType(ASTNode::ID type) {
264 const ASTNode& node = this->getNode(type);
265 SkASSERT(node.fKind == ASTNode::Kind::kType);
266 return node.begin() != node.end();
267}
268
Ethan Nicholas11d53972016-11-28 11:23:23 -0500269/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
ethannicholas5961bc92016-10-12 06:39:56 -0700270 DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400271ASTNode::ID Parser::directive() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700272 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400273 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400274 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700275 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400276 skstd::string_view text = this->text(start);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400277 if (text == "#extension") {
ethannicholasb3058bd2016-07-01 08:22:01 -0700278 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500279 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400280 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700281 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400282 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400283 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700284 }
285 // FIXME: need to start paying attention to this token
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400286 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400287 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700288 }
John Stiles3b209362020-11-16 17:03:10 -0500289 return this->createNode(start.fOffset, ASTNode::Kind::kExtension, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700290 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700291 this->error(start, "unsupported directive '" + this->text(start) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400292 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 }
294}
295
Brian Osmanc9145f32021-07-08 13:40:10 -0400296/* modifiers (interfaceBlock | structVarDeclaration | SEMICOLON |
John Stiles147cfda2021-05-21 14:11:38 -0400297 type IDENTIFIER (varDeclarationEnd | LPAREN functionDeclarationEnd))) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400298ASTNode::ID Parser::declaration() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 Token lookahead = this->peek();
Ethan Nicholasda6320c2020-09-02 14:08:23 -0400300 switch (lookahead.fKind) {
Ethan Nicholasda6320c2020-09-02 14:08:23 -0400301 case Token::Kind::TK_SEMICOLON:
302 this->error(lookahead.fOffset, "expected a declaration, but found ';'");
303 return ASTNode::ID::Invalid();
304 default:
305 break;
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500306 }
307 Modifiers modifiers = this->modifiers();
308 lookahead = this->peek();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400309 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !this->isType(this->text(lookahead))) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 // we have an identifier that's not a type, could be the start of an interface block
311 return this->interfaceBlock(modifiers);
312 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400313 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700314 return this->structVarDeclaration(modifiers);
315 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400316 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
ethannicholas5961bc92016-10-12 06:39:56 -0700317 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -0500318 return this->createNode(lookahead.fOffset, ASTNode::Kind::kModifiers, modifiers);
ethannicholas5961bc92016-10-12 06:39:56 -0700319 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400320 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700321 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400322 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700323 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700324 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500325 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400326 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700327 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400328 if (this->checkNext(Token::Kind::TK_LPAREN)) {
John Stiles147cfda2021-05-21 14:11:38 -0400329 return this->functionDeclarationEnd(modifiers, type, name);
ethannicholasb3058bd2016-07-01 08:22:01 -0700330 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400331 return this->varDeclarationEnd(modifiers, type, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700332 }
333}
334
John Stiles147cfda2021-05-21 14:11:38 -0400335/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
336ASTNode::ID Parser::functionDeclarationEnd(Modifiers modifiers,
337 ASTNode::ID type,
338 const Token& name) {
339 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kFunction);
340 ASTNode::FunctionData fd(modifiers, this->text(name), 0);
341 getNode(result).addChild(type);
342 Token lookahead = this->peek();
343 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
344 // `()` means no parameters at all.
345 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
346 // `(void)` also means no parameters at all.
347 this->nextToken();
348 } else {
349 for (;;) {
350 ASTNode::ID parameter = this->parameter();
351 if (!parameter) {
352 return ASTNode::ID::Invalid();
353 }
354 ++fd.fParameterCount;
355 getNode(result).addChild(parameter);
356 if (!this->checkNext(Token::Kind::TK_COMMA)) {
357 break;
358 }
359 }
360 }
361 getNode(result).setFunctionData(fd);
362 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
363 return ASTNode::ID::Invalid();
364 }
365 ASTNode::ID body;
366 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
367 body = this->block();
368 if (!body) {
369 return ASTNode::ID::Invalid();
370 }
371 getNode(result).addChild(body);
372 }
373 return result;
374}
375
John Stiles76389b72021-01-25 13:49:05 -0500376/* (varDeclarations | expressionStatement) */
377ASTNode::ID Parser::varDeclarationsOrExpressionStatement() {
John Stiles89b484a2021-04-19 14:57:27 -0400378 Token nextToken = this->peek();
379 if (nextToken.fKind == Token::Kind::TK_CONST) {
380 // Statements that begin with `const` might be variable declarations, but can't be legal
381 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
382 return this->varDeclarations();
383 }
384
John Stiles02014312021-08-04 16:03:12 -0400385 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
386 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
387 nextToken.fKind == Token::Kind::TK_LOWP ||
388 this->isType(this->text(nextToken))) {
John Stiles76389b72021-01-25 13:49:05 -0500389 // Statements that begin with a typename are most often variable declarations, but
390 // occasionally the type is part of a constructor, and these are actually expression-
391 // statements in disguise. First, attempt the common case: parse it as a vardecl.
392 Checkpoint checkpoint(this);
John Stiles8dabeac2021-02-12 16:05:00 -0500393 VarDeclarationsPrefix prefix;
394 if (this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholas55478662021-08-10 17:14:26 -0400395 checkpoint.accept();
John Stiles8dabeac2021-02-12 16:05:00 -0500396 return this->varDeclarationEnd(prefix.modifiers, prefix.type, this->text(prefix.name));
John Stiles76389b72021-01-25 13:49:05 -0500397 }
398
399 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
400 // expression-statement instead.
401 checkpoint.rewind();
402 }
403
404 return this->expressionStatement();
405}
406
John Stiles8dabeac2021-02-12 16:05:00 -0500407// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
408// statement is a variable-declaration statement, not an expression-statement.
409bool Parser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
410 prefixData->modifiers = this->modifiers();
411 prefixData->type = this->type();
412 if (!prefixData->type) {
413 return false;
414 }
415 return this->expectIdentifier(&prefixData->name);
416}
417
ethannicholasb3058bd2016-07-01 08:22:01 -0700418/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400419ASTNode::ID Parser::varDeclarations() {
John Stiles8dabeac2021-02-12 16:05:00 -0500420 VarDeclarationsPrefix prefix;
421 if (!this->varDeclarationsPrefix(&prefix)) {
John Stiles76389b72021-01-25 13:49:05 -0500422 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700423 }
John Stiles8dabeac2021-02-12 16:05:00 -0500424 return this->varDeclarationEnd(prefix.modifiers, prefix.type, this->text(prefix.name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700425}
426
427/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400428ASTNode::ID Parser::structDeclaration() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400429 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400430 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700431 }
432 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500433 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400434 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700435 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400436 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400437 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700438 }
439 std::vector<Type::Field> fields;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400440 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400441 ASTNode::ID decls = this->varDeclarations();
442 if (!decls) {
443 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400445 ASTNode& declsNode = getNode(decls);
John Stilesece1bf02021-03-08 11:15:55 -0500446 const Modifiers& modifiers = declsNode.begin()->getModifiers();
John Stiles13fc2602020-10-09 17:42:31 -0400447 if (modifiers.fFlags != Modifiers::kNo_Flag) {
448 String desc = modifiers.description();
449 desc.pop_back(); // remove trailing space
450 this->error(declsNode.fOffset,
451 "modifier '" + desc + "' is not permitted on a struct field");
452 }
453
Ethan Nicholas962dec42021-06-10 13:06:39 -0400454 const Symbol* symbol = fSymbols[(declsNode.begin() + 1)->getStringView()];
John Stiles13fc2602020-10-09 17:42:31 -0400455 SkASSERT(symbol);
456 const Type* type = &symbol->as<Type>();
John Stiles1d757782020-11-17 09:43:22 -0500457 if (type->isOpaque()) {
458 this->error(declsNode.fOffset,
459 "opaque type '" + type->name() + "' is not permitted in a struct");
460 }
John Stiles13fc2602020-10-09 17:42:31 -0400461
Ethan Nicholasfc994162019-06-06 10:04:27 -0400462 for (auto iter = declsNode.begin() + 2; iter != declsNode.end(); ++iter) {
463 ASTNode& var = *iter;
John Stilesece1bf02021-03-08 11:15:55 -0500464 const ASTNode::VarData& vd = var.getVarData();
John Stiles6bef6a72020-12-02 14:26:04 -0500465
John Stilesd39aec92020-12-03 14:37:16 -0500466 // Read array size if one is present.
John Stiles31c87102021-08-25 12:01:21 -0400467 const Type* fieldType = type;
John Stilesd39aec92020-12-03 14:37:16 -0500468 if (vd.fIsArray) {
469 const ASTNode& size = *var.begin();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400470 if (!size || size.fKind != ASTNode::Kind::kInt) {
471 this->error(declsNode.fOffset, "array size in struct field must be a constant");
472 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700473 }
John Stiles6bef6a72020-12-02 14:26:04 -0500474 if (size.getInt() <= 0 || size.getInt() > INT_MAX) {
475 this->error(declsNode.fOffset, "array size is invalid");
476 return ASTNode::ID::Invalid();
477 }
John Stilesd39aec92020-12-03 14:37:16 -0500478 // Add the array dimensions to our type.
479 int arraySize = size.getInt();
John Stiles31c87102021-08-25 12:01:21 -0400480 fieldType = fSymbols.addArrayDimension(fieldType, arraySize);
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 }
John Stiles13fc2602020-10-09 17:42:31 -0400482
John Stiles31c87102021-08-25 12:01:21 -0400483 fields.push_back(Type::Field(modifiers, vd.fName, fieldType));
John Stilesd39aec92020-12-03 14:37:16 -0500484 if (vd.fIsArray ? var.begin()->fNext : var.fFirstChild) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400485 this->error(declsNode.fOffset, "initializers are not permitted on struct fields");
ethannicholasb3058bd2016-07-01 08:22:01 -0700486 }
487 }
488 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400489 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400490 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 }
Brian Osman6c3b23f2021-02-12 13:09:58 -0500492 if (fields.empty()) {
493 this->error(name.fOffset,
494 "struct '" + this->text(name) + "' must contain at least one field");
495 return ASTNode::ID::Invalid();
496 }
Ethan Nicholas27f06eb2021-07-26 16:39:40 -0400497 std::unique_ptr<Type> newType = Type::MakeStructType(name.fOffset, this->text(name), fields);
John Stilesa695d622020-11-10 10:04:26 -0500498 if (struct_is_too_deeply_nested(*newType, kMaxStructDepth)) {
499 this->error(name.fOffset, "struct '" + this->text(name) + "' is too deeply nested");
500 return ASTNode::ID::Invalid();
501 }
502 fSymbols.add(std::move(newType));
Brian Osman00fea5b2021-01-28 09:46:30 -0500503 return this->createNode(name.fOffset, ASTNode::Kind::kType, this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700504}
505
506/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400507ASTNode::ID Parser::structVarDeclaration(Modifiers modifiers) {
508 ASTNode::ID type = this->structDeclaration();
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400510 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -0400512 Token name;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400513 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400514 return this->varDeclarationEnd(modifiers, std::move(type), this->text(name));
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400516 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesdc75a972020-11-25 16:24:55 -0500517 return type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700518}
519
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400520/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
521 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400522ASTNode::ID Parser::varDeclarationEnd(Modifiers mods, ASTNode::ID type, skstd::string_view name) {
John Stiles08070f62020-11-17 10:45:49 -0500523 int offset = this->peek().fOffset;
524 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kVarDeclarations);
525 this->addChild(result, this->createNode(offset, ASTNode::Kind::kModifiers, mods));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400526 getNode(result).addChild(type);
John Stilesd39aec92020-12-03 14:37:16 -0500527
John Stiles80b02af2021-02-12 17:07:51 -0500528 auto parseArrayDimensions = [&](ASTNode::ID currentVar, ASTNode::VarData* vd) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400529 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stiles80b02af2021-02-12 17:07:51 -0500530 if (vd->fIsArray || this->isArrayType(type)) {
John Stilesd39aec92020-12-03 14:37:16 -0500531 this->error(this->peek(), "multi-dimensional arrays are not supported");
532 return false;
533 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400534 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -0500535 this->createEmptyChild(currentVar);
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400537 ASTNode::ID size = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700538 if (!size) {
John Stilesd39aec92020-12-03 14:37:16 -0500539 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700540 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400541 getNode(currentVar).addChild(size);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400542 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
John Stilesd39aec92020-12-03 14:37:16 -0500543 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700544 }
545 }
John Stilesd39aec92020-12-03 14:37:16 -0500546 vd->fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700547 }
John Stilesd39aec92020-12-03 14:37:16 -0500548 return true;
549 };
550
551 auto parseInitializer = [this](ASTNode::ID currentVar) -> bool {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400552 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400553 ASTNode::ID value = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700554 if (!value) {
John Stilesd39aec92020-12-03 14:37:16 -0500555 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -0700556 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400557 getNode(currentVar).addChild(value);
ethannicholasb3058bd2016-07-01 08:22:01 -0700558 }
John Stilesd39aec92020-12-03 14:37:16 -0500559 return true;
560 };
561
562 ASTNode::ID currentVar = this->createNode(offset, ASTNode::Kind::kVarDeclaration);
563 ASTNode::VarData vd{name, /*isArray=*/false};
564
565 getNode(result).addChild(currentVar);
566 if (!parseArrayDimensions(currentVar, &vd)) {
567 return ASTNode::ID::Invalid();
568 }
569 getNode(currentVar).setVarData(vd);
570 if (!parseInitializer(currentVar)) {
571 return ASTNode::ID::Invalid();
572 }
573
574 while (this->checkNext(Token::Kind::TK_COMMA)) {
575 Token identifierName;
John Stiles2630ea32020-12-04 10:51:21 -0500576 if (!this->expectIdentifier(&identifierName)) {
John Stilesd39aec92020-12-03 14:37:16 -0500577 return ASTNode::ID::Invalid();
578 }
579
580 currentVar = ASTNode::ID(fFile->fNodes.size());
581 vd = ASTNode::VarData{this->text(identifierName), /*isArray=*/false};
582 fFile->fNodes.emplace_back(&fFile->fNodes, offset, ASTNode::Kind::kVarDeclaration);
583
584 getNode(result).addChild(currentVar);
585 if (!parseArrayDimensions(currentVar, &vd)) {
586 return ASTNode::ID::Invalid();
587 }
588 getNode(currentVar).setVarData(vd);
589 if (!parseInitializer(currentVar)) {
590 return ASTNode::ID::Invalid();
591 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700592 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400593 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400594 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700595 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400596 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700597}
598
599/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400600ASTNode::ID Parser::parameter() {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -0400601 Modifiers modifiers = this->modifiersWithDefaults(0);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400602 ASTNode::ID type = this->type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 if (!type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400604 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700605 }
606 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500607 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400608 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700609 }
John Stiles3b209362020-11-16 17:03:10 -0500610 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kParameter);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400611 ASTNode::ParameterData pd(modifiers, this->text(name), 0);
612 getNode(result).addChild(type);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400613 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stiles80b02af2021-02-12 17:07:51 -0500614 if (pd.fIsArray || this->isArrayType(type)) {
John Stilesd39aec92020-12-03 14:37:16 -0500615 this->error(this->peek(), "multi-dimensional arrays are not supported");
616 return ASTNode::ID::Invalid();
617 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700618 Token sizeToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400619 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400620 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700621 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400622 skstd::string_view arraySizeFrag = this->text(sizeToken);
John Stilesf94348f2020-12-23 18:58:43 -0500623 SKSL_INT arraySize;
624 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
625 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
626 return ASTNode::ID::Invalid();
627 }
628 this->addChild(result, this->createNode(sizeToken.fOffset, ASTNode::Kind::kInt, arraySize));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400629 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400630 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 }
John Stilesd39aec92020-12-03 14:37:16 -0500632 pd.fIsArray = true;
ethannicholasb3058bd2016-07-01 08:22:01 -0700633 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400634 getNode(result).setParameterData(pd);
635 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700636}
637
Ethan Nicholasd608c092017-10-26 09:30:08 -0400638/** EQ INT_LITERAL */
ethannicholasb3058bd2016-07-01 08:22:01 -0700639int Parser::layoutInt() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400640 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 return -1;
642 }
643 Token resultToken;
John Stilesf94348f2020-12-23 18:58:43 -0500644 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
645 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 }
Ethan Nicholas962dec42021-06-10 13:06:39 -0400647 skstd::string_view resultFrag = this->text(resultToken);
John Stilesf94348f2020-12-23 18:58:43 -0500648 SKSL_INT resultValue;
649 if (!SkSL::stoi(resultFrag, &resultValue)) {
650 this->error(resultToken, "value in layout is too large: " + resultFrag);
651 return -1;
652 }
653 return resultValue;
ethannicholasb3058bd2016-07-01 08:22:01 -0700654}
655
Ethan Nicholasd608c092017-10-26 09:30:08 -0400656/** EQ IDENTIFIER */
Ethan Nicholas962dec42021-06-10 13:06:39 -0400657skstd::string_view Parser::layoutIdentifier() {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400658 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400659 return skstd::string_view();
Ethan Nicholasd608c092017-10-26 09:30:08 -0400660 }
661 Token resultToken;
John Stiles2630ea32020-12-04 10:51:21 -0500662 if (!this->expectIdentifier(&resultToken)) {
Ethan Nicholas962dec42021-06-10 13:06:39 -0400663 return skstd::string_view();
Ethan Nicholasd608c092017-10-26 09:30:08 -0400664 }
665 return this->text(resultToken);
666}
667
ethannicholas8ac838d2016-11-22 08:39:36 -0800668/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500669Layout Parser::layout() {
Ethan Nicholas39204fd2017-11-27 13:12:30 -0500670 int flags = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700671 int location = -1;
Ethan Nicholas19671772016-11-28 16:30:17 -0500672 int offset = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700673 int binding = -1;
674 int index = -1;
675 int set = -1;
676 int builtin = -1;
Greg Daniel64773e62016-11-22 09:44:03 -0500677 int inputAttachmentIndex = -1;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400678 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
679 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Brian Osman99ddd2a2021-08-27 11:21:12 -0400680 return Layout(
681 flags, location, offset, binding, index, set, builtin, inputAttachmentIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -0700682 }
683 for (;;) {
684 Token t = this->nextToken();
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400685 String text(this->text(t));
Brian Osmana77ed8b2021-02-23 12:54:22 -0500686 auto setFlag = [&](Layout::Flag f) {
687 if (flags & f) {
688 this->error(t, "layout qualifier '" + text + "' appears more than once");
689 }
690 flags |= f;
691 };
Brian Osmana77ed8b2021-02-23 12:54:22 -0500692
Ethan Nicholasb93af7e2018-07-24 11:28:52 -0400693 auto found = layoutTokens->find(text);
694 if (found != layoutTokens->end()) {
695 switch (found->second) {
Brian Osmana77ed8b2021-02-23 12:54:22 -0500696 case LayoutToken::ORIGIN_UPPER_LEFT:
697 setFlag(Layout::kOriginUpperLeft_Flag);
698 break;
Brian Osmana77ed8b2021-02-23 12:54:22 -0500699 case LayoutToken::PUSH_CONSTANT:
700 setFlag(Layout::kPushConstant_Flag);
701 break;
702 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
703 setFlag(Layout::kBlendSupportAllEquations_Flag);
704 break;
Brian Osmana77ed8b2021-02-23 12:54:22 -0500705 case LayoutToken::SRGB_UNPREMUL:
706 setFlag(Layout::kSRGBUnpremul_Flag);
707 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700708 case LayoutToken::LOCATION:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500709 setFlag(Layout::kLocation_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500710 location = this->layoutInt();
711 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700712 case LayoutToken::OFFSET:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500713 setFlag(Layout::kOffset_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500714 offset = this->layoutInt();
715 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700716 case LayoutToken::BINDING:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500717 setFlag(Layout::kBinding_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500718 binding = this->layoutInt();
719 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700720 case LayoutToken::INDEX:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500721 setFlag(Layout::kIndex_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500722 index = this->layoutInt();
723 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700724 case LayoutToken::SET:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500725 setFlag(Layout::kSet_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500726 set = this->layoutInt();
727 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700728 case LayoutToken::BUILTIN:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500729 setFlag(Layout::kBuiltin_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500730 builtin = this->layoutInt();
731 break;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700732 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500733 setFlag(Layout::kInputAttachmentIndex_Flag);
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500734 inputAttachmentIndex = this->layoutInt();
735 break;
Ethan Nicholas78aceb22018-08-31 16:13:58 -0400736 default:
Brian Osmana77ed8b2021-02-23 12:54:22 -0500737 this->error(t, "'" + text + "' is not a valid layout qualifier");
Ethan Nicholasd608c092017-10-26 09:30:08 -0400738 break;
Ethan Nicholas3614d9a2017-02-15 12:33:30 -0500739 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700740 } else {
Brian Osmana77ed8b2021-02-23 12:54:22 -0500741 this->error(t, "'" + text + "' is not a valid layout qualifier");
ethannicholasb3058bd2016-07-01 08:22:01 -0700742 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400743 if (this->checkNext(Token::Kind::TK_RPAREN)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700744 break;
745 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400746 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700747 break;
748 }
749 }
750 }
Brian Osman99ddd2a2021-08-27 11:21:12 -0400751 return Layout(flags, location, offset, binding, index, set, builtin, inputAttachmentIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -0700752}
753
Brian Osmane49703f2021-04-19 11:15:24 -0400754/* layout? (UNIFORM | CONST | IN | OUT | INOUT | FLAT | NOPERSPECTIVE | INLINE)* */
Ethan Nicholas11d53972016-11-28 11:23:23 -0500755Modifiers Parser::modifiers() {
756 Layout layout = this->layout();
ethannicholasb3058bd2016-07-01 08:22:01 -0700757 int flags = 0;
758 for (;;) {
759 // TODO: handle duplicate / incompatible flags
John Stiles7d5b90a2021-01-21 14:26:51 -0500760 int tokenFlag = parse_modifier_token(peek().fKind);
761 if (!tokenFlag) {
762 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700763 }
John Stiles7d5b90a2021-01-21 14:26:51 -0500764 flags |= tokenFlag;
765 this->nextToken();
ethannicholasb3058bd2016-07-01 08:22:01 -0700766 }
John Stiles7d5b90a2021-01-21 14:26:51 -0500767 return Modifiers(layout, flags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700768}
769
Ethan Nicholas11d53972016-11-28 11:23:23 -0500770Modifiers Parser::modifiersWithDefaults(int defaultFlags) {
771 Modifiers result = this->modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -0700772 if (!result.fFlags) {
Ethan Nicholas11d53972016-11-28 11:23:23 -0500773 return Modifiers(result.fLayout, defaultFlags);
ethannicholasb3058bd2016-07-01 08:22:01 -0700774 }
775 return result;
776}
777
778/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400779ASTNode::ID Parser::statement() {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -0400780 Token start = this->nextToken();
781 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -0400782 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -0400783 return ASTNode::ID::Invalid();
784 }
785 this->pushback(start);
ethannicholasb3058bd2016-07-01 08:22:01 -0700786 switch (start.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400787 case Token::Kind::TK_IF: // fall through
788 case Token::Kind::TK_STATIC_IF:
ethannicholasb3058bd2016-07-01 08:22:01 -0700789 return this->ifStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400790 case Token::Kind::TK_FOR:
ethannicholasb3058bd2016-07-01 08:22:01 -0700791 return this->forStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400792 case Token::Kind::TK_DO:
ethannicholasb3058bd2016-07-01 08:22:01 -0700793 return this->doStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400794 case Token::Kind::TK_WHILE:
ethannicholasb3058bd2016-07-01 08:22:01 -0700795 return this->whileStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400796 case Token::Kind::TK_SWITCH: // fall through
797 case Token::Kind::TK_STATIC_SWITCH:
Ethan Nicholasaf197692017-02-27 13:26:45 -0500798 return this->switchStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400799 case Token::Kind::TK_RETURN:
ethannicholasb3058bd2016-07-01 08:22:01 -0700800 return this->returnStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400801 case Token::Kind::TK_BREAK:
ethannicholasb3058bd2016-07-01 08:22:01 -0700802 return this->breakStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400803 case Token::Kind::TK_CONTINUE:
ethannicholasb3058bd2016-07-01 08:22:01 -0700804 return this->continueStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400805 case Token::Kind::TK_DISCARD:
ethannicholasb3058bd2016-07-01 08:22:01 -0700806 return this->discardStatement();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400807 case Token::Kind::TK_LBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -0700808 return this->block();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400809 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas11d53972016-11-28 11:23:23 -0500810 this->nextToken();
John Stiles3b209362020-11-16 17:03:10 -0500811 return this->createNode(start.fOffset, ASTNode::Kind::kBlock);
John Stiles02014312021-08-04 16:03:12 -0400812 case Token::Kind::TK_HIGHP:
813 case Token::Kind::TK_MEDIUMP:
814 case Token::Kind::TK_LOWP:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400815 case Token::Kind::TK_CONST:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400816 case Token::Kind::TK_IDENTIFIER:
John Stiles76389b72021-01-25 13:49:05 -0500817 return this->varDeclarationsOrExpressionStatement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700818 default:
819 return this->expressionStatement();
Ethan Nicholas11d53972016-11-28 11:23:23 -0500820 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700821}
822
Ethan Nicholasee1c8a72019-02-22 10:50:47 -0500823/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400824ASTNode::ID Parser::type() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700825 Token type;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400826 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400827 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700828 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700829 if (!this->isType(this->text(type))) {
830 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
Ethan Nicholasfc994162019-06-06 10:04:27 -0400831 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700832 }
Brian Osman00fea5b2021-01-28 09:46:30 -0500833 ASTNode::ID result = this->createNode(type.fOffset, ASTNode::Kind::kType, this->text(type));
John Stilesd39aec92020-12-03 14:37:16 -0500834 bool isArray = false;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400835 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -0500836 if (isArray) {
837 this->error(this->peek(), "multi-dimensional arrays are not supported");
838 return ASTNode::ID::Invalid();
839 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400840 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400841 SKSL_INT i;
Ethan Nicholas50afc172017-02-16 14:49:57 -0500842 if (this->intLiteral(&i)) {
John Stiles08070f62020-11-17 10:45:49 -0500843 this->addChild(result, this->createNode(this->peek().fOffset,
844 ASTNode::Kind::kInt, i));
Ethan Nicholas50afc172017-02-16 14:49:57 -0500845 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400846 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500847 }
848 } else {
John Stiles3b209362020-11-16 17:03:10 -0500849 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500850 }
John Stilesd39aec92020-12-03 14:37:16 -0500851 isArray = true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400852 this->expect(Token::Kind::TK_RBRACKET, "']'");
Ethan Nicholas50afc172017-02-16 14:49:57 -0500853 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400854 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700855}
856
John Stiles57a996b2020-04-19 19:05:12 -0700857/* IDENTIFIER LBRACE
858 varDeclaration+
859 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400860ASTNode::ID Parser::interfaceBlock(Modifiers mods) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700861 Token name;
John Stiles2630ea32020-12-04 10:51:21 -0500862 if (!this->expectIdentifier(&name)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400863 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700864 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400865 if (peek().fKind != Token::Kind::TK_LBRACE) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700866 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
Ethan Nicholas11d53972016-11-28 11:23:23 -0500867 // 99% of the time, the user was not actually intending to create an interface block, so
ethannicholasb3058bd2016-07-01 08:22:01 -0700868 // it's better to report it as an unknown type
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700869 this->error(name, "no type named '" + this->text(name) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400870 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700871 }
John Stiles3b209362020-11-16 17:03:10 -0500872 ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kInterfaceBlock);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400873 ASTNode::InterfaceBlockData id(mods, this->text(name), 0, "", 0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700874 this->nextToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400875 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400876 ASTNode::ID decl = this->varDeclarations();
ethannicholasb3058bd2016-07-01 08:22:01 -0700877 if (!decl) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400878 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700879 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400880 getNode(result).addChild(decl);
881 ++id.fDeclarationCount;
ethannicholasb3058bd2016-07-01 08:22:01 -0700882 }
John Stiles57a996b2020-04-19 19:05:12 -0700883 if (id.fDeclarationCount == 0) {
884 this->error(name, "interface block '" + this->text(name) +
885 "' must contain at least one member");
886 return ASTNode::ID::Invalid();
887 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700888 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -0400889 std::vector<ASTNode> sizes;
Ethan Nicholas962dec42021-06-10 13:06:39 -0400890 skstd::string_view instanceName;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700891 Token instanceNameToken;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400892 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400893 id.fInstanceName = this->text(instanceNameToken);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400894 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
John Stilesd39aec92020-12-03 14:37:16 -0500895 if (id.fIsArray) {
896 this->error(this->peek(), "multi-dimensional arrays are not supported");
897 return false;
898 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400899 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400900 ASTNode::ID size = this->expression();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500901 if (!size) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400902 return ASTNode::ID::Invalid();
Ethan Nicholas50afc172017-02-16 14:49:57 -0500903 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400904 getNode(result).addChild(size);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500905 } else {
John Stiles3b209362020-11-16 17:03:10 -0500906 this->createEmptyChild(result);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500907 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400908 this->expect(Token::Kind::TK_RBRACKET, "']'");
John Stilesd39aec92020-12-03 14:37:16 -0500909 id.fIsArray = true;
Ethan Nicholas50afc172017-02-16 14:49:57 -0500910 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700911 instanceName = this->text(instanceNameToken);
ethannicholasb3058bd2016-07-01 08:22:01 -0700912 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400913 getNode(result).setInterfaceBlockData(id);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400914 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasfc994162019-06-06 10:04:27 -0400915 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700916}
917
918/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400919ASTNode::ID Parser::ifStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700920 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400921 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
922 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400923 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700924 }
John Stiles3b209362020-11-16 17:03:10 -0500925 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kIf, isStatic);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400926 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
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 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700930 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400931 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700932 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400933 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400934 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400935 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700936 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400937 ASTNode::ID ifTrue = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700938 if (!ifTrue) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400939 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700940 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400941 getNode(result).addChild(ifTrue);
942 ASTNode::ID ifFalse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400943 if (this->checkNext(Token::Kind::TK_ELSE)) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700944 ifFalse = this->statement();
945 if (!ifFalse) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400946 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700947 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400948 getNode(result).addChild(ifFalse);
ethannicholasb3058bd2016-07-01 08:22:01 -0700949 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400950 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700951}
952
953/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400954ASTNode::ID Parser::doStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700955 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400956 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400957 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700958 }
John Stiles3b209362020-11-16 17:03:10 -0500959 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kDo);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400960 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -0700961 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400962 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700963 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400964 getNode(result).addChild(statement);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400965 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400966 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700967 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400968 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400969 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700970 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400971 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700972 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400973 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700974 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400975 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400976 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400977 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700978 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400979 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
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 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700983}
984
985/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -0400986ASTNode::ID Parser::whileStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -0700987 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400988 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400989 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700990 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400991 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400992 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700993 }
John Stiles3b209362020-11-16 17:03:10 -0500994 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kWhile);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400995 ASTNode::ID test = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -0700996 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400997 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -0700998 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400999 getNode(result).addChild(test);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001000 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001001 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001002 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001003 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001005 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001006 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001007 getNode(result).addChild(statement);
1008 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001009}
1010
Ethan Nicholasaf197692017-02-27 13:26:45 -05001011/* CASE expression COLON statement* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001012ASTNode::ID Parser::switchCase() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001013 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001014 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001015 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001016 }
John Stiles3b209362020-11-16 17:03:10 -05001017 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitchCase);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001018 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001019 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001020 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001021 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001022 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001023 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001024 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001025 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001026 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1027 this->peek().fKind != Token::Kind::TK_CASE &&
1028 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001029 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001030 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001031 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001032 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001033 getNode(result).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001034 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001035 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001036}
1037
1038/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001039ASTNode::ID Parser::switchStatement() {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001040 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001041 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1042 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001043 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001044 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001045 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001046 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001047 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001048 ASTNode::ID value = this->expression();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001049 if (!value) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001050 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001051 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001052 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001053 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001054 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001055 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001056 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001057 }
John Stiles3b209362020-11-16 17:03:10 -05001058 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kSwitch, isStatic);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001059 getNode(result).addChild(value);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001060 while (this->peek().fKind == Token::Kind::TK_CASE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001061 ASTNode::ID c = this->switchCase();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001062 if (!c) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001063 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001064 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001065 getNode(result).addChild(c);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001066 }
1067 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1068 // parts of the compiler may rely upon this assumption.
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001069 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001070 Token defaultStart;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001071 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1072 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001073 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001074 }
John Stiles3b209362020-11-16 17:03:10 -05001075 ASTNode::ID defaultCase = this->addChild(
1076 result, this->createNode(defaultStart.fOffset, ASTNode::Kind::kSwitchCase));
1077 this->createEmptyChild(defaultCase); // empty test to signify default case
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001078 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001079 ASTNode::ID s = this->statement();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001080 if (!s) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001081 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001082 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001083 getNode(defaultCase).addChild(s);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001084 }
Ethan Nicholasaf197692017-02-27 13:26:45 -05001085 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001086 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001087 return ASTNode::ID::Invalid();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001088 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001089 return result;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001090}
1091
Ethan Nicholas11d53972016-11-28 11:23:23 -05001092/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
ethannicholasb3058bd2016-07-01 08:22:01 -07001093 STATEMENT */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001094ASTNode::ID Parser::forStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001095 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001096 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001097 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001099 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001100 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001101 }
John Stiles3b209362020-11-16 17:03:10 -05001102 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kFor);
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 Token nextToken = this->peek();
John Stiles89b484a2021-04-19 14:57:27 -04001104 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1105 // An empty init-statement.
1106 this->nextToken();
1107 this->createEmptyChild(result);
1108 } else {
1109 // The init-statement must be an expression or variable declaration.
1110 ASTNode::ID initializer = this->varDeclarationsOrExpressionStatement();
1111 if (!initializer) {
1112 return ASTNode::ID::Invalid();
ethannicholasa54401d2016-10-14 08:37:32 -07001113 }
John Stiles89b484a2021-04-19 14:57:27 -04001114 getNode(result).addChild(initializer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001115 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001116 ASTNode::ID test;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001117 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001118 test = this->expression();
1119 if (!test) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001120 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001122 getNode(result).addChild(test);
1123 } else {
John Stiles3b209362020-11-16 17:03:10 -05001124 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001125 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001126 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001127 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001128 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001129 ASTNode::ID next;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001130 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001131 next = this->expression();
1132 if (!next) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001133 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001134 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001135 getNode(result).addChild(next);
1136 } else {
John Stiles3b209362020-11-16 17:03:10 -05001137 this->createEmptyChild(result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001139 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001140 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001142 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001143 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001144 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001146 getNode(result).addChild(statement);
1147 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001148}
1149
1150/* RETURN expression? SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001151ASTNode::ID Parser::returnStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001152 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001153 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001154 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001155 }
John Stiles3b209362020-11-16 17:03:10 -05001156 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kReturn);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001157 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001158 ASTNode::ID expression = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001159 if (!expression) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001160 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001161 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001162 getNode(result).addChild(expression);
ethannicholasb3058bd2016-07-01 08:22:01 -07001163 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001164 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001165 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001166 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001167 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001168}
1169
1170/* BREAK SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001171ASTNode::ID Parser::breakStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001172 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001173 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001174 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001175 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001176 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001177 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001178 }
John Stiles3b209362020-11-16 17:03:10 -05001179 return this->createNode(start.fOffset, ASTNode::Kind::kBreak);
ethannicholasb3058bd2016-07-01 08:22:01 -07001180}
1181
1182/* CONTINUE SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001183ASTNode::ID Parser::continueStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001184 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001185 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001186 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001187 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001188 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001189 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001190 }
John Stiles3b209362020-11-16 17:03:10 -05001191 return this->createNode(start.fOffset, ASTNode::Kind::kContinue);
ethannicholasb3058bd2016-07-01 08:22:01 -07001192}
1193
1194/* DISCARD SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001195ASTNode::ID Parser::discardStatement() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001196 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001197 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001198 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001200 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001201 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001202 }
John Stiles3b209362020-11-16 17:03:10 -05001203 return this->createNode(start.fOffset, ASTNode::Kind::kDiscard);
ethannicholasb3058bd2016-07-01 08:22:01 -07001204}
1205
1206/* LBRACE statement* RBRACE */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001207ASTNode::ID Parser::block() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001208 Token start;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001209 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001210 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001211 }
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001212 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001213 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001214 return ASTNode::ID::Invalid();
1215 }
John Stiles3b209362020-11-16 17:03:10 -05001216 ASTNode::ID result = this->createNode(start.fOffset, ASTNode::Kind::kBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -07001217 for (;;) {
1218 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001219 case Token::Kind::TK_RBRACE:
ethannicholasb3058bd2016-07-01 08:22:01 -07001220 this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001221 return result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001222 case Token::Kind::TK_END_OF_FILE:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001223 this->error(this->peek(), "expected '}', but found end of file");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001224 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001225 default: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001226 ASTNode::ID statement = this->statement();
ethannicholasb3058bd2016-07-01 08:22:01 -07001227 if (!statement) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001228 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001229 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001230 getNode(result).addChild(statement);
ethannicholasb3058bd2016-07-01 08:22:01 -07001231 }
1232 }
1233 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001234 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001235}
1236
1237/* expression SEMICOLON */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001238ASTNode::ID Parser::expressionStatement() {
1239 ASTNode::ID expr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001240 if (expr) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001241 if (this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001242 return expr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001243 }
1244 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001245 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001246}
1247
1248/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001249ASTNode::ID Parser::expression() {
1250 ASTNode::ID result = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001251 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001252 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001253 }
1254 Token t;
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001255 AutoDepth depth(this);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001256 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
Ethan Nicholasb67d0562020-04-30 16:10:00 -04001257 if (!depth.increase()) {
1258 return ASTNode::ID::Invalid();
1259 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001260 ASTNode::ID right = this->assignmentExpression();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001261 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001262 return ASTNode::ID::Invalid();
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001263 }
John Stiles45990502021-02-16 10:55:27 -05001264 ASTNode::ID newResult = this->createNode(t.fOffset, ASTNode::Kind::kBinary,
1265 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001266 getNode(newResult).addChild(result);
1267 getNode(newResult).addChild(right);
1268 result = newResult;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001269 }
1270 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001271}
1272
1273/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1274 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1275 assignmentExpression)*
1276 */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001277ASTNode::ID Parser::assignmentExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001278 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001279 ASTNode::ID result = this->ternaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001281 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001282 }
1283 for (;;) {
1284 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001285 case Token::Kind::TK_EQ: // fall through
1286 case Token::Kind::TK_STAREQ: // fall through
1287 case Token::Kind::TK_SLASHEQ: // fall through
1288 case Token::Kind::TK_PERCENTEQ: // fall through
1289 case Token::Kind::TK_PLUSEQ: // fall through
1290 case Token::Kind::TK_MINUSEQ: // fall through
1291 case Token::Kind::TK_SHLEQ: // fall through
1292 case Token::Kind::TK_SHREQ: // fall through
1293 case Token::Kind::TK_BITWISEANDEQ: // fall through
1294 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05001295 case Token::Kind::TK_BITWISEOREQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001296 if (!depth.increase()) {
1297 return ASTNode::ID::Invalid();
1298 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001299 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001300 ASTNode::ID right = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001301 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001302 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001303 }
John Stiles3b209362020-11-16 17:03:10 -05001304 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001305 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001306 getNode(newResult).addChild(result);
1307 getNode(newResult).addChild(right);
1308 result = newResult;
1309 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001310 }
1311 default:
1312 return result;
1313 }
1314 }
1315}
1316
1317/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001318ASTNode::ID Parser::ternaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001319 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001320 ASTNode::ID base = this->logicalOrExpression();
1321 if (!base) {
1322 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001323 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001324 if (this->checkNext(Token::Kind::TK_QUESTION)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001325 if (!depth.increase()) {
1326 return ASTNode::ID::Invalid();
1327 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001328 ASTNode::ID trueExpr = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001329 if (!trueExpr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001330 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001331 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001332 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001333 ASTNode::ID falseExpr = this->assignmentExpression();
1334 if (!falseExpr) {
1335 return ASTNode::ID::Invalid();
1336 }
John Stiles3b209362020-11-16 17:03:10 -05001337 ASTNode::ID ternary = this->createNode(getNode(base).fOffset, ASTNode::Kind::kTernary);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001338 getNode(ternary).addChild(base);
1339 getNode(ternary).addChild(trueExpr);
1340 getNode(ternary).addChild(falseExpr);
1341 return ternary;
ethannicholasb3058bd2016-07-01 08:22:01 -07001342 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001343 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001344 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001345 return base;
ethannicholasb3058bd2016-07-01 08:22:01 -07001346}
1347
1348/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001349ASTNode::ID Parser::logicalOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001350 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001351 ASTNode::ID result = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001352 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001353 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001354 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001355 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001356 while (this->checkNext(Token::Kind::TK_LOGICALOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001357 if (!depth.increase()) {
1358 return ASTNode::ID::Invalid();
1359 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001360 ASTNode::ID right = this->logicalXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001361 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001362 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001363 }
John Stiles3b209362020-11-16 17:03:10 -05001364 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001365 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001366 getNode(newResult).addChild(result);
1367 getNode(newResult).addChild(right);
1368 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001369 }
1370 return result;
1371}
1372
1373/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001374ASTNode::ID Parser::logicalXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001375 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001376 ASTNode::ID result = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001377 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001378 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001379 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001380 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001381 while (this->checkNext(Token::Kind::TK_LOGICALXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001382 if (!depth.increase()) {
1383 return ASTNode::ID::Invalid();
1384 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001385 ASTNode::ID right = this->logicalAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001386 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001387 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001388 }
John Stiles3b209362020-11-16 17:03:10 -05001389 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001390 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001391 getNode(newResult).addChild(result);
1392 getNode(newResult).addChild(right);
1393 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001394 }
1395 return result;
1396}
1397
1398/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001399ASTNode::ID Parser::logicalAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001400 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001401 ASTNode::ID result = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001402 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001403 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001404 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001405 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001406 while (this->checkNext(Token::Kind::TK_LOGICALAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001407 if (!depth.increase()) {
1408 return ASTNode::ID::Invalid();
1409 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001410 ASTNode::ID right = this->bitwiseOrExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001411 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001412 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 }
John Stiles3b209362020-11-16 17:03:10 -05001414 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001415 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001416 getNode(newResult).addChild(result);
1417 getNode(newResult).addChild(right);
1418 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 }
1420 return result;
1421}
1422
1423/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001424ASTNode::ID Parser::bitwiseOrExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001425 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001426 ASTNode::ID result = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001427 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001428 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001429 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001430 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001431 while (this->checkNext(Token::Kind::TK_BITWISEOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001432 if (!depth.increase()) {
1433 return ASTNode::ID::Invalid();
1434 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001435 ASTNode::ID right = this->bitwiseXorExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001436 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001437 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001438 }
John Stiles45990502021-02-16 10:55:27 -05001439 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1440 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001441 getNode(newResult).addChild(result);
1442 getNode(newResult).addChild(right);
1443 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001444 }
1445 return result;
1446}
1447
1448/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001449ASTNode::ID Parser::bitwiseXorExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001450 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001451 ASTNode::ID result = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001453 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001455 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001456 while (this->checkNext(Token::Kind::TK_BITWISEXOR, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001457 if (!depth.increase()) {
1458 return ASTNode::ID::Invalid();
1459 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001460 ASTNode::ID right = this->bitwiseAndExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001461 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001462 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001463 }
John Stiles45990502021-02-16 10:55:27 -05001464 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
1465 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001466 getNode(newResult).addChild(result);
1467 getNode(newResult).addChild(right);
1468 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001469 }
1470 return result;
1471}
1472
1473/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001474ASTNode::ID Parser::bitwiseAndExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001475 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001476 ASTNode::ID result = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001477 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001478 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001479 }
Ethan Nicholas0c9d13b2017-05-08 16:18:19 -04001480 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001481 while (this->checkNext(Token::Kind::TK_BITWISEAND, &t)) {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001482 if (!depth.increase()) {
1483 return ASTNode::ID::Invalid();
1484 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001485 ASTNode::ID right = this->equalityExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001486 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001487 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001488 }
John Stiles3b209362020-11-16 17:03:10 -05001489 ASTNode::ID newResult = this->createNode(getNode(result).fOffset, ASTNode::Kind::kBinary,
John Stiles45990502021-02-16 10:55:27 -05001490 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001491 getNode(newResult).addChild(result);
1492 getNode(newResult).addChild(right);
1493 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001494 }
1495 return result;
1496}
1497
1498/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001499ASTNode::ID Parser::equalityExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001500 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001501 ASTNode::ID result = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001502 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001503 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001504 }
1505 for (;;) {
1506 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001507 case Token::Kind::TK_EQEQ: // fall through
1508 case Token::Kind::TK_NEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001509 if (!depth.increase()) {
1510 return ASTNode::ID::Invalid();
1511 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001513 ASTNode::ID right = this->relationalExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001514 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001515 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 }
John Stiles3b209362020-11-16 17:03:10 -05001517 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001518 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001519 getNode(newResult).addChild(result);
1520 getNode(newResult).addChild(right);
1521 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001522 break;
1523 }
1524 default:
1525 return result;
1526 }
1527 }
1528}
1529
1530/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001531ASTNode::ID Parser::relationalExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001532 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001533 ASTNode::ID result = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001534 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001535 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001536 }
1537 for (;;) {
1538 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001539 case Token::Kind::TK_LT: // fall through
1540 case Token::Kind::TK_GT: // fall through
1541 case Token::Kind::TK_LTEQ: // fall through
1542 case Token::Kind::TK_GTEQ: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001543 if (!depth.increase()) {
1544 return ASTNode::ID::Invalid();
1545 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001546 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001547 ASTNode::ID right = this->shiftExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001548 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001549 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001550 }
John Stiles3b209362020-11-16 17:03:10 -05001551 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001552 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001553 getNode(newResult).addChild(result);
1554 getNode(newResult).addChild(right);
1555 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 break;
1557 }
1558 default:
1559 return result;
1560 }
1561 }
1562}
1563
1564/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001565ASTNode::ID Parser::shiftExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001566 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001567 ASTNode::ID result = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001569 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001570 }
1571 for (;;) {
1572 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001573 case Token::Kind::TK_SHL: // fall through
1574 case Token::Kind::TK_SHR: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001575 if (!depth.increase()) {
1576 return ASTNode::ID::Invalid();
1577 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001579 ASTNode::ID right = this->additiveExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001580 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001581 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 }
John Stiles3b209362020-11-16 17:03:10 -05001583 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001584 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001585 getNode(newResult).addChild(result);
1586 getNode(newResult).addChild(right);
1587 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 break;
1589 }
1590 default:
1591 return result;
1592 }
1593 }
1594}
1595
1596/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001597ASTNode::ID Parser::additiveExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001598 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001599 ASTNode::ID result = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001601 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001602 }
1603 for (;;) {
1604 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001605 case Token::Kind::TK_PLUS: // fall through
1606 case Token::Kind::TK_MINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001607 if (!depth.increase()) {
1608 return ASTNode::ID::Invalid();
1609 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001610 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001611 ASTNode::ID right = this->multiplicativeExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001612 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001613 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001614 }
John Stiles3b209362020-11-16 17:03:10 -05001615 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001616 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001617 getNode(newResult).addChild(result);
1618 getNode(newResult).addChild(right);
1619 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 break;
1621 }
1622 default:
1623 return result;
1624 }
1625 }
1626}
1627
1628/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001629ASTNode::ID Parser::multiplicativeExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001630 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001631 ASTNode::ID result = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001633 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 }
1635 for (;;) {
1636 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001637 case Token::Kind::TK_STAR: // fall through
1638 case Token::Kind::TK_SLASH: // fall through
1639 case Token::Kind::TK_PERCENT: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001640 if (!depth.increase()) {
1641 return ASTNode::ID::Invalid();
1642 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001644 ASTNode::ID right = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001645 if (!right) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001646 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 }
John Stiles3b209362020-11-16 17:03:10 -05001648 ASTNode::ID newResult = this->createNode(getNode(result).fOffset,
John Stiles45990502021-02-16 10:55:27 -05001649 ASTNode::Kind::kBinary, Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001650 getNode(newResult).addChild(result);
1651 getNode(newResult).addChild(right);
1652 result = newResult;
ethannicholasb3058bd2016-07-01 08:22:01 -07001653 break;
1654 }
1655 default:
1656 return result;
1657 }
1658 }
1659}
1660
1661/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001662ASTNode::ID Parser::unaryExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001663 AutoDepth depth(this);
ethannicholasb3058bd2016-07-01 08:22:01 -07001664 switch (this->peek().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001665 case Token::Kind::TK_PLUS: // fall through
1666 case Token::Kind::TK_MINUS: // fall through
1667 case Token::Kind::TK_LOGICALNOT: // fall through
1668 case Token::Kind::TK_BITWISENOT: // fall through
1669 case Token::Kind::TK_PLUSPLUS: // fall through
1670 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001671 if (!depth.increase()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001672 return ASTNode::ID::Invalid();
Ethan Nicholas6dcc3252019-02-20 15:18:36 -05001673 }
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001674 Token t = this->nextToken();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001675 ASTNode::ID expr = this->unaryExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001677 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001678 }
John Stiles45990502021-02-16 10:55:27 -05001679 ASTNode::ID result = this->createNode(t.fOffset, ASTNode::Kind::kPrefix,
1680 Operator(t.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001681 getNode(result).addChild(expr);
1682 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001683 }
1684 default:
1685 return this->postfixExpression();
1686 }
1687}
1688
1689/* term suffix* */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001690ASTNode::ID Parser::postfixExpression() {
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001691 AutoDepth depth(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001692 ASTNode::ID result = this->term();
ethannicholasb3058bd2016-07-01 08:22:01 -07001693 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001694 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001695 }
1696 for (;;) {
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04001697 Token t = this->peek();
1698 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001699 case Token::Kind::TK_FLOAT_LITERAL:
Ethan Nicholas5a9a0b32019-09-17 16:18:22 -04001700 if (this->text(t)[0] != '.') {
1701 return result;
1702 }
John Stiles30212b72020-06-11 17:55:07 -04001703 [[fallthrough]];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001704 case Token::Kind::TK_LBRACKET:
1705 case Token::Kind::TK_DOT:
1706 case Token::Kind::TK_LPAREN:
1707 case Token::Kind::TK_PLUSPLUS:
1708 case Token::Kind::TK_MINUSMINUS:
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001709 if (!depth.increase()) {
1710 return ASTNode::ID::Invalid();
1711 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001712 result = this->suffix(result);
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001713 if (!result) {
1714 return ASTNode::ID::Invalid();
1715 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001716 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001717 default:
1718 return result;
1719 }
1720 }
1721}
1722
Ethan Nicholas11d53972016-11-28 11:23:23 -05001723/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
Brian Osmanc9145f32021-07-08 13:40:10 -04001724 PLUSPLUS | MINUSMINUS | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001725ASTNode::ID Parser::suffix(ASTNode::ID base) {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001726 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001727 Token next = this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001728 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001729 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001730 return ASTNode::ID::Invalid();
1731 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001732 switch (next.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001733 case Token::Kind::TK_LBRACKET: {
1734 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
John Stiles3b209362020-11-16 17:03:10 -05001735 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001736 getNode(result).addChild(base);
1737 return result;
ethannicholas5961bc92016-10-12 06:39:56 -07001738 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001739 ASTNode::ID e = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001740 if (!e) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001741 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001743 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
John Stiles3b209362020-11-16 17:03:10 -05001744 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kIndex);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001745 getNode(result).addChild(base);
1746 getNode(result).addChild(e);
1747 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001748 }
Brian Osman6518d772020-09-10 16:50:06 -04001749 case Token::Kind::TK_DOT: {
1750 int offset = this->peek().fOffset;
Ethan Nicholas962dec42021-06-10 13:06:39 -04001751 skstd::string_view text;
Brian Osman6518d772020-09-10 16:50:06 -04001752 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05001753 ASTNode::ID result = this->createNode(offset, ASTNode::Kind::kField,
1754 std::move(text));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001755 getNode(result).addChild(base);
1756 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001757 }
Brian Osman6518d772020-09-10 16:50:06 -04001758 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04001759 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001760 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholase455f652019-09-13 12:52:55 -04001761 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1762 // floating point literals, possibly followed by an identifier. Handle that here.
Ethan Nicholas962dec42021-06-10 13:06:39 -04001763 skstd::string_view field = this->text(next);
Ethan Nicholasd2e09602021-06-10 11:21:59 -04001764 SkASSERT(field[0] == '.');
1765 field.remove_prefix(1);
1766 for (auto iter = field.begin(); iter != field.end(); ++iter) {
1767 if (*iter != '0' && *iter != '1') {
Ethan Nicholase455f652019-09-13 12:52:55 -04001768 this->error(next, "invalid swizzle");
1769 return ASTNode::ID::Invalid();
1770 }
1771 }
1772 // use the next *raw* token so we don't ignore whitespace - we only care about
1773 // identifiers that directly follow the float
1774 Token id = this->nextRawToken();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001775 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas962dec42021-06-10 13:06:39 -04001776 field = skstd::string_view(field.data(), field.length() + id.fLength);
Ethan Nicholase455f652019-09-13 12:52:55 -04001777 } else {
1778 this->pushback(id);
1779 }
John Stiles3b209362020-11-16 17:03:10 -05001780 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kField, field);
Ethan Nicholase455f652019-09-13 12:52:55 -04001781 getNode(result).addChild(base);
1782 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001783 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001784 case Token::Kind::TK_LPAREN: {
John Stiles3b209362020-11-16 17:03:10 -05001785 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kCall);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001786 getNode(result).addChild(base);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001787 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001788 for (;;) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001789 ASTNode::ID expr = this->assignmentExpression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 if (!expr) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001791 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001793 getNode(result).addChild(expr);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001794 if (!this->checkNext(Token::Kind::TK_COMMA)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001795 break;
1796 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 }
1798 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001799 this->expect(Token::Kind::TK_RPAREN, "')' to complete function parameters");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001800 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001802 case Token::Kind::TK_PLUSPLUS: // fall through
1803 case Token::Kind::TK_MINUSMINUS: {
John Stiles45990502021-02-16 10:55:27 -05001804 ASTNode::ID result = this->createNode(next.fOffset, ASTNode::Kind::kPostfix,
1805 Operator(next.fKind));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001806 getNode(result).addChild(base);
1807 return result;
1808 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001809 default: {
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001810 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001811 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001812 }
1813 }
1814}
1815
Brian Osman33c64a42020-12-23 10:26:38 -05001816/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001817ASTNode::ID Parser::term() {
ethannicholasb3058bd2016-07-01 08:22:01 -07001818 Token t = this->peek();
1819 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001820 case Token::Kind::TK_IDENTIFIER: {
Ethan Nicholas962dec42021-06-10 13:06:39 -04001821 skstd::string_view text;
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 if (this->identifier(&text)) {
John Stiles3b209362020-11-16 17:03:10 -05001823 return this->createNode(t.fOffset, ASTNode::Kind::kIdentifier, std::move(text));
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 }
John Stiles30212b72020-06-11 17:55:07 -04001825 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001826 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001827 case Token::Kind::TK_INT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001828 SKSL_INT i;
ethannicholasb3058bd2016-07-01 08:22:01 -07001829 if (this->intLiteral(&i)) {
John Stiles3b209362020-11-16 17:03:10 -05001830 return this->createNode(t.fOffset, ASTNode::Kind::kInt, i);
ethannicholasb3058bd2016-07-01 08:22:01 -07001831 }
1832 break;
1833 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001834 case Token::Kind::TK_FLOAT_LITERAL: {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001835 SKSL_FLOAT f;
ethannicholasb3058bd2016-07-01 08:22:01 -07001836 if (this->floatLiteral(&f)) {
John Stiles3b209362020-11-16 17:03:10 -05001837 return this->createNode(t.fOffset, ASTNode::Kind::kFloat, f);
ethannicholasb3058bd2016-07-01 08:22:01 -07001838 }
1839 break;
1840 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001841 case Token::Kind::TK_TRUE_LITERAL: // fall through
1842 case Token::Kind::TK_FALSE_LITERAL: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001843 bool b;
1844 if (this->boolLiteral(&b)) {
John Stiles3b209362020-11-16 17:03:10 -05001845 return this->createNode(t.fOffset, ASTNode::Kind::kBool, b);
ethannicholasb3058bd2016-07-01 08:22:01 -07001846 }
1847 break;
1848 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001849 case Token::Kind::TK_LPAREN: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 this->nextToken();
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001851 AutoDepth depth(this);
Ethan Nicholascf4deab2019-09-13 16:28:14 -04001852 if (!depth.increase()) {
Ethan Nicholas4e3b0112019-06-07 16:49:07 -04001853 return ASTNode::ID::Invalid();
1854 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001855 ASTNode::ID result = this->expression();
ethannicholasb3058bd2016-07-01 08:22:01 -07001856 if (result) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001857 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
Ethan Nicholasfc994162019-06-06 10:04:27 -04001858 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001859 }
1860 break;
1861 }
1862 default:
1863 this->nextToken();
John Stilesf94348f2020-12-23 18:58:43 -05001864 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001865 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001866 return ASTNode::ID::Invalid();
ethannicholasb3058bd2016-07-01 08:22:01 -07001867}
1868
1869/* INT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001870bool Parser::intLiteral(SKSL_INT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001871 Token t;
John Stilesf94348f2020-12-23 18:58:43 -05001872 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1873 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -07001874 }
Ethan Nicholas962dec42021-06-10 13:06:39 -04001875 skstd::string_view s = this->text(t);
John Stilesf94348f2020-12-23 18:58:43 -05001876 if (!SkSL::stoi(s, dest)) {
1877 this->error(t, "integer is too large: " + s);
1878 return false;
1879 }
1880 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001881}
1882
John Stilesf94348f2020-12-23 18:58:43 -05001883
ethannicholasb3058bd2016-07-01 08:22:01 -07001884/* FLOAT_LITERAL */
Ethan Nicholasfc994162019-06-06 10:04:27 -04001885bool Parser::floatLiteral(SKSL_FLOAT* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001886 Token t;
John Stilesf94348f2020-12-23 18:58:43 -05001887 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1888 return false;
ethannicholasb3058bd2016-07-01 08:22:01 -07001889 }
Ethan Nicholas962dec42021-06-10 13:06:39 -04001890 skstd::string_view s = this->text(t);
John Stilesf94348f2020-12-23 18:58:43 -05001891 if (!SkSL::stod(s, dest)) {
1892 this->error(t, "floating-point value is too large: " + s);
1893 return false;
1894 }
1895 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001896}
1897
1898/* TRUE_LITERAL | FALSE_LITERAL */
1899bool Parser::boolLiteral(bool* dest) {
1900 Token t = this->nextToken();
1901 switch (t.fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001902 case Token::Kind::TK_TRUE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07001903 *dest = true;
1904 return true;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001905 case Token::Kind::TK_FALSE_LITERAL:
ethannicholasb3058bd2016-07-01 08:22:01 -07001906 *dest = false;
1907 return true;
1908 default:
Ethan Nicholas0c8582e2019-07-19 09:26:46 -04001909 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001910 return false;
1911 }
1912}
1913
1914/* IDENTIFIER */
Ethan Nicholas962dec42021-06-10 13:06:39 -04001915bool Parser::identifier(skstd::string_view* dest) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 Token t;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001917 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001918 *dest = this->text(t);
ethannicholasb3058bd2016-07-01 08:22:01 -07001919 return true;
1920 }
1921 return false;
1922}
1923
John Stilesa6841be2020-08-06 14:11:56 -04001924} // namespace SkSL