blob: e261403e82c5673739c666f9ca28fcf2643948c0 [file] [log] [blame]
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001/*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/sksl/SkSLDSLParser.h"
9
10#include "include/private/SkSLString.h"
11#include "src/sksl/SkSLCompiler.h"
Ethan Nicholas6c302ba2021-09-14 09:16:12 -040012#include "src/sksl/dsl/priv/DSLWriter.h"
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040013
14#include <memory>
15
16#if SKSL_DSL_PARSER
17
18using namespace SkSL::dsl;
19
20namespace SkSL {
21
22static constexpr int kMaxParseDepth = 50;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040023
24static int parse_modifier_token(Token::Kind token) {
25 switch (token) {
26 case Token::Kind::TK_UNIFORM: return Modifiers::kUniform_Flag;
27 case Token::Kind::TK_CONST: return Modifiers::kConst_Flag;
28 case Token::Kind::TK_IN: return Modifiers::kIn_Flag;
29 case Token::Kind::TK_OUT: return Modifiers::kOut_Flag;
30 case Token::Kind::TK_INOUT: return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
31 case Token::Kind::TK_FLAT: return Modifiers::kFlat_Flag;
32 case Token::Kind::TK_NOPERSPECTIVE: return Modifiers::kNoPerspective_Flag;
33 case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
34 case Token::Kind::TK_INLINE: return Modifiers::kInline_Flag;
35 case Token::Kind::TK_NOINLINE: return Modifiers::kNoInline_Flag;
John Stiles02014312021-08-04 16:03:12 -040036 case Token::Kind::TK_HIGHP: return Modifiers::kHighp_Flag;
37 case Token::Kind::TK_MEDIUMP: return Modifiers::kMediump_Flag;
38 case Token::Kind::TK_LOWP: return Modifiers::kLowp_Flag;
John Stilesefde90d2021-08-12 23:06:24 -040039 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040040 default: return 0;
41 }
42}
43
44class AutoDSLDepth {
45public:
46 AutoDSLDepth(DSLParser* p)
47 : fParser(p)
48 , fDepth(0) {}
49
50 ~AutoDSLDepth() {
51 fParser->fDepth -= fDepth;
52 }
53
54 bool increase() {
55 ++fDepth;
56 ++fParser->fDepth;
57 if (fParser->fDepth > kMaxParseDepth) {
58 fParser->error(fParser->peek(), String("exceeded max parse depth"));
59 return false;
60 }
61 return true;
62 }
63
64private:
65 DSLParser* fParser;
66 int fDepth;
67};
68
69class AutoDSLSymbolTable {
70public:
71 AutoDSLSymbolTable() {
72 dsl::PushSymbolTable();
73 }
74
75 ~AutoDSLSymbolTable() {
76 dsl::PopSymbolTable();
77 }
78};
79
80std::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
81
82void DSLParser::InitLayoutMap() {
83 layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
84 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
85 TOKEN(LOCATION, "location");
86 TOKEN(OFFSET, "offset");
87 TOKEN(BINDING, "binding");
88 TOKEN(INDEX, "index");
89 TOKEN(SET, "set");
90 TOKEN(BUILTIN, "builtin");
91 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
92 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
93 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
94 TOKEN(PUSH_CONSTANT, "push_constant");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040095 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
96 #undef TOKEN
97}
98
99DSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
100 String text)
101 : fCompiler(*compiler)
102 , fSettings(settings)
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400103 , fKind(kind)
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400104 , fText(std::make_unique<String>(std::move(text)))
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400105 , fPushback(Token::Kind::TK_NONE, -1, -1) {
106 // We don't want to have to worry about manually releasing all of the objects in the event that
107 // an error occurs
108 fSettings.fAssertDSLObjectsReleased = false;
Ethan Nicholasae9b4462021-09-16 16:23:05 -0400109 // We manage our symbol tables manually, so no need for name mangling
110 fSettings.fDSLMangling = false;
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400111 fLexer.start(*fText);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400112 static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
113 (void) layoutMapInitialized;
114}
115
116Token DSLParser::nextRawToken() {
117 if (fPushback.fKind != Token::Kind::TK_NONE) {
118 Token result = fPushback;
119 fPushback.fKind = Token::Kind::TK_NONE;
120 return result;
121 }
122 return fLexer.next();
123}
124
125Token DSLParser::nextToken() {
126 Token token = this->nextRawToken();
127 while (token.fKind == Token::Kind::TK_WHITESPACE ||
128 token.fKind == Token::Kind::TK_LINE_COMMENT ||
129 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
130 token = this->nextRawToken();
131 }
132 return token;
133}
134
135void DSLParser::pushback(Token t) {
136 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
137 fPushback = std::move(t);
138}
139
140Token DSLParser::peek() {
141 if (fPushback.fKind == Token::Kind::TK_NONE) {
142 fPushback = this->nextToken();
143 }
144 return fPushback;
145}
146
147bool DSLParser::checkNext(Token::Kind kind, Token* result) {
148 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
149 return false;
150 }
151 Token next = this->nextToken();
152 if (next.fKind == kind) {
153 if (result) {
154 *result = next;
155 }
156 return true;
157 }
158 this->pushback(std::move(next));
159 return false;
160}
161
162bool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
163 Token next = this->nextToken();
164 if (next.fKind == kind) {
165 if (result) {
166 *result = std::move(next);
167 }
168 return true;
169 } else {
170 this->error(next, "expected " + String(expected) + ", but found '" +
171 this->text(next) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400172 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400173 return false;
174 }
175}
176
177bool DSLParser::expectIdentifier(Token* result) {
178 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
179 return false;
180 }
181 if (IsType(this->text(*result))) {
182 this->error(*result, "expected an identifier, but found type '" +
183 this->text(*result) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400184 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400185 return false;
186 }
187 return true;
188}
189
190skstd::string_view DSLParser::text(Token token) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400191 return skstd::string_view(fText->data() + token.fOffset, token.fLength);
192}
193
194PositionInfo DSLParser::position(Token t) {
195 return this->position(t.fOffset);
196}
197
198PositionInfo DSLParser::position(int offset) {
199 return PositionInfo::Offset("<unknown>", fText->c_str(), offset);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400200}
201
202void DSLParser::error(Token token, String msg) {
203 this->error(token.fOffset, msg);
204}
205
206void DSLParser::error(int offset, String msg) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400207 GetErrorReporter().error(msg.c_str(), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400208}
209
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400210/* declaration* END_OF_FILE */
211std::unique_ptr<Program> DSLParser::program() {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400212 ErrorReporter* errorReporter = &fCompiler.errorReporter();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400213 Start(&fCompiler, fKind, fSettings);
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400214 SetErrorReporter(errorReporter);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400215 errorReporter->setSource(fText->c_str());
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400216 fEncounteredFatalError = false;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400217 std::unique_ptr<Program> result;
218 bool done = false;
219 while (!done) {
220 switch (this->peek().fKind) {
221 case Token::Kind::TK_END_OF_FILE:
222 done = true;
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400223 if (!errorReporter->errorCount()) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400224 result = dsl::ReleaseProgram(std::move(fText));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400225 }
226 break;
Ethan Nicholas642215e2021-09-03 11:10:54 -0400227 case Token::Kind::TK_DIRECTIVE:
228 this->directive();
229 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400230 case Token::Kind::TK_INVALID: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400231 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400232 this->error(this->peek(), String("invalid token"));
Ethan Nicholasf8f1fa02021-08-29 14:12:17 -0400233 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400234 break;
235 }
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400236 default:
237 this->declaration();
238 done = fEncounteredFatalError;
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400239 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400240 }
241 }
242 End();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400243 errorReporter->setSource(nullptr);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400244 return result;
245}
246
Ethan Nicholas642215e2021-09-03 11:10:54 -0400247/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
248void DSLParser::directive() {
249 Token start;
250 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
251 return;
252 }
253 skstd::string_view text = this->text(start);
254 if (text == "#extension") {
255 Token name;
256 if (!this->expectIdentifier(&name)) {
257 return;
258 }
259 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
260 return;
261 }
262 Token behavior;
263 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
264 return;
265 }
266 skstd::string_view behaviorText = this->text(behavior);
267 if (behaviorText == "disable") {
268 return;
269 }
270 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
271 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
272 }
273 // We don't currently do anything different between require, enable, and warn
274 dsl::AddExtension(this->text(name));
275 } else {
276 this->error(start, "unsupported directive '" + this->text(start) + "'");
277 }
278}
279
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400280/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
281 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
282bool DSLParser::declaration() {
283 Token lookahead = this->peek();
284 switch (lookahead.fKind) {
285 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400286 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400287 this->error(lookahead.fOffset, "expected a declaration, but found ';'");
288 return false;
289 default:
290 break;
291 }
292 DSLModifiers modifiers = this->modifiers();
293 lookahead = this->peek();
294 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
295 // we have an identifier that's not a type, could be the start of an interface block
296 return this->interfaceBlock(modifiers);
297 }
298 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
Ethan Nicholas678ec712021-09-03 06:33:47 -0400299 this->nextToken();
300 Declare(modifiers, position(lookahead));
301 return true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400302 }
303 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400304 this->structVarDeclaration(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400305 return true;
306 }
John Stiles4adb66f2021-08-05 10:15:16 -0400307 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400308 if (!type) {
309 return false;
310 }
311 Token name;
312 if (!this->expectIdentifier(&name)) {
313 return false;
314 }
315 if (this->checkNext(Token::Kind::TK_LPAREN)) {
316 return this->functionDeclarationEnd(modifiers, *type, name);
317 } else {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400318 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400319 return true;
320 }
321}
322
323/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400324bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
325 DSLType type,
326 const Token& name) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400327 SkTArray<DSLWrapper<DSLParameter>> parameters;
328 Token lookahead = this->peek();
329 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
330 // `()` means no parameters at all.
331 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
332 // `(void)` also means no parameters at all.
333 this->nextToken();
334 } else {
335 for (;;) {
336 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
337 if (!parameter) {
338 return false;
339 }
340 parameters.push_back(std::move(*parameter));
341 if (!this->checkNext(Token::Kind::TK_COMMA)) {
342 break;
343 }
344 }
345 }
346 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
347 return false;
348 }
349 SkTArray<DSLParameter*> parameterPointers;
350 for (DSLWrapper<DSLParameter>& param : parameters) {
351 parameterPointers.push_back(&param.get());
352 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400353 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400354 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
355 AutoDSLSymbolTable symbols;
356 for (DSLParameter* var : parameterPointers) {
357 AddToSymbolTable(*var);
358 }
359 skstd::optional<DSLBlock> body = this->block();
360 if (!body) {
361 return false;
362 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -0400363 result.define(std::move(*body), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400364 }
365 return true;
366}
367
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400368SKSL_INT DSLParser::arraySize() {
369 Token next = this->peek();
370 if (next.fKind == Token::Kind::TK_INT_LITERAL) {
371 SKSL_INT size;
372 if (this->intLiteral(&size)) {
373 if (size > INT32_MAX) {
374 this->error(next, "array size out of bounds");
375 return 1;
376 }
377 if (size <= 0) {
378 this->error(next, "array size must be positive");
379 return 1;
380 }
381 return size;
382 }
383 return 1;
384 } else if (this->checkNext(Token::Kind::TK_MINUS) &&
385 this->checkNext(Token::Kind::TK_INT_LITERAL)) {
386 this->error(next, "array size must be positive");
387 return 1;
388 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400389 DSLExpression expr = this->expression();
390 if (expr.isValid()) {
Ethan Nicholas51b4b862021-08-31 16:12:40 -0400391 this->error(next, "expected int literal");
392 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400393 return 1;
394 }
395}
396
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400397bool DSLParser::parseArrayDimensions(int offset, DSLType* type) {
398 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
399 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
400 this->error(offset, "expected array dimension");
401 } else {
402 *type = Array(*type, this->arraySize(), this->position(offset));
403 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400404 return false;
405 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400406 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400407 }
408 return true;
409}
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400410
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400411bool DSLParser::parseInitializer(int offset, DSLExpression* initializer) {
412 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400413 DSLExpression value = this->assignmentExpression();
414 if (!value.hasValue()) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400415 return false;
416 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400417 initializer->swap(value);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400418 }
419 return true;
420}
421
422/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
423 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
424void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
425 dsl::DSLType baseType, skstd::string_view name) {
426 using namespace dsl;
427 int offset = this->peek().fOffset;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400428 DSLType type = baseType;
429 DSLExpression initializer;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400430 if (!this->parseArrayDimensions(offset, &type)) {
431 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400432 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400433 this->parseInitializer(offset, &initializer);
434 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
435 Declare(first);
436 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400437
438 while (this->checkNext(Token::Kind::TK_COMMA)) {
439 type = baseType;
440 Token identifierName;
441 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400442 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400443 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400444 if (!this->parseArrayDimensions(offset, &type)) {
445 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400446 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400447 DSLExpression anotherInitializer;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400448 if (!this->parseInitializer(offset, &anotherInitializer)) {
449 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400450 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400451 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer));
452 Declare(next);
453 AddToSymbolTable(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400454 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400455 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400456}
457
458/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
459 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400460DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
461 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400462 using namespace dsl;
463 int offset = this->peek().fOffset;
464 DSLType type = baseType;
465 DSLExpression initializer;
466 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400467 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400468 }
469 this->parseInitializer(offset, &initializer);
470 DSLVar first(mods, type, name, std::move(initializer), pos);
471 DSLStatement result = Declare(first);
472 AddToSymbolTable(first);
473
474 while (this->checkNext(Token::Kind::TK_COMMA)) {
475 type = baseType;
476 Token identifierName;
477 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400478 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400479 }
480 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400481 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400482 }
483 DSLExpression anotherInitializer;
484 if (!this->parseInitializer(offset, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400485 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400486 }
487 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer));
488 DSLWriter::AddVarDeclaration(result, next);
489 AddToSymbolTable(next);
490 }
491 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400492 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400493}
494
495/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400496DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400497 Token nextToken = this->peek();
498 if (nextToken.fKind == Token::Kind::TK_CONST) {
499 // Statements that begin with `const` might be variable declarations, but can't be legal
500 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
501 return this->varDeclarations();
502 }
503
John Stiles02014312021-08-04 16:03:12 -0400504 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
505 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
506 nextToken.fKind == Token::Kind::TK_LOWP ||
507 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400508 // Statements that begin with a typename are most often variable declarations, but
509 // occasionally the type is part of a constructor, and these are actually expression-
510 // statements in disguise. First, attempt the common case: parse it as a vardecl.
511 Checkpoint checkpoint(this);
512 VarDeclarationsPrefix prefix;
513 if (this->varDeclarationsPrefix(&prefix)) {
514 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400515 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
516 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400517 }
518
519 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
520 // expression-statement instead.
521 checkpoint.rewind();
522 }
523 return this->expressionStatement();
524}
525
526// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
527// statement is a variable-declaration statement, not an expression-statement.
528bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400529 prefixData->fPosition = this->position(this->peek());
530 prefixData->fModifiers = this->modifiers();
531 skstd::optional<DSLType> type = this->type(prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400532 if (!type) {
533 return false;
534 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400535 prefixData->fType = *type;
536 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400537}
538
539/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400540DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400541 VarDeclarationsPrefix prefix;
542 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400543 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400544 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400545 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
546 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400547}
548
549/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
550skstd::optional<DSLType> DSLParser::structDeclaration() {
551 AutoDSLDepth depth(this);
552 if (!depth.increase()) {
553 return skstd::nullopt;
554 }
555 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
556 return skstd::nullopt;
557 }
558 Token name;
559 if (!this->expectIdentifier(&name)) {
560 return skstd::nullopt;
561 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400562 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
563 return skstd::nullopt;
564 }
565 SkTArray<DSLField> fields;
566 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
567 DSLModifiers modifiers = this->modifiers();
568
John Stiles4adb66f2021-08-05 10:15:16 -0400569 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400570 if (!type) {
571 return skstd::nullopt;
572 }
573
574 do {
575 DSLType actualType = *type;
576 Token memberName;
577 if (!this->expectIdentifier(&memberName)) {
578 return skstd::nullopt;
579 }
580
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400581 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
582 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400583 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
584 return skstd::nullopt;
585 }
586 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400587 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
588 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400589 } while (this->checkNext(Token::Kind::TK_COMMA));
590 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
591 return skstd::nullopt;
592 }
593 }
594 if (fields.empty()) {
595 this->error(name.fOffset,
596 "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400597 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400598 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400599}
600
601/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400602SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400603 skstd::optional<DSLType> type = this->structDeclaration();
604 if (!type) {
605 return {};
606 }
607 Token name;
608 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400609 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
610 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400611 } else {
612 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400613 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400614 return {};
615}
616
617/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
618skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
619 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles4adb66f2021-08-05 10:15:16 -0400620 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400621 if (!type) {
622 return skstd::nullopt;
623 }
624 Token name;
625 if (!this->expectIdentifier(&name)) {
626 return skstd::nullopt;
627 }
628 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400629 Token sizeToken;
630 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
631 return skstd::nullopt;
632 }
633 skstd::string_view arraySizeFrag = this->text(sizeToken);
634 SKSL_INT arraySize;
635 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
636 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400637 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400638 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400639 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400640 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
641 return skstd::nullopt;
642 }
643 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400644 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400645}
646
647/** EQ INT_LITERAL */
648int DSLParser::layoutInt() {
649 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
650 return -1;
651 }
652 Token resultToken;
653 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
654 return -1;
655 }
656 skstd::string_view resultFrag = this->text(resultToken);
657 SKSL_INT resultValue;
658 if (!SkSL::stoi(resultFrag, &resultValue)) {
659 this->error(resultToken, "value in layout is too large: " + resultFrag);
660 return -1;
661 }
662 return resultValue;
663}
664
665/** EQ IDENTIFIER */
666skstd::string_view DSLParser::layoutIdentifier() {
667 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
668 return {};
669 }
670 Token resultToken;
671 if (!this->expectIdentifier(&resultToken)) {
672 return {};
673 }
674 return this->text(resultToken);
675}
676
677/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
678DSLLayout DSLParser::layout() {
679 DSLLayout result;
680 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
681 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
682 return result;
683 }
684 for (;;) {
685 Token t = this->nextToken();
686 String text(this->text(t));
687 auto found = layoutTokens->find(text);
688 if (found != layoutTokens->end()) {
689 switch (found->second) {
690 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400691 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400692 break;
693 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400694 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400695 break;
696 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400697 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400698 break;
699 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400700 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400701 break;
702 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400703 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400704 break;
705 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400706 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400707 break;
708 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400709 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400710 break;
711 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400712 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400713 break;
714 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400715 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400716 break;
717 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400718 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400719 break;
720 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400721 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400722 break;
723 default:
724 this->error(t, "'" + text + "' is not a valid layout qualifier");
725 break;
726 }
727 } else {
728 this->error(t, "'" + text + "' is not a valid layout qualifier");
729 }
730 if (this->checkNext(Token::Kind::TK_RPAREN)) {
731 break;
732 }
733 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
734 break;
735 }
736 }
737 }
738 return result;
739}
740
741/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
742 VARYING | INLINE)* */
743DSLModifiers DSLParser::modifiers() {
744 DSLLayout layout = this->layout();
745 int flags = 0;
746 for (;;) {
747 // TODO(ethannicholas): handle duplicate / incompatible flags
748 int tokenFlag = parse_modifier_token(peek().fKind);
749 if (!tokenFlag) {
750 break;
751 }
752 flags |= tokenFlag;
753 this->nextToken();
754 }
755 return DSLModifiers(std::move(layout), flags);
756}
757
758DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
759 DSLModifiers result = this->modifiers();
760 if (defaultFlags && !result.flags()) {
761 return DSLModifiers(result.layout(), defaultFlags);
762 }
763 return result;
764}
765
766/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400767DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400768 Token start = this->nextToken();
769 AutoDSLDepth depth(this);
770 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400771 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400772 }
773 this->pushback(start);
774 switch (start.fKind) {
775 case Token::Kind::TK_IF: // fall through
776 case Token::Kind::TK_STATIC_IF:
777 return this->ifStatement();
778 case Token::Kind::TK_FOR:
779 return this->forStatement();
780 case Token::Kind::TK_DO:
781 return this->doStatement();
782 case Token::Kind::TK_WHILE:
783 return this->whileStatement();
784 case Token::Kind::TK_SWITCH: // fall through
785 case Token::Kind::TK_STATIC_SWITCH:
786 return this->switchStatement();
787 case Token::Kind::TK_RETURN:
788 return this->returnStatement();
789 case Token::Kind::TK_BREAK:
790 return this->breakStatement();
791 case Token::Kind::TK_CONTINUE:
792 return this->continueStatement();
793 case Token::Kind::TK_DISCARD:
794 return this->discardStatement();
795 case Token::Kind::TK_LBRACE: {
796 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400797 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400798 }
799 case Token::Kind::TK_SEMICOLON:
800 this->nextToken();
801 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400802 case Token::Kind::TK_HIGHP:
803 case Token::Kind::TK_MEDIUMP:
804 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400805 case Token::Kind::TK_CONST:
806 case Token::Kind::TK_IDENTIFIER:
807 return this->varDeclarationsOrExpressionStatement();
808 default:
809 return this->expressionStatement();
810 }
811}
812
813/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stilese53c7212021-08-05 10:19:11 -0400814skstd::optional<DSLType> DSLParser::type(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400815 Token type;
816 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
817 return skstd::nullopt;
818 }
819 if (!IsType(this->text(type))) {
820 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
821 return skstd::nullopt;
822 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400823 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400824 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400825 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400826 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400827 } else {
828 this->error(this->peek(), "expected array dimension");
829 }
830 this->expect(Token::Kind::TK_RBRACKET, "']'");
831 }
832 return result;
833}
834
835/* IDENTIFIER LBRACE
836 varDeclaration+
837 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400838bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400839 Token typeName;
840 if (!this->expectIdentifier(&typeName)) {
841 return false;
842 }
843 if (peek().fKind != Token::Kind::TK_LBRACE) {
844 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
845 // 99% of the time, the user was not actually intending to create an interface block, so
846 // it's better to report it as an unknown type
847 this->error(typeName, "no type named '" + this->text(typeName) + "'");
848 return false;
849 }
850 this->nextToken();
851 SkTArray<dsl::Field> fields;
852 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400853 DSLModifiers fieldModifiers = this->modifiers();
854 skstd::optional<dsl::DSLType> type = this->type(fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400855 if (!type) {
856 return false;
857 }
858 do {
859 Token fieldName;
860 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
861 return false;
862 }
863 DSLType actualType = *type;
864 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
865 Token sizeToken = this->peek();
866 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400867 actualType = Array(std::move(actualType), this->arraySize(),
868 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400869 } else {
870 this->error(sizeToken, "unsized arrays are not permitted");
871 }
872 this->expect(Token::Kind::TK_RBRACKET, "']'");
873 }
874 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
875 return false;
876 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400877 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
878 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400879 }
880 while (this->checkNext(Token::Kind::TK_COMMA));
881 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400882 skstd::string_view instanceName;
883 Token instanceNameToken;
884 SKSL_INT arraySize = 0;
885 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
886 instanceName = this->text(instanceNameToken);
887 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400888 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400889 this->expect(Token::Kind::TK_RBRACKET, "']'");
890 }
891 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400892 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400893 if (fields.empty()) {
894 this->error(typeName, "interface block '" + this->text(typeName) +
895 "' must contain at least one member");
896 } else {
897 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
898 arraySize, this->position(typeName));
899 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400900 return true;
901}
902
903/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400904DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400905 Token start;
906 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
907 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400908 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400909 }
910 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400911 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400912 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400913 DSLExpression test = this->expression();
914 if (!test.hasValue()) {
915 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400916 }
917 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400918 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400919 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400920 DSLStatement ifTrue = this->statement();
921 if (!ifTrue.hasValue()) {
922 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400923 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400924 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400925 if (this->checkNext(Token::Kind::TK_ELSE)) {
926 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400927 if (!ifFalse.hasValue()) {
928 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400929 }
930 }
931 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400932 return StaticIf(std::move(test), std::move(ifTrue),
933 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400934 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400935 return If(std::move(test), std::move(ifTrue),
936 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400937 }
938}
939
940/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400941DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400942 Token start;
943 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400944 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400945 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400946 DSLStatement statement = this->statement();
947 if (!statement.hasValue()) {
948 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400949 }
950 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400951 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400952 }
953 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400954 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400955 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400956 DSLExpression test = this->expression();
957 if (!test.hasValue()) {
958 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400959 }
960 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400961 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400962 }
963 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400964 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400965 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400966 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400967}
968
969/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400970DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400971 Token start;
972 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400973 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400974 }
975 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400976 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400977 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400978 DSLExpression test = this->expression();
979 if (!test.hasValue()) {
980 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400981 }
982 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400983 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400984 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400985 DSLStatement statement = this->statement();
986 if (!statement.hasValue()) {
987 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400988 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400989 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400990}
991
992/* CASE expression COLON statement* */
993skstd::optional<DSLCase> DSLParser::switchCase() {
994 Token start;
995 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400996 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400997 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400998 DSLExpression value = this->expression();
999 if (!value.hasValue()) {
1000 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001001 }
1002 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001003 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001004 }
1005 SkTArray<DSLStatement> statements;
1006 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1007 this->peek().fKind != Token::Kind::TK_CASE &&
1008 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001009 DSLStatement s = this->statement();
1010 if (!s.hasValue()) {
1011 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001012 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001013 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001014 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001015 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001016}
1017
1018/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001019DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001020 Token start;
1021 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1022 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001023 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001024 }
1025 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001026 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001027 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001028 DSLExpression value = this->expression();
1029 if (!value.hasValue()) {
1030 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001031 }
1032 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001033 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001034 }
1035 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001036 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001037 }
1038 SkTArray<DSLCase> cases;
1039 while (this->peek().fKind == Token::Kind::TK_CASE) {
1040 skstd::optional<DSLCase> c = this->switchCase();
1041 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001042 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001043 }
1044 cases.push_back(std::move(*c));
1045 }
1046 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1047 // parts of the compiler may rely upon this assumption.
1048 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1049 SkTArray<DSLStatement> statements;
1050 Token defaultStart;
1051 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1052 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001053 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001054 }
1055 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001056 DSLStatement s = this->statement();
1057 if (!s.hasValue()) {
1058 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001059 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001060 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001061 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001062 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001063 }
1064 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001065 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001066 }
1067 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001068 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001069 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001070 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001071 }
1072}
1073
1074/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1075 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001076dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001077 Token start;
1078 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001079 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001080 }
1081 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001082 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001083 }
1084 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001085 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001086 Token nextToken = this->peek();
1087 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1088 // An empty init-statement.
1089 this->nextToken();
1090 } else {
1091 // The init-statement must be an expression or variable declaration.
1092 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001093 if (!initializer.hasValue()) {
1094 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001095 }
1096 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001097 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001098 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001099 dsl::DSLExpression testValue = this->expression();
1100 if (!testValue.hasValue()) {
1101 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001102 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001103 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001104 }
1105 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001106 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001107 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001108 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001109 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001110 dsl::DSLExpression nextValue = this->expression();
1111 if (!nextValue.hasValue()) {
1112 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001113 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001114 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001115 }
1116 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001117 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001118 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001119 dsl::DSLStatement statement = this->statement();
1120 if (!statement.hasValue()) {
1121 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001122 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001123 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1124 test.hasValue() ? std::move(test) : DSLExpression(),
1125 next.hasValue() ? std::move(next) : DSLExpression(),
1126 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001127 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001128}
1129
1130/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001131DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001132 Token start;
1133 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001134 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001135 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001136 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001137 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001138 DSLExpression next = this->expression();
1139 if (!next.hasValue()) {
1140 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001141 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001142 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001143 }
1144 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001145 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001146 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001147 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1148 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001149}
1150
1151/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001152DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001153 Token start;
1154 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001155 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001156 }
1157 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001158 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001159 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001160 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001161}
1162
1163/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001164DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001165 Token start;
1166 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001167 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001168 }
1169 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001170 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001171 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001172 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001173}
1174
1175/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001176DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001177 Token start;
1178 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001179 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001180 }
1181 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001182 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001183 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001184 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001185}
1186
1187/* LBRACE statement* RBRACE */
1188skstd::optional<DSLBlock> DSLParser::block() {
1189 Token start;
1190 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1191 return skstd::nullopt;
1192 }
1193 AutoDSLDepth depth(this);
1194 if (!depth.increase()) {
1195 return skstd::nullopt;
1196 }
1197 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001198 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001199 for (;;) {
1200 switch (this->peek().fKind) {
1201 case Token::Kind::TK_RBRACE:
1202 this->nextToken();
1203 return DSLBlock(std::move(statements), CurrentSymbolTable());
1204 case Token::Kind::TK_END_OF_FILE:
1205 this->error(this->peek(), "expected '}', but found end of file");
1206 return skstd::nullopt;
1207 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001208 DSLStatement statement = this->statement();
1209 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001210 return skstd::nullopt;
1211 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001212 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001213 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001214 }
1215 }
1216 }
1217}
1218
1219/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001220DSLStatement DSLParser::expressionStatement() {
1221 DSLExpression expr = this->expression();
1222 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001223 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001224 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001225 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001226 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001227 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001228 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001229}
1230
1231/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001232DSLExpression DSLParser::expression() {
1233 DSLExpression result = this->assignmentExpression();
1234 if (!result.hasValue()) {
1235 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001236 }
1237 Token t;
1238 AutoDSLDepth depth(this);
1239 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1240 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001241 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001242 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001243 DSLExpression right = this->assignmentExpression();
1244 if (!right.hasValue()) {
1245 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001246 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001247 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1248 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001249 }
1250 return result;
1251}
1252
1253#define OPERATOR_RIGHT(op, exprType) \
1254 do { \
1255 this->nextToken(); \
1256 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001257 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001258 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001259 DSLExpression right = this->exprType(); \
1260 if (!right.hasValue()) { \
1261 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001262 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001263 DSLExpression next = std::move(result) op std::move(right); \
1264 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001265 } while (false)
1266
1267/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1268 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1269 assignmentExpression)*
1270 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001271DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001272 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001273 DSLExpression result = this->ternaryExpression();
1274 if (!result.hasValue()) {
1275 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001276 }
1277 for (;;) {
1278 switch (this->peek().fKind) {
1279 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1280 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1281 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1282 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1283 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1284 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1285 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1286 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1287 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1288 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1289 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1290 default:
1291 return result;
1292 }
1293 }
1294}
1295
1296/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001297DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001298 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001299 DSLExpression base = this->logicalOrExpression();
1300 if (!base.hasValue()) {
1301 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001302 }
1303 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1304 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001305 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001306 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001307 DSLExpression trueExpr = this->expression();
1308 if (!trueExpr.hasValue()) {
1309 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001310 }
1311 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001312 DSLExpression falseExpr = this->assignmentExpression();
1313 if (!falseExpr.hasValue()) {
1314 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001315 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001316 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001317 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001318 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001319 }
1320 return base;
1321}
1322
1323/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001324DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001325 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001326 DSLExpression result = this->logicalXorExpression();
1327 if (!result.hasValue()) {
1328 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001329 }
1330 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1331 OPERATOR_RIGHT(||, logicalXorExpression);
1332 }
1333 return result;
1334}
1335
1336/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001337DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001338 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001339 DSLExpression result = this->logicalAndExpression();
1340 if (!result.hasValue()) {
1341 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001342 }
1343 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1344 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001345 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001346 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001347 DSLExpression right = this->logicalAndExpression();
1348 if (!right.hasValue()) {
1349 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001350 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001351 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1352 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001353 }
1354 return result;
1355}
1356
1357/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001358DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001359 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001360 DSLExpression result = this->bitwiseOrExpression();
1361 if (!result.hasValue()) {
1362 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001363 }
1364 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1365 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1366 }
1367 return result;
1368}
1369
1370/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001371DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001372 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001373 DSLExpression result = this->bitwiseXorExpression();
1374 if (!result.hasValue()) {
1375 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001376 }
1377 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1378 OPERATOR_RIGHT(|, bitwiseXorExpression);
1379 }
1380 return result;
1381}
1382
1383/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001384DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001385 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001386 DSLExpression result = this->bitwiseAndExpression();
1387 if (!result.hasValue()) {
1388 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001389 }
1390 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1391 OPERATOR_RIGHT(^, bitwiseAndExpression);
1392 }
1393 return result;
1394}
1395
1396/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001397DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001398 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001399 DSLExpression result = this->equalityExpression();
1400 if (!result.hasValue()) {
1401 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001402 }
1403 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1404 OPERATOR_RIGHT(&, equalityExpression);
1405 }
1406 return result;
1407}
1408
1409/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001410DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001411 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001412 DSLExpression result = this->relationalExpression();
1413 if (!result.hasValue()) {
1414 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001415 }
1416 for (;;) {
1417 switch (this->peek().fKind) {
1418 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1419 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1420 default: return result;
1421 }
1422 }
1423}
1424
1425/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001426DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001427 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001428 DSLExpression result = this->shiftExpression();
1429 if (!result.hasValue()) {
1430 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001431 }
1432 for (;;) {
1433 switch (this->peek().fKind) {
1434 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1435 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1436 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1437 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1438 default: return result;
1439 }
1440 }
1441}
1442
1443/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001444DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001445 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001446 DSLExpression result = this->additiveExpression();
1447 if (!result.hasValue()) {
1448 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001449 }
1450 for (;;) {
1451 switch (this->peek().fKind) {
1452 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1453 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1454 default: return result;
1455 }
1456 }
1457}
1458
1459/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001460DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001461 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001462 DSLExpression result = this->multiplicativeExpression();
1463 if (!result.hasValue()) {
1464 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001465 }
1466 for (;;) {
1467 switch (this->peek().fKind) {
1468 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1469 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1470 default: return result;
1471 }
1472 }
1473}
1474
1475/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001476DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001477 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001478 DSLExpression result = this->unaryExpression();
1479 if (!result.hasValue()) {
1480 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001481 }
1482 for (;;) {
1483 switch (this->peek().fKind) {
1484 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1485 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1486 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1487 default: return result;
1488 }
1489 }
1490}
1491
1492/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001493DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001494 AutoDSLDepth depth(this);
1495 Token next = this->peek();
1496 switch (next.fKind) {
1497 case Token::Kind::TK_PLUS:
1498 case Token::Kind::TK_MINUS:
1499 case Token::Kind::TK_LOGICALNOT:
1500 case Token::Kind::TK_BITWISENOT:
1501 case Token::Kind::TK_PLUSPLUS:
1502 case Token::Kind::TK_MINUSMINUS: {
1503 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001504 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001505 }
1506 this->nextToken();
1507 skstd::optional<DSLWrapper<DSLExpression>> expr = this->unaryExpression();
1508 if (!expr) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001509 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001510 }
1511 switch (next.fKind) {
1512 case Token::Kind::TK_PLUS: return {{ +std::move(**expr)}};
1513 case Token::Kind::TK_MINUS: return {{ -std::move(**expr)}};
1514 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(**expr)}};
1515 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(**expr)}};
1516 case Token::Kind::TK_PLUSPLUS: return {{++std::move(**expr)}};
1517 case Token::Kind::TK_MINUSMINUS: return {{--std::move(**expr)}};
1518 default: SkUNREACHABLE;
1519 }
1520 }
1521 default:
1522 return this->postfixExpression();
1523 }
1524}
1525
1526/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001527DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001528 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001529 DSLExpression result = this->term();
1530 if (!result.hasValue()) {
1531 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001532 }
1533 for (;;) {
1534 Token t = this->peek();
1535 switch (t.fKind) {
1536 case Token::Kind::TK_FLOAT_LITERAL:
1537 if (this->text(t)[0] != '.') {
1538 return result;
1539 }
1540 [[fallthrough]];
1541 case Token::Kind::TK_LBRACKET:
1542 case Token::Kind::TK_DOT:
1543 case Token::Kind::TK_LPAREN:
1544 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001545 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001546 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001547 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001548 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001549 DSLExpression next = this->suffix(std::move(result));
1550 if (!next.hasValue()) {
1551 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001552 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001553 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001554 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001555 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001556 default:
1557 return result;
1558 }
1559 }
1560}
1561
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001562DSLExpression DSLParser::swizzle(int offset, DSLExpression base,
1563 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001564 SkASSERT(swizzleMask.length() > 0);
1565 if (!base.type().isVector() && !base.type().isScalar()) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001566 return base.field(swizzleMask, this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001567 }
1568 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001569 SkSL::SwizzleComponent::Type components[4];
1570 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001571 if (i >= 4) {
1572 this->error(offset, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001573 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001574 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001575 switch (swizzleMask[i]) {
1576 case '0': components[i] = SwizzleComponent::ZERO; break;
1577 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001578 case 'r': components[i] = SwizzleComponent::R; break;
1579 case 'x': components[i] = SwizzleComponent::X; break;
1580 case 's': components[i] = SwizzleComponent::S; break;
1581 case 'L': components[i] = SwizzleComponent::UL; break;
1582 case 'g': components[i] = SwizzleComponent::G; break;
1583 case 'y': components[i] = SwizzleComponent::Y; break;
1584 case 't': components[i] = SwizzleComponent::T; break;
1585 case 'T': components[i] = SwizzleComponent::UT; break;
1586 case 'b': components[i] = SwizzleComponent::B; break;
1587 case 'z': components[i] = SwizzleComponent::Z; break;
1588 case 'p': components[i] = SwizzleComponent::P; break;
1589 case 'R': components[i] = SwizzleComponent::UR; break;
1590 case 'a': components[i] = SwizzleComponent::A; break;
1591 case 'w': components[i] = SwizzleComponent::W; break;
1592 case 'q': components[i] = SwizzleComponent::Q; break;
1593 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001594 default:
1595 this->error(offset,
1596 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001597 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001598 }
1599 }
1600 switch (length) {
1601 case 1: return dsl::Swizzle(std::move(base), components[0]);
1602 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1603 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1604 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1605 components[3]);
1606 default: SkUNREACHABLE;
1607 }
1608}
1609
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001610dsl::DSLExpression DSLParser::call(int offset, dsl::DSLExpression base, ExpressionArray args) {
1611 return DSLExpression(base(std::move(args), this->position(offset)), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001612}
1613
1614/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1615 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001616DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001617 Token next = this->nextToken();
1618 AutoDSLDepth depth(this);
1619 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001620 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001621 }
1622 switch (next.fKind) {
1623 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001624 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1625 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001626 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001627 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001628 DSLExpression index = this->expression();
1629 if (!index.hasValue()) {
1630 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001631 }
1632 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001633 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001634 if (!result.valid()) {
1635 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001636 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001637 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001638 }
1639 case Token::Kind::TK_DOT: {
1640 int offset = this->peek().fOffset;
1641 skstd::string_view text;
1642 if (this->identifier(&text)) {
1643 return this->swizzle(offset, std::move(base), text);
1644 }
1645 [[fallthrough]];
1646 }
1647 case Token::Kind::TK_FLOAT_LITERAL: {
1648 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1649 // floating point literals, possibly followed by an identifier. Handle that here.
1650 skstd::string_view field = this->text(next);
1651 SkASSERT(field[0] == '.');
1652 field.remove_prefix(1);
1653 // use the next *raw* token so we don't ignore whitespace - we only care about
1654 // identifiers that directly follow the float
1655 Token id = this->nextRawToken();
1656 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
1657 return this->swizzle(next.fOffset, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001658 } else if (field.empty()) {
1659 this->error(next, "expected field name or swizzle mask after '.'");
1660 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001661 }
1662 this->pushback(id);
1663 return this->swizzle(next.fOffset, std::move(base), field);
1664 }
1665 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001666 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001667 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1668 for (;;) {
1669 skstd::optional<DSLWrapper<DSLExpression>> expr = this->assignmentExpression();
1670 if (!expr) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001671 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001672 }
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001673 args.push_back((**expr).release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001674 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1675 break;
1676 }
1677 }
1678 }
1679 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
1680 return this->call(next.fOffset, std::move(base), std::move(args));
1681 }
1682 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001683 return std::move(base)++;
1684 case Token::Kind::TK_MINUSMINUS:
1685 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001686 default: {
1687 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001688 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001689 }
1690 }
1691}
1692
1693/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001694DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001695 Token t = this->peek();
1696 switch (t.fKind) {
1697 case Token::Kind::TK_IDENTIFIER: {
1698 skstd::string_view text;
1699 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001700 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001701 }
1702 break;
1703 }
1704 case Token::Kind::TK_INT_LITERAL: {
1705 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001706 if (!this->intLiteral(&i)) {
1707 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001708 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001709 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001710 }
1711 case Token::Kind::TK_FLOAT_LITERAL: {
1712 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001713 if (!this->floatLiteral(&f)) {
1714 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001715 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001716 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001717 }
1718 case Token::Kind::TK_TRUE_LITERAL: // fall through
1719 case Token::Kind::TK_FALSE_LITERAL: {
1720 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001721 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001722 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001723 }
1724 case Token::Kind::TK_LPAREN: {
1725 this->nextToken();
1726 AutoDSLDepth depth(this);
1727 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001728 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001729 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001730 DSLExpression result = this->expression();
1731 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001732 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1733 return result;
1734 }
1735 break;
1736 }
1737 default:
1738 this->nextToken();
1739 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001740 fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001741 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001742 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001743}
1744
1745/* INT_LITERAL */
1746bool DSLParser::intLiteral(SKSL_INT* dest) {
1747 Token t;
1748 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1749 return false;
1750 }
1751 skstd::string_view s = this->text(t);
1752 if (!SkSL::stoi(s, dest)) {
1753 this->error(t, "integer is too large: " + s);
1754 return false;
1755 }
1756 return true;
1757}
1758
1759/* FLOAT_LITERAL */
1760bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1761 Token t;
1762 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1763 return false;
1764 }
1765 skstd::string_view s = this->text(t);
1766 if (!SkSL::stod(s, dest)) {
1767 this->error(t, "floating-point value is too large: " + s);
1768 return false;
1769 }
1770 return true;
1771}
1772
1773/* TRUE_LITERAL | FALSE_LITERAL */
1774bool DSLParser::boolLiteral(bool* dest) {
1775 Token t = this->nextToken();
1776 switch (t.fKind) {
1777 case Token::Kind::TK_TRUE_LITERAL:
1778 *dest = true;
1779 return true;
1780 case Token::Kind::TK_FALSE_LITERAL:
1781 *dest = false;
1782 return true;
1783 default:
1784 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1785 return false;
1786 }
1787}
1788
1789/* IDENTIFIER */
1790bool DSLParser::identifier(skstd::string_view* dest) {
1791 Token t;
1792 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1793 *dest = this->text(t);
1794 return true;
1795 }
1796 return false;
1797}
1798
1799} // namespace SkSL
1800
1801#endif // SKSL_DSL_PARSER