blob: 439aa08aa966f6068ff3f51103b1292e8e02241e [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 Nicholas051aeb72021-09-24 16:39:19 -040013#include "src/sksl/dsl/priv/DSL_priv.h"
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040014
15#include <memory>
16
17#if SKSL_DSL_PARSER
18
19using namespace SkSL::dsl;
20
21namespace SkSL {
22
23static constexpr int kMaxParseDepth = 50;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040024
25static int parse_modifier_token(Token::Kind token) {
26 switch (token) {
27 case Token::Kind::TK_UNIFORM: return Modifiers::kUniform_Flag;
28 case Token::Kind::TK_CONST: return Modifiers::kConst_Flag;
29 case Token::Kind::TK_IN: return Modifiers::kIn_Flag;
30 case Token::Kind::TK_OUT: return Modifiers::kOut_Flag;
31 case Token::Kind::TK_INOUT: return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
32 case Token::Kind::TK_FLAT: return Modifiers::kFlat_Flag;
33 case Token::Kind::TK_NOPERSPECTIVE: return Modifiers::kNoPerspective_Flag;
34 case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
35 case Token::Kind::TK_INLINE: return Modifiers::kInline_Flag;
36 case Token::Kind::TK_NOINLINE: return Modifiers::kNoInline_Flag;
John Stiles02014312021-08-04 16:03:12 -040037 case Token::Kind::TK_HIGHP: return Modifiers::kHighp_Flag;
38 case Token::Kind::TK_MEDIUMP: return Modifiers::kMediump_Flag;
39 case Token::Kind::TK_LOWP: return Modifiers::kLowp_Flag;
John Stilesefde90d2021-08-12 23:06:24 -040040 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040041 default: return 0;
42 }
43}
44
45class AutoDSLDepth {
46public:
47 AutoDSLDepth(DSLParser* p)
48 : fParser(p)
49 , fDepth(0) {}
50
51 ~AutoDSLDepth() {
52 fParser->fDepth -= fDepth;
53 }
54
55 bool increase() {
56 ++fDepth;
57 ++fParser->fDepth;
58 if (fParser->fDepth > kMaxParseDepth) {
59 fParser->error(fParser->peek(), String("exceeded max parse depth"));
60 return false;
61 }
62 return true;
63 }
64
65private:
66 DSLParser* fParser;
67 int fDepth;
68};
69
70class AutoDSLSymbolTable {
71public:
72 AutoDSLSymbolTable() {
73 dsl::PushSymbolTable();
74 }
75
76 ~AutoDSLSymbolTable() {
77 dsl::PopSymbolTable();
78 }
79};
80
81std::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
82
83void DSLParser::InitLayoutMap() {
84 layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
85 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
86 TOKEN(LOCATION, "location");
87 TOKEN(OFFSET, "offset");
88 TOKEN(BINDING, "binding");
89 TOKEN(INDEX, "index");
90 TOKEN(SET, "set");
91 TOKEN(BUILTIN, "builtin");
92 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
93 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
94 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
95 TOKEN(PUSH_CONSTANT, "push_constant");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040096 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
97 #undef TOKEN
98}
99
100DSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
101 String text)
102 : fCompiler(*compiler)
103 , fSettings(settings)
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400104 , fKind(kind)
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400105 , fText(std::make_unique<String>(std::move(text)))
Brian Osmana909dd62021-09-24 19:00:35 +0000106 , fPushback(Token::Kind::TK_NONE, -1, -1) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400107 // We don't want to have to worry about manually releasing all of the objects in the event that
108 // an error occurs
109 fSettings.fAssertDSLObjectsReleased = false;
Ethan Nicholasae9b4462021-09-16 16:23:05 -0400110 // We manage our symbol tables manually, so no need for name mangling
111 fSettings.fDSLMangling = false;
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400112 fLexer.start(*fText);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400113 static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
114 (void) layoutMapInitialized;
115}
116
117Token DSLParser::nextRawToken() {
118 if (fPushback.fKind != Token::Kind::TK_NONE) {
119 Token result = fPushback;
120 fPushback.fKind = Token::Kind::TK_NONE;
121 return result;
122 }
123 return fLexer.next();
124}
125
126Token DSLParser::nextToken() {
127 Token token = this->nextRawToken();
128 while (token.fKind == Token::Kind::TK_WHITESPACE ||
129 token.fKind == Token::Kind::TK_LINE_COMMENT ||
130 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
131 token = this->nextRawToken();
132 }
133 return token;
134}
135
136void DSLParser::pushback(Token t) {
137 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
138 fPushback = std::move(t);
139}
140
141Token DSLParser::peek() {
142 if (fPushback.fKind == Token::Kind::TK_NONE) {
143 fPushback = this->nextToken();
144 }
145 return fPushback;
146}
147
148bool DSLParser::checkNext(Token::Kind kind, Token* result) {
149 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
150 return false;
151 }
152 Token next = this->nextToken();
153 if (next.fKind == kind) {
154 if (result) {
155 *result = next;
156 }
157 return true;
158 }
159 this->pushback(std::move(next));
160 return false;
161}
162
163bool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
164 Token next = this->nextToken();
165 if (next.fKind == kind) {
166 if (result) {
167 *result = std::move(next);
168 }
169 return true;
170 } else {
171 this->error(next, "expected " + String(expected) + ", but found '" +
172 this->text(next) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400173 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400174 return false;
175 }
176}
177
178bool DSLParser::expectIdentifier(Token* result) {
179 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
180 return false;
181 }
182 if (IsType(this->text(*result))) {
183 this->error(*result, "expected an identifier, but found type '" +
184 this->text(*result) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400185 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400186 return false;
187 }
188 return true;
189}
190
191skstd::string_view DSLParser::text(Token token) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400192 return skstd::string_view(fText->data() + token.fOffset, token.fLength);
193}
194
195PositionInfo DSLParser::position(Token t) {
Brian Osmana909dd62021-09-24 19:00:35 +0000196 return this->position(t.fOffset);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400197}
198
Brian Osmancc914522021-09-24 18:58:37 +0000199PositionInfo DSLParser::position(int offset) {
Brian Osmana909dd62021-09-24 19:00:35 +0000200 return PositionInfo::Offset("<unknown>", fText->c_str(), offset);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400201}
202
203void DSLParser::error(Token token, String msg) {
Brian Osmana909dd62021-09-24 19:00:35 +0000204 this->error(token.fOffset, msg);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400205}
206
Brian Osmancc914522021-09-24 18:58:37 +0000207void DSLParser::error(int offset, String msg) {
208 GetErrorReporter().error(msg.c_str(), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400209}
210
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400211/* declaration* END_OF_FILE */
212std::unique_ptr<Program> DSLParser::program() {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400213 ErrorReporter* errorReporter = &fCompiler.errorReporter();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400214 Start(&fCompiler, fKind, fSettings);
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400215 SetErrorReporter(errorReporter);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400216 errorReporter->setSource(fText->c_str());
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400217 this->declarations();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400218 std::unique_ptr<Program> result;
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400219 if (!GetErrorReporter().errorCount()) {
220 result = dsl::ReleaseProgram(std::move(fText));
221 }
222 errorReporter->setSource(nullptr);
223 End();
224 return result;
225}
226
227SkSL::LoadedModule DSLParser::moduleInheritingFrom(SkSL::ParsedModule baseModule) {
228 ErrorReporter* errorReporter = &fCompiler.errorReporter();
229 StartModule(&fCompiler, fKind, fSettings, std::move(baseModule));
230 SetErrorReporter(errorReporter);
231 errorReporter->setSource(fText->c_str());
232 this->declarations();
233 CurrentSymbolTable()->takeOwnershipOfString(std::move(*fText));
234 SkSL::LoadedModule result{ fKind, CurrentSymbolTable(),
235 std::move(DSLWriter::ProgramElements()) };
236 errorReporter->setSource(nullptr);
237 End();
238 return result;
239}
240
241void DSLParser::declarations() {
242 fEncounteredFatalError = false;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400243 bool done = false;
244 while (!done) {
245 switch (this->peek().fKind) {
246 case Token::Kind::TK_END_OF_FILE:
247 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400248 break;
Ethan Nicholas642215e2021-09-03 11:10:54 -0400249 case Token::Kind::TK_DIRECTIVE:
250 this->directive();
251 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400252 case Token::Kind::TK_INVALID: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400253 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400254 this->error(this->peek(), String("invalid token"));
Ethan Nicholasf8f1fa02021-08-29 14:12:17 -0400255 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400256 break;
257 }
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400258 default:
259 this->declaration();
260 done = fEncounteredFatalError;
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400261 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400262 }
263 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400264}
265
Ethan Nicholas642215e2021-09-03 11:10:54 -0400266/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
267void DSLParser::directive() {
268 Token start;
269 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
270 return;
271 }
272 skstd::string_view text = this->text(start);
273 if (text == "#extension") {
274 Token name;
275 if (!this->expectIdentifier(&name)) {
276 return;
277 }
278 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
279 return;
280 }
281 Token behavior;
282 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
283 return;
284 }
285 skstd::string_view behaviorText = this->text(behavior);
286 if (behaviorText == "disable") {
287 return;
288 }
289 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
290 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
291 }
292 // We don't currently do anything different between require, enable, and warn
293 dsl::AddExtension(this->text(name));
294 } else {
295 this->error(start, "unsupported directive '" + this->text(start) + "'");
296 }
297}
298
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400299/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
300 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
301bool DSLParser::declaration() {
302 Token lookahead = this->peek();
303 switch (lookahead.fKind) {
304 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400305 this->nextToken();
Brian Osmana909dd62021-09-24 19:00:35 +0000306 this->error(lookahead.fOffset, "expected a declaration, but found ';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400307 return false;
308 default:
309 break;
310 }
311 DSLModifiers modifiers = this->modifiers();
312 lookahead = this->peek();
313 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
314 // we have an identifier that's not a type, could be the start of an interface block
315 return this->interfaceBlock(modifiers);
316 }
317 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
Ethan Nicholas678ec712021-09-03 06:33:47 -0400318 this->nextToken();
319 Declare(modifiers, position(lookahead));
320 return true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400321 }
322 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400323 this->structVarDeclaration(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400324 return true;
325 }
John Stiles4adb66f2021-08-05 10:15:16 -0400326 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400327 if (!type) {
328 return false;
329 }
330 Token name;
331 if (!this->expectIdentifier(&name)) {
332 return false;
333 }
334 if (this->checkNext(Token::Kind::TK_LPAREN)) {
335 return this->functionDeclarationEnd(modifiers, *type, name);
336 } else {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400337 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400338 return true;
339 }
340}
341
342/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400343bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
344 DSLType type,
345 const Token& name) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400346 SkTArray<DSLWrapper<DSLParameter>> parameters;
347 Token lookahead = this->peek();
348 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
349 // `()` means no parameters at all.
350 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
351 // `(void)` also means no parameters at all.
352 this->nextToken();
353 } else {
354 for (;;) {
355 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
356 if (!parameter) {
357 return false;
358 }
359 parameters.push_back(std::move(*parameter));
360 if (!this->checkNext(Token::Kind::TK_COMMA)) {
361 break;
362 }
363 }
364 }
365 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
366 return false;
367 }
368 SkTArray<DSLParameter*> parameterPointers;
369 for (DSLWrapper<DSLParameter>& param : parameters) {
370 parameterPointers.push_back(&param.get());
371 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400372 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400373 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
374 AutoDSLSymbolTable symbols;
375 for (DSLParameter* var : parameterPointers) {
376 AddToSymbolTable(*var);
377 }
378 skstd::optional<DSLBlock> body = this->block();
379 if (!body) {
380 return false;
381 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -0400382 result.define(std::move(*body), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400383 }
384 return true;
385}
386
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400387SKSL_INT DSLParser::arraySize() {
388 Token next = this->peek();
389 if (next.fKind == Token::Kind::TK_INT_LITERAL) {
390 SKSL_INT size;
391 if (this->intLiteral(&size)) {
392 if (size > INT32_MAX) {
393 this->error(next, "array size out of bounds");
394 return 1;
395 }
396 if (size <= 0) {
397 this->error(next, "array size must be positive");
398 return 1;
399 }
400 return size;
401 }
402 return 1;
403 } else if (this->checkNext(Token::Kind::TK_MINUS) &&
404 this->checkNext(Token::Kind::TK_INT_LITERAL)) {
405 this->error(next, "array size must be positive");
406 return 1;
407 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400408 DSLExpression expr = this->expression();
409 if (expr.isValid()) {
Ethan Nicholas51b4b862021-08-31 16:12:40 -0400410 this->error(next, "expected int literal");
411 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400412 return 1;
413 }
414}
415
Brian Osmancc914522021-09-24 18:58:37 +0000416bool DSLParser::parseArrayDimensions(int offset, DSLType* type) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400417 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
418 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
Brian Osmancc914522021-09-24 18:58:37 +0000419 this->error(offset, "expected array dimension");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400420 } else {
Brian Osmancc914522021-09-24 18:58:37 +0000421 *type = Array(*type, this->arraySize(), this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400422 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400423 return false;
424 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400425 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400426 }
427 return true;
428}
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400429
Brian Osmancc914522021-09-24 18:58:37 +0000430bool DSLParser::parseInitializer(int offset, DSLExpression* initializer) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400431 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400432 DSLExpression value = this->assignmentExpression();
433 if (!value.hasValue()) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400434 return false;
435 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400436 initializer->swap(value);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400437 }
438 return true;
439}
440
441/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
442 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
443void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
444 dsl::DSLType baseType, skstd::string_view name) {
445 using namespace dsl;
Brian Osmana909dd62021-09-24 19:00:35 +0000446 int offset = this->peek().fOffset;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400447 DSLType type = baseType;
448 DSLExpression initializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000449 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400450 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400451 }
John Stilesb05bbd02021-09-24 15:11:16 -0400452 if (!this->parseInitializer(offset, &initializer)) {
453 return;
454 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400455 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
456 Declare(first);
457 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400458
459 while (this->checkNext(Token::Kind::TK_COMMA)) {
460 type = baseType;
461 Token identifierName;
462 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400463 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400464 }
Brian Osmana909dd62021-09-24 19:00:35 +0000465 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400466 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400467 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400468 DSLExpression anotherInitializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000469 if (!this->parseInitializer(offset, &anotherInitializer)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400470 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400471 }
John Stilesb05bbd02021-09-24 15:11:16 -0400472 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
473 this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400474 Declare(next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400475 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400476 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400477 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400478}
479
480/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
481 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400482DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
483 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400484 using namespace dsl;
Brian Osmana909dd62021-09-24 19:00:35 +0000485 int offset = this->peek().fOffset;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400486 DSLType type = baseType;
487 DSLExpression initializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000488 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400489 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400490 }
John Stilesb05bbd02021-09-24 15:11:16 -0400491 if (!this->parseInitializer(offset, &initializer)) {
492 return {};
493 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400494 DSLVar first(mods, type, name, std::move(initializer), pos);
495 DSLStatement result = Declare(first);
496 AddToSymbolTable(first);
497
498 while (this->checkNext(Token::Kind::TK_COMMA)) {
499 type = baseType;
500 Token identifierName;
501 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400502 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400503 }
Brian Osmana909dd62021-09-24 19:00:35 +0000504 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400505 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400506 }
507 DSLExpression anotherInitializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000508 if (!this->parseInitializer(offset, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400509 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400510 }
John Stilesb05bbd02021-09-24 15:11:16 -0400511 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
512 this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400513 DSLWriter::AddVarDeclaration(result, next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400514 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400515 }
516 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400517 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400518}
519
520/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400521DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400522 Token nextToken = this->peek();
523 if (nextToken.fKind == Token::Kind::TK_CONST) {
524 // Statements that begin with `const` might be variable declarations, but can't be legal
525 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
526 return this->varDeclarations();
527 }
528
John Stiles02014312021-08-04 16:03:12 -0400529 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
530 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
531 nextToken.fKind == Token::Kind::TK_LOWP ||
532 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400533 // Statements that begin with a typename are most often variable declarations, but
534 // occasionally the type is part of a constructor, and these are actually expression-
535 // statements in disguise. First, attempt the common case: parse it as a vardecl.
536 Checkpoint checkpoint(this);
537 VarDeclarationsPrefix prefix;
538 if (this->varDeclarationsPrefix(&prefix)) {
539 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400540 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
541 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400542 }
543
544 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
545 // expression-statement instead.
546 checkpoint.rewind();
547 }
548 return this->expressionStatement();
549}
550
551// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
552// statement is a variable-declaration statement, not an expression-statement.
553bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400554 prefixData->fPosition = this->position(this->peek());
555 prefixData->fModifiers = this->modifiers();
556 skstd::optional<DSLType> type = this->type(prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400557 if (!type) {
558 return false;
559 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400560 prefixData->fType = *type;
561 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400562}
563
564/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400565DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400566 VarDeclarationsPrefix prefix;
567 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400568 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400569 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400570 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
571 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400572}
573
574/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
575skstd::optional<DSLType> DSLParser::structDeclaration() {
576 AutoDSLDepth depth(this);
577 if (!depth.increase()) {
578 return skstd::nullopt;
579 }
580 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
581 return skstd::nullopt;
582 }
583 Token name;
584 if (!this->expectIdentifier(&name)) {
585 return skstd::nullopt;
586 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400587 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
588 return skstd::nullopt;
589 }
590 SkTArray<DSLField> fields;
591 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
592 DSLModifiers modifiers = this->modifiers();
593
John Stiles4adb66f2021-08-05 10:15:16 -0400594 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400595 if (!type) {
596 return skstd::nullopt;
597 }
598
599 do {
600 DSLType actualType = *type;
601 Token memberName;
602 if (!this->expectIdentifier(&memberName)) {
603 return skstd::nullopt;
604 }
605
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400606 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
607 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400608 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
609 return skstd::nullopt;
610 }
611 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400612 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
613 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400614 } while (this->checkNext(Token::Kind::TK_COMMA));
615 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
616 return skstd::nullopt;
617 }
618 }
619 if (fields.empty()) {
Brian Osmana909dd62021-09-24 19:00:35 +0000620 this->error(name.fOffset,
621 "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400622 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400623 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400624}
625
626/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400627SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400628 skstd::optional<DSLType> type = this->structDeclaration();
629 if (!type) {
630 return {};
631 }
632 Token name;
633 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400634 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
635 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400636 } else {
637 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400638 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400639 return {};
640}
641
642/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
643skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
644 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles4adb66f2021-08-05 10:15:16 -0400645 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400646 if (!type) {
647 return skstd::nullopt;
648 }
649 Token name;
650 if (!this->expectIdentifier(&name)) {
651 return skstd::nullopt;
652 }
653 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400654 Token sizeToken;
655 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
656 return skstd::nullopt;
657 }
658 skstd::string_view arraySizeFrag = this->text(sizeToken);
659 SKSL_INT arraySize;
660 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
661 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400662 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400663 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400664 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400665 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
666 return skstd::nullopt;
667 }
668 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400669 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400670}
671
672/** EQ INT_LITERAL */
673int DSLParser::layoutInt() {
674 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
675 return -1;
676 }
677 Token resultToken;
678 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
679 return -1;
680 }
681 skstd::string_view resultFrag = this->text(resultToken);
682 SKSL_INT resultValue;
683 if (!SkSL::stoi(resultFrag, &resultValue)) {
684 this->error(resultToken, "value in layout is too large: " + resultFrag);
685 return -1;
686 }
687 return resultValue;
688}
689
690/** EQ IDENTIFIER */
691skstd::string_view DSLParser::layoutIdentifier() {
692 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
693 return {};
694 }
695 Token resultToken;
696 if (!this->expectIdentifier(&resultToken)) {
697 return {};
698 }
699 return this->text(resultToken);
700}
701
702/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
703DSLLayout DSLParser::layout() {
704 DSLLayout result;
705 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
706 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
707 return result;
708 }
709 for (;;) {
710 Token t = this->nextToken();
711 String text(this->text(t));
712 auto found = layoutTokens->find(text);
713 if (found != layoutTokens->end()) {
714 switch (found->second) {
715 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400716 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400717 break;
718 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400719 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400720 break;
721 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400722 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400723 break;
724 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400725 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400726 break;
727 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400728 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400729 break;
730 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400731 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400732 break;
733 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400734 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400735 break;
736 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400737 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400738 break;
739 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400740 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400741 break;
742 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400743 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400744 break;
745 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400746 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400747 break;
748 default:
749 this->error(t, "'" + text + "' is not a valid layout qualifier");
750 break;
751 }
752 } else {
753 this->error(t, "'" + text + "' is not a valid layout qualifier");
754 }
755 if (this->checkNext(Token::Kind::TK_RPAREN)) {
756 break;
757 }
758 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
759 break;
760 }
761 }
762 }
763 return result;
764}
765
766/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
767 VARYING | INLINE)* */
768DSLModifiers DSLParser::modifiers() {
769 DSLLayout layout = this->layout();
770 int flags = 0;
771 for (;;) {
772 // TODO(ethannicholas): handle duplicate / incompatible flags
773 int tokenFlag = parse_modifier_token(peek().fKind);
774 if (!tokenFlag) {
775 break;
776 }
777 flags |= tokenFlag;
778 this->nextToken();
779 }
780 return DSLModifiers(std::move(layout), flags);
781}
782
783DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
784 DSLModifiers result = this->modifiers();
785 if (defaultFlags && !result.flags()) {
786 return DSLModifiers(result.layout(), defaultFlags);
787 }
788 return result;
789}
790
791/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400792DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400793 Token start = this->nextToken();
794 AutoDSLDepth depth(this);
795 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400796 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400797 }
798 this->pushback(start);
799 switch (start.fKind) {
800 case Token::Kind::TK_IF: // fall through
801 case Token::Kind::TK_STATIC_IF:
802 return this->ifStatement();
803 case Token::Kind::TK_FOR:
804 return this->forStatement();
805 case Token::Kind::TK_DO:
806 return this->doStatement();
807 case Token::Kind::TK_WHILE:
808 return this->whileStatement();
809 case Token::Kind::TK_SWITCH: // fall through
810 case Token::Kind::TK_STATIC_SWITCH:
811 return this->switchStatement();
812 case Token::Kind::TK_RETURN:
813 return this->returnStatement();
814 case Token::Kind::TK_BREAK:
815 return this->breakStatement();
816 case Token::Kind::TK_CONTINUE:
817 return this->continueStatement();
818 case Token::Kind::TK_DISCARD:
819 return this->discardStatement();
820 case Token::Kind::TK_LBRACE: {
821 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400822 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400823 }
824 case Token::Kind::TK_SEMICOLON:
825 this->nextToken();
826 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400827 case Token::Kind::TK_HIGHP:
828 case Token::Kind::TK_MEDIUMP:
829 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400830 case Token::Kind::TK_CONST:
831 case Token::Kind::TK_IDENTIFIER:
832 return this->varDeclarationsOrExpressionStatement();
833 default:
834 return this->expressionStatement();
835 }
836}
837
838/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stilese53c7212021-08-05 10:19:11 -0400839skstd::optional<DSLType> DSLParser::type(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400840 Token type;
841 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
842 return skstd::nullopt;
843 }
844 if (!IsType(this->text(type))) {
845 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
846 return skstd::nullopt;
847 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400848 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400849 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400850 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400851 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400852 } else {
853 this->error(this->peek(), "expected array dimension");
854 }
855 this->expect(Token::Kind::TK_RBRACKET, "']'");
856 }
857 return result;
858}
859
860/* IDENTIFIER LBRACE
861 varDeclaration+
862 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400863bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400864 Token typeName;
865 if (!this->expectIdentifier(&typeName)) {
866 return false;
867 }
868 if (peek().fKind != Token::Kind::TK_LBRACE) {
869 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
870 // 99% of the time, the user was not actually intending to create an interface block, so
871 // it's better to report it as an unknown type
872 this->error(typeName, "no type named '" + this->text(typeName) + "'");
873 return false;
874 }
875 this->nextToken();
876 SkTArray<dsl::Field> fields;
877 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400878 DSLModifiers fieldModifiers = this->modifiers();
879 skstd::optional<dsl::DSLType> type = this->type(fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400880 if (!type) {
881 return false;
882 }
883 do {
884 Token fieldName;
885 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
886 return false;
887 }
888 DSLType actualType = *type;
889 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
890 Token sizeToken = this->peek();
891 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400892 actualType = Array(std::move(actualType), this->arraySize(),
893 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400894 } else {
895 this->error(sizeToken, "unsized arrays are not permitted");
896 }
897 this->expect(Token::Kind::TK_RBRACKET, "']'");
898 }
899 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
900 return false;
901 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400902 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
903 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400904 }
905 while (this->checkNext(Token::Kind::TK_COMMA));
906 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400907 skstd::string_view instanceName;
908 Token instanceNameToken;
909 SKSL_INT arraySize = 0;
910 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
911 instanceName = this->text(instanceNameToken);
912 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400913 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400914 this->expect(Token::Kind::TK_RBRACKET, "']'");
915 }
916 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400917 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400918 if (fields.empty()) {
919 this->error(typeName, "interface block '" + this->text(typeName) +
920 "' must contain at least one member");
921 } else {
922 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
923 arraySize, this->position(typeName));
924 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400925 return true;
926}
927
928/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400929DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400930 Token start;
931 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
932 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400933 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400934 }
935 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400936 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400937 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400938 DSLExpression test = this->expression();
939 if (!test.hasValue()) {
940 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400941 }
942 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400943 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400944 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400945 DSLStatement ifTrue = this->statement();
946 if (!ifTrue.hasValue()) {
947 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400948 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400949 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400950 if (this->checkNext(Token::Kind::TK_ELSE)) {
951 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400952 if (!ifFalse.hasValue()) {
953 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400954 }
955 }
956 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400957 return StaticIf(std::move(test), std::move(ifTrue),
958 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400959 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400960 return If(std::move(test), std::move(ifTrue),
961 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400962 }
963}
964
965/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400966DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400967 Token start;
968 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400969 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400970 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400971 DSLStatement statement = this->statement();
972 if (!statement.hasValue()) {
973 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400974 }
975 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400976 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400977 }
978 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400979 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400980 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400981 DSLExpression test = this->expression();
982 if (!test.hasValue()) {
983 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400984 }
985 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400986 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400987 }
988 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400989 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400990 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400991 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400992}
993
994/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400995DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400996 Token start;
997 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400998 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400999 }
1000 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001001 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001002 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001003 DSLExpression test = this->expression();
1004 if (!test.hasValue()) {
1005 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001006 }
1007 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001008 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001009 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001010 DSLStatement statement = this->statement();
1011 if (!statement.hasValue()) {
1012 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001013 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001014 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001015}
1016
1017/* CASE expression COLON statement* */
1018skstd::optional<DSLCase> DSLParser::switchCase() {
1019 Token start;
1020 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001021 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001022 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001023 DSLExpression value = this->expression();
1024 if (!value.hasValue()) {
1025 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001026 }
1027 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001028 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001029 }
1030 SkTArray<DSLStatement> statements;
1031 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1032 this->peek().fKind != Token::Kind::TK_CASE &&
1033 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001034 DSLStatement s = this->statement();
1035 if (!s.hasValue()) {
1036 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001037 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001038 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001039 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001040 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001041}
1042
1043/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001044DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001045 Token start;
1046 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1047 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001048 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001049 }
1050 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001051 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001052 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001053 DSLExpression value = this->expression();
1054 if (!value.hasValue()) {
1055 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001056 }
1057 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001058 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001059 }
1060 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001061 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001062 }
1063 SkTArray<DSLCase> cases;
1064 while (this->peek().fKind == Token::Kind::TK_CASE) {
1065 skstd::optional<DSLCase> c = this->switchCase();
1066 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001067 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001068 }
1069 cases.push_back(std::move(*c));
1070 }
1071 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1072 // parts of the compiler may rely upon this assumption.
1073 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1074 SkTArray<DSLStatement> statements;
1075 Token defaultStart;
1076 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1077 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001078 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001079 }
1080 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001081 DSLStatement s = this->statement();
1082 if (!s.hasValue()) {
1083 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001084 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001085 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001086 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001087 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001088 }
1089 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001090 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001091 }
1092 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001093 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001094 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001095 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001096 }
1097}
1098
1099/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1100 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001101dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001102 Token start;
1103 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001104 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001105 }
1106 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001107 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001108 }
1109 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001110 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001111 Token nextToken = this->peek();
1112 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1113 // An empty init-statement.
1114 this->nextToken();
1115 } else {
1116 // The init-statement must be an expression or variable declaration.
1117 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001118 if (!initializer.hasValue()) {
1119 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001120 }
1121 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001122 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001123 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001124 dsl::DSLExpression testValue = this->expression();
1125 if (!testValue.hasValue()) {
1126 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001127 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001128 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001129 }
1130 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001131 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001132 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001133 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001134 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001135 dsl::DSLExpression nextValue = this->expression();
1136 if (!nextValue.hasValue()) {
1137 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001138 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001139 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001140 }
1141 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001142 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001143 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001144 dsl::DSLStatement statement = this->statement();
1145 if (!statement.hasValue()) {
1146 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001147 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001148 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1149 test.hasValue() ? std::move(test) : DSLExpression(),
1150 next.hasValue() ? std::move(next) : DSLExpression(),
1151 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001152 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001153}
1154
1155/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001156DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001157 Token start;
1158 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001159 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001160 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001161 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001162 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001163 DSLExpression next = this->expression();
1164 if (!next.hasValue()) {
1165 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001166 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001167 expression.swap(next);
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 Nicholasb7cb38f2021-09-15 08:29:14 -04001172 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1173 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001174}
1175
1176/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001177DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001178 Token start;
1179 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001180 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001181 }
1182 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001183 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001184 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001185 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001186}
1187
1188/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001189DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001190 Token start;
1191 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001192 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001193 }
1194 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001195 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001196 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001197 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001198}
1199
1200/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001201DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001202 Token start;
1203 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001204 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001205 }
1206 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001207 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001208 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001209 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001210}
1211
1212/* LBRACE statement* RBRACE */
1213skstd::optional<DSLBlock> DSLParser::block() {
1214 Token start;
1215 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1216 return skstd::nullopt;
1217 }
1218 AutoDSLDepth depth(this);
1219 if (!depth.increase()) {
1220 return skstd::nullopt;
1221 }
1222 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001223 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001224 for (;;) {
1225 switch (this->peek().fKind) {
1226 case Token::Kind::TK_RBRACE:
1227 this->nextToken();
1228 return DSLBlock(std::move(statements), CurrentSymbolTable());
1229 case Token::Kind::TK_END_OF_FILE:
1230 this->error(this->peek(), "expected '}', but found end of file");
1231 return skstd::nullopt;
1232 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001233 DSLStatement statement = this->statement();
1234 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001235 return skstd::nullopt;
1236 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001237 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001238 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001239 }
1240 }
1241 }
1242}
1243
1244/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001245DSLStatement DSLParser::expressionStatement() {
1246 DSLExpression expr = this->expression();
1247 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001248 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001249 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001250 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001251 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001252 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001253 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001254}
1255
1256/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001257DSLExpression DSLParser::expression() {
1258 DSLExpression result = this->assignmentExpression();
1259 if (!result.hasValue()) {
1260 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001261 }
1262 Token t;
1263 AutoDSLDepth depth(this);
1264 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1265 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001266 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001267 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001268 DSLExpression right = this->assignmentExpression();
1269 if (!right.hasValue()) {
1270 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001271 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001272 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1273 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001274 }
1275 return result;
1276}
1277
1278#define OPERATOR_RIGHT(op, exprType) \
1279 do { \
1280 this->nextToken(); \
1281 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001282 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001283 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001284 DSLExpression right = this->exprType(); \
1285 if (!right.hasValue()) { \
1286 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001287 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001288 DSLExpression next = std::move(result) op std::move(right); \
1289 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001290 } while (false)
1291
1292/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1293 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1294 assignmentExpression)*
1295 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001296DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001297 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001298 DSLExpression result = this->ternaryExpression();
1299 if (!result.hasValue()) {
1300 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001301 }
1302 for (;;) {
1303 switch (this->peek().fKind) {
1304 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1305 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1306 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1307 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1308 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1309 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1310 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1311 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1312 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1313 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1314 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1315 default:
1316 return result;
1317 }
1318 }
1319}
1320
1321/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001322DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001323 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001324 DSLExpression base = this->logicalOrExpression();
1325 if (!base.hasValue()) {
1326 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001327 }
1328 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1329 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001330 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001331 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001332 DSLExpression trueExpr = this->expression();
1333 if (!trueExpr.hasValue()) {
1334 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001335 }
1336 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001337 DSLExpression falseExpr = this->assignmentExpression();
1338 if (!falseExpr.hasValue()) {
1339 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001340 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001341 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001342 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001343 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001344 }
1345 return base;
1346}
1347
1348/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001349DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001350 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001351 DSLExpression result = this->logicalXorExpression();
1352 if (!result.hasValue()) {
1353 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001354 }
1355 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1356 OPERATOR_RIGHT(||, logicalXorExpression);
1357 }
1358 return result;
1359}
1360
1361/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001362DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001363 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001364 DSLExpression result = this->logicalAndExpression();
1365 if (!result.hasValue()) {
1366 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001367 }
1368 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1369 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001370 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001371 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001372 DSLExpression right = this->logicalAndExpression();
1373 if (!right.hasValue()) {
1374 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001375 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001376 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1377 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001378 }
1379 return result;
1380}
1381
1382/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001383DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001384 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001385 DSLExpression result = this->bitwiseOrExpression();
1386 if (!result.hasValue()) {
1387 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001388 }
1389 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1390 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1391 }
1392 return result;
1393}
1394
1395/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001396DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001397 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001398 DSLExpression result = this->bitwiseXorExpression();
1399 if (!result.hasValue()) {
1400 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001401 }
1402 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1403 OPERATOR_RIGHT(|, bitwiseXorExpression);
1404 }
1405 return result;
1406}
1407
1408/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001409DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001410 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001411 DSLExpression result = this->bitwiseAndExpression();
1412 if (!result.hasValue()) {
1413 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001414 }
1415 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1416 OPERATOR_RIGHT(^, bitwiseAndExpression);
1417 }
1418 return result;
1419}
1420
1421/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001422DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001423 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001424 DSLExpression result = this->equalityExpression();
1425 if (!result.hasValue()) {
1426 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001427 }
1428 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1429 OPERATOR_RIGHT(&, equalityExpression);
1430 }
1431 return result;
1432}
1433
1434/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001435DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001436 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001437 DSLExpression result = this->relationalExpression();
1438 if (!result.hasValue()) {
1439 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001440 }
1441 for (;;) {
1442 switch (this->peek().fKind) {
1443 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1444 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1445 default: return result;
1446 }
1447 }
1448}
1449
1450/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001451DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001452 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001453 DSLExpression result = this->shiftExpression();
1454 if (!result.hasValue()) {
1455 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001456 }
1457 for (;;) {
1458 switch (this->peek().fKind) {
1459 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1460 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1461 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1462 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1463 default: return result;
1464 }
1465 }
1466}
1467
1468/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001469DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001470 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001471 DSLExpression result = this->additiveExpression();
1472 if (!result.hasValue()) {
1473 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001474 }
1475 for (;;) {
1476 switch (this->peek().fKind) {
1477 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1478 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1479 default: return result;
1480 }
1481 }
1482}
1483
1484/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001485DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001486 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001487 DSLExpression result = this->multiplicativeExpression();
1488 if (!result.hasValue()) {
1489 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001490 }
1491 for (;;) {
1492 switch (this->peek().fKind) {
1493 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1494 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1495 default: return result;
1496 }
1497 }
1498}
1499
1500/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001501DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001502 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001503 DSLExpression result = this->unaryExpression();
1504 if (!result.hasValue()) {
1505 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001506 }
1507 for (;;) {
1508 switch (this->peek().fKind) {
1509 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1510 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1511 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1512 default: return result;
1513 }
1514 }
1515}
1516
1517/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001518DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001519 AutoDSLDepth depth(this);
1520 Token next = this->peek();
1521 switch (next.fKind) {
1522 case Token::Kind::TK_PLUS:
1523 case Token::Kind::TK_MINUS:
1524 case Token::Kind::TK_LOGICALNOT:
1525 case Token::Kind::TK_BITWISENOT:
1526 case Token::Kind::TK_PLUSPLUS:
1527 case Token::Kind::TK_MINUSMINUS: {
1528 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001529 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001530 }
1531 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001532 DSLExpression expr = this->unaryExpression();
1533 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001534 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001535 }
1536 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001537 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1538 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1539 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1540 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1541 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1542 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001543 default: SkUNREACHABLE;
1544 }
1545 }
1546 default:
1547 return this->postfixExpression();
1548 }
1549}
1550
1551/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001552DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001553 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001554 DSLExpression result = this->term();
1555 if (!result.hasValue()) {
1556 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001557 }
1558 for (;;) {
1559 Token t = this->peek();
1560 switch (t.fKind) {
1561 case Token::Kind::TK_FLOAT_LITERAL:
1562 if (this->text(t)[0] != '.') {
1563 return result;
1564 }
1565 [[fallthrough]];
1566 case Token::Kind::TK_LBRACKET:
1567 case Token::Kind::TK_DOT:
1568 case Token::Kind::TK_LPAREN:
1569 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001570 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001571 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001572 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001573 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001574 DSLExpression next = this->suffix(std::move(result));
1575 if (!next.hasValue()) {
1576 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001577 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001578 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001579 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001580 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001581 default:
1582 return result;
1583 }
1584 }
1585}
1586
Brian Osmancc914522021-09-24 18:58:37 +00001587DSLExpression DSLParser::swizzle(int offset, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001588 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001589 SkASSERT(swizzleMask.length() > 0);
1590 if (!base.type().isVector() && !base.type().isScalar()) {
Brian Osmancc914522021-09-24 18:58:37 +00001591 return base.field(swizzleMask, this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001592 }
1593 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001594 SkSL::SwizzleComponent::Type components[4];
1595 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001596 if (i >= 4) {
Brian Osmancc914522021-09-24 18:58:37 +00001597 this->error(offset, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001598 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001599 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001600 switch (swizzleMask[i]) {
1601 case '0': components[i] = SwizzleComponent::ZERO; break;
1602 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001603 case 'r': components[i] = SwizzleComponent::R; break;
1604 case 'x': components[i] = SwizzleComponent::X; break;
1605 case 's': components[i] = SwizzleComponent::S; break;
1606 case 'L': components[i] = SwizzleComponent::UL; break;
1607 case 'g': components[i] = SwizzleComponent::G; break;
1608 case 'y': components[i] = SwizzleComponent::Y; break;
1609 case 't': components[i] = SwizzleComponent::T; break;
1610 case 'T': components[i] = SwizzleComponent::UT; break;
1611 case 'b': components[i] = SwizzleComponent::B; break;
1612 case 'z': components[i] = SwizzleComponent::Z; break;
1613 case 'p': components[i] = SwizzleComponent::P; break;
1614 case 'R': components[i] = SwizzleComponent::UR; break;
1615 case 'a': components[i] = SwizzleComponent::A; break;
1616 case 'w': components[i] = SwizzleComponent::W; break;
1617 case 'q': components[i] = SwizzleComponent::Q; break;
1618 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001619 default:
Brian Osmancc914522021-09-24 18:58:37 +00001620 this->error(offset,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001621 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001622 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001623 }
1624 }
1625 switch (length) {
1626 case 1: return dsl::Swizzle(std::move(base), components[0]);
1627 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1628 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1629 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1630 components[3]);
1631 default: SkUNREACHABLE;
1632 }
1633}
1634
Brian Osmancc914522021-09-24 18:58:37 +00001635dsl::DSLExpression DSLParser::call(int offset, dsl::DSLExpression base, ExpressionArray args) {
1636 return DSLExpression(base(std::move(args), this->position(offset)), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001637}
1638
1639/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1640 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001641DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001642 Token next = this->nextToken();
1643 AutoDSLDepth depth(this);
1644 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001645 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001646 }
1647 switch (next.fKind) {
1648 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001649 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1650 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001651 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001652 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001653 DSLExpression index = this->expression();
1654 if (!index.hasValue()) {
1655 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001656 }
1657 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001658 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001659 if (!result.valid()) {
1660 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001661 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001662 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001663 }
1664 case Token::Kind::TK_DOT: {
Brian Osmana909dd62021-09-24 19:00:35 +00001665 int offset = this->peek().fOffset;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001666 skstd::string_view text;
1667 if (this->identifier(&text)) {
Brian Osmana909dd62021-09-24 19:00:35 +00001668 return this->swizzle(offset, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001669 }
1670 [[fallthrough]];
1671 }
1672 case Token::Kind::TK_FLOAT_LITERAL: {
1673 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1674 // floating point literals, possibly followed by an identifier. Handle that here.
1675 skstd::string_view field = this->text(next);
1676 SkASSERT(field[0] == '.');
1677 field.remove_prefix(1);
1678 // use the next *raw* token so we don't ignore whitespace - we only care about
1679 // identifiers that directly follow the float
1680 Token id = this->nextRawToken();
1681 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Brian Osmana909dd62021-09-24 19:00:35 +00001682 return this->swizzle(next.fOffset, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001683 } else if (field.empty()) {
1684 this->error(next, "expected field name or swizzle mask after '.'");
1685 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001686 }
1687 this->pushback(id);
Brian Osmana909dd62021-09-24 19:00:35 +00001688 return this->swizzle(next.fOffset, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001689 }
1690 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001691 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001692 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1693 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001694 DSLExpression expr = this->assignmentExpression();
1695 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001696 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001697 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001698 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001699 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1700 break;
1701 }
1702 }
1703 }
1704 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Brian Osmana909dd62021-09-24 19:00:35 +00001705 return this->call(next.fOffset, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001706 }
1707 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001708 return std::move(base)++;
1709 case Token::Kind::TK_MINUSMINUS:
1710 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001711 default: {
1712 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001713 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001714 }
1715 }
1716}
1717
1718/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001719DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001720 Token t = this->peek();
1721 switch (t.fKind) {
1722 case Token::Kind::TK_IDENTIFIER: {
1723 skstd::string_view text;
1724 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001725 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001726 }
1727 break;
1728 }
1729 case Token::Kind::TK_INT_LITERAL: {
1730 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001731 if (!this->intLiteral(&i)) {
1732 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001733 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001734 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001735 }
1736 case Token::Kind::TK_FLOAT_LITERAL: {
1737 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001738 if (!this->floatLiteral(&f)) {
1739 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001740 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001741 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001742 }
1743 case Token::Kind::TK_TRUE_LITERAL: // fall through
1744 case Token::Kind::TK_FALSE_LITERAL: {
1745 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001746 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001747 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001748 }
1749 case Token::Kind::TK_LPAREN: {
1750 this->nextToken();
1751 AutoDSLDepth depth(this);
1752 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001753 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001754 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001755 DSLExpression result = this->expression();
1756 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001757 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1758 return result;
1759 }
1760 break;
1761 }
1762 default:
1763 this->nextToken();
Brian Osmana909dd62021-09-24 19:00:35 +00001764 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001765 fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001766 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001767 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001768}
1769
1770/* INT_LITERAL */
1771bool DSLParser::intLiteral(SKSL_INT* dest) {
1772 Token t;
1773 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1774 return false;
1775 }
1776 skstd::string_view s = this->text(t);
1777 if (!SkSL::stoi(s, dest)) {
1778 this->error(t, "integer is too large: " + s);
1779 return false;
1780 }
1781 return true;
1782}
1783
1784/* FLOAT_LITERAL */
1785bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1786 Token t;
1787 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1788 return false;
1789 }
1790 skstd::string_view s = this->text(t);
1791 if (!SkSL::stod(s, dest)) {
1792 this->error(t, "floating-point value is too large: " + s);
1793 return false;
1794 }
1795 return true;
1796}
1797
1798/* TRUE_LITERAL | FALSE_LITERAL */
1799bool DSLParser::boolLiteral(bool* dest) {
1800 Token t = this->nextToken();
1801 switch (t.fKind) {
1802 case Token::Kind::TK_TRUE_LITERAL:
1803 *dest = true;
1804 return true;
1805 case Token::Kind::TK_FALSE_LITERAL:
1806 *dest = false;
1807 return true;
1808 default:
1809 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1810 return false;
1811 }
1812}
1813
1814/* IDENTIFIER */
1815bool DSLParser::identifier(skstd::string_view* dest) {
1816 Token t;
1817 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1818 *dest = this->text(t);
1819 return true;
1820 }
1821 return false;
1822}
1823
1824} // namespace SkSL
1825
1826#endif // SKSL_DSL_PARSER