blob: d742fa59cb2ea237466c729733c02da479148f09 [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 Nicholasdd2fdea2021-07-20 15:23:04 -040013
14#include <memory>
15
16#if SKSL_DSL_PARSER
17
18using 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 Nicholas47f76852021-09-23 14:44:33 -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 Nicholas47f76852021-09-23 14:44:33 -0400195 return this->position(t.fLine);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400196}
197
Brian Osmancc914522021-09-24 18:58:37 +0000198PositionInfo DSLParser::position(int offset) {
199 return PositionInfo("<unknown>", offset);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400200}
201
202void DSLParser::error(Token token, String msg) {
Ethan Nicholas47f76852021-09-23 14:44:33 -0400203 this->error(token.fLine, msg);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400204}
205
Brian Osmancc914522021-09-24 18:58:37 +0000206void DSLParser::error(int offset, String msg) {
207 GetErrorReporter().error(msg.c_str(), this->position(offset));
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 Nicholas5d97a962021-08-30 15:58:52 -0400216 fEncounteredFatalError = false;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400217 std::unique_ptr<Program> result;
218 bool done = false;
219 while (!done) {
220 switch (this->peek().fKind) {
221 case Token::Kind::TK_END_OF_FILE:
222 done = true;
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400223 if (!errorReporter->errorCount()) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400224 result = dsl::ReleaseProgram(std::move(fText));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400225 }
226 break;
Ethan Nicholas642215e2021-09-03 11:10:54 -0400227 case Token::Kind::TK_DIRECTIVE:
228 this->directive();
229 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400230 case Token::Kind::TK_INVALID: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400231 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400232 this->error(this->peek(), String("invalid token"));
Ethan Nicholasf8f1fa02021-08-29 14:12:17 -0400233 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400234 break;
235 }
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400236 default:
237 this->declaration();
238 done = fEncounteredFatalError;
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400239 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400240 }
241 }
242 End();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400243 errorReporter->setSource(nullptr);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400244 return result;
245}
246
Ethan Nicholas642215e2021-09-03 11:10:54 -0400247/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
248void DSLParser::directive() {
249 Token start;
250 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
251 return;
252 }
253 skstd::string_view text = this->text(start);
254 if (text == "#extension") {
255 Token name;
256 if (!this->expectIdentifier(&name)) {
257 return;
258 }
259 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
260 return;
261 }
262 Token behavior;
263 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
264 return;
265 }
266 skstd::string_view behaviorText = this->text(behavior);
267 if (behaviorText == "disable") {
268 return;
269 }
270 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
271 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
272 }
273 // We don't currently do anything different between require, enable, and warn
274 dsl::AddExtension(this->text(name));
275 } else {
276 this->error(start, "unsupported directive '" + this->text(start) + "'");
277 }
278}
279
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400280/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
281 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
282bool DSLParser::declaration() {
283 Token lookahead = this->peek();
284 switch (lookahead.fKind) {
285 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400286 this->nextToken();
Ethan Nicholas47f76852021-09-23 14:44:33 -0400287 this->error(lookahead, "expected a declaration, but found ';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400288 return false;
289 default:
290 break;
291 }
292 DSLModifiers modifiers = this->modifiers();
293 lookahead = this->peek();
294 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
295 // we have an identifier that's not a type, could be the start of an interface block
296 return this->interfaceBlock(modifiers);
297 }
298 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
Ethan Nicholas678ec712021-09-03 06:33:47 -0400299 this->nextToken();
300 Declare(modifiers, position(lookahead));
301 return true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400302 }
303 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400304 this->structVarDeclaration(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400305 return true;
306 }
John Stiles4adb66f2021-08-05 10:15:16 -0400307 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400308 if (!type) {
309 return false;
310 }
311 Token name;
312 if (!this->expectIdentifier(&name)) {
313 return false;
314 }
315 if (this->checkNext(Token::Kind::TK_LPAREN)) {
316 return this->functionDeclarationEnd(modifiers, *type, name);
317 } else {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400318 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400319 return true;
320 }
321}
322
323/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400324bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
325 DSLType type,
326 const Token& name) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400327 SkTArray<DSLWrapper<DSLParameter>> parameters;
328 Token lookahead = this->peek();
329 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
330 // `()` means no parameters at all.
331 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
332 // `(void)` also means no parameters at all.
333 this->nextToken();
334 } else {
335 for (;;) {
336 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
337 if (!parameter) {
338 return false;
339 }
340 parameters.push_back(std::move(*parameter));
341 if (!this->checkNext(Token::Kind::TK_COMMA)) {
342 break;
343 }
344 }
345 }
346 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
347 return false;
348 }
349 SkTArray<DSLParameter*> parameterPointers;
350 for (DSLWrapper<DSLParameter>& param : parameters) {
351 parameterPointers.push_back(&param.get());
352 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400353 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400354 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
355 AutoDSLSymbolTable symbols;
356 for (DSLParameter* var : parameterPointers) {
357 AddToSymbolTable(*var);
358 }
359 skstd::optional<DSLBlock> body = this->block();
360 if (!body) {
361 return false;
362 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -0400363 result.define(std::move(*body), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400364 }
365 return true;
366}
367
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400368SKSL_INT DSLParser::arraySize() {
369 Token next = this->peek();
370 if (next.fKind == Token::Kind::TK_INT_LITERAL) {
371 SKSL_INT size;
372 if (this->intLiteral(&size)) {
373 if (size > INT32_MAX) {
374 this->error(next, "array size out of bounds");
375 return 1;
376 }
377 if (size <= 0) {
378 this->error(next, "array size must be positive");
379 return 1;
380 }
381 return size;
382 }
383 return 1;
384 } else if (this->checkNext(Token::Kind::TK_MINUS) &&
385 this->checkNext(Token::Kind::TK_INT_LITERAL)) {
386 this->error(next, "array size must be positive");
387 return 1;
388 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400389 DSLExpression expr = this->expression();
390 if (expr.isValid()) {
Ethan Nicholas51b4b862021-08-31 16:12:40 -0400391 this->error(next, "expected int literal");
392 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400393 return 1;
394 }
395}
396
Brian Osmancc914522021-09-24 18:58:37 +0000397bool DSLParser::parseArrayDimensions(int offset, DSLType* type) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400398 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
399 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
Brian Osmancc914522021-09-24 18:58:37 +0000400 this->error(offset, "expected array dimension");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400401 } else {
Brian Osmancc914522021-09-24 18:58:37 +0000402 *type = Array(*type, this->arraySize(), this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400403 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400404 return false;
405 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400406 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400407 }
408 return true;
409}
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400410
Brian Osmancc914522021-09-24 18:58:37 +0000411bool DSLParser::parseInitializer(int offset, DSLExpression* initializer) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400412 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400413 DSLExpression value = this->assignmentExpression();
414 if (!value.hasValue()) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400415 return false;
416 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400417 initializer->swap(value);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400418 }
419 return true;
420}
421
422/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
423 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
424void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
425 dsl::DSLType baseType, skstd::string_view name) {
426 using namespace dsl;
Ethan Nicholas47f76852021-09-23 14:44:33 -0400427 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400428 DSLType type = baseType;
429 DSLExpression initializer;
Ethan Nicholas47f76852021-09-23 14:44:33 -0400430 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400431 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400432 }
Ethan Nicholas47f76852021-09-23 14:44:33 -0400433 this->parseInitializer(line, &initializer);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400434 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
435 Declare(first);
436 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400437
438 while (this->checkNext(Token::Kind::TK_COMMA)) {
439 type = baseType;
440 Token identifierName;
441 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400442 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400443 }
Ethan Nicholas47f76852021-09-23 14:44:33 -0400444 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400445 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400446 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400447 DSLExpression anotherInitializer;
Ethan Nicholas47f76852021-09-23 14:44:33 -0400448 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400449 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400450 }
Ethan Nicholas47f76852021-09-23 14:44:33 -0400451 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
452 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400453 Declare(next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400454 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400455 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400456 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400457}
458
459/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
460 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400461DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
462 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400463 using namespace dsl;
Ethan Nicholas47f76852021-09-23 14:44:33 -0400464 int line = this->peek().fLine;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400465 DSLType type = baseType;
466 DSLExpression initializer;
Ethan Nicholas47f76852021-09-23 14:44:33 -0400467 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400468 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400469 }
Ethan Nicholas47f76852021-09-23 14:44:33 -0400470 this->parseInitializer(line, &initializer);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400471 DSLVar first(mods, type, name, std::move(initializer), pos);
472 DSLStatement result = Declare(first);
473 AddToSymbolTable(first);
474
475 while (this->checkNext(Token::Kind::TK_COMMA)) {
476 type = baseType;
477 Token identifierName;
478 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400479 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400480 }
Ethan Nicholas47f76852021-09-23 14:44:33 -0400481 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400482 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400483 }
484 DSLExpression anotherInitializer;
Ethan Nicholas47f76852021-09-23 14:44:33 -0400485 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400486 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400487 }
Ethan Nicholas47f76852021-09-23 14:44:33 -0400488 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
489 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400490 DSLWriter::AddVarDeclaration(result, next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400491 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400492 }
493 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400494 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400495}
496
497/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400498DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400499 Token nextToken = this->peek();
500 if (nextToken.fKind == Token::Kind::TK_CONST) {
501 // Statements that begin with `const` might be variable declarations, but can't be legal
502 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
503 return this->varDeclarations();
504 }
505
John Stiles02014312021-08-04 16:03:12 -0400506 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
507 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
508 nextToken.fKind == Token::Kind::TK_LOWP ||
509 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400510 // Statements that begin with a typename are most often variable declarations, but
511 // occasionally the type is part of a constructor, and these are actually expression-
512 // statements in disguise. First, attempt the common case: parse it as a vardecl.
513 Checkpoint checkpoint(this);
514 VarDeclarationsPrefix prefix;
515 if (this->varDeclarationsPrefix(&prefix)) {
516 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400517 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
518 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400519 }
520
521 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
522 // expression-statement instead.
523 checkpoint.rewind();
524 }
525 return this->expressionStatement();
526}
527
528// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
529// statement is a variable-declaration statement, not an expression-statement.
530bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400531 prefixData->fPosition = this->position(this->peek());
532 prefixData->fModifiers = this->modifiers();
533 skstd::optional<DSLType> type = this->type(prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400534 if (!type) {
535 return false;
536 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400537 prefixData->fType = *type;
538 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400539}
540
541/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400542DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400543 VarDeclarationsPrefix prefix;
544 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400545 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400546 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400547 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
548 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400549}
550
551/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
552skstd::optional<DSLType> DSLParser::structDeclaration() {
553 AutoDSLDepth depth(this);
554 if (!depth.increase()) {
555 return skstd::nullopt;
556 }
557 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
558 return skstd::nullopt;
559 }
560 Token name;
561 if (!this->expectIdentifier(&name)) {
562 return skstd::nullopt;
563 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400564 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
565 return skstd::nullopt;
566 }
567 SkTArray<DSLField> fields;
568 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
569 DSLModifiers modifiers = this->modifiers();
570
John Stiles4adb66f2021-08-05 10:15:16 -0400571 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400572 if (!type) {
573 return skstd::nullopt;
574 }
575
576 do {
577 DSLType actualType = *type;
578 Token memberName;
579 if (!this->expectIdentifier(&memberName)) {
580 return skstd::nullopt;
581 }
582
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400583 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
584 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400585 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
586 return skstd::nullopt;
587 }
588 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400589 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
590 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400591 } while (this->checkNext(Token::Kind::TK_COMMA));
592 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
593 return skstd::nullopt;
594 }
595 }
596 if (fields.empty()) {
Ethan Nicholas47f76852021-09-23 14:44:33 -0400597 this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400598 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400599 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400600}
601
602/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400603SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400604 skstd::optional<DSLType> type = this->structDeclaration();
605 if (!type) {
606 return {};
607 }
608 Token name;
609 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400610 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
611 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400612 } else {
613 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400614 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400615 return {};
616}
617
618/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
619skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
620 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles4adb66f2021-08-05 10:15:16 -0400621 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400622 if (!type) {
623 return skstd::nullopt;
624 }
625 Token name;
626 if (!this->expectIdentifier(&name)) {
627 return skstd::nullopt;
628 }
629 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400630 Token sizeToken;
631 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
632 return skstd::nullopt;
633 }
634 skstd::string_view arraySizeFrag = this->text(sizeToken);
635 SKSL_INT arraySize;
636 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
637 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400638 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400639 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400640 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400641 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
642 return skstd::nullopt;
643 }
644 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400645 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400646}
647
648/** EQ INT_LITERAL */
649int DSLParser::layoutInt() {
650 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
651 return -1;
652 }
653 Token resultToken;
654 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
655 return -1;
656 }
657 skstd::string_view resultFrag = this->text(resultToken);
658 SKSL_INT resultValue;
659 if (!SkSL::stoi(resultFrag, &resultValue)) {
660 this->error(resultToken, "value in layout is too large: " + resultFrag);
661 return -1;
662 }
663 return resultValue;
664}
665
666/** EQ IDENTIFIER */
667skstd::string_view DSLParser::layoutIdentifier() {
668 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
669 return {};
670 }
671 Token resultToken;
672 if (!this->expectIdentifier(&resultToken)) {
673 return {};
674 }
675 return this->text(resultToken);
676}
677
678/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
679DSLLayout DSLParser::layout() {
680 DSLLayout result;
681 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
682 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
683 return result;
684 }
685 for (;;) {
686 Token t = this->nextToken();
687 String text(this->text(t));
688 auto found = layoutTokens->find(text);
689 if (found != layoutTokens->end()) {
690 switch (found->second) {
691 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400692 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400693 break;
694 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400695 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400696 break;
697 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400698 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400699 break;
700 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400701 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400702 break;
703 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400704 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400705 break;
706 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400707 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400708 break;
709 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400710 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400711 break;
712 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400713 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400714 break;
715 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400716 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400717 break;
718 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400719 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400720 break;
721 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400722 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400723 break;
724 default:
725 this->error(t, "'" + text + "' is not a valid layout qualifier");
726 break;
727 }
728 } else {
729 this->error(t, "'" + text + "' is not a valid layout qualifier");
730 }
731 if (this->checkNext(Token::Kind::TK_RPAREN)) {
732 break;
733 }
734 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
735 break;
736 }
737 }
738 }
739 return result;
740}
741
742/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
743 VARYING | INLINE)* */
744DSLModifiers DSLParser::modifiers() {
745 DSLLayout layout = this->layout();
746 int flags = 0;
747 for (;;) {
748 // TODO(ethannicholas): handle duplicate / incompatible flags
749 int tokenFlag = parse_modifier_token(peek().fKind);
750 if (!tokenFlag) {
751 break;
752 }
753 flags |= tokenFlag;
754 this->nextToken();
755 }
756 return DSLModifiers(std::move(layout), flags);
757}
758
759DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
760 DSLModifiers result = this->modifiers();
761 if (defaultFlags && !result.flags()) {
762 return DSLModifiers(result.layout(), defaultFlags);
763 }
764 return result;
765}
766
767/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400768DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400769 Token start = this->nextToken();
770 AutoDSLDepth depth(this);
771 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400772 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400773 }
774 this->pushback(start);
775 switch (start.fKind) {
776 case Token::Kind::TK_IF: // fall through
777 case Token::Kind::TK_STATIC_IF:
778 return this->ifStatement();
779 case Token::Kind::TK_FOR:
780 return this->forStatement();
781 case Token::Kind::TK_DO:
782 return this->doStatement();
783 case Token::Kind::TK_WHILE:
784 return this->whileStatement();
785 case Token::Kind::TK_SWITCH: // fall through
786 case Token::Kind::TK_STATIC_SWITCH:
787 return this->switchStatement();
788 case Token::Kind::TK_RETURN:
789 return this->returnStatement();
790 case Token::Kind::TK_BREAK:
791 return this->breakStatement();
792 case Token::Kind::TK_CONTINUE:
793 return this->continueStatement();
794 case Token::Kind::TK_DISCARD:
795 return this->discardStatement();
796 case Token::Kind::TK_LBRACE: {
797 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400798 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400799 }
800 case Token::Kind::TK_SEMICOLON:
801 this->nextToken();
802 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400803 case Token::Kind::TK_HIGHP:
804 case Token::Kind::TK_MEDIUMP:
805 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400806 case Token::Kind::TK_CONST:
807 case Token::Kind::TK_IDENTIFIER:
808 return this->varDeclarationsOrExpressionStatement();
809 default:
810 return this->expressionStatement();
811 }
812}
813
814/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stilese53c7212021-08-05 10:19:11 -0400815skstd::optional<DSLType> DSLParser::type(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400816 Token type;
817 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
818 return skstd::nullopt;
819 }
820 if (!IsType(this->text(type))) {
821 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
822 return skstd::nullopt;
823 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400824 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400825 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400826 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400827 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400828 } else {
829 this->error(this->peek(), "expected array dimension");
830 }
831 this->expect(Token::Kind::TK_RBRACKET, "']'");
832 }
833 return result;
834}
835
836/* IDENTIFIER LBRACE
837 varDeclaration+
838 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400839bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400840 Token typeName;
841 if (!this->expectIdentifier(&typeName)) {
842 return false;
843 }
844 if (peek().fKind != Token::Kind::TK_LBRACE) {
845 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
846 // 99% of the time, the user was not actually intending to create an interface block, so
847 // it's better to report it as an unknown type
848 this->error(typeName, "no type named '" + this->text(typeName) + "'");
849 return false;
850 }
851 this->nextToken();
852 SkTArray<dsl::Field> fields;
853 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400854 DSLModifiers fieldModifiers = this->modifiers();
855 skstd::optional<dsl::DSLType> type = this->type(fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400856 if (!type) {
857 return false;
858 }
859 do {
860 Token fieldName;
861 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
862 return false;
863 }
864 DSLType actualType = *type;
865 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
866 Token sizeToken = this->peek();
867 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400868 actualType = Array(std::move(actualType), this->arraySize(),
869 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400870 } else {
871 this->error(sizeToken, "unsized arrays are not permitted");
872 }
873 this->expect(Token::Kind::TK_RBRACKET, "']'");
874 }
875 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
876 return false;
877 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400878 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
879 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400880 }
881 while (this->checkNext(Token::Kind::TK_COMMA));
882 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400883 skstd::string_view instanceName;
884 Token instanceNameToken;
885 SKSL_INT arraySize = 0;
886 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
887 instanceName = this->text(instanceNameToken);
888 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400889 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400890 this->expect(Token::Kind::TK_RBRACKET, "']'");
891 }
892 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400893 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400894 if (fields.empty()) {
895 this->error(typeName, "interface block '" + this->text(typeName) +
896 "' must contain at least one member");
897 } else {
898 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
899 arraySize, this->position(typeName));
900 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400901 return true;
902}
903
904/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400905DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400906 Token start;
907 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
908 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400909 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400910 }
911 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400912 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400913 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400914 DSLExpression test = this->expression();
915 if (!test.hasValue()) {
916 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400917 }
918 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400919 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400920 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400921 DSLStatement ifTrue = this->statement();
922 if (!ifTrue.hasValue()) {
923 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400924 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400925 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400926 if (this->checkNext(Token::Kind::TK_ELSE)) {
927 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400928 if (!ifFalse.hasValue()) {
929 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400930 }
931 }
932 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400933 return StaticIf(std::move(test), std::move(ifTrue),
934 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400935 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400936 return If(std::move(test), std::move(ifTrue),
937 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400938 }
939}
940
941/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400942DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400943 Token start;
944 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400945 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400946 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400947 DSLStatement statement = this->statement();
948 if (!statement.hasValue()) {
949 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400950 }
951 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400952 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400953 }
954 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400955 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400956 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400957 DSLExpression test = this->expression();
958 if (!test.hasValue()) {
959 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400960 }
961 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400962 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400963 }
964 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400965 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400966 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400967 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400968}
969
970/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400971DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400972 Token start;
973 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400974 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400975 }
976 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
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 DSLExpression test = this->expression();
980 if (!test.hasValue()) {
981 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400982 }
983 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400984 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400985 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400986 DSLStatement statement = this->statement();
987 if (!statement.hasValue()) {
988 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400989 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400990 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400991}
992
993/* CASE expression COLON statement* */
994skstd::optional<DSLCase> DSLParser::switchCase() {
995 Token start;
996 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400997 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400998 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400999 DSLExpression value = this->expression();
1000 if (!value.hasValue()) {
1001 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001002 }
1003 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001004 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001005 }
1006 SkTArray<DSLStatement> statements;
1007 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1008 this->peek().fKind != Token::Kind::TK_CASE &&
1009 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001010 DSLStatement s = this->statement();
1011 if (!s.hasValue()) {
1012 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001013 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001014 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001015 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001016 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001017}
1018
1019/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001020DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001021 Token start;
1022 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1023 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001024 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001025 }
1026 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001027 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001028 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001029 DSLExpression value = this->expression();
1030 if (!value.hasValue()) {
1031 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001032 }
1033 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001034 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001035 }
1036 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001037 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001038 }
1039 SkTArray<DSLCase> cases;
1040 while (this->peek().fKind == Token::Kind::TK_CASE) {
1041 skstd::optional<DSLCase> c = this->switchCase();
1042 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001043 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001044 }
1045 cases.push_back(std::move(*c));
1046 }
1047 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1048 // parts of the compiler may rely upon this assumption.
1049 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1050 SkTArray<DSLStatement> statements;
1051 Token defaultStart;
1052 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1053 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001054 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001055 }
1056 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001057 DSLStatement s = this->statement();
1058 if (!s.hasValue()) {
1059 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001060 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001061 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001062 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001063 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001064 }
1065 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001066 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001067 }
1068 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001069 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001070 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001071 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001072 }
1073}
1074
1075/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1076 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001077dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001078 Token start;
1079 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001080 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001081 }
1082 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001083 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001084 }
1085 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001086 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001087 Token nextToken = this->peek();
1088 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1089 // An empty init-statement.
1090 this->nextToken();
1091 } else {
1092 // The init-statement must be an expression or variable declaration.
1093 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001094 if (!initializer.hasValue()) {
1095 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001096 }
1097 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001098 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001099 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001100 dsl::DSLExpression testValue = this->expression();
1101 if (!testValue.hasValue()) {
1102 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001103 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001104 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001105 }
1106 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001107 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001108 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001109 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001110 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001111 dsl::DSLExpression nextValue = this->expression();
1112 if (!nextValue.hasValue()) {
1113 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001114 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001115 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001116 }
1117 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001118 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001119 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001120 dsl::DSLStatement statement = this->statement();
1121 if (!statement.hasValue()) {
1122 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001123 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001124 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1125 test.hasValue() ? std::move(test) : DSLExpression(),
1126 next.hasValue() ? std::move(next) : DSLExpression(),
1127 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001128 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001129}
1130
1131/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001132DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001133 Token start;
1134 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001135 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001136 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001137 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001138 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001139 DSLExpression next = this->expression();
1140 if (!next.hasValue()) {
1141 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001142 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001143 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001144 }
1145 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001146 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001147 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001148 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1149 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001150}
1151
1152/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001153DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001154 Token start;
1155 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001156 return {};
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 Nicholas6f20b8d2021-08-31 07:40:24 -04001161 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001162}
1163
1164/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001165DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001166 Token start;
1167 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &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 Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001174}
1175
1176/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001177DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001178 Token start;
1179 if (!this->expect(Token::Kind::TK_DISCARD, "'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 Nicholas360db872021-09-03 17:00:09 -04001185 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001186}
1187
1188/* LBRACE statement* RBRACE */
1189skstd::optional<DSLBlock> DSLParser::block() {
1190 Token start;
1191 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1192 return skstd::nullopt;
1193 }
1194 AutoDSLDepth depth(this);
1195 if (!depth.increase()) {
1196 return skstd::nullopt;
1197 }
1198 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001199 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001200 for (;;) {
1201 switch (this->peek().fKind) {
1202 case Token::Kind::TK_RBRACE:
1203 this->nextToken();
1204 return DSLBlock(std::move(statements), CurrentSymbolTable());
1205 case Token::Kind::TK_END_OF_FILE:
1206 this->error(this->peek(), "expected '}', but found end of file");
1207 return skstd::nullopt;
1208 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001209 DSLStatement statement = this->statement();
1210 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001211 return skstd::nullopt;
1212 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001213 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001214 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001215 }
1216 }
1217 }
1218}
1219
1220/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001221DSLStatement DSLParser::expressionStatement() {
1222 DSLExpression expr = this->expression();
1223 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001224 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001225 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001226 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001227 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001228 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001229 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001230}
1231
1232/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001233DSLExpression DSLParser::expression() {
1234 DSLExpression result = this->assignmentExpression();
1235 if (!result.hasValue()) {
1236 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001237 }
1238 Token t;
1239 AutoDSLDepth depth(this);
1240 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1241 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001242 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001243 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001244 DSLExpression right = this->assignmentExpression();
1245 if (!right.hasValue()) {
1246 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001247 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001248 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1249 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001250 }
1251 return result;
1252}
1253
1254#define OPERATOR_RIGHT(op, exprType) \
1255 do { \
1256 this->nextToken(); \
1257 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001258 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001259 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001260 DSLExpression right = this->exprType(); \
1261 if (!right.hasValue()) { \
1262 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001263 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001264 DSLExpression next = std::move(result) op std::move(right); \
1265 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001266 } while (false)
1267
1268/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1269 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1270 assignmentExpression)*
1271 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001272DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001273 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001274 DSLExpression result = this->ternaryExpression();
1275 if (!result.hasValue()) {
1276 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001277 }
1278 for (;;) {
1279 switch (this->peek().fKind) {
1280 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1281 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1282 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1283 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1284 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1285 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1286 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1287 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1288 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1289 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1290 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1291 default:
1292 return result;
1293 }
1294 }
1295}
1296
1297/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001298DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001299 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001300 DSLExpression base = this->logicalOrExpression();
1301 if (!base.hasValue()) {
1302 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001303 }
1304 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1305 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001306 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001307 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001308 DSLExpression trueExpr = this->expression();
1309 if (!trueExpr.hasValue()) {
1310 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001311 }
1312 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001313 DSLExpression falseExpr = this->assignmentExpression();
1314 if (!falseExpr.hasValue()) {
1315 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001316 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001317 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001318 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001319 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001320 }
1321 return base;
1322}
1323
1324/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001325DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001326 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001327 DSLExpression result = this->logicalXorExpression();
1328 if (!result.hasValue()) {
1329 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001330 }
1331 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1332 OPERATOR_RIGHT(||, logicalXorExpression);
1333 }
1334 return result;
1335}
1336
1337/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001338DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001339 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001340 DSLExpression result = this->logicalAndExpression();
1341 if (!result.hasValue()) {
1342 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001343 }
1344 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1345 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001346 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001347 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001348 DSLExpression right = this->logicalAndExpression();
1349 if (!right.hasValue()) {
1350 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001351 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001352 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1353 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001354 }
1355 return result;
1356}
1357
1358/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001359DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001360 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001361 DSLExpression result = this->bitwiseOrExpression();
1362 if (!result.hasValue()) {
1363 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001364 }
1365 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1366 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1367 }
1368 return result;
1369}
1370
1371/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001372DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001373 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001374 DSLExpression result = this->bitwiseXorExpression();
1375 if (!result.hasValue()) {
1376 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001377 }
1378 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1379 OPERATOR_RIGHT(|, bitwiseXorExpression);
1380 }
1381 return result;
1382}
1383
1384/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001385DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001386 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001387 DSLExpression result = this->bitwiseAndExpression();
1388 if (!result.hasValue()) {
1389 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001390 }
1391 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1392 OPERATOR_RIGHT(^, bitwiseAndExpression);
1393 }
1394 return result;
1395}
1396
1397/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001398DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001399 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001400 DSLExpression result = this->equalityExpression();
1401 if (!result.hasValue()) {
1402 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001403 }
1404 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1405 OPERATOR_RIGHT(&, equalityExpression);
1406 }
1407 return result;
1408}
1409
1410/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001411DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001412 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001413 DSLExpression result = this->relationalExpression();
1414 if (!result.hasValue()) {
1415 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001416 }
1417 for (;;) {
1418 switch (this->peek().fKind) {
1419 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1420 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1421 default: return result;
1422 }
1423 }
1424}
1425
1426/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001427DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001428 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001429 DSLExpression result = this->shiftExpression();
1430 if (!result.hasValue()) {
1431 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001432 }
1433 for (;;) {
1434 switch (this->peek().fKind) {
1435 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1436 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1437 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1438 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1439 default: return result;
1440 }
1441 }
1442}
1443
1444/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001445DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001446 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001447 DSLExpression result = this->additiveExpression();
1448 if (!result.hasValue()) {
1449 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001450 }
1451 for (;;) {
1452 switch (this->peek().fKind) {
1453 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1454 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1455 default: return result;
1456 }
1457 }
1458}
1459
1460/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001461DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001462 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001463 DSLExpression result = this->multiplicativeExpression();
1464 if (!result.hasValue()) {
1465 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001466 }
1467 for (;;) {
1468 switch (this->peek().fKind) {
1469 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1470 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1471 default: return result;
1472 }
1473 }
1474}
1475
1476/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001477DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001478 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001479 DSLExpression result = this->unaryExpression();
1480 if (!result.hasValue()) {
1481 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001482 }
1483 for (;;) {
1484 switch (this->peek().fKind) {
1485 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1486 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1487 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1488 default: return result;
1489 }
1490 }
1491}
1492
1493/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001494DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001495 AutoDSLDepth depth(this);
1496 Token next = this->peek();
1497 switch (next.fKind) {
1498 case Token::Kind::TK_PLUS:
1499 case Token::Kind::TK_MINUS:
1500 case Token::Kind::TK_LOGICALNOT:
1501 case Token::Kind::TK_BITWISENOT:
1502 case Token::Kind::TK_PLUSPLUS:
1503 case Token::Kind::TK_MINUSMINUS: {
1504 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001505 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001506 }
1507 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001508 DSLExpression expr = this->unaryExpression();
1509 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001510 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001511 }
1512 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001513 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1514 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1515 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1516 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1517 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1518 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001519 default: SkUNREACHABLE;
1520 }
1521 }
1522 default:
1523 return this->postfixExpression();
1524 }
1525}
1526
1527/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001528DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001529 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001530 DSLExpression result = this->term();
1531 if (!result.hasValue()) {
1532 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001533 }
1534 for (;;) {
1535 Token t = this->peek();
1536 switch (t.fKind) {
1537 case Token::Kind::TK_FLOAT_LITERAL:
1538 if (this->text(t)[0] != '.') {
1539 return result;
1540 }
1541 [[fallthrough]];
1542 case Token::Kind::TK_LBRACKET:
1543 case Token::Kind::TK_DOT:
1544 case Token::Kind::TK_LPAREN:
1545 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001546 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001547 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001548 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001549 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001550 DSLExpression next = this->suffix(std::move(result));
1551 if (!next.hasValue()) {
1552 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001553 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001554 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001555 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001556 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001557 default:
1558 return result;
1559 }
1560 }
1561}
1562
Brian Osmancc914522021-09-24 18:58:37 +00001563DSLExpression DSLParser::swizzle(int offset, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001564 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001565 SkASSERT(swizzleMask.length() > 0);
1566 if (!base.type().isVector() && !base.type().isScalar()) {
Brian Osmancc914522021-09-24 18:58:37 +00001567 return base.field(swizzleMask, this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001568 }
1569 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001570 SkSL::SwizzleComponent::Type components[4];
1571 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001572 if (i >= 4) {
Brian Osmancc914522021-09-24 18:58:37 +00001573 this->error(offset, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001574 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001575 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001576 switch (swizzleMask[i]) {
1577 case '0': components[i] = SwizzleComponent::ZERO; break;
1578 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001579 case 'r': components[i] = SwizzleComponent::R; break;
1580 case 'x': components[i] = SwizzleComponent::X; break;
1581 case 's': components[i] = SwizzleComponent::S; break;
1582 case 'L': components[i] = SwizzleComponent::UL; break;
1583 case 'g': components[i] = SwizzleComponent::G; break;
1584 case 'y': components[i] = SwizzleComponent::Y; break;
1585 case 't': components[i] = SwizzleComponent::T; break;
1586 case 'T': components[i] = SwizzleComponent::UT; break;
1587 case 'b': components[i] = SwizzleComponent::B; break;
1588 case 'z': components[i] = SwizzleComponent::Z; break;
1589 case 'p': components[i] = SwizzleComponent::P; break;
1590 case 'R': components[i] = SwizzleComponent::UR; break;
1591 case 'a': components[i] = SwizzleComponent::A; break;
1592 case 'w': components[i] = SwizzleComponent::W; break;
1593 case 'q': components[i] = SwizzleComponent::Q; break;
1594 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001595 default:
Brian Osmancc914522021-09-24 18:58:37 +00001596 this->error(offset,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001597 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001598 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001599 }
1600 }
1601 switch (length) {
1602 case 1: return dsl::Swizzle(std::move(base), components[0]);
1603 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1604 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1605 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1606 components[3]);
1607 default: SkUNREACHABLE;
1608 }
1609}
1610
Brian Osmancc914522021-09-24 18:58:37 +00001611dsl::DSLExpression DSLParser::call(int offset, dsl::DSLExpression base, ExpressionArray args) {
1612 return DSLExpression(base(std::move(args), this->position(offset)), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001613}
1614
1615/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1616 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001617DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001618 Token next = this->nextToken();
1619 AutoDSLDepth depth(this);
1620 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001621 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001622 }
1623 switch (next.fKind) {
1624 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001625 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1626 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001627 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001628 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001629 DSLExpression index = this->expression();
1630 if (!index.hasValue()) {
1631 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001632 }
1633 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001634 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001635 if (!result.valid()) {
1636 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001637 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001638 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001639 }
1640 case Token::Kind::TK_DOT: {
Ethan Nicholas47f76852021-09-23 14:44:33 -04001641 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001642 skstd::string_view text;
1643 if (this->identifier(&text)) {
Ethan Nicholas47f76852021-09-23 14:44:33 -04001644 return this->swizzle(line, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001645 }
1646 [[fallthrough]];
1647 }
1648 case Token::Kind::TK_FLOAT_LITERAL: {
1649 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1650 // floating point literals, possibly followed by an identifier. Handle that here.
1651 skstd::string_view field = this->text(next);
1652 SkASSERT(field[0] == '.');
1653 field.remove_prefix(1);
1654 // use the next *raw* token so we don't ignore whitespace - we only care about
1655 // identifiers that directly follow the float
1656 Token id = this->nextRawToken();
1657 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas47f76852021-09-23 14:44:33 -04001658 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001659 } else if (field.empty()) {
1660 this->error(next, "expected field name or swizzle mask after '.'");
1661 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001662 }
1663 this->pushback(id);
Ethan Nicholas47f76852021-09-23 14:44:33 -04001664 return this->swizzle(next.fLine, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001665 }
1666 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001667 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001668 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1669 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001670 DSLExpression expr = this->assignmentExpression();
1671 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001672 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001673 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001674 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001675 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1676 break;
1677 }
1678 }
1679 }
1680 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Ethan Nicholas47f76852021-09-23 14:44:33 -04001681 return this->call(next.fLine, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001682 }
1683 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001684 return std::move(base)++;
1685 case Token::Kind::TK_MINUSMINUS:
1686 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001687 default: {
1688 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001689 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001690 }
1691 }
1692}
1693
1694/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001695DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001696 Token t = this->peek();
1697 switch (t.fKind) {
1698 case Token::Kind::TK_IDENTIFIER: {
1699 skstd::string_view text;
1700 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001701 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001702 }
1703 break;
1704 }
1705 case Token::Kind::TK_INT_LITERAL: {
1706 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001707 if (!this->intLiteral(&i)) {
1708 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001709 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001710 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001711 }
1712 case Token::Kind::TK_FLOAT_LITERAL: {
1713 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001714 if (!this->floatLiteral(&f)) {
1715 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001716 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001717 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001718 }
1719 case Token::Kind::TK_TRUE_LITERAL: // fall through
1720 case Token::Kind::TK_FALSE_LITERAL: {
1721 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001722 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001723 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001724 }
1725 case Token::Kind::TK_LPAREN: {
1726 this->nextToken();
1727 AutoDSLDepth depth(this);
1728 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001729 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001730 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001731 DSLExpression result = this->expression();
1732 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001733 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1734 return result;
1735 }
1736 break;
1737 }
1738 default:
1739 this->nextToken();
Ethan Nicholas47f76852021-09-23 14:44:33 -04001740 this->error(t, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001741 fEncounteredFatalError = true;
Ethan Nicholas47f76852021-09-23 14:44:33 -04001742 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001743 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001744 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001745}
1746
1747/* INT_LITERAL */
1748bool DSLParser::intLiteral(SKSL_INT* dest) {
1749 Token t;
1750 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1751 return false;
1752 }
1753 skstd::string_view s = this->text(t);
1754 if (!SkSL::stoi(s, dest)) {
1755 this->error(t, "integer is too large: " + s);
1756 return false;
1757 }
1758 return true;
1759}
1760
1761/* FLOAT_LITERAL */
1762bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1763 Token t;
1764 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1765 return false;
1766 }
1767 skstd::string_view s = this->text(t);
1768 if (!SkSL::stod(s, dest)) {
1769 this->error(t, "floating-point value is too large: " + s);
1770 return false;
1771 }
1772 return true;
1773}
1774
1775/* TRUE_LITERAL | FALSE_LITERAL */
1776bool DSLParser::boolLiteral(bool* dest) {
1777 Token t = this->nextToken();
1778 switch (t.fKind) {
1779 case Token::Kind::TK_TRUE_LITERAL:
1780 *dest = true;
1781 return true;
1782 case Token::Kind::TK_FALSE_LITERAL:
1783 *dest = false;
1784 return true;
1785 default:
1786 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1787 return false;
1788 }
1789}
1790
1791/* IDENTIFIER */
1792bool DSLParser::identifier(skstd::string_view* dest) {
1793 Token t;
1794 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1795 *dest = this->text(t);
1796 return true;
1797 }
1798 return false;
1799}
1800
1801} // namespace SkSL
1802
1803#endif // SKSL_DSL_PARSER