blob: c3cfc329e8854c507a30177874f14fecc1c6a9bd [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() {
Ethan Nicholas6389bfa2021-10-01 16:33:43 -0400640 DSLModifiers modifiers = this->modifiers();
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
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400779/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400780DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400781 Token start = this->nextToken();
782 AutoDSLDepth depth(this);
783 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400784 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400785 }
786 this->pushback(start);
787 switch (start.fKind) {
788 case Token::Kind::TK_IF: // fall through
789 case Token::Kind::TK_STATIC_IF:
790 return this->ifStatement();
791 case Token::Kind::TK_FOR:
792 return this->forStatement();
793 case Token::Kind::TK_DO:
794 return this->doStatement();
795 case Token::Kind::TK_WHILE:
796 return this->whileStatement();
797 case Token::Kind::TK_SWITCH: // fall through
798 case Token::Kind::TK_STATIC_SWITCH:
799 return this->switchStatement();
800 case Token::Kind::TK_RETURN:
801 return this->returnStatement();
802 case Token::Kind::TK_BREAK:
803 return this->breakStatement();
804 case Token::Kind::TK_CONTINUE:
805 return this->continueStatement();
806 case Token::Kind::TK_DISCARD:
807 return this->discardStatement();
808 case Token::Kind::TK_LBRACE: {
809 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400810 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400811 }
812 case Token::Kind::TK_SEMICOLON:
813 this->nextToken();
814 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400815 case Token::Kind::TK_HIGHP:
816 case Token::Kind::TK_MEDIUMP:
817 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400818 case Token::Kind::TK_CONST:
819 case Token::Kind::TK_IDENTIFIER:
820 return this->varDeclarationsOrExpressionStatement();
821 default:
822 return this->expressionStatement();
823 }
824}
825
826/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stiles66aa1de2021-10-01 13:59:20 -0400827skstd::optional<DSLType> DSLParser::type(DSLModifiers* modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400828 Token type;
829 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
830 return skstd::nullopt;
831 }
832 if (!IsType(this->text(type))) {
833 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
834 return skstd::nullopt;
835 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400836 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400837 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400838 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400839 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400840 } else {
841 this->error(this->peek(), "expected array dimension");
842 }
843 this->expect(Token::Kind::TK_RBRACKET, "']'");
844 }
845 return result;
846}
847
848/* IDENTIFIER LBRACE
849 varDeclaration+
850 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400851bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400852 Token typeName;
853 if (!this->expectIdentifier(&typeName)) {
854 return false;
855 }
856 if (peek().fKind != Token::Kind::TK_LBRACE) {
857 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
858 // 99% of the time, the user was not actually intending to create an interface block, so
859 // it's better to report it as an unknown type
860 this->error(typeName, "no type named '" + this->text(typeName) + "'");
861 return false;
862 }
863 this->nextToken();
864 SkTArray<dsl::Field> fields;
865 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400866 DSLModifiers fieldModifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -0400867 skstd::optional<dsl::DSLType> type = this->type(&fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400868 if (!type) {
869 return false;
870 }
871 do {
872 Token fieldName;
873 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
874 return false;
875 }
876 DSLType actualType = *type;
877 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
878 Token sizeToken = this->peek();
879 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400880 actualType = Array(std::move(actualType), this->arraySize(),
881 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400882 } else {
883 this->error(sizeToken, "unsized arrays are not permitted");
884 }
885 this->expect(Token::Kind::TK_RBRACKET, "']'");
886 }
887 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
888 return false;
889 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400890 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
891 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400892 }
893 while (this->checkNext(Token::Kind::TK_COMMA));
894 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400895 skstd::string_view instanceName;
896 Token instanceNameToken;
897 SKSL_INT arraySize = 0;
898 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
899 instanceName = this->text(instanceNameToken);
900 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400901 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400902 this->expect(Token::Kind::TK_RBRACKET, "']'");
903 }
904 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400905 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400906 if (fields.empty()) {
907 this->error(typeName, "interface block '" + this->text(typeName) +
908 "' must contain at least one member");
909 } else {
910 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
911 arraySize, this->position(typeName));
912 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400913 return true;
914}
915
916/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400917DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400918 Token start;
919 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
920 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400921 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400922 }
923 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400924 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400925 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400926 DSLExpression test = this->expression();
927 if (!test.hasValue()) {
928 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400929 }
930 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400931 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400932 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400933 DSLStatement ifTrue = this->statement();
934 if (!ifTrue.hasValue()) {
935 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400936 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400937 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400938 if (this->checkNext(Token::Kind::TK_ELSE)) {
939 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400940 if (!ifFalse.hasValue()) {
941 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400942 }
943 }
944 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400945 return StaticIf(std::move(test), std::move(ifTrue),
946 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400947 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400948 return If(std::move(test), std::move(ifTrue),
949 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400950 }
951}
952
953/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400954DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400955 Token start;
956 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400957 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400958 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400959 DSLStatement statement = this->statement();
960 if (!statement.hasValue()) {
961 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400962 }
963 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400964 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400965 }
966 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400967 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400968 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400969 DSLExpression test = this->expression();
970 if (!test.hasValue()) {
971 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400972 }
973 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400974 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400975 }
976 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400977 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400978 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400979 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400980}
981
982/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400983DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400984 Token start;
985 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400986 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400987 }
988 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400989 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400990 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400991 DSLExpression test = this->expression();
992 if (!test.hasValue()) {
993 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400994 }
995 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400996 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400997 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400998 DSLStatement statement = this->statement();
999 if (!statement.hasValue()) {
1000 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001001 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001002 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001003}
1004
1005/* CASE expression COLON statement* */
1006skstd::optional<DSLCase> DSLParser::switchCase() {
1007 Token start;
1008 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001009 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001010 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001011 DSLExpression value = this->expression();
1012 if (!value.hasValue()) {
1013 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001014 }
1015 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001016 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001017 }
1018 SkTArray<DSLStatement> statements;
1019 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1020 this->peek().fKind != Token::Kind::TK_CASE &&
1021 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001022 DSLStatement s = this->statement();
1023 if (!s.hasValue()) {
1024 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001025 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001026 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001027 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001028 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001029}
1030
1031/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001032DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001033 Token start;
1034 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1035 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001036 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001037 }
1038 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001039 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001040 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001041 DSLExpression value = this->expression();
1042 if (!value.hasValue()) {
1043 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001044 }
1045 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001046 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001047 }
1048 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001049 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001050 }
1051 SkTArray<DSLCase> cases;
1052 while (this->peek().fKind == Token::Kind::TK_CASE) {
1053 skstd::optional<DSLCase> c = this->switchCase();
1054 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001055 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001056 }
1057 cases.push_back(std::move(*c));
1058 }
1059 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1060 // parts of the compiler may rely upon this assumption.
1061 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1062 SkTArray<DSLStatement> statements;
1063 Token defaultStart;
1064 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1065 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001066 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001067 }
1068 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001069 DSLStatement s = this->statement();
1070 if (!s.hasValue()) {
1071 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001072 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001073 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001074 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001075 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001076 }
1077 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001078 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001079 }
1080 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001081 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001082 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001083 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001084 }
1085}
1086
1087/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1088 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001089dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001090 Token start;
1091 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001092 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001093 }
1094 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001095 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001096 }
1097 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001098 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001099 Token nextToken = this->peek();
1100 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1101 // An empty init-statement.
1102 this->nextToken();
1103 } else {
1104 // The init-statement must be an expression or variable declaration.
1105 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001106 if (!initializer.hasValue()) {
1107 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001108 }
1109 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001110 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001111 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001112 dsl::DSLExpression testValue = this->expression();
1113 if (!testValue.hasValue()) {
1114 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001115 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001116 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001117 }
1118 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001119 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001120 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001121 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001122 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001123 dsl::DSLExpression nextValue = this->expression();
1124 if (!nextValue.hasValue()) {
1125 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001126 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001127 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001128 }
1129 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001130 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001131 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001132 dsl::DSLStatement statement = this->statement();
1133 if (!statement.hasValue()) {
1134 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001135 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001136 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1137 test.hasValue() ? std::move(test) : DSLExpression(),
1138 next.hasValue() ? std::move(next) : DSLExpression(),
1139 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001140 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001141}
1142
1143/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001144DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001145 Token start;
1146 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001147 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001148 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001149 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001150 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001151 DSLExpression next = this->expression();
1152 if (!next.hasValue()) {
1153 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001154 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001155 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001156 }
1157 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001158 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001159 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001160 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1161 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001162}
1163
1164/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001165DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001166 Token start;
1167 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001168 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001169 }
1170 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001171 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001172 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001173 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001174}
1175
1176/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001177DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001178 Token start;
1179 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001180 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001181 }
1182 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001183 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001184 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001185 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001186}
1187
1188/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001189DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001190 Token start;
1191 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001192 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001193 }
1194 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001195 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001196 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001197 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001198}
1199
1200/* LBRACE statement* RBRACE */
1201skstd::optional<DSLBlock> DSLParser::block() {
1202 Token start;
1203 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1204 return skstd::nullopt;
1205 }
1206 AutoDSLDepth depth(this);
1207 if (!depth.increase()) {
1208 return skstd::nullopt;
1209 }
1210 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001211 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001212 for (;;) {
1213 switch (this->peek().fKind) {
1214 case Token::Kind::TK_RBRACE:
1215 this->nextToken();
1216 return DSLBlock(std::move(statements), CurrentSymbolTable());
1217 case Token::Kind::TK_END_OF_FILE:
1218 this->error(this->peek(), "expected '}', but found end of file");
1219 return skstd::nullopt;
1220 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001221 DSLStatement statement = this->statement();
1222 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001223 return skstd::nullopt;
1224 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001225 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001226 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001227 }
1228 }
1229 }
1230}
1231
1232/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001233DSLStatement DSLParser::expressionStatement() {
1234 DSLExpression expr = this->expression();
1235 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001236 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001237 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001238 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001239 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001240 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001241 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001242}
1243
1244/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001245DSLExpression DSLParser::expression() {
1246 DSLExpression result = this->assignmentExpression();
1247 if (!result.hasValue()) {
1248 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001249 }
1250 Token t;
1251 AutoDSLDepth depth(this);
1252 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1253 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001254 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001255 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001256 DSLExpression right = this->assignmentExpression();
1257 if (!right.hasValue()) {
1258 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001259 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001260 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1261 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001262 }
1263 return result;
1264}
1265
1266#define OPERATOR_RIGHT(op, exprType) \
1267 do { \
1268 this->nextToken(); \
1269 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001270 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001271 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001272 DSLExpression right = this->exprType(); \
1273 if (!right.hasValue()) { \
1274 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001275 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001276 DSLExpression next = std::move(result) op std::move(right); \
1277 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001278 } while (false)
1279
1280/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1281 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1282 assignmentExpression)*
1283 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001284DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001285 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001286 DSLExpression result = this->ternaryExpression();
1287 if (!result.hasValue()) {
1288 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001289 }
1290 for (;;) {
1291 switch (this->peek().fKind) {
1292 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1293 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1294 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1295 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1296 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1297 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1298 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1299 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1300 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1301 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1302 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1303 default:
1304 return result;
1305 }
1306 }
1307}
1308
1309/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001310DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001311 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001312 DSLExpression base = this->logicalOrExpression();
1313 if (!base.hasValue()) {
1314 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001315 }
1316 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1317 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001318 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001319 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001320 DSLExpression trueExpr = this->expression();
1321 if (!trueExpr.hasValue()) {
1322 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001323 }
1324 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001325 DSLExpression falseExpr = this->assignmentExpression();
1326 if (!falseExpr.hasValue()) {
1327 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001328 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001329 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001330 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001331 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001332 }
1333 return base;
1334}
1335
1336/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001337DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001338 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001339 DSLExpression result = this->logicalXorExpression();
1340 if (!result.hasValue()) {
1341 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001342 }
1343 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1344 OPERATOR_RIGHT(||, logicalXorExpression);
1345 }
1346 return result;
1347}
1348
1349/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001350DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001351 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001352 DSLExpression result = this->logicalAndExpression();
1353 if (!result.hasValue()) {
1354 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001355 }
1356 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1357 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001358 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001359 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001360 DSLExpression right = this->logicalAndExpression();
1361 if (!right.hasValue()) {
1362 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001363 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001364 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1365 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001366 }
1367 return result;
1368}
1369
1370/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001371DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001372 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001373 DSLExpression result = this->bitwiseOrExpression();
1374 if (!result.hasValue()) {
1375 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001376 }
1377 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1378 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1379 }
1380 return result;
1381}
1382
1383/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001384DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001385 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001386 DSLExpression result = this->bitwiseXorExpression();
1387 if (!result.hasValue()) {
1388 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001389 }
1390 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1391 OPERATOR_RIGHT(|, bitwiseXorExpression);
1392 }
1393 return result;
1394}
1395
1396/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001397DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001398 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001399 DSLExpression result = this->bitwiseAndExpression();
1400 if (!result.hasValue()) {
1401 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001402 }
1403 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1404 OPERATOR_RIGHT(^, bitwiseAndExpression);
1405 }
1406 return result;
1407}
1408
1409/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001410DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001411 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001412 DSLExpression result = this->equalityExpression();
1413 if (!result.hasValue()) {
1414 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001415 }
1416 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1417 OPERATOR_RIGHT(&, equalityExpression);
1418 }
1419 return result;
1420}
1421
1422/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001423DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001424 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001425 DSLExpression result = this->relationalExpression();
1426 if (!result.hasValue()) {
1427 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001428 }
1429 for (;;) {
1430 switch (this->peek().fKind) {
1431 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1432 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1433 default: return result;
1434 }
1435 }
1436}
1437
1438/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001439DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001440 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001441 DSLExpression result = this->shiftExpression();
1442 if (!result.hasValue()) {
1443 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001444 }
1445 for (;;) {
1446 switch (this->peek().fKind) {
1447 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1448 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1449 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1450 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1451 default: return result;
1452 }
1453 }
1454}
1455
1456/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001457DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001458 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001459 DSLExpression result = this->additiveExpression();
1460 if (!result.hasValue()) {
1461 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001462 }
1463 for (;;) {
1464 switch (this->peek().fKind) {
1465 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1466 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1467 default: return result;
1468 }
1469 }
1470}
1471
1472/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001473DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001474 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001475 DSLExpression result = this->multiplicativeExpression();
1476 if (!result.hasValue()) {
1477 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001478 }
1479 for (;;) {
1480 switch (this->peek().fKind) {
1481 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1482 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1483 default: return result;
1484 }
1485 }
1486}
1487
1488/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001489DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001490 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001491 DSLExpression result = this->unaryExpression();
1492 if (!result.hasValue()) {
1493 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001494 }
1495 for (;;) {
1496 switch (this->peek().fKind) {
1497 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1498 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1499 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1500 default: return result;
1501 }
1502 }
1503}
1504
1505/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001506DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001507 AutoDSLDepth depth(this);
1508 Token next = this->peek();
1509 switch (next.fKind) {
1510 case Token::Kind::TK_PLUS:
1511 case Token::Kind::TK_MINUS:
1512 case Token::Kind::TK_LOGICALNOT:
1513 case Token::Kind::TK_BITWISENOT:
1514 case Token::Kind::TK_PLUSPLUS:
1515 case Token::Kind::TK_MINUSMINUS: {
1516 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001517 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001518 }
1519 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001520 DSLExpression expr = this->unaryExpression();
1521 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001522 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001523 }
1524 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001525 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1526 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1527 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1528 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1529 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1530 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001531 default: SkUNREACHABLE;
1532 }
1533 }
1534 default:
1535 return this->postfixExpression();
1536 }
1537}
1538
1539/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001540DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001541 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001542 DSLExpression result = this->term();
1543 if (!result.hasValue()) {
1544 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001545 }
1546 for (;;) {
1547 Token t = this->peek();
1548 switch (t.fKind) {
1549 case Token::Kind::TK_FLOAT_LITERAL:
1550 if (this->text(t)[0] != '.') {
1551 return result;
1552 }
1553 [[fallthrough]];
1554 case Token::Kind::TK_LBRACKET:
1555 case Token::Kind::TK_DOT:
1556 case Token::Kind::TK_LPAREN:
1557 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001558 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001559 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001560 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001561 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001562 DSLExpression next = this->suffix(std::move(result));
1563 if (!next.hasValue()) {
1564 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001565 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001566 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001567 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001568 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001569 default:
1570 return result;
1571 }
1572 }
1573}
1574
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001575DSLExpression DSLParser::swizzle(int line, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001576 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001577 SkASSERT(swizzleMask.length() > 0);
1578 if (!base.type().isVector() && !base.type().isScalar()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001579 return base.field(swizzleMask, this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001580 }
1581 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001582 SkSL::SwizzleComponent::Type components[4];
1583 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001584 if (i >= 4) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001585 this->error(line, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001586 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001587 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001588 switch (swizzleMask[i]) {
1589 case '0': components[i] = SwizzleComponent::ZERO; break;
1590 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001591 case 'r': components[i] = SwizzleComponent::R; break;
1592 case 'x': components[i] = SwizzleComponent::X; break;
1593 case 's': components[i] = SwizzleComponent::S; break;
1594 case 'L': components[i] = SwizzleComponent::UL; break;
1595 case 'g': components[i] = SwizzleComponent::G; break;
1596 case 'y': components[i] = SwizzleComponent::Y; break;
1597 case 't': components[i] = SwizzleComponent::T; break;
1598 case 'T': components[i] = SwizzleComponent::UT; break;
1599 case 'b': components[i] = SwizzleComponent::B; break;
1600 case 'z': components[i] = SwizzleComponent::Z; break;
1601 case 'p': components[i] = SwizzleComponent::P; break;
1602 case 'R': components[i] = SwizzleComponent::UR; break;
1603 case 'a': components[i] = SwizzleComponent::A; break;
1604 case 'w': components[i] = SwizzleComponent::W; break;
1605 case 'q': components[i] = SwizzleComponent::Q; break;
1606 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001607 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001608 this->error(line,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001609 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001610 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001611 }
1612 }
1613 switch (length) {
1614 case 1: return dsl::Swizzle(std::move(base), components[0]);
1615 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1616 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1617 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1618 components[3]);
1619 default: SkUNREACHABLE;
1620 }
1621}
1622
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001623dsl::DSLExpression DSLParser::call(int line, dsl::DSLExpression base, ExpressionArray args) {
1624 return DSLExpression(base(std::move(args), this->position(line)), this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001625}
1626
1627/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1628 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001629DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001630 Token next = this->nextToken();
1631 AutoDSLDepth depth(this);
1632 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001633 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001634 }
1635 switch (next.fKind) {
1636 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001637 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1638 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001639 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001640 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001641 DSLExpression index = this->expression();
1642 if (!index.hasValue()) {
1643 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001644 }
1645 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001646 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001647 if (!result.valid()) {
1648 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001649 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001650 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001651 }
1652 case Token::Kind::TK_DOT: {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001653 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001654 skstd::string_view text;
1655 if (this->identifier(&text)) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001656 return this->swizzle(line, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001657 }
1658 [[fallthrough]];
1659 }
1660 case Token::Kind::TK_FLOAT_LITERAL: {
1661 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1662 // floating point literals, possibly followed by an identifier. Handle that here.
1663 skstd::string_view field = this->text(next);
1664 SkASSERT(field[0] == '.');
1665 field.remove_prefix(1);
1666 // use the next *raw* token so we don't ignore whitespace - we only care about
1667 // identifiers that directly follow the float
1668 Token id = this->nextRawToken();
1669 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001670 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001671 } else if (field.empty()) {
1672 this->error(next, "expected field name or swizzle mask after '.'");
1673 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001674 }
1675 this->pushback(id);
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001676 return this->swizzle(next.fLine, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001677 }
1678 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001679 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001680 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1681 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001682 DSLExpression expr = this->assignmentExpression();
1683 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001684 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001685 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001686 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001687 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1688 break;
1689 }
1690 }
1691 }
1692 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001693 return this->call(next.fLine, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001694 }
1695 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001696 return std::move(base)++;
1697 case Token::Kind::TK_MINUSMINUS:
1698 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001699 default: {
1700 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001701 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001702 }
1703 }
1704}
1705
1706/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001707DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001708 Token t = this->peek();
1709 switch (t.fKind) {
1710 case Token::Kind::TK_IDENTIFIER: {
1711 skstd::string_view text;
1712 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001713 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001714 }
1715 break;
1716 }
1717 case Token::Kind::TK_INT_LITERAL: {
1718 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001719 if (!this->intLiteral(&i)) {
1720 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001721 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001722 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001723 }
1724 case Token::Kind::TK_FLOAT_LITERAL: {
1725 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001726 if (!this->floatLiteral(&f)) {
1727 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001728 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001729 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001730 }
1731 case Token::Kind::TK_TRUE_LITERAL: // fall through
1732 case Token::Kind::TK_FALSE_LITERAL: {
1733 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001734 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001735 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001736 }
1737 case Token::Kind::TK_LPAREN: {
1738 this->nextToken();
1739 AutoDSLDepth depth(this);
1740 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001741 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001742 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001743 DSLExpression result = this->expression();
1744 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001745 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1746 return result;
1747 }
1748 break;
1749 }
1750 default:
1751 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001752 this->error(t, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001753 fEncounteredFatalError = true;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001754 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001755 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001756 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001757}
1758
1759/* INT_LITERAL */
1760bool DSLParser::intLiteral(SKSL_INT* dest) {
1761 Token t;
1762 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1763 return false;
1764 }
1765 skstd::string_view s = this->text(t);
1766 if (!SkSL::stoi(s, dest)) {
1767 this->error(t, "integer is too large: " + s);
1768 return false;
1769 }
1770 return true;
1771}
1772
1773/* FLOAT_LITERAL */
1774bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1775 Token t;
1776 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1777 return false;
1778 }
1779 skstd::string_view s = this->text(t);
1780 if (!SkSL::stod(s, dest)) {
1781 this->error(t, "floating-point value is too large: " + s);
1782 return false;
1783 }
1784 return true;
1785}
1786
1787/* TRUE_LITERAL | FALSE_LITERAL */
1788bool DSLParser::boolLiteral(bool* dest) {
1789 Token t = this->nextToken();
1790 switch (t.fKind) {
1791 case Token::Kind::TK_TRUE_LITERAL:
1792 *dest = true;
1793 return true;
1794 case Token::Kind::TK_FALSE_LITERAL:
1795 *dest = false;
1796 return true;
1797 default:
1798 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1799 return false;
1800 }
1801}
1802
1803/* IDENTIFIER */
1804bool DSLParser::identifier(skstd::string_view* dest) {
1805 Token t;
1806 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1807 *dest = this->text(t);
1808 return true;
1809 }
1810 return false;
1811}
1812
1813} // namespace SkSL