blob: a704855bc3366eba72697a492c22aa09e573a405 [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)))
Brian Osmana909dd62021-09-24 19:00:35 +0000105 , fPushback(Token::Kind::TK_NONE, -1, -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) {
Brian Osmana909dd62021-09-24 19:00:35 +0000195 return this->position(t.fOffset);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400196}
197
Brian Osmancc914522021-09-24 18:58:37 +0000198PositionInfo DSLParser::position(int offset) {
Brian Osmana909dd62021-09-24 19:00:35 +0000199 return PositionInfo::Offset("<unknown>", fText->c_str(), offset);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400200}
201
202void DSLParser::error(Token token, String msg) {
Brian Osmana909dd62021-09-24 19:00:35 +0000203 this->error(token.fOffset, 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();
Brian Osmana909dd62021-09-24 19:00:35 +0000287 this->error(lookahead.fOffset, "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;
Brian Osmana909dd62021-09-24 19:00:35 +0000427 int offset = this->peek().fOffset;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400428 DSLType type = baseType;
429 DSLExpression initializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000430 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400431 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400432 }
John Stilesb05bbd02021-09-24 15:11:16 -0400433 if (!this->parseInitializer(offset, &initializer)) {
434 return;
435 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400436 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
437 Declare(first);
438 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400439
440 while (this->checkNext(Token::Kind::TK_COMMA)) {
441 type = baseType;
442 Token identifierName;
443 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400444 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400445 }
Brian Osmana909dd62021-09-24 19:00:35 +0000446 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400447 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400448 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400449 DSLExpression anotherInitializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000450 if (!this->parseInitializer(offset, &anotherInitializer)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400451 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400452 }
John Stilesb05bbd02021-09-24 15:11:16 -0400453 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
454 this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400455 Declare(next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400456 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400457 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400458 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400459}
460
461/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
462 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400463DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
464 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400465 using namespace dsl;
Brian Osmana909dd62021-09-24 19:00:35 +0000466 int offset = this->peek().fOffset;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400467 DSLType type = baseType;
468 DSLExpression initializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000469 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400470 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400471 }
John Stilesb05bbd02021-09-24 15:11:16 -0400472 if (!this->parseInitializer(offset, &initializer)) {
473 return {};
474 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400475 DSLVar first(mods, type, name, std::move(initializer), pos);
476 DSLStatement result = Declare(first);
477 AddToSymbolTable(first);
478
479 while (this->checkNext(Token::Kind::TK_COMMA)) {
480 type = baseType;
481 Token identifierName;
482 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400483 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400484 }
Brian Osmana909dd62021-09-24 19:00:35 +0000485 if (!this->parseArrayDimensions(offset, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400486 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400487 }
488 DSLExpression anotherInitializer;
Brian Osmana909dd62021-09-24 19:00:35 +0000489 if (!this->parseInitializer(offset, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400490 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400491 }
John Stilesb05bbd02021-09-24 15:11:16 -0400492 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
493 this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400494 DSLWriter::AddVarDeclaration(result, next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400495 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400496 }
497 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400498 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400499}
500
501/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400502DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400503 Token nextToken = this->peek();
504 if (nextToken.fKind == Token::Kind::TK_CONST) {
505 // Statements that begin with `const` might be variable declarations, but can't be legal
506 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
507 return this->varDeclarations();
508 }
509
John Stiles02014312021-08-04 16:03:12 -0400510 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
511 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
512 nextToken.fKind == Token::Kind::TK_LOWP ||
513 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400514 // Statements that begin with a typename are most often variable declarations, but
515 // occasionally the type is part of a constructor, and these are actually expression-
516 // statements in disguise. First, attempt the common case: parse it as a vardecl.
517 Checkpoint checkpoint(this);
518 VarDeclarationsPrefix prefix;
519 if (this->varDeclarationsPrefix(&prefix)) {
520 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400521 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
522 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400523 }
524
525 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
526 // expression-statement instead.
527 checkpoint.rewind();
528 }
529 return this->expressionStatement();
530}
531
532// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
533// statement is a variable-declaration statement, not an expression-statement.
534bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400535 prefixData->fPosition = this->position(this->peek());
536 prefixData->fModifiers = this->modifiers();
537 skstd::optional<DSLType> type = this->type(prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400538 if (!type) {
539 return false;
540 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400541 prefixData->fType = *type;
542 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400543}
544
545/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400546DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400547 VarDeclarationsPrefix prefix;
548 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400549 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400550 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400551 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
552 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400553}
554
555/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
556skstd::optional<DSLType> DSLParser::structDeclaration() {
557 AutoDSLDepth depth(this);
558 if (!depth.increase()) {
559 return skstd::nullopt;
560 }
561 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
562 return skstd::nullopt;
563 }
564 Token name;
565 if (!this->expectIdentifier(&name)) {
566 return skstd::nullopt;
567 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400568 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
569 return skstd::nullopt;
570 }
571 SkTArray<DSLField> fields;
572 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
573 DSLModifiers modifiers = this->modifiers();
574
John Stiles4adb66f2021-08-05 10:15:16 -0400575 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400576 if (!type) {
577 return skstd::nullopt;
578 }
579
580 do {
581 DSLType actualType = *type;
582 Token memberName;
583 if (!this->expectIdentifier(&memberName)) {
584 return skstd::nullopt;
585 }
586
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400587 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
588 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400589 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
590 return skstd::nullopt;
591 }
592 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400593 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
594 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400595 } while (this->checkNext(Token::Kind::TK_COMMA));
596 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
597 return skstd::nullopt;
598 }
599 }
600 if (fields.empty()) {
Brian Osmana909dd62021-09-24 19:00:35 +0000601 this->error(name.fOffset,
602 "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400603 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400604 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400605}
606
607/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400608SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400609 skstd::optional<DSLType> type = this->structDeclaration();
610 if (!type) {
611 return {};
612 }
613 Token name;
614 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400615 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
616 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400617 } else {
618 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400619 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400620 return {};
621}
622
623/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
624skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
625 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles4adb66f2021-08-05 10:15:16 -0400626 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400627 if (!type) {
628 return skstd::nullopt;
629 }
630 Token name;
631 if (!this->expectIdentifier(&name)) {
632 return skstd::nullopt;
633 }
634 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400635 Token sizeToken;
636 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
637 return skstd::nullopt;
638 }
639 skstd::string_view arraySizeFrag = this->text(sizeToken);
640 SKSL_INT arraySize;
641 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
642 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400643 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400644 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400645 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400646 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
647 return skstd::nullopt;
648 }
649 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400650 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400651}
652
653/** EQ INT_LITERAL */
654int DSLParser::layoutInt() {
655 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
656 return -1;
657 }
658 Token resultToken;
659 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
660 return -1;
661 }
662 skstd::string_view resultFrag = this->text(resultToken);
663 SKSL_INT resultValue;
664 if (!SkSL::stoi(resultFrag, &resultValue)) {
665 this->error(resultToken, "value in layout is too large: " + resultFrag);
666 return -1;
667 }
668 return resultValue;
669}
670
671/** EQ IDENTIFIER */
672skstd::string_view DSLParser::layoutIdentifier() {
673 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
674 return {};
675 }
676 Token resultToken;
677 if (!this->expectIdentifier(&resultToken)) {
678 return {};
679 }
680 return this->text(resultToken);
681}
682
683/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
684DSLLayout DSLParser::layout() {
685 DSLLayout result;
686 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
687 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
688 return result;
689 }
690 for (;;) {
691 Token t = this->nextToken();
692 String text(this->text(t));
693 auto found = layoutTokens->find(text);
694 if (found != layoutTokens->end()) {
695 switch (found->second) {
696 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400697 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400698 break;
699 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400700 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400701 break;
702 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400703 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400704 break;
705 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400706 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400707 break;
708 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400709 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400710 break;
711 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400712 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400713 break;
714 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400715 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400716 break;
717 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400718 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400719 break;
720 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400721 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400722 break;
723 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400724 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400725 break;
726 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400727 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400728 break;
729 default:
730 this->error(t, "'" + text + "' is not a valid layout qualifier");
731 break;
732 }
733 } else {
734 this->error(t, "'" + text + "' is not a valid layout qualifier");
735 }
736 if (this->checkNext(Token::Kind::TK_RPAREN)) {
737 break;
738 }
739 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
740 break;
741 }
742 }
743 }
744 return result;
745}
746
747/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
748 VARYING | INLINE)* */
749DSLModifiers DSLParser::modifiers() {
750 DSLLayout layout = this->layout();
751 int flags = 0;
752 for (;;) {
753 // TODO(ethannicholas): handle duplicate / incompatible flags
754 int tokenFlag = parse_modifier_token(peek().fKind);
755 if (!tokenFlag) {
756 break;
757 }
758 flags |= tokenFlag;
759 this->nextToken();
760 }
761 return DSLModifiers(std::move(layout), flags);
762}
763
764DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
765 DSLModifiers result = this->modifiers();
766 if (defaultFlags && !result.flags()) {
767 return DSLModifiers(result.layout(), defaultFlags);
768 }
769 return result;
770}
771
772/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400773DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400774 Token start = this->nextToken();
775 AutoDSLDepth depth(this);
776 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400777 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400778 }
779 this->pushback(start);
780 switch (start.fKind) {
781 case Token::Kind::TK_IF: // fall through
782 case Token::Kind::TK_STATIC_IF:
783 return this->ifStatement();
784 case Token::Kind::TK_FOR:
785 return this->forStatement();
786 case Token::Kind::TK_DO:
787 return this->doStatement();
788 case Token::Kind::TK_WHILE:
789 return this->whileStatement();
790 case Token::Kind::TK_SWITCH: // fall through
791 case Token::Kind::TK_STATIC_SWITCH:
792 return this->switchStatement();
793 case Token::Kind::TK_RETURN:
794 return this->returnStatement();
795 case Token::Kind::TK_BREAK:
796 return this->breakStatement();
797 case Token::Kind::TK_CONTINUE:
798 return this->continueStatement();
799 case Token::Kind::TK_DISCARD:
800 return this->discardStatement();
801 case Token::Kind::TK_LBRACE: {
802 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400803 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400804 }
805 case Token::Kind::TK_SEMICOLON:
806 this->nextToken();
807 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400808 case Token::Kind::TK_HIGHP:
809 case Token::Kind::TK_MEDIUMP:
810 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400811 case Token::Kind::TK_CONST:
812 case Token::Kind::TK_IDENTIFIER:
813 return this->varDeclarationsOrExpressionStatement();
814 default:
815 return this->expressionStatement();
816 }
817}
818
819/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stilese53c7212021-08-05 10:19:11 -0400820skstd::optional<DSLType> DSLParser::type(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400821 Token type;
822 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
823 return skstd::nullopt;
824 }
825 if (!IsType(this->text(type))) {
826 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
827 return skstd::nullopt;
828 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400829 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400830 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400831 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400832 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400833 } else {
834 this->error(this->peek(), "expected array dimension");
835 }
836 this->expect(Token::Kind::TK_RBRACKET, "']'");
837 }
838 return result;
839}
840
841/* IDENTIFIER LBRACE
842 varDeclaration+
843 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400844bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400845 Token typeName;
846 if (!this->expectIdentifier(&typeName)) {
847 return false;
848 }
849 if (peek().fKind != Token::Kind::TK_LBRACE) {
850 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
851 // 99% of the time, the user was not actually intending to create an interface block, so
852 // it's better to report it as an unknown type
853 this->error(typeName, "no type named '" + this->text(typeName) + "'");
854 return false;
855 }
856 this->nextToken();
857 SkTArray<dsl::Field> fields;
858 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400859 DSLModifiers fieldModifiers = this->modifiers();
860 skstd::optional<dsl::DSLType> type = this->type(fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400861 if (!type) {
862 return false;
863 }
864 do {
865 Token fieldName;
866 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
867 return false;
868 }
869 DSLType actualType = *type;
870 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
871 Token sizeToken = this->peek();
872 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400873 actualType = Array(std::move(actualType), this->arraySize(),
874 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400875 } else {
876 this->error(sizeToken, "unsized arrays are not permitted");
877 }
878 this->expect(Token::Kind::TK_RBRACKET, "']'");
879 }
880 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
881 return false;
882 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400883 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
884 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400885 }
886 while (this->checkNext(Token::Kind::TK_COMMA));
887 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400888 skstd::string_view instanceName;
889 Token instanceNameToken;
890 SKSL_INT arraySize = 0;
891 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
892 instanceName = this->text(instanceNameToken);
893 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400894 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400895 this->expect(Token::Kind::TK_RBRACKET, "']'");
896 }
897 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400898 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400899 if (fields.empty()) {
900 this->error(typeName, "interface block '" + this->text(typeName) +
901 "' must contain at least one member");
902 } else {
903 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
904 arraySize, this->position(typeName));
905 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400906 return true;
907}
908
909/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400910DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400911 Token start;
912 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
913 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400914 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400915 }
916 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400917 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400918 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400919 DSLExpression test = this->expression();
920 if (!test.hasValue()) {
921 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400922 }
923 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400924 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400925 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400926 DSLStatement ifTrue = this->statement();
927 if (!ifTrue.hasValue()) {
928 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400929 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400930 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400931 if (this->checkNext(Token::Kind::TK_ELSE)) {
932 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400933 if (!ifFalse.hasValue()) {
934 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400935 }
936 }
937 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400938 return StaticIf(std::move(test), std::move(ifTrue),
939 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400940 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400941 return If(std::move(test), std::move(ifTrue),
942 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400943 }
944}
945
946/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400947DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400948 Token start;
949 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400950 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400951 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400952 DSLStatement statement = this->statement();
953 if (!statement.hasValue()) {
954 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400955 }
956 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400957 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400958 }
959 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400960 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400961 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400962 DSLExpression test = this->expression();
963 if (!test.hasValue()) {
964 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400965 }
966 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400967 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400968 }
969 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400970 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400971 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400972 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400973}
974
975/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400976DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400977 Token start;
978 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400979 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400980 }
981 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400982 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400983 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400984 DSLExpression test = this->expression();
985 if (!test.hasValue()) {
986 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400987 }
988 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400989 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400990 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400991 DSLStatement statement = this->statement();
992 if (!statement.hasValue()) {
993 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400994 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400995 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400996}
997
998/* CASE expression COLON statement* */
999skstd::optional<DSLCase> DSLParser::switchCase() {
1000 Token start;
1001 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001002 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001003 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001004 DSLExpression value = this->expression();
1005 if (!value.hasValue()) {
1006 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001007 }
1008 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001009 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001010 }
1011 SkTArray<DSLStatement> statements;
1012 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1013 this->peek().fKind != Token::Kind::TK_CASE &&
1014 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001015 DSLStatement s = this->statement();
1016 if (!s.hasValue()) {
1017 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001018 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001019 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001020 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001021 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001022}
1023
1024/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001025DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001026 Token start;
1027 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1028 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001029 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001030 }
1031 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001032 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001033 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001034 DSLExpression value = this->expression();
1035 if (!value.hasValue()) {
1036 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001037 }
1038 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001039 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001040 }
1041 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001042 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001043 }
1044 SkTArray<DSLCase> cases;
1045 while (this->peek().fKind == Token::Kind::TK_CASE) {
1046 skstd::optional<DSLCase> c = this->switchCase();
1047 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001048 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001049 }
1050 cases.push_back(std::move(*c));
1051 }
1052 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1053 // parts of the compiler may rely upon this assumption.
1054 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1055 SkTArray<DSLStatement> statements;
1056 Token defaultStart;
1057 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1058 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001059 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001060 }
1061 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001062 DSLStatement s = this->statement();
1063 if (!s.hasValue()) {
1064 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001065 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001066 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001067 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001068 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001069 }
1070 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001071 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001072 }
1073 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001074 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001075 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001076 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001077 }
1078}
1079
1080/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1081 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001082dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001083 Token start;
1084 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001085 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001086 }
1087 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001088 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001089 }
1090 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001091 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001092 Token nextToken = this->peek();
1093 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1094 // An empty init-statement.
1095 this->nextToken();
1096 } else {
1097 // The init-statement must be an expression or variable declaration.
1098 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001099 if (!initializer.hasValue()) {
1100 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001101 }
1102 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001103 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001104 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001105 dsl::DSLExpression testValue = this->expression();
1106 if (!testValue.hasValue()) {
1107 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001108 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001109 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001110 }
1111 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001112 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001113 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001114 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001115 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001116 dsl::DSLExpression nextValue = this->expression();
1117 if (!nextValue.hasValue()) {
1118 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001119 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001120 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001121 }
1122 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001123 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001124 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001125 dsl::DSLStatement statement = this->statement();
1126 if (!statement.hasValue()) {
1127 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001128 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001129 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1130 test.hasValue() ? std::move(test) : DSLExpression(),
1131 next.hasValue() ? std::move(next) : DSLExpression(),
1132 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001133 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001134}
1135
1136/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001137DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001138 Token start;
1139 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001140 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001141 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001142 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001143 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001144 DSLExpression next = this->expression();
1145 if (!next.hasValue()) {
1146 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001147 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001148 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001149 }
1150 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001151 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001152 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001153 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1154 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001155}
1156
1157/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001158DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001159 Token start;
1160 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001161 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001162 }
1163 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001164 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001165 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001166 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001167}
1168
1169/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001170DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001171 Token start;
1172 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001173 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001174 }
1175 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001176 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001177 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001178 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001179}
1180
1181/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001182DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001183 Token start;
1184 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001185 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001186 }
1187 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001188 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001189 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001190 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001191}
1192
1193/* LBRACE statement* RBRACE */
1194skstd::optional<DSLBlock> DSLParser::block() {
1195 Token start;
1196 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1197 return skstd::nullopt;
1198 }
1199 AutoDSLDepth depth(this);
1200 if (!depth.increase()) {
1201 return skstd::nullopt;
1202 }
1203 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001204 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001205 for (;;) {
1206 switch (this->peek().fKind) {
1207 case Token::Kind::TK_RBRACE:
1208 this->nextToken();
1209 return DSLBlock(std::move(statements), CurrentSymbolTable());
1210 case Token::Kind::TK_END_OF_FILE:
1211 this->error(this->peek(), "expected '}', but found end of file");
1212 return skstd::nullopt;
1213 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001214 DSLStatement statement = this->statement();
1215 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001216 return skstd::nullopt;
1217 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001218 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001219 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001220 }
1221 }
1222 }
1223}
1224
1225/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001226DSLStatement DSLParser::expressionStatement() {
1227 DSLExpression expr = this->expression();
1228 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001229 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001230 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001231 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001232 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001233 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001234 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001235}
1236
1237/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001238DSLExpression DSLParser::expression() {
1239 DSLExpression result = this->assignmentExpression();
1240 if (!result.hasValue()) {
1241 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001242 }
1243 Token t;
1244 AutoDSLDepth depth(this);
1245 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1246 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001247 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001248 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001249 DSLExpression right = this->assignmentExpression();
1250 if (!right.hasValue()) {
1251 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001252 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001253 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1254 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001255 }
1256 return result;
1257}
1258
1259#define OPERATOR_RIGHT(op, exprType) \
1260 do { \
1261 this->nextToken(); \
1262 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001263 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001264 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001265 DSLExpression right = this->exprType(); \
1266 if (!right.hasValue()) { \
1267 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001268 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001269 DSLExpression next = std::move(result) op std::move(right); \
1270 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001271 } while (false)
1272
1273/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1274 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1275 assignmentExpression)*
1276 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001277DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001278 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001279 DSLExpression result = this->ternaryExpression();
1280 if (!result.hasValue()) {
1281 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001282 }
1283 for (;;) {
1284 switch (this->peek().fKind) {
1285 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1286 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1287 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1288 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1289 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1290 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1291 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1292 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1293 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1294 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1295 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1296 default:
1297 return result;
1298 }
1299 }
1300}
1301
1302/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001303DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001304 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001305 DSLExpression base = this->logicalOrExpression();
1306 if (!base.hasValue()) {
1307 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001308 }
1309 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1310 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001311 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001312 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001313 DSLExpression trueExpr = this->expression();
1314 if (!trueExpr.hasValue()) {
1315 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001316 }
1317 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001318 DSLExpression falseExpr = this->assignmentExpression();
1319 if (!falseExpr.hasValue()) {
1320 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001321 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001322 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001323 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001324 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001325 }
1326 return base;
1327}
1328
1329/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001330DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001331 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001332 DSLExpression result = this->logicalXorExpression();
1333 if (!result.hasValue()) {
1334 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001335 }
1336 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1337 OPERATOR_RIGHT(||, logicalXorExpression);
1338 }
1339 return result;
1340}
1341
1342/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001343DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001344 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001345 DSLExpression result = this->logicalAndExpression();
1346 if (!result.hasValue()) {
1347 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001348 }
1349 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1350 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001351 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001352 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001353 DSLExpression right = this->logicalAndExpression();
1354 if (!right.hasValue()) {
1355 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001356 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001357 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1358 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001359 }
1360 return result;
1361}
1362
1363/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001364DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001365 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001366 DSLExpression result = this->bitwiseOrExpression();
1367 if (!result.hasValue()) {
1368 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001369 }
1370 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1371 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1372 }
1373 return result;
1374}
1375
1376/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001377DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001378 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001379 DSLExpression result = this->bitwiseXorExpression();
1380 if (!result.hasValue()) {
1381 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001382 }
1383 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1384 OPERATOR_RIGHT(|, bitwiseXorExpression);
1385 }
1386 return result;
1387}
1388
1389/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001390DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001391 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001392 DSLExpression result = this->bitwiseAndExpression();
1393 if (!result.hasValue()) {
1394 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001395 }
1396 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1397 OPERATOR_RIGHT(^, bitwiseAndExpression);
1398 }
1399 return result;
1400}
1401
1402/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001403DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001404 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001405 DSLExpression result = this->equalityExpression();
1406 if (!result.hasValue()) {
1407 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001408 }
1409 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1410 OPERATOR_RIGHT(&, equalityExpression);
1411 }
1412 return result;
1413}
1414
1415/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001416DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001417 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001418 DSLExpression result = this->relationalExpression();
1419 if (!result.hasValue()) {
1420 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001421 }
1422 for (;;) {
1423 switch (this->peek().fKind) {
1424 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1425 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1426 default: return result;
1427 }
1428 }
1429}
1430
1431/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001432DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001433 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001434 DSLExpression result = this->shiftExpression();
1435 if (!result.hasValue()) {
1436 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001437 }
1438 for (;;) {
1439 switch (this->peek().fKind) {
1440 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1441 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1442 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1443 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1444 default: return result;
1445 }
1446 }
1447}
1448
1449/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001450DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001451 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001452 DSLExpression result = this->additiveExpression();
1453 if (!result.hasValue()) {
1454 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001455 }
1456 for (;;) {
1457 switch (this->peek().fKind) {
1458 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1459 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1460 default: return result;
1461 }
1462 }
1463}
1464
1465/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001466DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001467 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001468 DSLExpression result = this->multiplicativeExpression();
1469 if (!result.hasValue()) {
1470 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001471 }
1472 for (;;) {
1473 switch (this->peek().fKind) {
1474 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1475 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1476 default: return result;
1477 }
1478 }
1479}
1480
1481/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001482DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001483 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001484 DSLExpression result = this->unaryExpression();
1485 if (!result.hasValue()) {
1486 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001487 }
1488 for (;;) {
1489 switch (this->peek().fKind) {
1490 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1491 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1492 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1493 default: return result;
1494 }
1495 }
1496}
1497
1498/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001499DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001500 AutoDSLDepth depth(this);
1501 Token next = this->peek();
1502 switch (next.fKind) {
1503 case Token::Kind::TK_PLUS:
1504 case Token::Kind::TK_MINUS:
1505 case Token::Kind::TK_LOGICALNOT:
1506 case Token::Kind::TK_BITWISENOT:
1507 case Token::Kind::TK_PLUSPLUS:
1508 case Token::Kind::TK_MINUSMINUS: {
1509 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001510 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001511 }
1512 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001513 DSLExpression expr = this->unaryExpression();
1514 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001515 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001516 }
1517 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001518 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1519 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1520 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1521 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1522 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1523 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001524 default: SkUNREACHABLE;
1525 }
1526 }
1527 default:
1528 return this->postfixExpression();
1529 }
1530}
1531
1532/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001533DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001534 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001535 DSLExpression result = this->term();
1536 if (!result.hasValue()) {
1537 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001538 }
1539 for (;;) {
1540 Token t = this->peek();
1541 switch (t.fKind) {
1542 case Token::Kind::TK_FLOAT_LITERAL:
1543 if (this->text(t)[0] != '.') {
1544 return result;
1545 }
1546 [[fallthrough]];
1547 case Token::Kind::TK_LBRACKET:
1548 case Token::Kind::TK_DOT:
1549 case Token::Kind::TK_LPAREN:
1550 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001551 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001552 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001553 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001554 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001555 DSLExpression next = this->suffix(std::move(result));
1556 if (!next.hasValue()) {
1557 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001558 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001559 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001560 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001561 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001562 default:
1563 return result;
1564 }
1565 }
1566}
1567
Brian Osmancc914522021-09-24 18:58:37 +00001568DSLExpression DSLParser::swizzle(int offset, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001569 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001570 SkASSERT(swizzleMask.length() > 0);
1571 if (!base.type().isVector() && !base.type().isScalar()) {
Brian Osmancc914522021-09-24 18:58:37 +00001572 return base.field(swizzleMask, this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001573 }
1574 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001575 SkSL::SwizzleComponent::Type components[4];
1576 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001577 if (i >= 4) {
Brian Osmancc914522021-09-24 18:58:37 +00001578 this->error(offset, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001579 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001580 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001581 switch (swizzleMask[i]) {
1582 case '0': components[i] = SwizzleComponent::ZERO; break;
1583 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001584 case 'r': components[i] = SwizzleComponent::R; break;
1585 case 'x': components[i] = SwizzleComponent::X; break;
1586 case 's': components[i] = SwizzleComponent::S; break;
1587 case 'L': components[i] = SwizzleComponent::UL; break;
1588 case 'g': components[i] = SwizzleComponent::G; break;
1589 case 'y': components[i] = SwizzleComponent::Y; break;
1590 case 't': components[i] = SwizzleComponent::T; break;
1591 case 'T': components[i] = SwizzleComponent::UT; break;
1592 case 'b': components[i] = SwizzleComponent::B; break;
1593 case 'z': components[i] = SwizzleComponent::Z; break;
1594 case 'p': components[i] = SwizzleComponent::P; break;
1595 case 'R': components[i] = SwizzleComponent::UR; break;
1596 case 'a': components[i] = SwizzleComponent::A; break;
1597 case 'w': components[i] = SwizzleComponent::W; break;
1598 case 'q': components[i] = SwizzleComponent::Q; break;
1599 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001600 default:
Brian Osmancc914522021-09-24 18:58:37 +00001601 this->error(offset,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001602 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001603 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001604 }
1605 }
1606 switch (length) {
1607 case 1: return dsl::Swizzle(std::move(base), components[0]);
1608 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1609 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1610 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1611 components[3]);
1612 default: SkUNREACHABLE;
1613 }
1614}
1615
Brian Osmancc914522021-09-24 18:58:37 +00001616dsl::DSLExpression DSLParser::call(int offset, dsl::DSLExpression base, ExpressionArray args) {
1617 return DSLExpression(base(std::move(args), this->position(offset)), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001618}
1619
1620/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1621 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001622DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001623 Token next = this->nextToken();
1624 AutoDSLDepth depth(this);
1625 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001626 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001627 }
1628 switch (next.fKind) {
1629 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001630 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1631 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001632 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001633 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001634 DSLExpression index = this->expression();
1635 if (!index.hasValue()) {
1636 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001637 }
1638 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001639 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001640 if (!result.valid()) {
1641 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001642 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001643 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001644 }
1645 case Token::Kind::TK_DOT: {
Brian Osmana909dd62021-09-24 19:00:35 +00001646 int offset = this->peek().fOffset;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001647 skstd::string_view text;
1648 if (this->identifier(&text)) {
Brian Osmana909dd62021-09-24 19:00:35 +00001649 return this->swizzle(offset, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001650 }
1651 [[fallthrough]];
1652 }
1653 case Token::Kind::TK_FLOAT_LITERAL: {
1654 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1655 // floating point literals, possibly followed by an identifier. Handle that here.
1656 skstd::string_view field = this->text(next);
1657 SkASSERT(field[0] == '.');
1658 field.remove_prefix(1);
1659 // use the next *raw* token so we don't ignore whitespace - we only care about
1660 // identifiers that directly follow the float
1661 Token id = this->nextRawToken();
1662 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Brian Osmana909dd62021-09-24 19:00:35 +00001663 return this->swizzle(next.fOffset, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001664 } else if (field.empty()) {
1665 this->error(next, "expected field name or swizzle mask after '.'");
1666 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001667 }
1668 this->pushback(id);
Brian Osmana909dd62021-09-24 19:00:35 +00001669 return this->swizzle(next.fOffset, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001670 }
1671 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001672 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001673 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1674 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001675 DSLExpression expr = this->assignmentExpression();
1676 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001677 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001678 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001679 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001680 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1681 break;
1682 }
1683 }
1684 }
1685 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Brian Osmana909dd62021-09-24 19:00:35 +00001686 return this->call(next.fOffset, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001687 }
1688 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001689 return std::move(base)++;
1690 case Token::Kind::TK_MINUSMINUS:
1691 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001692 default: {
1693 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001694 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001695 }
1696 }
1697}
1698
1699/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001700DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001701 Token t = this->peek();
1702 switch (t.fKind) {
1703 case Token::Kind::TK_IDENTIFIER: {
1704 skstd::string_view text;
1705 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001706 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001707 }
1708 break;
1709 }
1710 case Token::Kind::TK_INT_LITERAL: {
1711 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001712 if (!this->intLiteral(&i)) {
1713 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001714 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001715 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001716 }
1717 case Token::Kind::TK_FLOAT_LITERAL: {
1718 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001719 if (!this->floatLiteral(&f)) {
1720 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001721 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001722 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001723 }
1724 case Token::Kind::TK_TRUE_LITERAL: // fall through
1725 case Token::Kind::TK_FALSE_LITERAL: {
1726 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001727 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001728 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001729 }
1730 case Token::Kind::TK_LPAREN: {
1731 this->nextToken();
1732 AutoDSLDepth depth(this);
1733 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001734 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001735 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001736 DSLExpression result = this->expression();
1737 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001738 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1739 return result;
1740 }
1741 break;
1742 }
1743 default:
1744 this->nextToken();
Brian Osmana909dd62021-09-24 19:00:35 +00001745 this->error(t.fOffset, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001746 fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001747 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001748 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001749}
1750
1751/* INT_LITERAL */
1752bool DSLParser::intLiteral(SKSL_INT* dest) {
1753 Token t;
1754 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1755 return false;
1756 }
1757 skstd::string_view s = this->text(t);
1758 if (!SkSL::stoi(s, dest)) {
1759 this->error(t, "integer is too large: " + s);
1760 return false;
1761 }
1762 return true;
1763}
1764
1765/* FLOAT_LITERAL */
1766bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1767 Token t;
1768 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1769 return false;
1770 }
1771 skstd::string_view s = this->text(t);
1772 if (!SkSL::stod(s, dest)) {
1773 this->error(t, "floating-point value is too large: " + s);
1774 return false;
1775 }
1776 return true;
1777}
1778
1779/* TRUE_LITERAL | FALSE_LITERAL */
1780bool DSLParser::boolLiteral(bool* dest) {
1781 Token t = this->nextToken();
1782 switch (t.fKind) {
1783 case Token::Kind::TK_TRUE_LITERAL:
1784 *dest = true;
1785 return true;
1786 case Token::Kind::TK_FALSE_LITERAL:
1787 *dest = false;
1788 return true;
1789 default:
1790 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1791 return false;
1792 }
1793}
1794
1795/* IDENTIFIER */
1796bool DSLParser::identifier(skstd::string_view* dest) {
1797 Token t;
1798 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1799 *dest = this->text(t);
1800 return true;
1801 }
1802 return false;
1803}
1804
1805} // namespace SkSL
1806
1807#endif // SKSL_DSL_PARSER