blob: 830bac6e0007eb5d892b6e1e163027aeac986924 [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
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040017using namespace SkSL::dsl;
18
19namespace SkSL {
20
21static constexpr int kMaxParseDepth = 50;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040022
23static int parse_modifier_token(Token::Kind token) {
24 switch (token) {
25 case Token::Kind::TK_UNIFORM: return Modifiers::kUniform_Flag;
26 case Token::Kind::TK_CONST: return Modifiers::kConst_Flag;
27 case Token::Kind::TK_IN: return Modifiers::kIn_Flag;
28 case Token::Kind::TK_OUT: return Modifiers::kOut_Flag;
29 case Token::Kind::TK_INOUT: return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
30 case Token::Kind::TK_FLAT: return Modifiers::kFlat_Flag;
31 case Token::Kind::TK_NOPERSPECTIVE: return Modifiers::kNoPerspective_Flag;
32 case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
33 case Token::Kind::TK_INLINE: return Modifiers::kInline_Flag;
34 case Token::Kind::TK_NOINLINE: return Modifiers::kNoInline_Flag;
John Stiles02014312021-08-04 16:03:12 -040035 case Token::Kind::TK_HIGHP: return Modifiers::kHighp_Flag;
36 case Token::Kind::TK_MEDIUMP: return Modifiers::kMediump_Flag;
37 case Token::Kind::TK_LOWP: return Modifiers::kLowp_Flag;
John Stilesefde90d2021-08-12 23:06:24 -040038 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040039 default: return 0;
40 }
41}
42
43class AutoDSLDepth {
44public:
45 AutoDSLDepth(DSLParser* p)
46 : fParser(p)
47 , fDepth(0) {}
48
49 ~AutoDSLDepth() {
50 fParser->fDepth -= fDepth;
51 }
52
53 bool increase() {
54 ++fDepth;
55 ++fParser->fDepth;
56 if (fParser->fDepth > kMaxParseDepth) {
57 fParser->error(fParser->peek(), String("exceeded max parse depth"));
58 return false;
59 }
60 return true;
61 }
62
63private:
64 DSLParser* fParser;
65 int fDepth;
66};
67
68class AutoDSLSymbolTable {
69public:
70 AutoDSLSymbolTable() {
71 dsl::PushSymbolTable();
72 }
73
74 ~AutoDSLSymbolTable() {
75 dsl::PopSymbolTable();
76 }
77};
78
79std::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
80
81void DSLParser::InitLayoutMap() {
82 layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
83 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
84 TOKEN(LOCATION, "location");
85 TOKEN(OFFSET, "offset");
86 TOKEN(BINDING, "binding");
87 TOKEN(INDEX, "index");
88 TOKEN(SET, "set");
89 TOKEN(BUILTIN, "builtin");
90 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
91 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
92 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
93 TOKEN(PUSH_CONSTANT, "push_constant");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040094 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
95 #undef TOKEN
96}
97
98DSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
99 String text)
100 : fCompiler(*compiler)
101 , fSettings(settings)
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400102 , fKind(kind)
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400103 , fText(std::make_unique<String>(std::move(text)))
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400104 , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1, /*line=*/-1) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400105 // We don't want to have to worry about manually releasing all of the objects in the event that
106 // an error occurs
107 fSettings.fAssertDSLObjectsReleased = false;
Ethan Nicholasae9b4462021-09-16 16:23:05 -0400108 // We manage our symbol tables manually, so no need for name mangling
109 fSettings.fDSLMangling = false;
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400110 fLexer.start(*fText);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400111 static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
112 (void) layoutMapInitialized;
113}
114
115Token DSLParser::nextRawToken() {
116 if (fPushback.fKind != Token::Kind::TK_NONE) {
117 Token result = fPushback;
118 fPushback.fKind = Token::Kind::TK_NONE;
119 return result;
120 }
121 return fLexer.next();
122}
123
124Token DSLParser::nextToken() {
125 Token token = this->nextRawToken();
126 while (token.fKind == Token::Kind::TK_WHITESPACE ||
127 token.fKind == Token::Kind::TK_LINE_COMMENT ||
128 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
129 token = this->nextRawToken();
130 }
131 return token;
132}
133
134void DSLParser::pushback(Token t) {
135 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
136 fPushback = std::move(t);
137}
138
139Token DSLParser::peek() {
140 if (fPushback.fKind == Token::Kind::TK_NONE) {
141 fPushback = this->nextToken();
142 }
143 return fPushback;
144}
145
146bool DSLParser::checkNext(Token::Kind kind, Token* result) {
147 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
148 return false;
149 }
150 Token next = this->nextToken();
151 if (next.fKind == kind) {
152 if (result) {
153 *result = next;
154 }
155 return true;
156 }
157 this->pushback(std::move(next));
158 return false;
159}
160
161bool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
162 Token next = this->nextToken();
163 if (next.fKind == kind) {
164 if (result) {
165 *result = std::move(next);
166 }
167 return true;
168 } else {
169 this->error(next, "expected " + String(expected) + ", but found '" +
170 this->text(next) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400171 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400172 return false;
173 }
174}
175
176bool DSLParser::expectIdentifier(Token* result) {
177 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
178 return false;
179 }
180 if (IsType(this->text(*result))) {
181 this->error(*result, "expected an identifier, but found type '" +
182 this->text(*result) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400183 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400184 return false;
185 }
186 return true;
187}
188
189skstd::string_view DSLParser::text(Token token) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400190 return skstd::string_view(fText->data() + token.fOffset, token.fLength);
191}
192
193PositionInfo DSLParser::position(Token t) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400194 return this->position(t.fLine);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400195}
196
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400197PositionInfo DSLParser::position(int line) {
198 return PositionInfo("<unknown>", line);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400199}
200
201void DSLParser::error(Token token, String msg) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400202 this->error(token.fLine, msg);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400203}
204
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400205void DSLParser::error(int line, String msg) {
206 GetErrorReporter().error(msg.c_str(), this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400207}
208
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400209/* declaration* END_OF_FILE */
210std::unique_ptr<Program> DSLParser::program() {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400211 ErrorReporter* errorReporter = &fCompiler.errorReporter();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400212 Start(&fCompiler, fKind, fSettings);
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400213 SetErrorReporter(errorReporter);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400214 errorReporter->setSource(fText->c_str());
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400215 this->declarations();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400216 std::unique_ptr<Program> result;
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400217 if (!GetErrorReporter().errorCount()) {
218 result = dsl::ReleaseProgram(std::move(fText));
219 }
220 errorReporter->setSource(nullptr);
221 End();
222 return result;
223}
224
225SkSL::LoadedModule DSLParser::moduleInheritingFrom(SkSL::ParsedModule baseModule) {
226 ErrorReporter* errorReporter = &fCompiler.errorReporter();
227 StartModule(&fCompiler, fKind, fSettings, std::move(baseModule));
228 SetErrorReporter(errorReporter);
229 errorReporter->setSource(fText->c_str());
230 this->declarations();
231 CurrentSymbolTable()->takeOwnershipOfString(std::move(*fText));
232 SkSL::LoadedModule result{ fKind, CurrentSymbolTable(),
233 std::move(DSLWriter::ProgramElements()) };
234 errorReporter->setSource(nullptr);
235 End();
236 return result;
237}
238
239void DSLParser::declarations() {
240 fEncounteredFatalError = false;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400241 bool done = false;
242 while (!done) {
243 switch (this->peek().fKind) {
244 case Token::Kind::TK_END_OF_FILE:
245 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400246 break;
Ethan Nicholas642215e2021-09-03 11:10:54 -0400247 case Token::Kind::TK_DIRECTIVE:
248 this->directive();
249 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400250 case Token::Kind::TK_INVALID: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400251 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400252 this->error(this->peek(), String("invalid token"));
Ethan Nicholasf8f1fa02021-08-29 14:12:17 -0400253 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400254 break;
255 }
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400256 default:
257 this->declaration();
258 done = fEncounteredFatalError;
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400259 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400260 }
261 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400262}
263
Ethan Nicholas642215e2021-09-03 11:10:54 -0400264/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
265void DSLParser::directive() {
266 Token start;
267 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
268 return;
269 }
270 skstd::string_view text = this->text(start);
271 if (text == "#extension") {
272 Token name;
273 if (!this->expectIdentifier(&name)) {
274 return;
275 }
276 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
277 return;
278 }
279 Token behavior;
280 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
281 return;
282 }
283 skstd::string_view behaviorText = this->text(behavior);
284 if (behaviorText == "disable") {
285 return;
286 }
287 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
288 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
289 }
290 // We don't currently do anything different between require, enable, and warn
291 dsl::AddExtension(this->text(name));
292 } else {
293 this->error(start, "unsupported directive '" + this->text(start) + "'");
294 }
295}
296
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400297/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
298 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
299bool DSLParser::declaration() {
300 Token lookahead = this->peek();
301 switch (lookahead.fKind) {
302 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400303 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400304 this->error(lookahead, "expected a declaration, but found ';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400305 return false;
306 default:
307 break;
308 }
309 DSLModifiers modifiers = this->modifiers();
310 lookahead = this->peek();
311 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
312 // we have an identifier that's not a type, could be the start of an interface block
313 return this->interfaceBlock(modifiers);
314 }
315 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
Ethan Nicholas678ec712021-09-03 06:33:47 -0400316 this->nextToken();
317 Declare(modifiers, position(lookahead));
318 return true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400319 }
320 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400321 this->structVarDeclaration(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400322 return true;
323 }
John Stiles66aa1de2021-10-01 13:59:20 -0400324 skstd::optional<DSLType> type = this->type(&modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400325 if (!type) {
326 return false;
327 }
328 Token name;
329 if (!this->expectIdentifier(&name)) {
330 return false;
331 }
332 if (this->checkNext(Token::Kind::TK_LPAREN)) {
333 return this->functionDeclarationEnd(modifiers, *type, name);
334 } else {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400335 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400336 return true;
337 }
338}
339
340/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400341bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
342 DSLType type,
343 const Token& name) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400344 SkTArray<DSLWrapper<DSLParameter>> parameters;
345 Token lookahead = this->peek();
346 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
347 // `()` means no parameters at all.
348 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
349 // `(void)` also means no parameters at all.
350 this->nextToken();
351 } else {
352 for (;;) {
353 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
354 if (!parameter) {
355 return false;
356 }
357 parameters.push_back(std::move(*parameter));
358 if (!this->checkNext(Token::Kind::TK_COMMA)) {
359 break;
360 }
361 }
362 }
363 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
364 return false;
365 }
366 SkTArray<DSLParameter*> parameterPointers;
367 for (DSLWrapper<DSLParameter>& param : parameters) {
368 parameterPointers.push_back(&param.get());
369 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400370 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400371 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
372 AutoDSLSymbolTable symbols;
373 for (DSLParameter* var : parameterPointers) {
374 AddToSymbolTable(*var);
375 }
376 skstd::optional<DSLBlock> body = this->block();
377 if (!body) {
378 return false;
379 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -0400380 result.define(std::move(*body), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400381 }
382 return true;
383}
384
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400385SKSL_INT DSLParser::arraySize() {
386 Token next = this->peek();
387 if (next.fKind == Token::Kind::TK_INT_LITERAL) {
388 SKSL_INT size;
389 if (this->intLiteral(&size)) {
390 if (size > INT32_MAX) {
391 this->error(next, "array size out of bounds");
392 return 1;
393 }
394 if (size <= 0) {
395 this->error(next, "array size must be positive");
396 return 1;
397 }
398 return size;
399 }
400 return 1;
401 } else if (this->checkNext(Token::Kind::TK_MINUS) &&
402 this->checkNext(Token::Kind::TK_INT_LITERAL)) {
403 this->error(next, "array size must be positive");
404 return 1;
405 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400406 DSLExpression expr = this->expression();
407 if (expr.isValid()) {
Ethan Nicholas51b4b862021-08-31 16:12:40 -0400408 this->error(next, "expected int literal");
409 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400410 return 1;
411 }
412}
413
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400414bool DSLParser::parseArrayDimensions(int line, DSLType* type) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400415 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
416 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400417 this->error(line, "expected array dimension");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400418 } else {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400419 *type = Array(*type, this->arraySize(), this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400420 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400421 return false;
422 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400423 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400424 }
425 return true;
426}
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400427
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400428bool DSLParser::parseInitializer(int line, DSLExpression* initializer) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400429 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400430 DSLExpression value = this->assignmentExpression();
431 if (!value.hasValue()) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400432 return false;
433 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400434 initializer->swap(value);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400435 }
436 return true;
437}
438
439/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
440 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
441void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
442 dsl::DSLType baseType, skstd::string_view name) {
443 using namespace dsl;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400444 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400445 DSLType type = baseType;
446 DSLExpression initializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400447 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400448 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400449 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400450 if (!this->parseInitializer(line, &initializer)) {
John Stilesb05bbd02021-09-24 15:11:16 -0400451 return;
452 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400453 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
454 Declare(first);
455 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400456
457 while (this->checkNext(Token::Kind::TK_COMMA)) {
458 type = baseType;
459 Token identifierName;
460 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400461 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400462 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400463 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400464 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400465 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400466 DSLExpression anotherInitializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400467 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400468 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400469 }
John Stilesb05bbd02021-09-24 15:11:16 -0400470 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400471 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400472 Declare(next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400473 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400474 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400475 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400476}
477
478/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
479 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400480DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
481 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400482 using namespace dsl;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400483 int line = this->peek().fLine;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400484 DSLType type = baseType;
485 DSLExpression initializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400486 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400487 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400488 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400489 if (!this->parseInitializer(line, &initializer)) {
John Stilesb05bbd02021-09-24 15:11:16 -0400490 return {};
491 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400492 DSLVar first(mods, type, name, std::move(initializer), pos);
493 DSLStatement result = Declare(first);
494 AddToSymbolTable(first);
495
496 while (this->checkNext(Token::Kind::TK_COMMA)) {
497 type = baseType;
498 Token identifierName;
499 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400500 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400501 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400502 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400503 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400504 }
505 DSLExpression anotherInitializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400506 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400507 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400508 }
John Stilesb05bbd02021-09-24 15:11:16 -0400509 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400510 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400511 DSLWriter::AddVarDeclaration(result, next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400512 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400513 }
514 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400515 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400516}
517
518/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400519DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400520 Token nextToken = this->peek();
521 if (nextToken.fKind == Token::Kind::TK_CONST) {
522 // Statements that begin with `const` might be variable declarations, but can't be legal
523 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
524 return this->varDeclarations();
525 }
526
John Stiles02014312021-08-04 16:03:12 -0400527 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
528 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
529 nextToken.fKind == Token::Kind::TK_LOWP ||
530 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400531 // Statements that begin with a typename are most often variable declarations, but
532 // occasionally the type is part of a constructor, and these are actually expression-
533 // statements in disguise. First, attempt the common case: parse it as a vardecl.
534 Checkpoint checkpoint(this);
535 VarDeclarationsPrefix prefix;
536 if (this->varDeclarationsPrefix(&prefix)) {
537 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400538 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
539 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400540 }
541
542 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
543 // expression-statement instead.
544 checkpoint.rewind();
545 }
546 return this->expressionStatement();
547}
548
549// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
550// statement is a variable-declaration statement, not an expression-statement.
551bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400552 prefixData->fPosition = this->position(this->peek());
553 prefixData->fModifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -0400554 skstd::optional<DSLType> type = this->type(&prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400555 if (!type) {
556 return false;
557 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400558 prefixData->fType = *type;
559 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400560}
561
562/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400563DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400564 VarDeclarationsPrefix prefix;
565 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400566 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400567 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400568 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
569 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400570}
571
572/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
573skstd::optional<DSLType> DSLParser::structDeclaration() {
574 AutoDSLDepth depth(this);
575 if (!depth.increase()) {
576 return skstd::nullopt;
577 }
578 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
579 return skstd::nullopt;
580 }
581 Token name;
582 if (!this->expectIdentifier(&name)) {
583 return skstd::nullopt;
584 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400585 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
586 return skstd::nullopt;
587 }
588 SkTArray<DSLField> fields;
589 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
590 DSLModifiers modifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -0400591 skstd::optional<DSLType> type = this->type(&modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400592 if (!type) {
593 return skstd::nullopt;
594 }
595
596 do {
597 DSLType actualType = *type;
598 Token memberName;
599 if (!this->expectIdentifier(&memberName)) {
600 return skstd::nullopt;
601 }
602
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400603 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
604 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400605 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
606 return skstd::nullopt;
607 }
608 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400609 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
610 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400611 } while (this->checkNext(Token::Kind::TK_COMMA));
612 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
613 return skstd::nullopt;
614 }
615 }
616 if (fields.empty()) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400617 this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400618 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400619 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400620}
621
622/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400623SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400624 skstd::optional<DSLType> type = this->structDeclaration();
625 if (!type) {
626 return {};
627 }
628 Token name;
629 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400630 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
631 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400632 } else {
633 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400634 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400635 return {};
636}
637
638/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
639skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
640 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles66aa1de2021-10-01 13:59:20 -0400641 skstd::optional<DSLType> type = this->type(&modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400642 if (!type) {
643 return skstd::nullopt;
644 }
645 Token name;
646 if (!this->expectIdentifier(&name)) {
647 return skstd::nullopt;
648 }
649 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400650 Token sizeToken;
651 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
652 return skstd::nullopt;
653 }
654 skstd::string_view arraySizeFrag = this->text(sizeToken);
655 SKSL_INT arraySize;
656 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
657 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400658 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400659 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400660 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400661 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
662 return skstd::nullopt;
663 }
664 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400665 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400666}
667
668/** EQ INT_LITERAL */
669int DSLParser::layoutInt() {
670 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
671 return -1;
672 }
673 Token resultToken;
674 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
675 return -1;
676 }
677 skstd::string_view resultFrag = this->text(resultToken);
678 SKSL_INT resultValue;
679 if (!SkSL::stoi(resultFrag, &resultValue)) {
680 this->error(resultToken, "value in layout is too large: " + resultFrag);
681 return -1;
682 }
683 return resultValue;
684}
685
686/** EQ IDENTIFIER */
687skstd::string_view DSLParser::layoutIdentifier() {
688 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
689 return {};
690 }
691 Token resultToken;
692 if (!this->expectIdentifier(&resultToken)) {
693 return {};
694 }
695 return this->text(resultToken);
696}
697
698/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
699DSLLayout DSLParser::layout() {
700 DSLLayout result;
701 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
702 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
703 return result;
704 }
705 for (;;) {
706 Token t = this->nextToken();
707 String text(this->text(t));
708 auto found = layoutTokens->find(text);
709 if (found != layoutTokens->end()) {
710 switch (found->second) {
711 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400712 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400713 break;
714 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400715 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400716 break;
717 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400718 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400719 break;
720 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400721 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400722 break;
723 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400724 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400725 break;
726 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400727 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400728 break;
729 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400730 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400731 break;
732 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400733 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400734 break;
735 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400736 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400737 break;
738 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400739 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400740 break;
741 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400742 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400743 break;
744 default:
745 this->error(t, "'" + text + "' is not a valid layout qualifier");
746 break;
747 }
748 } else {
749 this->error(t, "'" + text + "' is not a valid layout qualifier");
750 }
751 if (this->checkNext(Token::Kind::TK_RPAREN)) {
752 break;
753 }
754 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
755 break;
756 }
757 }
758 }
759 return result;
760}
761
762/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
763 VARYING | INLINE)* */
764DSLModifiers DSLParser::modifiers() {
765 DSLLayout layout = this->layout();
766 int flags = 0;
767 for (;;) {
768 // TODO(ethannicholas): handle duplicate / incompatible flags
769 int tokenFlag = parse_modifier_token(peek().fKind);
770 if (!tokenFlag) {
771 break;
772 }
773 flags |= tokenFlag;
774 this->nextToken();
775 }
776 return DSLModifiers(std::move(layout), flags);
777}
778
779DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
780 DSLModifiers result = this->modifiers();
781 if (defaultFlags && !result.flags()) {
782 return DSLModifiers(result.layout(), defaultFlags);
783 }
784 return result;
785}
786
787/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400788DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400789 Token start = this->nextToken();
790 AutoDSLDepth depth(this);
791 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400792 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400793 }
794 this->pushback(start);
795 switch (start.fKind) {
796 case Token::Kind::TK_IF: // fall through
797 case Token::Kind::TK_STATIC_IF:
798 return this->ifStatement();
799 case Token::Kind::TK_FOR:
800 return this->forStatement();
801 case Token::Kind::TK_DO:
802 return this->doStatement();
803 case Token::Kind::TK_WHILE:
804 return this->whileStatement();
805 case Token::Kind::TK_SWITCH: // fall through
806 case Token::Kind::TK_STATIC_SWITCH:
807 return this->switchStatement();
808 case Token::Kind::TK_RETURN:
809 return this->returnStatement();
810 case Token::Kind::TK_BREAK:
811 return this->breakStatement();
812 case Token::Kind::TK_CONTINUE:
813 return this->continueStatement();
814 case Token::Kind::TK_DISCARD:
815 return this->discardStatement();
816 case Token::Kind::TK_LBRACE: {
817 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400818 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400819 }
820 case Token::Kind::TK_SEMICOLON:
821 this->nextToken();
822 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400823 case Token::Kind::TK_HIGHP:
824 case Token::Kind::TK_MEDIUMP:
825 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400826 case Token::Kind::TK_CONST:
827 case Token::Kind::TK_IDENTIFIER:
828 return this->varDeclarationsOrExpressionStatement();
829 default:
830 return this->expressionStatement();
831 }
832}
833
834/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stiles66aa1de2021-10-01 13:59:20 -0400835skstd::optional<DSLType> DSLParser::type(DSLModifiers* modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400836 Token type;
837 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
838 return skstd::nullopt;
839 }
840 if (!IsType(this->text(type))) {
841 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
842 return skstd::nullopt;
843 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400844 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400845 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400846 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400847 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400848 } else {
849 this->error(this->peek(), "expected array dimension");
850 }
851 this->expect(Token::Kind::TK_RBRACKET, "']'");
852 }
853 return result;
854}
855
856/* IDENTIFIER LBRACE
857 varDeclaration+
858 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400859bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400860 Token typeName;
861 if (!this->expectIdentifier(&typeName)) {
862 return false;
863 }
864 if (peek().fKind != Token::Kind::TK_LBRACE) {
865 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
866 // 99% of the time, the user was not actually intending to create an interface block, so
867 // it's better to report it as an unknown type
868 this->error(typeName, "no type named '" + this->text(typeName) + "'");
869 return false;
870 }
871 this->nextToken();
872 SkTArray<dsl::Field> fields;
873 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400874 DSLModifiers fieldModifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -0400875 skstd::optional<dsl::DSLType> type = this->type(&fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400876 if (!type) {
877 return false;
878 }
879 do {
880 Token fieldName;
881 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
882 return false;
883 }
884 DSLType actualType = *type;
885 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
886 Token sizeToken = this->peek();
887 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400888 actualType = Array(std::move(actualType), this->arraySize(),
889 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400890 } else {
891 this->error(sizeToken, "unsized arrays are not permitted");
892 }
893 this->expect(Token::Kind::TK_RBRACKET, "']'");
894 }
895 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
896 return false;
897 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400898 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
899 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400900 }
901 while (this->checkNext(Token::Kind::TK_COMMA));
902 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400903 skstd::string_view instanceName;
904 Token instanceNameToken;
905 SKSL_INT arraySize = 0;
906 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
907 instanceName = this->text(instanceNameToken);
908 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400909 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400910 this->expect(Token::Kind::TK_RBRACKET, "']'");
911 }
912 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400913 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400914 if (fields.empty()) {
915 this->error(typeName, "interface block '" + this->text(typeName) +
916 "' must contain at least one member");
917 } else {
918 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
919 arraySize, this->position(typeName));
920 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400921 return true;
922}
923
924/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400925DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400926 Token start;
927 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
928 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400929 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400930 }
931 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400932 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400933 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400934 DSLExpression test = this->expression();
935 if (!test.hasValue()) {
936 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400937 }
938 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400939 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400940 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400941 DSLStatement ifTrue = this->statement();
942 if (!ifTrue.hasValue()) {
943 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400944 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400945 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400946 if (this->checkNext(Token::Kind::TK_ELSE)) {
947 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400948 if (!ifFalse.hasValue()) {
949 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400950 }
951 }
952 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400953 return StaticIf(std::move(test), std::move(ifTrue),
954 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400955 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400956 return If(std::move(test), std::move(ifTrue),
957 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400958 }
959}
960
961/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400962DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400963 Token start;
964 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400965 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400966 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400967 DSLStatement statement = this->statement();
968 if (!statement.hasValue()) {
969 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400970 }
971 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400972 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400973 }
974 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400975 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400976 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400977 DSLExpression test = this->expression();
978 if (!test.hasValue()) {
979 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400980 }
981 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400982 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400983 }
984 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400985 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400986 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400987 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400988}
989
990/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400991DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400992 Token start;
993 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400994 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400995 }
996 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400997 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400998 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400999 DSLExpression test = this->expression();
1000 if (!test.hasValue()) {
1001 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001002 }
1003 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001004 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001005 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001006 DSLStatement statement = this->statement();
1007 if (!statement.hasValue()) {
1008 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001009 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001010 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001011}
1012
1013/* CASE expression COLON statement* */
1014skstd::optional<DSLCase> DSLParser::switchCase() {
1015 Token start;
1016 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001017 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001018 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001019 DSLExpression value = this->expression();
1020 if (!value.hasValue()) {
1021 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001022 }
1023 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001024 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001025 }
1026 SkTArray<DSLStatement> statements;
1027 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1028 this->peek().fKind != Token::Kind::TK_CASE &&
1029 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001030 DSLStatement s = this->statement();
1031 if (!s.hasValue()) {
1032 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001033 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001034 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001035 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001036 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001037}
1038
1039/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001040DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001041 Token start;
1042 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1043 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001044 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001045 }
1046 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001047 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001048 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001049 DSLExpression value = this->expression();
1050 if (!value.hasValue()) {
1051 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001052 }
1053 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001054 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001055 }
1056 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001057 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001058 }
1059 SkTArray<DSLCase> cases;
1060 while (this->peek().fKind == Token::Kind::TK_CASE) {
1061 skstd::optional<DSLCase> c = this->switchCase();
1062 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001063 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001064 }
1065 cases.push_back(std::move(*c));
1066 }
1067 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1068 // parts of the compiler may rely upon this assumption.
1069 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1070 SkTArray<DSLStatement> statements;
1071 Token defaultStart;
1072 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1073 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001074 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001075 }
1076 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001077 DSLStatement s = this->statement();
1078 if (!s.hasValue()) {
1079 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001080 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001081 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001082 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001083 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001084 }
1085 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001086 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001087 }
1088 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001089 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001090 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001091 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001092 }
1093}
1094
1095/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1096 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001097dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001098 Token start;
1099 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001100 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001101 }
1102 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001103 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001104 }
1105 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001106 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001107 Token nextToken = this->peek();
1108 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1109 // An empty init-statement.
1110 this->nextToken();
1111 } else {
1112 // The init-statement must be an expression or variable declaration.
1113 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001114 if (!initializer.hasValue()) {
1115 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001116 }
1117 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001118 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001119 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001120 dsl::DSLExpression testValue = this->expression();
1121 if (!testValue.hasValue()) {
1122 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001123 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001124 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001125 }
1126 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001127 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001128 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001129 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001130 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001131 dsl::DSLExpression nextValue = this->expression();
1132 if (!nextValue.hasValue()) {
1133 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001134 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001135 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001136 }
1137 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001138 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001139 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001140 dsl::DSLStatement statement = this->statement();
1141 if (!statement.hasValue()) {
1142 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001143 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001144 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1145 test.hasValue() ? std::move(test) : DSLExpression(),
1146 next.hasValue() ? std::move(next) : DSLExpression(),
1147 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001148 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001149}
1150
1151/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001152DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001153 Token start;
1154 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001155 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001156 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001157 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001158 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001159 DSLExpression next = this->expression();
1160 if (!next.hasValue()) {
1161 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001162 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001163 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001164 }
1165 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001166 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001167 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001168 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1169 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001170}
1171
1172/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001173DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001174 Token start;
1175 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001176 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001177 }
1178 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001179 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001180 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001181 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001182}
1183
1184/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001185DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001186 Token start;
1187 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001188 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001189 }
1190 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001191 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001192 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001193 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001194}
1195
1196/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001197DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001198 Token start;
1199 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001200 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001201 }
1202 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001203 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001204 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001205 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001206}
1207
1208/* LBRACE statement* RBRACE */
1209skstd::optional<DSLBlock> DSLParser::block() {
1210 Token start;
1211 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1212 return skstd::nullopt;
1213 }
1214 AutoDSLDepth depth(this);
1215 if (!depth.increase()) {
1216 return skstd::nullopt;
1217 }
1218 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001219 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001220 for (;;) {
1221 switch (this->peek().fKind) {
1222 case Token::Kind::TK_RBRACE:
1223 this->nextToken();
1224 return DSLBlock(std::move(statements), CurrentSymbolTable());
1225 case Token::Kind::TK_END_OF_FILE:
1226 this->error(this->peek(), "expected '}', but found end of file");
1227 return skstd::nullopt;
1228 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001229 DSLStatement statement = this->statement();
1230 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001231 return skstd::nullopt;
1232 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001233 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001234 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001235 }
1236 }
1237 }
1238}
1239
1240/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001241DSLStatement DSLParser::expressionStatement() {
1242 DSLExpression expr = this->expression();
1243 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001244 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001245 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001246 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001247 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001248 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001249 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001250}
1251
1252/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001253DSLExpression DSLParser::expression() {
1254 DSLExpression result = this->assignmentExpression();
1255 if (!result.hasValue()) {
1256 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001257 }
1258 Token t;
1259 AutoDSLDepth depth(this);
1260 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1261 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001262 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001263 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001264 DSLExpression right = this->assignmentExpression();
1265 if (!right.hasValue()) {
1266 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001267 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001268 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1269 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001270 }
1271 return result;
1272}
1273
1274#define OPERATOR_RIGHT(op, exprType) \
1275 do { \
1276 this->nextToken(); \
1277 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001278 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001279 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001280 DSLExpression right = this->exprType(); \
1281 if (!right.hasValue()) { \
1282 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001283 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001284 DSLExpression next = std::move(result) op std::move(right); \
1285 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001286 } while (false)
1287
1288/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1289 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1290 assignmentExpression)*
1291 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001292DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001293 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001294 DSLExpression result = this->ternaryExpression();
1295 if (!result.hasValue()) {
1296 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001297 }
1298 for (;;) {
1299 switch (this->peek().fKind) {
1300 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1301 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1302 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1303 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1304 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1305 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1306 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1307 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1308 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1309 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1310 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1311 default:
1312 return result;
1313 }
1314 }
1315}
1316
1317/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001318DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001319 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001320 DSLExpression base = this->logicalOrExpression();
1321 if (!base.hasValue()) {
1322 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001323 }
1324 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1325 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001326 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001327 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001328 DSLExpression trueExpr = this->expression();
1329 if (!trueExpr.hasValue()) {
1330 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001331 }
1332 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001333 DSLExpression falseExpr = this->assignmentExpression();
1334 if (!falseExpr.hasValue()) {
1335 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001336 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001337 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001338 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001339 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001340 }
1341 return base;
1342}
1343
1344/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001345DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001346 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001347 DSLExpression result = this->logicalXorExpression();
1348 if (!result.hasValue()) {
1349 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001350 }
1351 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1352 OPERATOR_RIGHT(||, logicalXorExpression);
1353 }
1354 return result;
1355}
1356
1357/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001358DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001359 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001360 DSLExpression result = this->logicalAndExpression();
1361 if (!result.hasValue()) {
1362 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001363 }
1364 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1365 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001366 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001367 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001368 DSLExpression right = this->logicalAndExpression();
1369 if (!right.hasValue()) {
1370 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001371 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001372 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1373 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001374 }
1375 return result;
1376}
1377
1378/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001379DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001380 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001381 DSLExpression result = this->bitwiseOrExpression();
1382 if (!result.hasValue()) {
1383 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001384 }
1385 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1386 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1387 }
1388 return result;
1389}
1390
1391/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001392DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001393 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001394 DSLExpression result = this->bitwiseXorExpression();
1395 if (!result.hasValue()) {
1396 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001397 }
1398 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1399 OPERATOR_RIGHT(|, bitwiseXorExpression);
1400 }
1401 return result;
1402}
1403
1404/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001405DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001406 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001407 DSLExpression result = this->bitwiseAndExpression();
1408 if (!result.hasValue()) {
1409 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001410 }
1411 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1412 OPERATOR_RIGHT(^, bitwiseAndExpression);
1413 }
1414 return result;
1415}
1416
1417/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001418DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001419 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001420 DSLExpression result = this->equalityExpression();
1421 if (!result.hasValue()) {
1422 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001423 }
1424 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1425 OPERATOR_RIGHT(&, equalityExpression);
1426 }
1427 return result;
1428}
1429
1430/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001431DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001432 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001433 DSLExpression result = this->relationalExpression();
1434 if (!result.hasValue()) {
1435 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001436 }
1437 for (;;) {
1438 switch (this->peek().fKind) {
1439 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1440 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1441 default: return result;
1442 }
1443 }
1444}
1445
1446/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001447DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001448 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001449 DSLExpression result = this->shiftExpression();
1450 if (!result.hasValue()) {
1451 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001452 }
1453 for (;;) {
1454 switch (this->peek().fKind) {
1455 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1456 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1457 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1458 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1459 default: return result;
1460 }
1461 }
1462}
1463
1464/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001465DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001466 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001467 DSLExpression result = this->additiveExpression();
1468 if (!result.hasValue()) {
1469 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001470 }
1471 for (;;) {
1472 switch (this->peek().fKind) {
1473 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1474 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1475 default: return result;
1476 }
1477 }
1478}
1479
1480/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001481DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001482 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001483 DSLExpression result = this->multiplicativeExpression();
1484 if (!result.hasValue()) {
1485 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001486 }
1487 for (;;) {
1488 switch (this->peek().fKind) {
1489 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1490 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1491 default: return result;
1492 }
1493 }
1494}
1495
1496/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001497DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001498 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001499 DSLExpression result = this->unaryExpression();
1500 if (!result.hasValue()) {
1501 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001502 }
1503 for (;;) {
1504 switch (this->peek().fKind) {
1505 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1506 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1507 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1508 default: return result;
1509 }
1510 }
1511}
1512
1513/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001514DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001515 AutoDSLDepth depth(this);
1516 Token next = this->peek();
1517 switch (next.fKind) {
1518 case Token::Kind::TK_PLUS:
1519 case Token::Kind::TK_MINUS:
1520 case Token::Kind::TK_LOGICALNOT:
1521 case Token::Kind::TK_BITWISENOT:
1522 case Token::Kind::TK_PLUSPLUS:
1523 case Token::Kind::TK_MINUSMINUS: {
1524 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001525 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001526 }
1527 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001528 DSLExpression expr = this->unaryExpression();
1529 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001530 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001531 }
1532 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001533 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1534 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1535 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1536 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1537 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1538 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001539 default: SkUNREACHABLE;
1540 }
1541 }
1542 default:
1543 return this->postfixExpression();
1544 }
1545}
1546
1547/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001548DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001549 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001550 DSLExpression result = this->term();
1551 if (!result.hasValue()) {
1552 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001553 }
1554 for (;;) {
1555 Token t = this->peek();
1556 switch (t.fKind) {
1557 case Token::Kind::TK_FLOAT_LITERAL:
1558 if (this->text(t)[0] != '.') {
1559 return result;
1560 }
1561 [[fallthrough]];
1562 case Token::Kind::TK_LBRACKET:
1563 case Token::Kind::TK_DOT:
1564 case Token::Kind::TK_LPAREN:
1565 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001566 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001567 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001568 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001569 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001570 DSLExpression next = this->suffix(std::move(result));
1571 if (!next.hasValue()) {
1572 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001573 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001574 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001575 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001576 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001577 default:
1578 return result;
1579 }
1580 }
1581}
1582
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001583DSLExpression DSLParser::swizzle(int line, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001584 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001585 SkASSERT(swizzleMask.length() > 0);
1586 if (!base.type().isVector() && !base.type().isScalar()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001587 return base.field(swizzleMask, this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001588 }
1589 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001590 SkSL::SwizzleComponent::Type components[4];
1591 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001592 if (i >= 4) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001593 this->error(line, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001594 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001595 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001596 switch (swizzleMask[i]) {
1597 case '0': components[i] = SwizzleComponent::ZERO; break;
1598 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001599 case 'r': components[i] = SwizzleComponent::R; break;
1600 case 'x': components[i] = SwizzleComponent::X; break;
1601 case 's': components[i] = SwizzleComponent::S; break;
1602 case 'L': components[i] = SwizzleComponent::UL; break;
1603 case 'g': components[i] = SwizzleComponent::G; break;
1604 case 'y': components[i] = SwizzleComponent::Y; break;
1605 case 't': components[i] = SwizzleComponent::T; break;
1606 case 'T': components[i] = SwizzleComponent::UT; break;
1607 case 'b': components[i] = SwizzleComponent::B; break;
1608 case 'z': components[i] = SwizzleComponent::Z; break;
1609 case 'p': components[i] = SwizzleComponent::P; break;
1610 case 'R': components[i] = SwizzleComponent::UR; break;
1611 case 'a': components[i] = SwizzleComponent::A; break;
1612 case 'w': components[i] = SwizzleComponent::W; break;
1613 case 'q': components[i] = SwizzleComponent::Q; break;
1614 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001615 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001616 this->error(line,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001617 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001618 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001619 }
1620 }
1621 switch (length) {
1622 case 1: return dsl::Swizzle(std::move(base), components[0]);
1623 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1624 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1625 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1626 components[3]);
1627 default: SkUNREACHABLE;
1628 }
1629}
1630
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001631dsl::DSLExpression DSLParser::call(int line, dsl::DSLExpression base, ExpressionArray args) {
1632 return DSLExpression(base(std::move(args), this->position(line)), this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001633}
1634
1635/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1636 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001637DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001638 Token next = this->nextToken();
1639 AutoDSLDepth depth(this);
1640 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001641 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001642 }
1643 switch (next.fKind) {
1644 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001645 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1646 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001647 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001648 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001649 DSLExpression index = this->expression();
1650 if (!index.hasValue()) {
1651 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001652 }
1653 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001654 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001655 if (!result.valid()) {
1656 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001657 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001658 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001659 }
1660 case Token::Kind::TK_DOT: {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001661 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001662 skstd::string_view text;
1663 if (this->identifier(&text)) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001664 return this->swizzle(line, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001665 }
1666 [[fallthrough]];
1667 }
1668 case Token::Kind::TK_FLOAT_LITERAL: {
1669 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1670 // floating point literals, possibly followed by an identifier. Handle that here.
1671 skstd::string_view field = this->text(next);
1672 SkASSERT(field[0] == '.');
1673 field.remove_prefix(1);
1674 // use the next *raw* token so we don't ignore whitespace - we only care about
1675 // identifiers that directly follow the float
1676 Token id = this->nextRawToken();
1677 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001678 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001679 } else if (field.empty()) {
1680 this->error(next, "expected field name or swizzle mask after '.'");
1681 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001682 }
1683 this->pushback(id);
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001684 return this->swizzle(next.fLine, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001685 }
1686 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001687 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001688 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1689 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001690 DSLExpression expr = this->assignmentExpression();
1691 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001692 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001693 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001694 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001695 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1696 break;
1697 }
1698 }
1699 }
1700 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001701 return this->call(next.fLine, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001702 }
1703 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001704 return std::move(base)++;
1705 case Token::Kind::TK_MINUSMINUS:
1706 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001707 default: {
1708 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001709 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001710 }
1711 }
1712}
1713
1714/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001715DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001716 Token t = this->peek();
1717 switch (t.fKind) {
1718 case Token::Kind::TK_IDENTIFIER: {
1719 skstd::string_view text;
1720 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001721 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001722 }
1723 break;
1724 }
1725 case Token::Kind::TK_INT_LITERAL: {
1726 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001727 if (!this->intLiteral(&i)) {
1728 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001729 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001730 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001731 }
1732 case Token::Kind::TK_FLOAT_LITERAL: {
1733 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001734 if (!this->floatLiteral(&f)) {
1735 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001736 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001737 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001738 }
1739 case Token::Kind::TK_TRUE_LITERAL: // fall through
1740 case Token::Kind::TK_FALSE_LITERAL: {
1741 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001742 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001743 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001744 }
1745 case Token::Kind::TK_LPAREN: {
1746 this->nextToken();
1747 AutoDSLDepth depth(this);
1748 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001749 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001750 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001751 DSLExpression result = this->expression();
1752 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001753 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1754 return result;
1755 }
1756 break;
1757 }
1758 default:
1759 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001760 this->error(t, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001761 fEncounteredFatalError = true;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001762 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001763 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001764 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001765}
1766
1767/* INT_LITERAL */
1768bool DSLParser::intLiteral(SKSL_INT* dest) {
1769 Token t;
1770 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1771 return false;
1772 }
1773 skstd::string_view s = this->text(t);
1774 if (!SkSL::stoi(s, dest)) {
1775 this->error(t, "integer is too large: " + s);
1776 return false;
1777 }
1778 return true;
1779}
1780
1781/* FLOAT_LITERAL */
1782bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1783 Token t;
1784 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1785 return false;
1786 }
1787 skstd::string_view s = this->text(t);
1788 if (!SkSL::stod(s, dest)) {
1789 this->error(t, "floating-point value is too large: " + s);
1790 return false;
1791 }
1792 return true;
1793}
1794
1795/* TRUE_LITERAL | FALSE_LITERAL */
1796bool DSLParser::boolLiteral(bool* dest) {
1797 Token t = this->nextToken();
1798 switch (t.fKind) {
1799 case Token::Kind::TK_TRUE_LITERAL:
1800 *dest = true;
1801 return true;
1802 case Token::Kind::TK_FALSE_LITERAL:
1803 *dest = false;
1804 return true;
1805 default:
1806 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1807 return false;
1808 }
1809}
1810
1811/* IDENTIFIER */
1812bool DSLParser::identifier(skstd::string_view* dest) {
1813 Token t;
1814 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1815 *dest = this->text(t);
1816 return true;
1817 }
1818 return false;
1819}
1820
1821} // namespace SkSL