blob: 95de449259d2a7dcfa6f566a8948ded77f10971f [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 Stiles4adb66f2021-08-05 10:15:16 -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();
554 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();
591
John Stiles4adb66f2021-08-05 10:15:16 -0400592 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400593 if (!type) {
594 return skstd::nullopt;
595 }
596
597 do {
598 DSLType actualType = *type;
599 Token memberName;
600 if (!this->expectIdentifier(&memberName)) {
601 return skstd::nullopt;
602 }
603
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400604 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
605 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400606 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
607 return skstd::nullopt;
608 }
609 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400610 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
611 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400612 } while (this->checkNext(Token::Kind::TK_COMMA));
613 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
614 return skstd::nullopt;
615 }
616 }
617 if (fields.empty()) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400618 this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400619 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400620 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400621}
622
623/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400624SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400625 skstd::optional<DSLType> type = this->structDeclaration();
626 if (!type) {
627 return {};
628 }
629 Token name;
630 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400631 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
632 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400633 } else {
634 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400635 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400636 return {};
637}
638
639/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
640skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
641 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles4adb66f2021-08-05 10:15:16 -0400642 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400643 if (!type) {
644 return skstd::nullopt;
645 }
646 Token name;
647 if (!this->expectIdentifier(&name)) {
648 return skstd::nullopt;
649 }
650 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400651 Token sizeToken;
652 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
653 return skstd::nullopt;
654 }
655 skstd::string_view arraySizeFrag = this->text(sizeToken);
656 SKSL_INT arraySize;
657 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
658 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400659 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400660 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400661 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400662 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
663 return skstd::nullopt;
664 }
665 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400666 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400667}
668
669/** EQ INT_LITERAL */
670int DSLParser::layoutInt() {
671 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
672 return -1;
673 }
674 Token resultToken;
675 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
676 return -1;
677 }
678 skstd::string_view resultFrag = this->text(resultToken);
679 SKSL_INT resultValue;
680 if (!SkSL::stoi(resultFrag, &resultValue)) {
681 this->error(resultToken, "value in layout is too large: " + resultFrag);
682 return -1;
683 }
684 return resultValue;
685}
686
687/** EQ IDENTIFIER */
688skstd::string_view DSLParser::layoutIdentifier() {
689 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
690 return {};
691 }
692 Token resultToken;
693 if (!this->expectIdentifier(&resultToken)) {
694 return {};
695 }
696 return this->text(resultToken);
697}
698
699/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
700DSLLayout DSLParser::layout() {
701 DSLLayout result;
702 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
703 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
704 return result;
705 }
706 for (;;) {
707 Token t = this->nextToken();
708 String text(this->text(t));
709 auto found = layoutTokens->find(text);
710 if (found != layoutTokens->end()) {
711 switch (found->second) {
712 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400713 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400714 break;
715 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400716 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400717 break;
718 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400719 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400720 break;
721 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400722 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400723 break;
724 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400725 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400726 break;
727 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400728 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400729 break;
730 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400731 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400732 break;
733 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400734 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400735 break;
736 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400737 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400738 break;
739 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400740 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400741 break;
742 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400743 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400744 break;
745 default:
746 this->error(t, "'" + text + "' is not a valid layout qualifier");
747 break;
748 }
749 } else {
750 this->error(t, "'" + text + "' is not a valid layout qualifier");
751 }
752 if (this->checkNext(Token::Kind::TK_RPAREN)) {
753 break;
754 }
755 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
756 break;
757 }
758 }
759 }
760 return result;
761}
762
763/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
764 VARYING | INLINE)* */
765DSLModifiers DSLParser::modifiers() {
766 DSLLayout layout = this->layout();
767 int flags = 0;
768 for (;;) {
769 // TODO(ethannicholas): handle duplicate / incompatible flags
770 int tokenFlag = parse_modifier_token(peek().fKind);
771 if (!tokenFlag) {
772 break;
773 }
774 flags |= tokenFlag;
775 this->nextToken();
776 }
777 return DSLModifiers(std::move(layout), flags);
778}
779
780DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
781 DSLModifiers result = this->modifiers();
782 if (defaultFlags && !result.flags()) {
783 return DSLModifiers(result.layout(), defaultFlags);
784 }
785 return result;
786}
787
788/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400789DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400790 Token start = this->nextToken();
791 AutoDSLDepth depth(this);
792 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400793 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400794 }
795 this->pushback(start);
796 switch (start.fKind) {
797 case Token::Kind::TK_IF: // fall through
798 case Token::Kind::TK_STATIC_IF:
799 return this->ifStatement();
800 case Token::Kind::TK_FOR:
801 return this->forStatement();
802 case Token::Kind::TK_DO:
803 return this->doStatement();
804 case Token::Kind::TK_WHILE:
805 return this->whileStatement();
806 case Token::Kind::TK_SWITCH: // fall through
807 case Token::Kind::TK_STATIC_SWITCH:
808 return this->switchStatement();
809 case Token::Kind::TK_RETURN:
810 return this->returnStatement();
811 case Token::Kind::TK_BREAK:
812 return this->breakStatement();
813 case Token::Kind::TK_CONTINUE:
814 return this->continueStatement();
815 case Token::Kind::TK_DISCARD:
816 return this->discardStatement();
817 case Token::Kind::TK_LBRACE: {
818 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400819 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400820 }
821 case Token::Kind::TK_SEMICOLON:
822 this->nextToken();
823 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400824 case Token::Kind::TK_HIGHP:
825 case Token::Kind::TK_MEDIUMP:
826 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400827 case Token::Kind::TK_CONST:
828 case Token::Kind::TK_IDENTIFIER:
829 return this->varDeclarationsOrExpressionStatement();
830 default:
831 return this->expressionStatement();
832 }
833}
834
835/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stilese53c7212021-08-05 10:19:11 -0400836skstd::optional<DSLType> DSLParser::type(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400837 Token type;
838 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
839 return skstd::nullopt;
840 }
841 if (!IsType(this->text(type))) {
842 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
843 return skstd::nullopt;
844 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400845 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400846 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400847 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400848 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400849 } else {
850 this->error(this->peek(), "expected array dimension");
851 }
852 this->expect(Token::Kind::TK_RBRACKET, "']'");
853 }
854 return result;
855}
856
857/* IDENTIFIER LBRACE
858 varDeclaration+
859 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400860bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400861 Token typeName;
862 if (!this->expectIdentifier(&typeName)) {
863 return false;
864 }
865 if (peek().fKind != Token::Kind::TK_LBRACE) {
866 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
867 // 99% of the time, the user was not actually intending to create an interface block, so
868 // it's better to report it as an unknown type
869 this->error(typeName, "no type named '" + this->text(typeName) + "'");
870 return false;
871 }
872 this->nextToken();
873 SkTArray<dsl::Field> fields;
874 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400875 DSLModifiers fieldModifiers = this->modifiers();
876 skstd::optional<dsl::DSLType> type = this->type(fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400877 if (!type) {
878 return false;
879 }
880 do {
881 Token fieldName;
882 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
883 return false;
884 }
885 DSLType actualType = *type;
886 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
887 Token sizeToken = this->peek();
888 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400889 actualType = Array(std::move(actualType), this->arraySize(),
890 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400891 } else {
892 this->error(sizeToken, "unsized arrays are not permitted");
893 }
894 this->expect(Token::Kind::TK_RBRACKET, "']'");
895 }
896 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
897 return false;
898 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400899 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
900 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400901 }
902 while (this->checkNext(Token::Kind::TK_COMMA));
903 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400904 skstd::string_view instanceName;
905 Token instanceNameToken;
906 SKSL_INT arraySize = 0;
907 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
908 instanceName = this->text(instanceNameToken);
909 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400910 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400911 this->expect(Token::Kind::TK_RBRACKET, "']'");
912 }
913 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400914 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400915 if (fields.empty()) {
916 this->error(typeName, "interface block '" + this->text(typeName) +
917 "' must contain at least one member");
918 } else {
919 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
920 arraySize, this->position(typeName));
921 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400922 return true;
923}
924
925/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400926DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400927 Token start;
928 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
929 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400930 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400931 }
932 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400933 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400934 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400935 DSLExpression test = this->expression();
936 if (!test.hasValue()) {
937 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400938 }
939 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400940 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400941 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400942 DSLStatement ifTrue = this->statement();
943 if (!ifTrue.hasValue()) {
944 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400945 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400946 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400947 if (this->checkNext(Token::Kind::TK_ELSE)) {
948 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400949 if (!ifFalse.hasValue()) {
950 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400951 }
952 }
953 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400954 return StaticIf(std::move(test), std::move(ifTrue),
955 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400956 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400957 return If(std::move(test), std::move(ifTrue),
958 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400959 }
960}
961
962/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400963DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400964 Token start;
965 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400966 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400967 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400968 DSLStatement statement = this->statement();
969 if (!statement.hasValue()) {
970 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400971 }
972 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400973 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400974 }
975 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400976 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400977 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400978 DSLExpression test = this->expression();
979 if (!test.hasValue()) {
980 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400981 }
982 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400983 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400984 }
985 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400986 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400987 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400988 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400989}
990
991/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400992DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400993 Token start;
994 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400995 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400996 }
997 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400998 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400999 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001000 DSLExpression test = this->expression();
1001 if (!test.hasValue()) {
1002 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001003 }
1004 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001005 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001006 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001007 DSLStatement statement = this->statement();
1008 if (!statement.hasValue()) {
1009 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001010 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001011 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001012}
1013
1014/* CASE expression COLON statement* */
1015skstd::optional<DSLCase> DSLParser::switchCase() {
1016 Token start;
1017 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001018 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001019 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001020 DSLExpression value = this->expression();
1021 if (!value.hasValue()) {
1022 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001023 }
1024 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001025 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001026 }
1027 SkTArray<DSLStatement> statements;
1028 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1029 this->peek().fKind != Token::Kind::TK_CASE &&
1030 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001031 DSLStatement s = this->statement();
1032 if (!s.hasValue()) {
1033 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001034 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001035 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001036 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001037 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001038}
1039
1040/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001041DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001042 Token start;
1043 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1044 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001045 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001046 }
1047 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001048 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001049 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001050 DSLExpression value = this->expression();
1051 if (!value.hasValue()) {
1052 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001053 }
1054 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001055 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001056 }
1057 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001058 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001059 }
1060 SkTArray<DSLCase> cases;
1061 while (this->peek().fKind == Token::Kind::TK_CASE) {
1062 skstd::optional<DSLCase> c = this->switchCase();
1063 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001064 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001065 }
1066 cases.push_back(std::move(*c));
1067 }
1068 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1069 // parts of the compiler may rely upon this assumption.
1070 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1071 SkTArray<DSLStatement> statements;
1072 Token defaultStart;
1073 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1074 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001075 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001076 }
1077 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001078 DSLStatement s = this->statement();
1079 if (!s.hasValue()) {
1080 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001081 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001082 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001083 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001084 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001085 }
1086 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001087 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001088 }
1089 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001090 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001091 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001092 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001093 }
1094}
1095
1096/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1097 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001098dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001099 Token start;
1100 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001101 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001102 }
1103 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001104 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001105 }
1106 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001107 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001108 Token nextToken = this->peek();
1109 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1110 // An empty init-statement.
1111 this->nextToken();
1112 } else {
1113 // The init-statement must be an expression or variable declaration.
1114 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001115 if (!initializer.hasValue()) {
1116 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001117 }
1118 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001119 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001120 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001121 dsl::DSLExpression testValue = this->expression();
1122 if (!testValue.hasValue()) {
1123 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001124 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001125 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001126 }
1127 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001128 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001129 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001130 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001131 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001132 dsl::DSLExpression nextValue = this->expression();
1133 if (!nextValue.hasValue()) {
1134 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001135 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001136 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001137 }
1138 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001139 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001140 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001141 dsl::DSLStatement statement = this->statement();
1142 if (!statement.hasValue()) {
1143 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001144 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001145 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1146 test.hasValue() ? std::move(test) : DSLExpression(),
1147 next.hasValue() ? std::move(next) : DSLExpression(),
1148 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001149 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001150}
1151
1152/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001153DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001154 Token start;
1155 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001156 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001157 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001158 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001159 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001160 DSLExpression next = this->expression();
1161 if (!next.hasValue()) {
1162 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001163 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001164 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001165 }
1166 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001167 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001168 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001169 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1170 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001171}
1172
1173/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001174DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001175 Token start;
1176 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001177 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001178 }
1179 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001180 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001181 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001182 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001183}
1184
1185/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001186DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001187 Token start;
1188 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001189 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001190 }
1191 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001192 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001193 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001194 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001195}
1196
1197/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001198DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001199 Token start;
1200 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001201 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001202 }
1203 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001204 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001205 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001206 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001207}
1208
1209/* LBRACE statement* RBRACE */
1210skstd::optional<DSLBlock> DSLParser::block() {
1211 Token start;
1212 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1213 return skstd::nullopt;
1214 }
1215 AutoDSLDepth depth(this);
1216 if (!depth.increase()) {
1217 return skstd::nullopt;
1218 }
1219 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001220 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001221 for (;;) {
1222 switch (this->peek().fKind) {
1223 case Token::Kind::TK_RBRACE:
1224 this->nextToken();
1225 return DSLBlock(std::move(statements), CurrentSymbolTable());
1226 case Token::Kind::TK_END_OF_FILE:
1227 this->error(this->peek(), "expected '}', but found end of file");
1228 return skstd::nullopt;
1229 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001230 DSLStatement statement = this->statement();
1231 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001232 return skstd::nullopt;
1233 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001234 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001235 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001236 }
1237 }
1238 }
1239}
1240
1241/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001242DSLStatement DSLParser::expressionStatement() {
1243 DSLExpression expr = this->expression();
1244 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001245 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001246 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001247 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001248 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001249 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001250 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001251}
1252
1253/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001254DSLExpression DSLParser::expression() {
1255 DSLExpression result = this->assignmentExpression();
1256 if (!result.hasValue()) {
1257 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001258 }
1259 Token t;
1260 AutoDSLDepth depth(this);
1261 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1262 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001263 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001264 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001265 DSLExpression right = this->assignmentExpression();
1266 if (!right.hasValue()) {
1267 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001268 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001269 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1270 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001271 }
1272 return result;
1273}
1274
1275#define OPERATOR_RIGHT(op, exprType) \
1276 do { \
1277 this->nextToken(); \
1278 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001279 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001280 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001281 DSLExpression right = this->exprType(); \
1282 if (!right.hasValue()) { \
1283 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001284 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001285 DSLExpression next = std::move(result) op std::move(right); \
1286 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001287 } while (false)
1288
1289/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1290 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1291 assignmentExpression)*
1292 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001293DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001294 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001295 DSLExpression result = this->ternaryExpression();
1296 if (!result.hasValue()) {
1297 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001298 }
1299 for (;;) {
1300 switch (this->peek().fKind) {
1301 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1302 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1303 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1304 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1305 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1306 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1307 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1308 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1309 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1310 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1311 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1312 default:
1313 return result;
1314 }
1315 }
1316}
1317
1318/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001319DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001320 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001321 DSLExpression base = this->logicalOrExpression();
1322 if (!base.hasValue()) {
1323 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001324 }
1325 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1326 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001327 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001328 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001329 DSLExpression trueExpr = this->expression();
1330 if (!trueExpr.hasValue()) {
1331 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001332 }
1333 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001334 DSLExpression falseExpr = this->assignmentExpression();
1335 if (!falseExpr.hasValue()) {
1336 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001337 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001338 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001339 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001340 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001341 }
1342 return base;
1343}
1344
1345/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001346DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001347 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001348 DSLExpression result = this->logicalXorExpression();
1349 if (!result.hasValue()) {
1350 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001351 }
1352 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1353 OPERATOR_RIGHT(||, logicalXorExpression);
1354 }
1355 return result;
1356}
1357
1358/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001359DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001360 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001361 DSLExpression result = this->logicalAndExpression();
1362 if (!result.hasValue()) {
1363 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001364 }
1365 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1366 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001367 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001368 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001369 DSLExpression right = this->logicalAndExpression();
1370 if (!right.hasValue()) {
1371 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001372 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001373 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1374 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001375 }
1376 return result;
1377}
1378
1379/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001380DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001381 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001382 DSLExpression result = this->bitwiseOrExpression();
1383 if (!result.hasValue()) {
1384 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001385 }
1386 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1387 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1388 }
1389 return result;
1390}
1391
1392/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001393DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001394 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001395 DSLExpression result = this->bitwiseXorExpression();
1396 if (!result.hasValue()) {
1397 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001398 }
1399 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1400 OPERATOR_RIGHT(|, bitwiseXorExpression);
1401 }
1402 return result;
1403}
1404
1405/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001406DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001407 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001408 DSLExpression result = this->bitwiseAndExpression();
1409 if (!result.hasValue()) {
1410 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001411 }
1412 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1413 OPERATOR_RIGHT(^, bitwiseAndExpression);
1414 }
1415 return result;
1416}
1417
1418/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001419DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001420 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001421 DSLExpression result = this->equalityExpression();
1422 if (!result.hasValue()) {
1423 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001424 }
1425 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1426 OPERATOR_RIGHT(&, equalityExpression);
1427 }
1428 return result;
1429}
1430
1431/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001432DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001433 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001434 DSLExpression result = this->relationalExpression();
1435 if (!result.hasValue()) {
1436 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001437 }
1438 for (;;) {
1439 switch (this->peek().fKind) {
1440 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1441 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1442 default: return result;
1443 }
1444 }
1445}
1446
1447/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001448DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001449 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001450 DSLExpression result = this->shiftExpression();
1451 if (!result.hasValue()) {
1452 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001453 }
1454 for (;;) {
1455 switch (this->peek().fKind) {
1456 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1457 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1458 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1459 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1460 default: return result;
1461 }
1462 }
1463}
1464
1465/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001466DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001467 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001468 DSLExpression result = this->additiveExpression();
1469 if (!result.hasValue()) {
1470 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001471 }
1472 for (;;) {
1473 switch (this->peek().fKind) {
1474 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1475 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1476 default: return result;
1477 }
1478 }
1479}
1480
1481/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001482DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001483 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001484 DSLExpression result = this->multiplicativeExpression();
1485 if (!result.hasValue()) {
1486 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001487 }
1488 for (;;) {
1489 switch (this->peek().fKind) {
1490 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1491 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1492 default: return result;
1493 }
1494 }
1495}
1496
1497/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001498DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001499 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001500 DSLExpression result = this->unaryExpression();
1501 if (!result.hasValue()) {
1502 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001503 }
1504 for (;;) {
1505 switch (this->peek().fKind) {
1506 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1507 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1508 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1509 default: return result;
1510 }
1511 }
1512}
1513
1514/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001515DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001516 AutoDSLDepth depth(this);
1517 Token next = this->peek();
1518 switch (next.fKind) {
1519 case Token::Kind::TK_PLUS:
1520 case Token::Kind::TK_MINUS:
1521 case Token::Kind::TK_LOGICALNOT:
1522 case Token::Kind::TK_BITWISENOT:
1523 case Token::Kind::TK_PLUSPLUS:
1524 case Token::Kind::TK_MINUSMINUS: {
1525 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001526 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001527 }
1528 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001529 DSLExpression expr = this->unaryExpression();
1530 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001531 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001532 }
1533 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001534 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1535 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1536 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1537 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1538 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1539 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001540 default: SkUNREACHABLE;
1541 }
1542 }
1543 default:
1544 return this->postfixExpression();
1545 }
1546}
1547
1548/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001549DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001550 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001551 DSLExpression result = this->term();
1552 if (!result.hasValue()) {
1553 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001554 }
1555 for (;;) {
1556 Token t = this->peek();
1557 switch (t.fKind) {
1558 case Token::Kind::TK_FLOAT_LITERAL:
1559 if (this->text(t)[0] != '.') {
1560 return result;
1561 }
1562 [[fallthrough]];
1563 case Token::Kind::TK_LBRACKET:
1564 case Token::Kind::TK_DOT:
1565 case Token::Kind::TK_LPAREN:
1566 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001567 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001568 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001569 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001570 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001571 DSLExpression next = this->suffix(std::move(result));
1572 if (!next.hasValue()) {
1573 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001574 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001575 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001576 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001577 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001578 default:
1579 return result;
1580 }
1581 }
1582}
1583
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001584DSLExpression DSLParser::swizzle(int line, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001585 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001586 SkASSERT(swizzleMask.length() > 0);
1587 if (!base.type().isVector() && !base.type().isScalar()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001588 return base.field(swizzleMask, this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001589 }
1590 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001591 SkSL::SwizzleComponent::Type components[4];
1592 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001593 if (i >= 4) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001594 this->error(line, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001595 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001596 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001597 switch (swizzleMask[i]) {
1598 case '0': components[i] = SwizzleComponent::ZERO; break;
1599 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001600 case 'r': components[i] = SwizzleComponent::R; break;
1601 case 'x': components[i] = SwizzleComponent::X; break;
1602 case 's': components[i] = SwizzleComponent::S; break;
1603 case 'L': components[i] = SwizzleComponent::UL; break;
1604 case 'g': components[i] = SwizzleComponent::G; break;
1605 case 'y': components[i] = SwizzleComponent::Y; break;
1606 case 't': components[i] = SwizzleComponent::T; break;
1607 case 'T': components[i] = SwizzleComponent::UT; break;
1608 case 'b': components[i] = SwizzleComponent::B; break;
1609 case 'z': components[i] = SwizzleComponent::Z; break;
1610 case 'p': components[i] = SwizzleComponent::P; break;
1611 case 'R': components[i] = SwizzleComponent::UR; break;
1612 case 'a': components[i] = SwizzleComponent::A; break;
1613 case 'w': components[i] = SwizzleComponent::W; break;
1614 case 'q': components[i] = SwizzleComponent::Q; break;
1615 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001616 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001617 this->error(line,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001618 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001619 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001620 }
1621 }
1622 switch (length) {
1623 case 1: return dsl::Swizzle(std::move(base), components[0]);
1624 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1625 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1626 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1627 components[3]);
1628 default: SkUNREACHABLE;
1629 }
1630}
1631
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001632dsl::DSLExpression DSLParser::call(int line, dsl::DSLExpression base, ExpressionArray args) {
1633 return DSLExpression(base(std::move(args), this->position(line)), this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001634}
1635
1636/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1637 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001638DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001639 Token next = this->nextToken();
1640 AutoDSLDepth depth(this);
1641 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001642 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001643 }
1644 switch (next.fKind) {
1645 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001646 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1647 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001648 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001649 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001650 DSLExpression index = this->expression();
1651 if (!index.hasValue()) {
1652 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001653 }
1654 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001655 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001656 if (!result.valid()) {
1657 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001658 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001659 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001660 }
1661 case Token::Kind::TK_DOT: {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001662 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001663 skstd::string_view text;
1664 if (this->identifier(&text)) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001665 return this->swizzle(line, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001666 }
1667 [[fallthrough]];
1668 }
1669 case Token::Kind::TK_FLOAT_LITERAL: {
1670 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1671 // floating point literals, possibly followed by an identifier. Handle that here.
1672 skstd::string_view field = this->text(next);
1673 SkASSERT(field[0] == '.');
1674 field.remove_prefix(1);
1675 // use the next *raw* token so we don't ignore whitespace - we only care about
1676 // identifiers that directly follow the float
1677 Token id = this->nextRawToken();
1678 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001679 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001680 } else if (field.empty()) {
1681 this->error(next, "expected field name or swizzle mask after '.'");
1682 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001683 }
1684 this->pushback(id);
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001685 return this->swizzle(next.fLine, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001686 }
1687 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001688 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001689 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1690 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001691 DSLExpression expr = this->assignmentExpression();
1692 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001693 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001694 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001695 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001696 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1697 break;
1698 }
1699 }
1700 }
1701 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001702 return this->call(next.fLine, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001703 }
1704 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001705 return std::move(base)++;
1706 case Token::Kind::TK_MINUSMINUS:
1707 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001708 default: {
1709 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001710 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001711 }
1712 }
1713}
1714
1715/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001716DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001717 Token t = this->peek();
1718 switch (t.fKind) {
1719 case Token::Kind::TK_IDENTIFIER: {
1720 skstd::string_view text;
1721 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001722 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001723 }
1724 break;
1725 }
1726 case Token::Kind::TK_INT_LITERAL: {
1727 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001728 if (!this->intLiteral(&i)) {
1729 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001730 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001731 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001732 }
1733 case Token::Kind::TK_FLOAT_LITERAL: {
1734 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001735 if (!this->floatLiteral(&f)) {
1736 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001737 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001738 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001739 }
1740 case Token::Kind::TK_TRUE_LITERAL: // fall through
1741 case Token::Kind::TK_FALSE_LITERAL: {
1742 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001743 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001744 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001745 }
1746 case Token::Kind::TK_LPAREN: {
1747 this->nextToken();
1748 AutoDSLDepth depth(this);
1749 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001750 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001751 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001752 DSLExpression result = this->expression();
1753 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001754 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1755 return result;
1756 }
1757 break;
1758 }
1759 default:
1760 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001761 this->error(t, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001762 fEncounteredFatalError = true;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001763 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001764 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001765 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001766}
1767
1768/* INT_LITERAL */
1769bool DSLParser::intLiteral(SKSL_INT* dest) {
1770 Token t;
1771 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1772 return false;
1773 }
1774 skstd::string_view s = this->text(t);
1775 if (!SkSL::stoi(s, dest)) {
1776 this->error(t, "integer is too large: " + s);
1777 return false;
1778 }
1779 return true;
1780}
1781
1782/* FLOAT_LITERAL */
1783bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1784 Token t;
1785 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1786 return false;
1787 }
1788 skstd::string_view s = this->text(t);
1789 if (!SkSL::stod(s, dest)) {
1790 this->error(t, "floating-point value is too large: " + s);
1791 return false;
1792 }
1793 return true;
1794}
1795
1796/* TRUE_LITERAL | FALSE_LITERAL */
1797bool DSLParser::boolLiteral(bool* dest) {
1798 Token t = this->nextToken();
1799 switch (t.fKind) {
1800 case Token::Kind::TK_TRUE_LITERAL:
1801 *dest = true;
1802 return true;
1803 case Token::Kind::TK_FALSE_LITERAL:
1804 *dest = false;
1805 return true;
1806 default:
1807 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1808 return false;
1809 }
1810}
1811
1812/* IDENTIFIER */
1813bool DSLParser::identifier(skstd::string_view* dest) {
1814 Token t;
1815 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1816 *dest = this->text(t);
1817 return true;
1818 }
1819 return false;
1820}
1821
1822} // namespace SkSL