blob: b2d0df1d5c31405572c04ae0dfdd5aaa3087c0d3 [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 Nicholasc8452722021-10-07 10:47:32 -040012#include "src/sksl/SkSLThreadContext.h"
Ethan Nicholas6c302ba2021-09-14 09:16:12 -040013#include "src/sksl/dsl/priv/DSLWriter.h"
Ethan Nicholas051aeb72021-09-24 16:39:19 -040014#include "src/sksl/dsl/priv/DSL_priv.h"
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040015
16#include <memory>
17
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040018using namespace SkSL::dsl;
19
20namespace SkSL {
21
22static constexpr int kMaxParseDepth = 50;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040023
24static int parse_modifier_token(Token::Kind token) {
25 switch (token) {
26 case Token::Kind::TK_UNIFORM: return Modifiers::kUniform_Flag;
27 case Token::Kind::TK_CONST: return Modifiers::kConst_Flag;
28 case Token::Kind::TK_IN: return Modifiers::kIn_Flag;
29 case Token::Kind::TK_OUT: return Modifiers::kOut_Flag;
30 case Token::Kind::TK_INOUT: return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
31 case Token::Kind::TK_FLAT: return Modifiers::kFlat_Flag;
32 case Token::Kind::TK_NOPERSPECTIVE: return Modifiers::kNoPerspective_Flag;
33 case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
34 case Token::Kind::TK_INLINE: return Modifiers::kInline_Flag;
35 case Token::Kind::TK_NOINLINE: return Modifiers::kNoInline_Flag;
John Stiles02014312021-08-04 16:03:12 -040036 case Token::Kind::TK_HIGHP: return Modifiers::kHighp_Flag;
37 case Token::Kind::TK_MEDIUMP: return Modifiers::kMediump_Flag;
38 case Token::Kind::TK_LOWP: return Modifiers::kLowp_Flag;
John Stilesefde90d2021-08-12 23:06:24 -040039 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040040 default: return 0;
41 }
42}
43
44class AutoDSLDepth {
45public:
46 AutoDSLDepth(DSLParser* p)
47 : fParser(p)
48 , fDepth(0) {}
49
50 ~AutoDSLDepth() {
51 fParser->fDepth -= fDepth;
52 }
53
54 bool increase() {
55 ++fDepth;
56 ++fParser->fDepth;
57 if (fParser->fDepth > kMaxParseDepth) {
58 fParser->error(fParser->peek(), String("exceeded max parse depth"));
59 return false;
60 }
61 return true;
62 }
63
64private:
65 DSLParser* fParser;
66 int fDepth;
67};
68
69class AutoDSLSymbolTable {
70public:
71 AutoDSLSymbolTable() {
72 dsl::PushSymbolTable();
73 }
74
75 ~AutoDSLSymbolTable() {
76 dsl::PopSymbolTable();
77 }
78};
79
80std::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
81
82void DSLParser::InitLayoutMap() {
83 layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
84 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
85 TOKEN(LOCATION, "location");
86 TOKEN(OFFSET, "offset");
87 TOKEN(BINDING, "binding");
88 TOKEN(INDEX, "index");
89 TOKEN(SET, "set");
90 TOKEN(BUILTIN, "builtin");
91 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
92 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
93 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
94 TOKEN(PUSH_CONSTANT, "push_constant");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040095 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
96 #undef TOKEN
97}
98
99DSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
100 String text)
101 : fCompiler(*compiler)
102 , fSettings(settings)
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400103 , fKind(kind)
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400104 , fText(std::make_unique<String>(std::move(text)))
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400105 , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1, /*line=*/-1) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400106 // We don't want to have to worry about manually releasing all of the objects in the event that
107 // an error occurs
108 fSettings.fAssertDSLObjectsReleased = false;
Ethan Nicholasae9b4462021-09-16 16:23:05 -0400109 // We manage our symbol tables manually, so no need for name mangling
110 fSettings.fDSLMangling = false;
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400111 fLexer.start(*fText);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400112 static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
113 (void) layoutMapInitialized;
114}
115
116Token DSLParser::nextRawToken() {
117 if (fPushback.fKind != Token::Kind::TK_NONE) {
118 Token result = fPushback;
119 fPushback.fKind = Token::Kind::TK_NONE;
120 return result;
121 }
122 return fLexer.next();
123}
124
125Token DSLParser::nextToken() {
126 Token token = this->nextRawToken();
127 while (token.fKind == Token::Kind::TK_WHITESPACE ||
128 token.fKind == Token::Kind::TK_LINE_COMMENT ||
129 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
130 token = this->nextRawToken();
131 }
132 return token;
133}
134
135void DSLParser::pushback(Token t) {
136 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
137 fPushback = std::move(t);
138}
139
140Token DSLParser::peek() {
141 if (fPushback.fKind == Token::Kind::TK_NONE) {
142 fPushback = this->nextToken();
143 }
144 return fPushback;
145}
146
147bool DSLParser::checkNext(Token::Kind kind, Token* result) {
148 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
149 return false;
150 }
151 Token next = this->nextToken();
152 if (next.fKind == kind) {
153 if (result) {
154 *result = next;
155 }
156 return true;
157 }
158 this->pushback(std::move(next));
159 return false;
160}
161
162bool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
163 Token next = this->nextToken();
164 if (next.fKind == kind) {
165 if (result) {
166 *result = std::move(next);
167 }
168 return true;
169 } else {
170 this->error(next, "expected " + String(expected) + ", but found '" +
171 this->text(next) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400172 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400173 return false;
174 }
175}
176
177bool DSLParser::expectIdentifier(Token* result) {
178 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
179 return false;
180 }
181 if (IsType(this->text(*result))) {
182 this->error(*result, "expected an identifier, but found type '" +
183 this->text(*result) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400184 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400185 return false;
186 }
187 return true;
188}
189
190skstd::string_view DSLParser::text(Token token) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400191 return skstd::string_view(fText->data() + token.fOffset, token.fLength);
192}
193
194PositionInfo DSLParser::position(Token t) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400195 return this->position(t.fLine);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400196}
197
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400198PositionInfo DSLParser::position(int line) {
199 return PositionInfo("<unknown>", line);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400200}
201
202void DSLParser::error(Token token, String msg) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400203 this->error(token.fLine, msg);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400204}
205
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400206void DSLParser::error(int line, String msg) {
207 GetErrorReporter().error(msg.c_str(), this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400208}
209
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400210/* declaration* END_OF_FILE */
211std::unique_ptr<Program> DSLParser::program() {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400212 ErrorReporter* errorReporter = &fCompiler.errorReporter();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400213 Start(&fCompiler, fKind, fSettings);
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400214 SetErrorReporter(errorReporter);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400215 errorReporter->setSource(fText->c_str());
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400216 this->declarations();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400217 std::unique_ptr<Program> result;
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400218 if (!GetErrorReporter().errorCount()) {
219 result = dsl::ReleaseProgram(std::move(fText));
220 }
221 errorReporter->setSource(nullptr);
222 End();
223 return result;
224}
225
226SkSL::LoadedModule DSLParser::moduleInheritingFrom(SkSL::ParsedModule baseModule) {
227 ErrorReporter* errorReporter = &fCompiler.errorReporter();
228 StartModule(&fCompiler, fKind, fSettings, std::move(baseModule));
229 SetErrorReporter(errorReporter);
230 errorReporter->setSource(fText->c_str());
231 this->declarations();
232 CurrentSymbolTable()->takeOwnershipOfString(std::move(*fText));
233 SkSL::LoadedModule result{ fKind, CurrentSymbolTable(),
Ethan Nicholasc8452722021-10-07 10:47:32 -0400234 std::move(ThreadContext::ProgramElements()) };
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400235 errorReporter->setSource(nullptr);
236 End();
237 return result;
238}
239
240void DSLParser::declarations() {
241 fEncounteredFatalError = false;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400242 bool done = false;
243 while (!done) {
244 switch (this->peek().fKind) {
245 case Token::Kind::TK_END_OF_FILE:
246 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400247 break;
Ethan Nicholas642215e2021-09-03 11:10:54 -0400248 case Token::Kind::TK_DIRECTIVE:
249 this->directive();
250 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400251 case Token::Kind::TK_INVALID: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400252 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400253 this->error(this->peek(), String("invalid token"));
Ethan Nicholasf8f1fa02021-08-29 14:12:17 -0400254 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400255 break;
256 }
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400257 default:
258 this->declaration();
259 done = fEncounteredFatalError;
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400260 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400261 }
262 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400263}
264
Ethan Nicholas642215e2021-09-03 11:10:54 -0400265/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
266void DSLParser::directive() {
267 Token start;
268 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
269 return;
270 }
271 skstd::string_view text = this->text(start);
272 if (text == "#extension") {
273 Token name;
274 if (!this->expectIdentifier(&name)) {
275 return;
276 }
277 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
278 return;
279 }
280 Token behavior;
281 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
282 return;
283 }
284 skstd::string_view behaviorText = this->text(behavior);
285 if (behaviorText == "disable") {
286 return;
287 }
288 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
289 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
290 }
291 // We don't currently do anything different between require, enable, and warn
292 dsl::AddExtension(this->text(name));
293 } else {
294 this->error(start, "unsupported directive '" + this->text(start) + "'");
295 }
296}
297
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400298/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
299 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
300bool DSLParser::declaration() {
301 Token lookahead = this->peek();
302 switch (lookahead.fKind) {
303 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400304 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400305 this->error(lookahead, "expected a declaration, but found ';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400306 return false;
307 default:
308 break;
309 }
310 DSLModifiers modifiers = this->modifiers();
311 lookahead = this->peek();
312 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
313 // we have an identifier that's not a type, could be the start of an interface block
314 return this->interfaceBlock(modifiers);
315 }
316 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
Ethan Nicholas678ec712021-09-03 06:33:47 -0400317 this->nextToken();
318 Declare(modifiers, position(lookahead));
319 return true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400320 }
321 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400322 this->structVarDeclaration(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400323 return true;
324 }
John Stiles66aa1de2021-10-01 13:59:20 -0400325 skstd::optional<DSLType> type = this->type(&modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400326 if (!type) {
327 return false;
328 }
329 Token name;
330 if (!this->expectIdentifier(&name)) {
331 return false;
332 }
333 if (this->checkNext(Token::Kind::TK_LPAREN)) {
334 return this->functionDeclarationEnd(modifiers, *type, name);
335 } else {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400336 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400337 return true;
338 }
339}
340
341/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400342bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
343 DSLType type,
344 const Token& name) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400345 SkTArray<DSLWrapper<DSLParameter>> parameters;
346 Token lookahead = this->peek();
347 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
348 // `()` means no parameters at all.
349 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
350 // `(void)` also means no parameters at all.
351 this->nextToken();
352 } else {
353 for (;;) {
354 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
355 if (!parameter) {
356 return false;
357 }
358 parameters.push_back(std::move(*parameter));
359 if (!this->checkNext(Token::Kind::TK_COMMA)) {
360 break;
361 }
362 }
363 }
364 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
365 return false;
366 }
367 SkTArray<DSLParameter*> parameterPointers;
368 for (DSLWrapper<DSLParameter>& param : parameters) {
369 parameterPointers.push_back(&param.get());
370 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400371 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400372 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
373 AutoDSLSymbolTable symbols;
374 for (DSLParameter* var : parameterPointers) {
375 AddToSymbolTable(*var);
376 }
377 skstd::optional<DSLBlock> body = this->block();
378 if (!body) {
379 return false;
380 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -0400381 result.define(std::move(*body), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400382 }
383 return true;
384}
385
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400386SKSL_INT DSLParser::arraySize() {
387 Token next = this->peek();
388 if (next.fKind == Token::Kind::TK_INT_LITERAL) {
389 SKSL_INT size;
390 if (this->intLiteral(&size)) {
391 if (size > INT32_MAX) {
392 this->error(next, "array size out of bounds");
393 return 1;
394 }
395 if (size <= 0) {
396 this->error(next, "array size must be positive");
397 return 1;
398 }
399 return size;
400 }
401 return 1;
402 } else if (this->checkNext(Token::Kind::TK_MINUS) &&
403 this->checkNext(Token::Kind::TK_INT_LITERAL)) {
404 this->error(next, "array size must be positive");
405 return 1;
406 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400407 DSLExpression expr = this->expression();
408 if (expr.isValid()) {
Ethan Nicholas51b4b862021-08-31 16:12:40 -0400409 this->error(next, "expected int literal");
410 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400411 return 1;
412 }
413}
414
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400415bool DSLParser::parseArrayDimensions(int line, DSLType* type) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400416 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
417 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400418 this->error(line, "expected array dimension");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400419 } else {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400420 *type = Array(*type, this->arraySize(), this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400421 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400422 return false;
423 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400424 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400425 }
426 return true;
427}
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400428
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400429bool DSLParser::parseInitializer(int line, DSLExpression* initializer) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400430 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400431 DSLExpression value = this->assignmentExpression();
432 if (!value.hasValue()) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400433 return false;
434 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400435 initializer->swap(value);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400436 }
437 return true;
438}
439
440/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
441 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
442void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
443 dsl::DSLType baseType, skstd::string_view name) {
444 using namespace dsl;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400445 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400446 DSLType type = baseType;
447 DSLExpression initializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400448 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400449 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400450 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400451 if (!this->parseInitializer(line, &initializer)) {
John Stilesb05bbd02021-09-24 15:11:16 -0400452 return;
453 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400454 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
455 Declare(first);
456 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400457
458 while (this->checkNext(Token::Kind::TK_COMMA)) {
459 type = baseType;
460 Token identifierName;
461 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400462 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400463 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400464 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400465 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400466 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400467 DSLExpression anotherInitializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400468 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400469 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400470 }
John Stilesb05bbd02021-09-24 15:11:16 -0400471 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400472 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400473 Declare(next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400474 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400475 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400476 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400477}
478
479/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
480 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400481DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
482 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400483 using namespace dsl;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400484 int line = this->peek().fLine;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400485 DSLType type = baseType;
486 DSLExpression initializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400487 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400488 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400489 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400490 if (!this->parseInitializer(line, &initializer)) {
John Stilesb05bbd02021-09-24 15:11:16 -0400491 return {};
492 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400493 DSLVar first(mods, type, name, std::move(initializer), pos);
494 DSLStatement result = Declare(first);
495 AddToSymbolTable(first);
496
497 while (this->checkNext(Token::Kind::TK_COMMA)) {
498 type = baseType;
499 Token identifierName;
500 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400501 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400502 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400503 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400504 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400505 }
506 DSLExpression anotherInitializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400507 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400508 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400509 }
John Stilesb05bbd02021-09-24 15:11:16 -0400510 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400511 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400512 DSLWriter::AddVarDeclaration(result, next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400513 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400514 }
515 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400516 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400517}
518
519/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400520DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400521 Token nextToken = this->peek();
522 if (nextToken.fKind == Token::Kind::TK_CONST) {
523 // Statements that begin with `const` might be variable declarations, but can't be legal
524 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
525 return this->varDeclarations();
526 }
527
John Stiles02014312021-08-04 16:03:12 -0400528 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
529 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
530 nextToken.fKind == Token::Kind::TK_LOWP ||
531 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400532 // Statements that begin with a typename are most often variable declarations, but
533 // occasionally the type is part of a constructor, and these are actually expression-
534 // statements in disguise. First, attempt the common case: parse it as a vardecl.
535 Checkpoint checkpoint(this);
536 VarDeclarationsPrefix prefix;
537 if (this->varDeclarationsPrefix(&prefix)) {
538 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400539 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
540 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400541 }
542
543 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
544 // expression-statement instead.
545 checkpoint.rewind();
546 }
547 return this->expressionStatement();
548}
549
550// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
551// statement is a variable-declaration statement, not an expression-statement.
552bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400553 prefixData->fPosition = this->position(this->peek());
554 prefixData->fModifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -0400555 skstd::optional<DSLType> type = this->type(&prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400556 if (!type) {
557 return false;
558 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400559 prefixData->fType = *type;
560 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400561}
562
563/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400564DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400565 VarDeclarationsPrefix prefix;
566 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400567 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400568 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400569 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
570 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400571}
572
573/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
574skstd::optional<DSLType> DSLParser::structDeclaration() {
575 AutoDSLDepth depth(this);
576 if (!depth.increase()) {
577 return skstd::nullopt;
578 }
579 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
580 return skstd::nullopt;
581 }
582 Token name;
583 if (!this->expectIdentifier(&name)) {
584 return skstd::nullopt;
585 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400586 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
587 return skstd::nullopt;
588 }
589 SkTArray<DSLField> fields;
590 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
591 DSLModifiers modifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -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() {
Ethan Nicholas6389bfa2021-10-01 16:33:43 -0400641 DSLModifiers modifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -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
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400780/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400781DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400782 Token start = this->nextToken();
783 AutoDSLDepth depth(this);
784 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400785 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400786 }
787 this->pushback(start);
788 switch (start.fKind) {
789 case Token::Kind::TK_IF: // fall through
790 case Token::Kind::TK_STATIC_IF:
791 return this->ifStatement();
792 case Token::Kind::TK_FOR:
793 return this->forStatement();
794 case Token::Kind::TK_DO:
795 return this->doStatement();
796 case Token::Kind::TK_WHILE:
797 return this->whileStatement();
798 case Token::Kind::TK_SWITCH: // fall through
799 case Token::Kind::TK_STATIC_SWITCH:
800 return this->switchStatement();
801 case Token::Kind::TK_RETURN:
802 return this->returnStatement();
803 case Token::Kind::TK_BREAK:
804 return this->breakStatement();
805 case Token::Kind::TK_CONTINUE:
806 return this->continueStatement();
807 case Token::Kind::TK_DISCARD:
808 return this->discardStatement();
809 case Token::Kind::TK_LBRACE: {
810 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400811 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400812 }
813 case Token::Kind::TK_SEMICOLON:
814 this->nextToken();
815 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400816 case Token::Kind::TK_HIGHP:
817 case Token::Kind::TK_MEDIUMP:
818 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400819 case Token::Kind::TK_CONST:
820 case Token::Kind::TK_IDENTIFIER:
821 return this->varDeclarationsOrExpressionStatement();
822 default:
823 return this->expressionStatement();
824 }
825}
826
827/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stiles66aa1de2021-10-01 13:59:20 -0400828skstd::optional<DSLType> DSLParser::type(DSLModifiers* modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400829 Token type;
830 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
831 return skstd::nullopt;
832 }
833 if (!IsType(this->text(type))) {
834 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
835 return skstd::nullopt;
836 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400837 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400838 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400839 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400840 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400841 } else {
842 this->error(this->peek(), "expected array dimension");
843 }
844 this->expect(Token::Kind::TK_RBRACKET, "']'");
845 }
846 return result;
847}
848
849/* IDENTIFIER LBRACE
850 varDeclaration+
851 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400852bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400853 Token typeName;
854 if (!this->expectIdentifier(&typeName)) {
855 return false;
856 }
857 if (peek().fKind != Token::Kind::TK_LBRACE) {
858 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
859 // 99% of the time, the user was not actually intending to create an interface block, so
860 // it's better to report it as an unknown type
861 this->error(typeName, "no type named '" + this->text(typeName) + "'");
862 return false;
863 }
864 this->nextToken();
865 SkTArray<dsl::Field> fields;
866 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400867 DSLModifiers fieldModifiers = this->modifiers();
John Stiles66aa1de2021-10-01 13:59:20 -0400868 skstd::optional<dsl::DSLType> type = this->type(&fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400869 if (!type) {
870 return false;
871 }
872 do {
873 Token fieldName;
874 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
875 return false;
876 }
877 DSLType actualType = *type;
878 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
879 Token sizeToken = this->peek();
880 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400881 actualType = Array(std::move(actualType), this->arraySize(),
882 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400883 } else {
884 this->error(sizeToken, "unsized arrays are not permitted");
885 }
886 this->expect(Token::Kind::TK_RBRACKET, "']'");
887 }
888 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
889 return false;
890 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400891 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
892 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400893 }
894 while (this->checkNext(Token::Kind::TK_COMMA));
895 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400896 skstd::string_view instanceName;
897 Token instanceNameToken;
898 SKSL_INT arraySize = 0;
899 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
900 instanceName = this->text(instanceNameToken);
901 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400902 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400903 this->expect(Token::Kind::TK_RBRACKET, "']'");
904 }
905 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400906 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400907 if (fields.empty()) {
908 this->error(typeName, "interface block '" + this->text(typeName) +
909 "' must contain at least one member");
910 } else {
911 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
912 arraySize, this->position(typeName));
913 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400914 return true;
915}
916
917/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400918DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400919 Token start;
920 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
921 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400922 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400923 }
924 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400925 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400926 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400927 DSLExpression test = this->expression();
928 if (!test.hasValue()) {
929 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400930 }
931 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400932 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400933 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400934 DSLStatement ifTrue = this->statement();
935 if (!ifTrue.hasValue()) {
936 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400937 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400938 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400939 if (this->checkNext(Token::Kind::TK_ELSE)) {
940 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400941 if (!ifFalse.hasValue()) {
942 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400943 }
944 }
945 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400946 return StaticIf(std::move(test), std::move(ifTrue),
947 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400948 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400949 return If(std::move(test), std::move(ifTrue),
950 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400951 }
952}
953
954/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400955DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400956 Token start;
957 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400958 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400959 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400960 DSLStatement statement = this->statement();
961 if (!statement.hasValue()) {
962 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400963 }
964 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400965 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400966 }
967 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400968 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400969 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400970 DSLExpression test = this->expression();
971 if (!test.hasValue()) {
972 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400973 }
974 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400975 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400976 }
977 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400978 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400979 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400980 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400981}
982
983/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400984DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400985 Token start;
986 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400987 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400988 }
989 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400990 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400991 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400992 DSLExpression test = this->expression();
993 if (!test.hasValue()) {
994 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400995 }
996 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400997 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400998 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400999 DSLStatement statement = this->statement();
1000 if (!statement.hasValue()) {
1001 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001002 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001003 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001004}
1005
1006/* CASE expression COLON statement* */
1007skstd::optional<DSLCase> DSLParser::switchCase() {
1008 Token start;
1009 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001010 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001011 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001012 DSLExpression value = this->expression();
1013 if (!value.hasValue()) {
1014 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001015 }
1016 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001017 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001018 }
1019 SkTArray<DSLStatement> statements;
1020 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1021 this->peek().fKind != Token::Kind::TK_CASE &&
1022 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001023 DSLStatement s = this->statement();
1024 if (!s.hasValue()) {
1025 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001026 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001027 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001028 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001029 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001030}
1031
1032/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001033DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001034 Token start;
1035 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1036 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001037 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001038 }
1039 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001040 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001041 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001042 DSLExpression value = this->expression();
1043 if (!value.hasValue()) {
1044 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001045 }
1046 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001047 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001048 }
1049 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001050 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001051 }
1052 SkTArray<DSLCase> cases;
1053 while (this->peek().fKind == Token::Kind::TK_CASE) {
1054 skstd::optional<DSLCase> c = this->switchCase();
1055 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001056 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001057 }
1058 cases.push_back(std::move(*c));
1059 }
1060 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1061 // parts of the compiler may rely upon this assumption.
1062 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1063 SkTArray<DSLStatement> statements;
1064 Token defaultStart;
1065 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1066 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001067 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001068 }
1069 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001070 DSLStatement s = this->statement();
1071 if (!s.hasValue()) {
1072 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001073 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001074 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001075 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001076 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001077 }
1078 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001079 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001080 }
1081 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001082 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001083 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001084 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001085 }
1086}
1087
1088/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1089 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001090dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001091 Token start;
1092 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001093 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001094 }
1095 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001096 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001097 }
1098 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001099 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001100 Token nextToken = this->peek();
1101 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1102 // An empty init-statement.
1103 this->nextToken();
1104 } else {
1105 // The init-statement must be an expression or variable declaration.
1106 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001107 if (!initializer.hasValue()) {
1108 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001109 }
1110 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001111 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001112 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001113 dsl::DSLExpression testValue = this->expression();
1114 if (!testValue.hasValue()) {
1115 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001116 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001117 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001118 }
1119 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001120 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001121 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001122 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001123 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001124 dsl::DSLExpression nextValue = this->expression();
1125 if (!nextValue.hasValue()) {
1126 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001127 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001128 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001129 }
1130 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001131 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001132 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001133 dsl::DSLStatement statement = this->statement();
1134 if (!statement.hasValue()) {
1135 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001136 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001137 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1138 test.hasValue() ? std::move(test) : DSLExpression(),
1139 next.hasValue() ? std::move(next) : DSLExpression(),
1140 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001141 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001142}
1143
1144/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001145DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001146 Token start;
1147 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001148 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001149 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001150 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001151 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001152 DSLExpression next = this->expression();
1153 if (!next.hasValue()) {
1154 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001155 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001156 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001157 }
1158 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001159 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001160 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001161 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1162 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001163}
1164
1165/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001166DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001167 Token start;
1168 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001169 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001170 }
1171 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001172 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001173 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001174 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001175}
1176
1177/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001178DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001179 Token start;
1180 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001181 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001182 }
1183 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001184 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001185 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001186 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001187}
1188
1189/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001190DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001191 Token start;
1192 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001193 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001194 }
1195 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001196 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001197 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001198 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001199}
1200
1201/* LBRACE statement* RBRACE */
1202skstd::optional<DSLBlock> DSLParser::block() {
1203 Token start;
1204 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1205 return skstd::nullopt;
1206 }
1207 AutoDSLDepth depth(this);
1208 if (!depth.increase()) {
1209 return skstd::nullopt;
1210 }
1211 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001212 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001213 for (;;) {
1214 switch (this->peek().fKind) {
1215 case Token::Kind::TK_RBRACE:
1216 this->nextToken();
1217 return DSLBlock(std::move(statements), CurrentSymbolTable());
1218 case Token::Kind::TK_END_OF_FILE:
1219 this->error(this->peek(), "expected '}', but found end of file");
1220 return skstd::nullopt;
1221 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001222 DSLStatement statement = this->statement();
1223 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001224 return skstd::nullopt;
1225 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001226 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001227 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001228 }
1229 }
1230 }
1231}
1232
1233/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001234DSLStatement DSLParser::expressionStatement() {
1235 DSLExpression expr = this->expression();
1236 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001237 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001238 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001239 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001240 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001241 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001242 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001243}
1244
1245/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001246DSLExpression DSLParser::expression() {
1247 DSLExpression result = this->assignmentExpression();
1248 if (!result.hasValue()) {
1249 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001250 }
1251 Token t;
1252 AutoDSLDepth depth(this);
1253 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1254 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001255 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001256 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001257 DSLExpression right = this->assignmentExpression();
1258 if (!right.hasValue()) {
1259 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001260 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001261 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1262 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001263 }
1264 return result;
1265}
1266
1267#define OPERATOR_RIGHT(op, exprType) \
1268 do { \
1269 this->nextToken(); \
1270 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001271 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001272 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001273 DSLExpression right = this->exprType(); \
1274 if (!right.hasValue()) { \
1275 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001276 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001277 DSLExpression next = std::move(result) op std::move(right); \
1278 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001279 } while (false)
1280
1281/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1282 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1283 assignmentExpression)*
1284 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001285DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001286 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001287 DSLExpression result = this->ternaryExpression();
1288 if (!result.hasValue()) {
1289 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001290 }
1291 for (;;) {
1292 switch (this->peek().fKind) {
1293 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1294 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1295 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1296 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1297 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1298 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1299 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1300 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1301 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1302 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1303 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1304 default:
1305 return result;
1306 }
1307 }
1308}
1309
1310/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001311DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001312 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001313 DSLExpression base = this->logicalOrExpression();
1314 if (!base.hasValue()) {
1315 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001316 }
1317 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1318 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001319 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001320 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001321 DSLExpression trueExpr = this->expression();
1322 if (!trueExpr.hasValue()) {
1323 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001324 }
1325 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001326 DSLExpression falseExpr = this->assignmentExpression();
1327 if (!falseExpr.hasValue()) {
1328 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001329 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001330 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001331 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001332 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001333 }
1334 return base;
1335}
1336
1337/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001338DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001339 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001340 DSLExpression result = this->logicalXorExpression();
1341 if (!result.hasValue()) {
1342 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001343 }
1344 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1345 OPERATOR_RIGHT(||, logicalXorExpression);
1346 }
1347 return result;
1348}
1349
1350/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001351DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001352 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001353 DSLExpression result = this->logicalAndExpression();
1354 if (!result.hasValue()) {
1355 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001356 }
1357 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1358 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001359 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001360 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001361 DSLExpression right = this->logicalAndExpression();
1362 if (!right.hasValue()) {
1363 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001364 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001365 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1366 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001367 }
1368 return result;
1369}
1370
1371/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001372DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001373 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001374 DSLExpression result = this->bitwiseOrExpression();
1375 if (!result.hasValue()) {
1376 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001377 }
1378 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1379 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1380 }
1381 return result;
1382}
1383
1384/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001385DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001386 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001387 DSLExpression result = this->bitwiseXorExpression();
1388 if (!result.hasValue()) {
1389 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001390 }
1391 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1392 OPERATOR_RIGHT(|, bitwiseXorExpression);
1393 }
1394 return result;
1395}
1396
1397/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001398DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001399 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001400 DSLExpression result = this->bitwiseAndExpression();
1401 if (!result.hasValue()) {
1402 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001403 }
1404 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1405 OPERATOR_RIGHT(^, bitwiseAndExpression);
1406 }
1407 return result;
1408}
1409
1410/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001411DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001412 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001413 DSLExpression result = this->equalityExpression();
1414 if (!result.hasValue()) {
1415 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001416 }
1417 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1418 OPERATOR_RIGHT(&, equalityExpression);
1419 }
1420 return result;
1421}
1422
1423/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001424DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001425 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001426 DSLExpression result = this->relationalExpression();
1427 if (!result.hasValue()) {
1428 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001429 }
1430 for (;;) {
1431 switch (this->peek().fKind) {
1432 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1433 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1434 default: return result;
1435 }
1436 }
1437}
1438
1439/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001440DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001441 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001442 DSLExpression result = this->shiftExpression();
1443 if (!result.hasValue()) {
1444 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001445 }
1446 for (;;) {
1447 switch (this->peek().fKind) {
1448 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1449 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1450 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1451 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1452 default: return result;
1453 }
1454 }
1455}
1456
1457/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001458DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001459 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001460 DSLExpression result = this->additiveExpression();
1461 if (!result.hasValue()) {
1462 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001463 }
1464 for (;;) {
1465 switch (this->peek().fKind) {
1466 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1467 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1468 default: return result;
1469 }
1470 }
1471}
1472
1473/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001474DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001475 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001476 DSLExpression result = this->multiplicativeExpression();
1477 if (!result.hasValue()) {
1478 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001479 }
1480 for (;;) {
1481 switch (this->peek().fKind) {
1482 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1483 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1484 default: return result;
1485 }
1486 }
1487}
1488
1489/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001490DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001491 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001492 DSLExpression result = this->unaryExpression();
1493 if (!result.hasValue()) {
1494 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001495 }
1496 for (;;) {
1497 switch (this->peek().fKind) {
1498 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1499 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1500 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1501 default: return result;
1502 }
1503 }
1504}
1505
1506/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001507DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001508 AutoDSLDepth depth(this);
1509 Token next = this->peek();
1510 switch (next.fKind) {
1511 case Token::Kind::TK_PLUS:
1512 case Token::Kind::TK_MINUS:
1513 case Token::Kind::TK_LOGICALNOT:
1514 case Token::Kind::TK_BITWISENOT:
1515 case Token::Kind::TK_PLUSPLUS:
1516 case Token::Kind::TK_MINUSMINUS: {
1517 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001518 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001519 }
1520 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001521 DSLExpression expr = this->unaryExpression();
1522 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001523 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001524 }
1525 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001526 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1527 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1528 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1529 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1530 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1531 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001532 default: SkUNREACHABLE;
1533 }
1534 }
1535 default:
1536 return this->postfixExpression();
1537 }
1538}
1539
1540/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001541DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001542 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001543 DSLExpression result = this->term();
1544 if (!result.hasValue()) {
1545 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001546 }
1547 for (;;) {
1548 Token t = this->peek();
1549 switch (t.fKind) {
1550 case Token::Kind::TK_FLOAT_LITERAL:
1551 if (this->text(t)[0] != '.') {
1552 return result;
1553 }
1554 [[fallthrough]];
1555 case Token::Kind::TK_LBRACKET:
1556 case Token::Kind::TK_DOT:
1557 case Token::Kind::TK_LPAREN:
1558 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001559 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001560 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001561 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001562 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001563 DSLExpression next = this->suffix(std::move(result));
1564 if (!next.hasValue()) {
1565 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001566 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001567 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001568 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001569 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001570 default:
1571 return result;
1572 }
1573 }
1574}
1575
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001576DSLExpression DSLParser::swizzle(int line, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001577 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001578 SkASSERT(swizzleMask.length() > 0);
1579 if (!base.type().isVector() && !base.type().isScalar()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001580 return base.field(swizzleMask, this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001581 }
1582 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001583 SkSL::SwizzleComponent::Type components[4];
1584 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001585 if (i >= 4) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001586 this->error(line, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001587 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001588 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001589 switch (swizzleMask[i]) {
1590 case '0': components[i] = SwizzleComponent::ZERO; break;
1591 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001592 case 'r': components[i] = SwizzleComponent::R; break;
1593 case 'x': components[i] = SwizzleComponent::X; break;
1594 case 's': components[i] = SwizzleComponent::S; break;
1595 case 'L': components[i] = SwizzleComponent::UL; break;
1596 case 'g': components[i] = SwizzleComponent::G; break;
1597 case 'y': components[i] = SwizzleComponent::Y; break;
1598 case 't': components[i] = SwizzleComponent::T; break;
1599 case 'T': components[i] = SwizzleComponent::UT; break;
1600 case 'b': components[i] = SwizzleComponent::B; break;
1601 case 'z': components[i] = SwizzleComponent::Z; break;
1602 case 'p': components[i] = SwizzleComponent::P; break;
1603 case 'R': components[i] = SwizzleComponent::UR; break;
1604 case 'a': components[i] = SwizzleComponent::A; break;
1605 case 'w': components[i] = SwizzleComponent::W; break;
1606 case 'q': components[i] = SwizzleComponent::Q; break;
1607 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001608 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001609 this->error(line,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001610 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001611 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001612 }
1613 }
1614 switch (length) {
1615 case 1: return dsl::Swizzle(std::move(base), components[0]);
1616 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1617 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1618 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1619 components[3]);
1620 default: SkUNREACHABLE;
1621 }
1622}
1623
Ethan Nicholas89cfde12021-09-27 11:20:34 -04001624dsl::DSLExpression DSLParser::call(int line, dsl::DSLExpression base, ExpressionArray args) {
1625 return DSLExpression(base(std::move(args), this->position(line)), this->position(line));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001626}
1627
1628/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1629 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001630DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001631 Token next = this->nextToken();
1632 AutoDSLDepth depth(this);
1633 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001634 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001635 }
1636 switch (next.fKind) {
1637 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001638 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1639 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001640 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001641 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001642 DSLExpression index = this->expression();
1643 if (!index.hasValue()) {
1644 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001645 }
1646 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001647 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001648 if (!result.valid()) {
1649 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001650 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001651 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001652 }
1653 case Token::Kind::TK_DOT: {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001654 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001655 skstd::string_view text;
1656 if (this->identifier(&text)) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001657 return this->swizzle(line, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001658 }
1659 [[fallthrough]];
1660 }
1661 case Token::Kind::TK_FLOAT_LITERAL: {
1662 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1663 // floating point literals, possibly followed by an identifier. Handle that here.
1664 skstd::string_view field = this->text(next);
1665 SkASSERT(field[0] == '.');
1666 field.remove_prefix(1);
1667 // use the next *raw* token so we don't ignore whitespace - we only care about
1668 // identifiers that directly follow the float
1669 Token id = this->nextRawToken();
1670 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001671 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001672 } else if (field.empty()) {
1673 this->error(next, "expected field name or swizzle mask after '.'");
1674 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001675 }
1676 this->pushback(id);
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001677 return this->swizzle(next.fLine, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001678 }
1679 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001680 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001681 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1682 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001683 DSLExpression expr = this->assignmentExpression();
1684 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001685 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001686 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001687 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001688 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1689 break;
1690 }
1691 }
1692 }
1693 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001694 return this->call(next.fLine, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001695 }
1696 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001697 return std::move(base)++;
1698 case Token::Kind::TK_MINUSMINUS:
1699 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001700 default: {
1701 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001702 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001703 }
1704 }
1705}
1706
1707/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001708DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001709 Token t = this->peek();
1710 switch (t.fKind) {
1711 case Token::Kind::TK_IDENTIFIER: {
1712 skstd::string_view text;
1713 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001714 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001715 }
1716 break;
1717 }
1718 case Token::Kind::TK_INT_LITERAL: {
1719 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001720 if (!this->intLiteral(&i)) {
1721 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001722 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001723 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001724 }
1725 case Token::Kind::TK_FLOAT_LITERAL: {
1726 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001727 if (!this->floatLiteral(&f)) {
1728 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001729 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001730 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001731 }
1732 case Token::Kind::TK_TRUE_LITERAL: // fall through
1733 case Token::Kind::TK_FALSE_LITERAL: {
1734 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001735 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001736 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001737 }
1738 case Token::Kind::TK_LPAREN: {
1739 this->nextToken();
1740 AutoDSLDepth depth(this);
1741 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001742 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001743 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001744 DSLExpression result = this->expression();
1745 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001746 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1747 return result;
1748 }
1749 break;
1750 }
1751 default:
1752 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001753 this->error(t, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001754 fEncounteredFatalError = true;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001755 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001756 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001757 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001758}
1759
1760/* INT_LITERAL */
1761bool DSLParser::intLiteral(SKSL_INT* dest) {
1762 Token t;
1763 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1764 return false;
1765 }
1766 skstd::string_view s = this->text(t);
1767 if (!SkSL::stoi(s, dest)) {
1768 this->error(t, "integer is too large: " + s);
1769 return false;
1770 }
1771 return true;
1772}
1773
1774/* FLOAT_LITERAL */
1775bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1776 Token t;
1777 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1778 return false;
1779 }
1780 skstd::string_view s = this->text(t);
1781 if (!SkSL::stod(s, dest)) {
1782 this->error(t, "floating-point value is too large: " + s);
1783 return false;
1784 }
1785 return true;
1786}
1787
1788/* TRUE_LITERAL | FALSE_LITERAL */
1789bool DSLParser::boolLiteral(bool* dest) {
1790 Token t = this->nextToken();
1791 switch (t.fKind) {
1792 case Token::Kind::TK_TRUE_LITERAL:
1793 *dest = true;
1794 return true;
1795 case Token::Kind::TK_FALSE_LITERAL:
1796 *dest = false;
1797 return true;
1798 default:
1799 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1800 return false;
1801 }
1802}
1803
1804/* IDENTIFIER */
1805bool DSLParser::identifier(skstd::string_view* dest) {
1806 Token t;
1807 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1808 *dest = this->text(t);
1809 return true;
1810 }
1811 return false;
1812}
1813
1814} // namespace SkSL