blob: 8b283e92686d5170978be17dfd79e6ed3898e184 [file] [log] [blame]
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001/*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/sksl/SkSLDSLParser.h"
9
10#include "include/private/SkSLString.h"
11#include "src/sksl/SkSLCompiler.h"
Ethan Nicholas6c302ba2021-09-14 09:16:12 -040012#include "src/sksl/dsl/priv/DSLWriter.h"
Ethan Nicholas051aeb72021-09-24 16:39:19 -040013#include "src/sksl/dsl/priv/DSL_priv.h"
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040014
15#include <memory>
16
17#if SKSL_DSL_PARSER
18
19using namespace SkSL::dsl;
20
21namespace SkSL {
22
23static constexpr int kMaxParseDepth = 50;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040024
25static int parse_modifier_token(Token::Kind token) {
26 switch (token) {
27 case Token::Kind::TK_UNIFORM: return Modifiers::kUniform_Flag;
28 case Token::Kind::TK_CONST: return Modifiers::kConst_Flag;
29 case Token::Kind::TK_IN: return Modifiers::kIn_Flag;
30 case Token::Kind::TK_OUT: return Modifiers::kOut_Flag;
31 case Token::Kind::TK_INOUT: return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
32 case Token::Kind::TK_FLAT: return Modifiers::kFlat_Flag;
33 case Token::Kind::TK_NOPERSPECTIVE: return Modifiers::kNoPerspective_Flag;
34 case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
35 case Token::Kind::TK_INLINE: return Modifiers::kInline_Flag;
36 case Token::Kind::TK_NOINLINE: return Modifiers::kNoInline_Flag;
John Stiles02014312021-08-04 16:03:12 -040037 case Token::Kind::TK_HIGHP: return Modifiers::kHighp_Flag;
38 case Token::Kind::TK_MEDIUMP: return Modifiers::kMediump_Flag;
39 case Token::Kind::TK_LOWP: return Modifiers::kLowp_Flag;
John Stilesefde90d2021-08-12 23:06:24 -040040 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040041 default: return 0;
42 }
43}
44
45class AutoDSLDepth {
46public:
47 AutoDSLDepth(DSLParser* p)
48 : fParser(p)
49 , fDepth(0) {}
50
51 ~AutoDSLDepth() {
52 fParser->fDepth -= fDepth;
53 }
54
55 bool increase() {
56 ++fDepth;
57 ++fParser->fDepth;
58 if (fParser->fDepth > kMaxParseDepth) {
59 fParser->error(fParser->peek(), String("exceeded max parse depth"));
60 return false;
61 }
62 return true;
63 }
64
65private:
66 DSLParser* fParser;
67 int fDepth;
68};
69
70class AutoDSLSymbolTable {
71public:
72 AutoDSLSymbolTable() {
73 dsl::PushSymbolTable();
74 }
75
76 ~AutoDSLSymbolTable() {
77 dsl::PopSymbolTable();
78 }
79};
80
81std::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
82
83void DSLParser::InitLayoutMap() {
84 layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
85 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
86 TOKEN(LOCATION, "location");
87 TOKEN(OFFSET, "offset");
88 TOKEN(BINDING, "binding");
89 TOKEN(INDEX, "index");
90 TOKEN(SET, "set");
91 TOKEN(BUILTIN, "builtin");
92 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
93 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
94 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
95 TOKEN(PUSH_CONSTANT, "push_constant");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -040096 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
97 #undef TOKEN
98}
99
100DSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
101 String text)
102 : fCompiler(*compiler)
103 , fSettings(settings)
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400104 , fKind(kind)
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400105 , fText(std::make_unique<String>(std::move(text)))
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400106 , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1, /*line=*/-1) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400107 // We don't want to have to worry about manually releasing all of the objects in the event that
108 // an error occurs
109 fSettings.fAssertDSLObjectsReleased = false;
Ethan Nicholasae9b4462021-09-16 16:23:05 -0400110 // We manage our symbol tables manually, so no need for name mangling
111 fSettings.fDSLMangling = false;
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400112 fLexer.start(*fText);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400113 static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
114 (void) layoutMapInitialized;
115}
116
117Token DSLParser::nextRawToken() {
118 if (fPushback.fKind != Token::Kind::TK_NONE) {
119 Token result = fPushback;
120 fPushback.fKind = Token::Kind::TK_NONE;
121 return result;
122 }
123 return fLexer.next();
124}
125
126Token DSLParser::nextToken() {
127 Token token = this->nextRawToken();
128 while (token.fKind == Token::Kind::TK_WHITESPACE ||
129 token.fKind == Token::Kind::TK_LINE_COMMENT ||
130 token.fKind == Token::Kind::TK_BLOCK_COMMENT) {
131 token = this->nextRawToken();
132 }
133 return token;
134}
135
136void DSLParser::pushback(Token t) {
137 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
138 fPushback = std::move(t);
139}
140
141Token DSLParser::peek() {
142 if (fPushback.fKind == Token::Kind::TK_NONE) {
143 fPushback = this->nextToken();
144 }
145 return fPushback;
146}
147
148bool DSLParser::checkNext(Token::Kind kind, Token* result) {
149 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
150 return false;
151 }
152 Token next = this->nextToken();
153 if (next.fKind == kind) {
154 if (result) {
155 *result = next;
156 }
157 return true;
158 }
159 this->pushback(std::move(next));
160 return false;
161}
162
163bool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
164 Token next = this->nextToken();
165 if (next.fKind == kind) {
166 if (result) {
167 *result = std::move(next);
168 }
169 return true;
170 } else {
171 this->error(next, "expected " + String(expected) + ", but found '" +
172 this->text(next) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400173 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400174 return false;
175 }
176}
177
178bool DSLParser::expectIdentifier(Token* result) {
179 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
180 return false;
181 }
182 if (IsType(this->text(*result))) {
183 this->error(*result, "expected an identifier, but found type '" +
184 this->text(*result) + "'");
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400185 this->fEncounteredFatalError = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400186 return false;
187 }
188 return true;
189}
190
191skstd::string_view DSLParser::text(Token token) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400192 return skstd::string_view(fText->data() + token.fOffset, token.fLength);
193}
194
195PositionInfo DSLParser::position(Token t) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400196 return this->position(t.fLine);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400197}
198
Brian Osmancc914522021-09-24 18:58:37 +0000199PositionInfo DSLParser::position(int offset) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400200 return PositionInfo("<unknown>", offset);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400201}
202
203void DSLParser::error(Token token, String msg) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400204 this->error(token.fLine, msg);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400205}
206
Brian Osmancc914522021-09-24 18:58:37 +0000207void DSLParser::error(int offset, String msg) {
208 GetErrorReporter().error(msg.c_str(), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400209}
210
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400211/* declaration* END_OF_FILE */
212std::unique_ptr<Program> DSLParser::program() {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400213 ErrorReporter* errorReporter = &fCompiler.errorReporter();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400214 Start(&fCompiler, fKind, fSettings);
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400215 SetErrorReporter(errorReporter);
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400216 errorReporter->setSource(fText->c_str());
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400217 this->declarations();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400218 std::unique_ptr<Program> result;
Ethan Nicholas051aeb72021-09-24 16:39:19 -0400219 if (!GetErrorReporter().errorCount()) {
220 result = dsl::ReleaseProgram(std::move(fText));
221 }
222 errorReporter->setSource(nullptr);
223 End();
224 return result;
225}
226
227SkSL::LoadedModule DSLParser::moduleInheritingFrom(SkSL::ParsedModule baseModule) {
228 ErrorReporter* errorReporter = &fCompiler.errorReporter();
229 StartModule(&fCompiler, fKind, fSettings, std::move(baseModule));
230 SetErrorReporter(errorReporter);
231 errorReporter->setSource(fText->c_str());
232 this->declarations();
233 CurrentSymbolTable()->takeOwnershipOfString(std::move(*fText));
234 SkSL::LoadedModule result{ fKind, CurrentSymbolTable(),
235 std::move(DSLWriter::ProgramElements()) };
236 errorReporter->setSource(nullptr);
237 End();
238 return result;
239}
240
241void DSLParser::declarations() {
242 fEncounteredFatalError = false;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400243 bool done = false;
244 while (!done) {
245 switch (this->peek().fKind) {
246 case Token::Kind::TK_END_OF_FILE:
247 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400248 break;
Ethan Nicholas642215e2021-09-03 11:10:54 -0400249 case Token::Kind::TK_DIRECTIVE:
250 this->directive();
251 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400252 case Token::Kind::TK_INVALID: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400253 this->nextToken();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400254 this->error(this->peek(), String("invalid token"));
Ethan Nicholasf8f1fa02021-08-29 14:12:17 -0400255 done = true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400256 break;
257 }
Ethan Nicholas5d97a962021-08-30 15:58:52 -0400258 default:
259 this->declaration();
260 done = fEncounteredFatalError;
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400261 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400262 }
263 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400264}
265
Ethan Nicholas642215e2021-09-03 11:10:54 -0400266/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
267void DSLParser::directive() {
268 Token start;
269 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
270 return;
271 }
272 skstd::string_view text = this->text(start);
273 if (text == "#extension") {
274 Token name;
275 if (!this->expectIdentifier(&name)) {
276 return;
277 }
278 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
279 return;
280 }
281 Token behavior;
282 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
283 return;
284 }
285 skstd::string_view behaviorText = this->text(behavior);
286 if (behaviorText == "disable") {
287 return;
288 }
289 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
290 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
291 }
292 // We don't currently do anything different between require, enable, and warn
293 dsl::AddExtension(this->text(name));
294 } else {
295 this->error(start, "unsupported directive '" + this->text(start) + "'");
296 }
297}
298
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400299/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
300 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
301bool DSLParser::declaration() {
302 Token lookahead = this->peek();
303 switch (lookahead.fKind) {
304 case Token::Kind::TK_SEMICOLON:
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400305 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400306 this->error(lookahead, "expected a declaration, but found ';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400307 return false;
308 default:
309 break;
310 }
311 DSLModifiers modifiers = this->modifiers();
312 lookahead = this->peek();
313 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
314 // we have an identifier that's not a type, could be the start of an interface block
315 return this->interfaceBlock(modifiers);
316 }
317 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
Ethan Nicholas678ec712021-09-03 06:33:47 -0400318 this->nextToken();
319 Declare(modifiers, position(lookahead));
320 return true;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400321 }
322 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400323 this->structVarDeclaration(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400324 return true;
325 }
John Stiles4adb66f2021-08-05 10:15:16 -0400326 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400327 if (!type) {
328 return false;
329 }
330 Token name;
331 if (!this->expectIdentifier(&name)) {
332 return false;
333 }
334 if (this->checkNext(Token::Kind::TK_LPAREN)) {
335 return this->functionDeclarationEnd(modifiers, *type, name);
336 } else {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400337 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400338 return true;
339 }
340}
341
342/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400343bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
344 DSLType type,
345 const Token& name) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400346 SkTArray<DSLWrapper<DSLParameter>> parameters;
347 Token lookahead = this->peek();
348 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
349 // `()` means no parameters at all.
350 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
351 // `(void)` also means no parameters at all.
352 this->nextToken();
353 } else {
354 for (;;) {
355 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
356 if (!parameter) {
357 return false;
358 }
359 parameters.push_back(std::move(*parameter));
360 if (!this->checkNext(Token::Kind::TK_COMMA)) {
361 break;
362 }
363 }
364 }
365 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
366 return false;
367 }
368 SkTArray<DSLParameter*> parameterPointers;
369 for (DSLWrapper<DSLParameter>& param : parameters) {
370 parameterPointers.push_back(&param.get());
371 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400372 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400373 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
374 AutoDSLSymbolTable symbols;
375 for (DSLParameter* var : parameterPointers) {
376 AddToSymbolTable(*var);
377 }
378 skstd::optional<DSLBlock> body = this->block();
379 if (!body) {
380 return false;
381 }
Ethan Nicholasc9d65f02021-09-10 11:57:46 -0400382 result.define(std::move(*body), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400383 }
384 return true;
385}
386
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400387SKSL_INT DSLParser::arraySize() {
388 Token next = this->peek();
389 if (next.fKind == Token::Kind::TK_INT_LITERAL) {
390 SKSL_INT size;
391 if (this->intLiteral(&size)) {
392 if (size > INT32_MAX) {
393 this->error(next, "array size out of bounds");
394 return 1;
395 }
396 if (size <= 0) {
397 this->error(next, "array size must be positive");
398 return 1;
399 }
400 return size;
401 }
402 return 1;
403 } else if (this->checkNext(Token::Kind::TK_MINUS) &&
404 this->checkNext(Token::Kind::TK_INT_LITERAL)) {
405 this->error(next, "array size must be positive");
406 return 1;
407 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400408 DSLExpression expr = this->expression();
409 if (expr.isValid()) {
Ethan Nicholas51b4b862021-08-31 16:12:40 -0400410 this->error(next, "expected int literal");
411 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400412 return 1;
413 }
414}
415
Brian Osmancc914522021-09-24 18:58:37 +0000416bool DSLParser::parseArrayDimensions(int offset, DSLType* type) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400417 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
418 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
Brian Osmancc914522021-09-24 18:58:37 +0000419 this->error(offset, "expected array dimension");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400420 } else {
Brian Osmancc914522021-09-24 18:58:37 +0000421 *type = Array(*type, this->arraySize(), this->position(offset));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400422 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400423 return false;
424 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400425 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400426 }
427 return true;
428}
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400429
Brian Osmancc914522021-09-24 18:58:37 +0000430bool DSLParser::parseInitializer(int offset, DSLExpression* initializer) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400431 if (this->checkNext(Token::Kind::TK_EQ)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400432 DSLExpression value = this->assignmentExpression();
433 if (!value.hasValue()) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400434 return false;
435 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400436 initializer->swap(value);
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400437 }
438 return true;
439}
440
441/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
442 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
443void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
444 dsl::DSLType baseType, skstd::string_view name) {
445 using namespace dsl;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400446 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400447 DSLType type = baseType;
448 DSLExpression initializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400449 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400450 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400451 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400452 if (!this->parseInitializer(line, &initializer)) {
John Stilesb05bbd02021-09-24 15:11:16 -0400453 return;
454 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400455 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
456 Declare(first);
457 AddToSymbolTable(first);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400458
459 while (this->checkNext(Token::Kind::TK_COMMA)) {
460 type = baseType;
461 Token identifierName;
462 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400463 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400464 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400465 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400466 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400467 }
Ethan Nicholas0ed278b2021-09-03 13:06:31 -0400468 DSLExpression anotherInitializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400469 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400470 return;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400471 }
John Stilesb05bbd02021-09-24 15:11:16 -0400472 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400473 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400474 Declare(next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400475 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400476 }
Ethan Nicholasb9c64892021-09-02 10:31:25 -0400477 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400478}
479
480/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
481 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400482DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
483 dsl::DSLType baseType, skstd::string_view name) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400484 using namespace dsl;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400485 int line = this->peek().fLine;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400486 DSLType type = baseType;
487 DSLExpression initializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400488 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400489 return {};
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400490 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400491 if (!this->parseInitializer(line, &initializer)) {
John Stilesb05bbd02021-09-24 15:11:16 -0400492 return {};
493 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400494 DSLVar first(mods, type, name, std::move(initializer), pos);
495 DSLStatement result = Declare(first);
496 AddToSymbolTable(first);
497
498 while (this->checkNext(Token::Kind::TK_COMMA)) {
499 type = baseType;
500 Token identifierName;
501 if (!this->expectIdentifier(&identifierName)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400502 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400503 }
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400504 if (!this->parseArrayDimensions(line, &type)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400505 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400506 }
507 DSLExpression anotherInitializer;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400508 if (!this->parseInitializer(line, &anotherInitializer)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400509 return result;
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400510 }
John Stilesb05bbd02021-09-24 15:11:16 -0400511 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400512 this->position(line));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400513 DSLWriter::AddVarDeclaration(result, next);
Ethan Nicholasc973d262021-09-17 16:10:29 -0400514 AddToSymbolTable(next, this->position(identifierName));
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400515 }
516 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400517 return result;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400518}
519
520/* (varDeclarations | expressionStatement) */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400521DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400522 Token nextToken = this->peek();
523 if (nextToken.fKind == Token::Kind::TK_CONST) {
524 // Statements that begin with `const` might be variable declarations, but can't be legal
525 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
526 return this->varDeclarations();
527 }
528
John Stiles02014312021-08-04 16:03:12 -0400529 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
530 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
531 nextToken.fKind == Token::Kind::TK_LOWP ||
532 IsType(this->text(nextToken))) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400533 // Statements that begin with a typename are most often variable declarations, but
534 // occasionally the type is part of a constructor, and these are actually expression-
535 // statements in disguise. First, attempt the common case: parse it as a vardecl.
536 Checkpoint checkpoint(this);
537 VarDeclarationsPrefix prefix;
538 if (this->varDeclarationsPrefix(&prefix)) {
539 checkpoint.accept();
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400540 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
541 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400542 }
543
544 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
545 // expression-statement instead.
546 checkpoint.rewind();
547 }
548 return this->expressionStatement();
549}
550
551// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
552// statement is a variable-declaration statement, not an expression-statement.
553bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400554 prefixData->fPosition = this->position(this->peek());
555 prefixData->fModifiers = this->modifiers();
556 skstd::optional<DSLType> type = this->type(prefixData->fModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400557 if (!type) {
558 return false;
559 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400560 prefixData->fType = *type;
561 return this->expectIdentifier(&prefixData->fName);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400562}
563
564/* modifiers type IDENTIFIER varDeclarationEnd */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400565DSLStatement DSLParser::varDeclarations() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400566 VarDeclarationsPrefix prefix;
567 if (!this->varDeclarationsPrefix(&prefix)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400568 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400569 }
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400570 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
571 this->text(prefix.fName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400572}
573
574/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
575skstd::optional<DSLType> DSLParser::structDeclaration() {
576 AutoDSLDepth depth(this);
577 if (!depth.increase()) {
578 return skstd::nullopt;
579 }
580 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
581 return skstd::nullopt;
582 }
583 Token name;
584 if (!this->expectIdentifier(&name)) {
585 return skstd::nullopt;
586 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400587 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
588 return skstd::nullopt;
589 }
590 SkTArray<DSLField> fields;
591 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
592 DSLModifiers modifiers = this->modifiers();
593
John Stiles4adb66f2021-08-05 10:15:16 -0400594 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400595 if (!type) {
596 return skstd::nullopt;
597 }
598
599 do {
600 DSLType actualType = *type;
601 Token memberName;
602 if (!this->expectIdentifier(&memberName)) {
603 return skstd::nullopt;
604 }
605
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400606 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
607 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400608 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
609 return skstd::nullopt;
610 }
611 }
Ethan Nicholas0c8a5982021-08-31 11:48:54 -0400612 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
613 this->position(memberName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400614 } while (this->checkNext(Token::Kind::TK_COMMA));
615 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
616 return skstd::nullopt;
617 }
618 }
619 if (fields.empty()) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -0400620 this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400621 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400622 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400623}
624
625/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
John Stilese53c7212021-08-05 10:19:11 -0400626SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400627 skstd::optional<DSLType> type = this->structDeclaration();
628 if (!type) {
629 return {};
630 }
631 Token name;
632 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
Ethan Nicholas6c302ba2021-09-14 09:16:12 -0400633 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
634 this->text(name));
Ethan Nicholas3e7cd002021-09-15 16:19:03 -0400635 } else {
636 this->expect(Token::Kind::TK_SEMICOLON, "';'");
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400637 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400638 return {};
639}
640
641/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
642skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
643 DSLModifiers modifiers = this->modifiersWithDefaults(0);
John Stiles4adb66f2021-08-05 10:15:16 -0400644 skstd::optional<DSLType> type = this->type(modifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400645 if (!type) {
646 return skstd::nullopt;
647 }
648 Token name;
649 if (!this->expectIdentifier(&name)) {
650 return skstd::nullopt;
651 }
652 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400653 Token sizeToken;
654 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a positive integer", &sizeToken)) {
655 return skstd::nullopt;
656 }
657 skstd::string_view arraySizeFrag = this->text(sizeToken);
658 SKSL_INT arraySize;
659 if (!SkSL::stoi(arraySizeFrag, &arraySize)) {
660 this->error(sizeToken, "array size is too large: " + arraySizeFrag);
Ethan Nicholas709ecd52021-09-01 15:48:42 -0400661 arraySize = 1;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400662 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400663 type = Array(*type, arraySize, this->position(name));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400664 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
665 return skstd::nullopt;
666 }
667 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400668 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400669}
670
671/** EQ INT_LITERAL */
672int DSLParser::layoutInt() {
673 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
674 return -1;
675 }
676 Token resultToken;
677 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
678 return -1;
679 }
680 skstd::string_view resultFrag = this->text(resultToken);
681 SKSL_INT resultValue;
682 if (!SkSL::stoi(resultFrag, &resultValue)) {
683 this->error(resultToken, "value in layout is too large: " + resultFrag);
684 return -1;
685 }
686 return resultValue;
687}
688
689/** EQ IDENTIFIER */
690skstd::string_view DSLParser::layoutIdentifier() {
691 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
692 return {};
693 }
694 Token resultToken;
695 if (!this->expectIdentifier(&resultToken)) {
696 return {};
697 }
698 return this->text(resultToken);
699}
700
701/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
702DSLLayout DSLParser::layout() {
703 DSLLayout result;
704 if (this->checkNext(Token::Kind::TK_LAYOUT)) {
705 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
706 return result;
707 }
708 for (;;) {
709 Token t = this->nextToken();
710 String text(this->text(t));
711 auto found = layoutTokens->find(text);
712 if (found != layoutTokens->end()) {
713 switch (found->second) {
714 case LayoutToken::ORIGIN_UPPER_LEFT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400715 result.originUpperLeft(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400716 break;
717 case LayoutToken::PUSH_CONSTANT:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400718 result.pushConstant(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400719 break;
720 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400721 result.blendSupportAllEquations(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400722 break;
723 case LayoutToken::SRGB_UNPREMUL:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400724 result.srgbUnpremul(this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400725 break;
726 case LayoutToken::LOCATION:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400727 result.location(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400728 break;
729 case LayoutToken::OFFSET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400730 result.offset(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400731 break;
732 case LayoutToken::BINDING:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400733 result.binding(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400734 break;
735 case LayoutToken::INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400736 result.index(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400737 break;
738 case LayoutToken::SET:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400739 result.set(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400740 break;
741 case LayoutToken::BUILTIN:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400742 result.builtin(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400743 break;
744 case LayoutToken::INPUT_ATTACHMENT_INDEX:
Ethan Nicholasdf803aa2021-08-29 14:22:45 -0400745 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400746 break;
747 default:
748 this->error(t, "'" + text + "' is not a valid layout qualifier");
749 break;
750 }
751 } else {
752 this->error(t, "'" + text + "' is not a valid layout qualifier");
753 }
754 if (this->checkNext(Token::Kind::TK_RPAREN)) {
755 break;
756 }
757 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
758 break;
759 }
760 }
761 }
762 return result;
763}
764
765/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
766 VARYING | INLINE)* */
767DSLModifiers DSLParser::modifiers() {
768 DSLLayout layout = this->layout();
769 int flags = 0;
770 for (;;) {
771 // TODO(ethannicholas): handle duplicate / incompatible flags
772 int tokenFlag = parse_modifier_token(peek().fKind);
773 if (!tokenFlag) {
774 break;
775 }
776 flags |= tokenFlag;
777 this->nextToken();
778 }
779 return DSLModifiers(std::move(layout), flags);
780}
781
782DSLModifiers DSLParser::modifiersWithDefaults(int defaultFlags) {
783 DSLModifiers result = this->modifiers();
784 if (defaultFlags && !result.flags()) {
785 return DSLModifiers(result.layout(), defaultFlags);
786 }
787 return result;
788}
789
790/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400791DSLStatement DSLParser::statement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400792 Token start = this->nextToken();
793 AutoDSLDepth depth(this);
794 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400795 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400796 }
797 this->pushback(start);
798 switch (start.fKind) {
799 case Token::Kind::TK_IF: // fall through
800 case Token::Kind::TK_STATIC_IF:
801 return this->ifStatement();
802 case Token::Kind::TK_FOR:
803 return this->forStatement();
804 case Token::Kind::TK_DO:
805 return this->doStatement();
806 case Token::Kind::TK_WHILE:
807 return this->whileStatement();
808 case Token::Kind::TK_SWITCH: // fall through
809 case Token::Kind::TK_STATIC_SWITCH:
810 return this->switchStatement();
811 case Token::Kind::TK_RETURN:
812 return this->returnStatement();
813 case Token::Kind::TK_BREAK:
814 return this->breakStatement();
815 case Token::Kind::TK_CONTINUE:
816 return this->continueStatement();
817 case Token::Kind::TK_DISCARD:
818 return this->discardStatement();
819 case Token::Kind::TK_LBRACE: {
820 skstd::optional<DSLBlock> result = this->block();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400821 return result ? DSLStatement(std::move(*result)) : DSLStatement();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400822 }
823 case Token::Kind::TK_SEMICOLON:
824 this->nextToken();
825 return dsl::Block();
John Stiles02014312021-08-04 16:03:12 -0400826 case Token::Kind::TK_HIGHP:
827 case Token::Kind::TK_MEDIUMP:
828 case Token::Kind::TK_LOWP:
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400829 case Token::Kind::TK_CONST:
830 case Token::Kind::TK_IDENTIFIER:
831 return this->varDeclarationsOrExpressionStatement();
832 default:
833 return this->expressionStatement();
834 }
835}
836
837/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
John Stilese53c7212021-08-05 10:19:11 -0400838skstd::optional<DSLType> DSLParser::type(const DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400839 Token type;
840 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
841 return skstd::nullopt;
842 }
843 if (!IsType(this->text(type))) {
844 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
845 return skstd::nullopt;
846 }
Ethan Nicholasa248a9a2021-09-01 16:40:25 -0400847 DSLType result(this->text(type), modifiers, this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400848 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400849 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400850 result = Array(result, this->arraySize(), this->position(type));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400851 } else {
852 this->error(this->peek(), "expected array dimension");
853 }
854 this->expect(Token::Kind::TK_RBRACKET, "']'");
855 }
856 return result;
857}
858
859/* IDENTIFIER LBRACE
860 varDeclaration+
861 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
John Stilese53c7212021-08-05 10:19:11 -0400862bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400863 Token typeName;
864 if (!this->expectIdentifier(&typeName)) {
865 return false;
866 }
867 if (peek().fKind != Token::Kind::TK_LBRACE) {
868 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
869 // 99% of the time, the user was not actually intending to create an interface block, so
870 // it's better to report it as an unknown type
871 this->error(typeName, "no type named '" + this->text(typeName) + "'");
872 return false;
873 }
874 this->nextToken();
875 SkTArray<dsl::Field> fields;
876 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
Ethan Nicholas5c4463e2021-08-29 14:31:19 -0400877 DSLModifiers fieldModifiers = this->modifiers();
878 skstd::optional<dsl::DSLType> type = this->type(fieldModifiers);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400879 if (!type) {
880 return false;
881 }
882 do {
883 Token fieldName;
884 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
885 return false;
886 }
887 DSLType actualType = *type;
888 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
889 Token sizeToken = this->peek();
890 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400891 actualType = Array(std::move(actualType), this->arraySize(),
892 this->position(typeName));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400893 } else {
894 this->error(sizeToken, "unsized arrays are not permitted");
895 }
896 this->expect(Token::Kind::TK_RBRACKET, "']'");
897 }
898 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
899 return false;
900 }
Ethan Nicholas27633232021-08-29 13:51:44 -0400901 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
902 this->text(fieldName), this->position(fieldName)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400903 }
904 while (this->checkNext(Token::Kind::TK_COMMA));
905 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400906 skstd::string_view instanceName;
907 Token instanceNameToken;
908 SKSL_INT arraySize = 0;
909 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
910 instanceName = this->text(instanceNameToken);
911 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -0400912 arraySize = this->arraySize();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400913 this->expect(Token::Kind::TK_RBRACKET, "']'");
914 }
915 }
Ethan Nicholase110f6e2021-08-29 14:03:06 -0400916 this->expect(Token::Kind::TK_SEMICOLON, "';'");
John Stilesd0665d92021-09-17 09:14:28 -0400917 if (fields.empty()) {
918 this->error(typeName, "interface block '" + this->text(typeName) +
919 "' must contain at least one member");
920 } else {
921 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
922 arraySize, this->position(typeName));
923 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400924 return true;
925}
926
927/* IF LPAREN expression RPAREN statement (ELSE statement)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400928DSLStatement DSLParser::ifStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400929 Token start;
930 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
931 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400932 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400933 }
934 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400935 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400936 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400937 DSLExpression test = this->expression();
938 if (!test.hasValue()) {
939 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400940 }
941 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400942 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400943 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400944 DSLStatement ifTrue = this->statement();
945 if (!ifTrue.hasValue()) {
946 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400947 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400948 DSLStatement ifFalse;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400949 if (this->checkNext(Token::Kind::TK_ELSE)) {
950 ifFalse = this->statement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400951 if (!ifFalse.hasValue()) {
952 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400953 }
954 }
955 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400956 return StaticIf(std::move(test), std::move(ifTrue),
957 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400958 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400959 return If(std::move(test), std::move(ifTrue),
960 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400961 }
962}
963
964/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400965DSLStatement DSLParser::doStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400966 Token start;
967 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400968 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400969 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400970 DSLStatement statement = this->statement();
971 if (!statement.hasValue()) {
972 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400973 }
974 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400975 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400976 }
977 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400978 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400979 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400980 DSLExpression test = this->expression();
981 if (!test.hasValue()) {
982 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400983 }
984 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400985 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400986 }
987 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400988 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400989 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400990 return Do(std::move(statement), std::move(test), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400991}
992
993/* WHILE LPAREN expression RPAREN STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400994DSLStatement DSLParser::whileStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400995 Token start;
996 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -0400997 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -0400998 }
999 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001000 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001001 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001002 DSLExpression test = this->expression();
1003 if (!test.hasValue()) {
1004 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001005 }
1006 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001007 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001008 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001009 DSLStatement statement = this->statement();
1010 if (!statement.hasValue()) {
1011 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001012 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001013 return While(std::move(test), std::move(statement), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001014}
1015
1016/* CASE expression COLON statement* */
1017skstd::optional<DSLCase> DSLParser::switchCase() {
1018 Token start;
1019 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001020 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001021 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001022 DSLExpression value = this->expression();
1023 if (!value.hasValue()) {
1024 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001025 }
1026 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001027 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001028 }
1029 SkTArray<DSLStatement> statements;
1030 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1031 this->peek().fKind != Token::Kind::TK_CASE &&
1032 this->peek().fKind != Token::Kind::TK_DEFAULT) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001033 DSLStatement s = this->statement();
1034 if (!s.hasValue()) {
1035 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001036 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001037 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001038 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001039 return DSLCase(std::move(value), std::move(statements));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001040}
1041
1042/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001043DSLStatement DSLParser::switchStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001044 Token start;
1045 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1046 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001047 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001048 }
1049 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001050 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001051 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001052 DSLExpression value = this->expression();
1053 if (!value.hasValue()) {
1054 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001055 }
1056 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001057 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001058 }
1059 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001060 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001061 }
1062 SkTArray<DSLCase> cases;
1063 while (this->peek().fKind == Token::Kind::TK_CASE) {
1064 skstd::optional<DSLCase> c = this->switchCase();
1065 if (!c) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001066 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001067 }
1068 cases.push_back(std::move(*c));
1069 }
1070 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1071 // parts of the compiler may rely upon this assumption.
1072 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1073 SkTArray<DSLStatement> statements;
1074 Token defaultStart;
1075 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1076 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001077 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001078 }
1079 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001080 DSLStatement s = this->statement();
1081 if (!s.hasValue()) {
1082 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001083 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001084 statements.push_back(std::move(s));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001085 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001086 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001087 }
1088 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001089 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001090 }
1091 if (isStatic) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001092 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001093 } else {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001094 return Switch(std::move(value), std::move(cases), this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001095 }
1096}
1097
1098/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1099 STATEMENT */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001100dsl::DSLStatement DSLParser::forStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001101 Token start;
1102 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001103 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001104 }
1105 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001106 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001107 }
1108 AutoDSLSymbolTable symbols;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001109 dsl::DSLStatement initializer;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001110 Token nextToken = this->peek();
1111 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1112 // An empty init-statement.
1113 this->nextToken();
1114 } else {
1115 // The init-statement must be an expression or variable declaration.
1116 initializer = this->varDeclarationsOrExpressionStatement();
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001117 if (!initializer.hasValue()) {
1118 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001119 }
1120 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001121 dsl::DSLExpression test;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001122 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001123 dsl::DSLExpression testValue = this->expression();
1124 if (!testValue.hasValue()) {
1125 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001126 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001127 test.swap(testValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001128 }
1129 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001130 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001131 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001132 dsl::DSLExpression next;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001133 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001134 dsl::DSLExpression nextValue = this->expression();
1135 if (!nextValue.hasValue()) {
1136 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001137 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001138 next.swap(nextValue);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001139 }
1140 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001141 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001142 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001143 dsl::DSLStatement statement = this->statement();
1144 if (!statement.hasValue()) {
1145 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001146 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001147 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1148 test.hasValue() ? std::move(test) : DSLExpression(),
1149 next.hasValue() ? std::move(next) : DSLExpression(),
1150 std::move(statement),
Ethan Nicholas360db872021-09-03 17:00:09 -04001151 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001152}
1153
1154/* RETURN expression? SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001155DSLStatement DSLParser::returnStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001156 Token start;
1157 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001158 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001159 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001160 DSLExpression expression;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001161 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001162 DSLExpression next = this->expression();
1163 if (!next.hasValue()) {
1164 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001165 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001166 expression.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001167 }
1168 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001169 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001170 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001171 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1172 this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001173}
1174
1175/* BREAK SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001176DSLStatement DSLParser::breakStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001177 Token start;
1178 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001179 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001180 }
1181 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001182 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001183 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001184 return Break(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001185}
1186
1187/* CONTINUE SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001188DSLStatement DSLParser::continueStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001189 Token start;
1190 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001191 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001192 }
1193 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001194 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001195 }
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001196 return Continue(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001197}
1198
1199/* DISCARD SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001200DSLStatement DSLParser::discardStatement() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001201 Token start;
1202 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001203 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001204 }
1205 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001206 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001207 }
Ethan Nicholas360db872021-09-03 17:00:09 -04001208 return Discard(this->position(start));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001209}
1210
1211/* LBRACE statement* RBRACE */
1212skstd::optional<DSLBlock> DSLParser::block() {
1213 Token start;
1214 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1215 return skstd::nullopt;
1216 }
1217 AutoDSLDepth depth(this);
1218 if (!depth.increase()) {
1219 return skstd::nullopt;
1220 }
1221 AutoDSLSymbolTable symbols;
Ethan Nicholas96dbf742021-09-10 15:59:11 -04001222 StatementArray statements;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001223 for (;;) {
1224 switch (this->peek().fKind) {
1225 case Token::Kind::TK_RBRACE:
1226 this->nextToken();
1227 return DSLBlock(std::move(statements), CurrentSymbolTable());
1228 case Token::Kind::TK_END_OF_FILE:
1229 this->error(this->peek(), "expected '}', but found end of file");
1230 return skstd::nullopt;
1231 default: {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001232 DSLStatement statement = this->statement();
1233 if (!statement.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001234 return skstd::nullopt;
1235 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001236 statements.push_back(statement.release());
Ethan Nicholasb13f3692021-09-10 16:49:42 -04001237 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001238 }
1239 }
1240 }
1241}
1242
1243/* expression SEMICOLON */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001244DSLStatement DSLParser::expressionStatement() {
1245 DSLExpression expr = this->expression();
1246 if (expr.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001247 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001248 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001249 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001250 return DSLStatement(std::move(expr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001251 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001252 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001253}
1254
1255/* assignmentExpression (COMMA assignmentExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001256DSLExpression DSLParser::expression() {
1257 DSLExpression result = this->assignmentExpression();
1258 if (!result.hasValue()) {
1259 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001260 }
1261 Token t;
1262 AutoDSLDepth depth(this);
1263 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1264 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001265 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001266 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001267 DSLExpression right = this->assignmentExpression();
1268 if (!right.hasValue()) {
1269 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001270 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001271 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1272 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001273 }
1274 return result;
1275}
1276
1277#define OPERATOR_RIGHT(op, exprType) \
1278 do { \
1279 this->nextToken(); \
1280 if (!depth.increase()) { \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001281 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001282 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001283 DSLExpression right = this->exprType(); \
1284 if (!right.hasValue()) { \
1285 return {}; \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001286 } \
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001287 DSLExpression next = std::move(result) op std::move(right); \
1288 result.swap(next); \
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001289 } while (false)
1290
1291/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1292 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1293 assignmentExpression)*
1294 */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001295DSLExpression DSLParser::assignmentExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001296 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001297 DSLExpression result = this->ternaryExpression();
1298 if (!result.hasValue()) {
1299 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001300 }
1301 for (;;) {
1302 switch (this->peek().fKind) {
1303 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1304 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1305 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1306 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1307 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1308 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1309 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1310 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1311 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1312 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1313 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1314 default:
1315 return result;
1316 }
1317 }
1318}
1319
1320/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001321DSLExpression DSLParser::ternaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001322 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001323 DSLExpression base = this->logicalOrExpression();
1324 if (!base.hasValue()) {
1325 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001326 }
1327 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1328 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001329 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001330 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001331 DSLExpression trueExpr = this->expression();
1332 if (!trueExpr.hasValue()) {
1333 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001334 }
1335 if (this->expect(Token::Kind::TK_COLON, "':'")) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001336 DSLExpression falseExpr = this->assignmentExpression();
1337 if (!falseExpr.hasValue()) {
1338 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001339 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001340 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001341 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001342 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001343 }
1344 return base;
1345}
1346
1347/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001348DSLExpression DSLParser::logicalOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001349 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001350 DSLExpression result = this->logicalXorExpression();
1351 if (!result.hasValue()) {
1352 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001353 }
1354 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1355 OPERATOR_RIGHT(||, logicalXorExpression);
1356 }
1357 return result;
1358}
1359
1360/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001361DSLExpression DSLParser::logicalXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001362 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001363 DSLExpression result = this->logicalAndExpression();
1364 if (!result.hasValue()) {
1365 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001366 }
1367 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1368 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001369 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001370 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001371 DSLExpression right = this->logicalAndExpression();
1372 if (!right.hasValue()) {
1373 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001374 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001375 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1376 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001377 }
1378 return result;
1379}
1380
1381/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001382DSLExpression DSLParser::logicalAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001383 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001384 DSLExpression result = this->bitwiseOrExpression();
1385 if (!result.hasValue()) {
1386 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001387 }
1388 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1389 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1390 }
1391 return result;
1392}
1393
1394/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001395DSLExpression DSLParser::bitwiseOrExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001396 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001397 DSLExpression result = this->bitwiseXorExpression();
1398 if (!result.hasValue()) {
1399 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001400 }
1401 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1402 OPERATOR_RIGHT(|, bitwiseXorExpression);
1403 }
1404 return result;
1405}
1406
1407/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001408DSLExpression DSLParser::bitwiseXorExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001409 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001410 DSLExpression result = this->bitwiseAndExpression();
1411 if (!result.hasValue()) {
1412 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001413 }
1414 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1415 OPERATOR_RIGHT(^, bitwiseAndExpression);
1416 }
1417 return result;
1418}
1419
1420/* equalityExpression (BITWISEAND equalityExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001421DSLExpression DSLParser::bitwiseAndExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001422 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001423 DSLExpression result = this->equalityExpression();
1424 if (!result.hasValue()) {
1425 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001426 }
1427 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1428 OPERATOR_RIGHT(&, equalityExpression);
1429 }
1430 return result;
1431}
1432
1433/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001434DSLExpression DSLParser::equalityExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001435 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001436 DSLExpression result = this->relationalExpression();
1437 if (!result.hasValue()) {
1438 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001439 }
1440 for (;;) {
1441 switch (this->peek().fKind) {
1442 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1443 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1444 default: return result;
1445 }
1446 }
1447}
1448
1449/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001450DSLExpression DSLParser::relationalExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001451 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001452 DSLExpression result = this->shiftExpression();
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_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1459 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1460 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1461 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1462 default: return result;
1463 }
1464 }
1465}
1466
1467/* additiveExpression ((SHL | SHR) additiveExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001468DSLExpression DSLParser::shiftExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001469 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001470 DSLExpression result = this->additiveExpression();
1471 if (!result.hasValue()) {
1472 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001473 }
1474 for (;;) {
1475 switch (this->peek().fKind) {
1476 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1477 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1478 default: return result;
1479 }
1480 }
1481}
1482
1483/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001484DSLExpression DSLParser::additiveExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001485 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001486 DSLExpression result = this->multiplicativeExpression();
1487 if (!result.hasValue()) {
1488 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001489 }
1490 for (;;) {
1491 switch (this->peek().fKind) {
1492 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1493 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1494 default: return result;
1495 }
1496 }
1497}
1498
1499/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001500DSLExpression DSLParser::multiplicativeExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001501 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001502 DSLExpression result = this->unaryExpression();
1503 if (!result.hasValue()) {
1504 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001505 }
1506 for (;;) {
1507 switch (this->peek().fKind) {
1508 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1509 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1510 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1511 default: return result;
1512 }
1513 }
1514}
1515
1516/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001517DSLExpression DSLParser::unaryExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001518 AutoDSLDepth depth(this);
1519 Token next = this->peek();
1520 switch (next.fKind) {
1521 case Token::Kind::TK_PLUS:
1522 case Token::Kind::TK_MINUS:
1523 case Token::Kind::TK_LOGICALNOT:
1524 case Token::Kind::TK_BITWISENOT:
1525 case Token::Kind::TK_PLUSPLUS:
1526 case Token::Kind::TK_MINUSMINUS: {
1527 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001528 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001529 }
1530 this->nextToken();
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001531 DSLExpression expr = this->unaryExpression();
1532 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001533 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001534 }
1535 switch (next.fKind) {
Ethan Nicholas0dc1e0f2021-09-17 12:52:55 -04001536 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1537 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1538 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1539 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1540 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1541 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001542 default: SkUNREACHABLE;
1543 }
1544 }
1545 default:
1546 return this->postfixExpression();
1547 }
1548}
1549
1550/* term suffix* */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001551DSLExpression DSLParser::postfixExpression() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001552 AutoDSLDepth depth(this);
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001553 DSLExpression result = this->term();
1554 if (!result.hasValue()) {
1555 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001556 }
1557 for (;;) {
1558 Token t = this->peek();
1559 switch (t.fKind) {
1560 case Token::Kind::TK_FLOAT_LITERAL:
1561 if (this->text(t)[0] != '.') {
1562 return result;
1563 }
1564 [[fallthrough]];
1565 case Token::Kind::TK_LBRACKET:
1566 case Token::Kind::TK_DOT:
1567 case Token::Kind::TK_LPAREN:
1568 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001569 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001570 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001571 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001572 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001573 DSLExpression next = this->suffix(std::move(result));
1574 if (!next.hasValue()) {
1575 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001576 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001577 result.swap(next);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001578 break;
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001579 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001580 default:
1581 return result;
1582 }
1583 }
1584}
1585
Brian Osmancc914522021-09-24 18:58:37 +00001586DSLExpression DSLParser::swizzle(int offset, DSLExpression base,
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001587 skstd::string_view swizzleMask) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001588 SkASSERT(swizzleMask.length() > 0);
1589 if (!base.type().isVector() && !base.type().isScalar()) {
Brian Osmancc914522021-09-24 18:58:37 +00001590 return base.field(swizzleMask, this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001591 }
1592 int length = swizzleMask.length();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001593 SkSL::SwizzleComponent::Type components[4];
1594 for (int i = 0; i < length; ++i) {
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001595 if (i >= 4) {
Brian Osmancc914522021-09-24 18:58:37 +00001596 this->error(offset, "too many components in swizzle mask");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001597 return DSLExpression::Poison();
Ethan Nicholasbe8f73d2021-08-28 19:50:03 -04001598 }
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001599 switch (swizzleMask[i]) {
1600 case '0': components[i] = SwizzleComponent::ZERO; break;
1601 case '1': components[i] = SwizzleComponent::ONE; break;
Ethan Nicholasb61a2432021-09-02 16:38:43 -04001602 case 'r': components[i] = SwizzleComponent::R; break;
1603 case 'x': components[i] = SwizzleComponent::X; break;
1604 case 's': components[i] = SwizzleComponent::S; break;
1605 case 'L': components[i] = SwizzleComponent::UL; break;
1606 case 'g': components[i] = SwizzleComponent::G; break;
1607 case 'y': components[i] = SwizzleComponent::Y; break;
1608 case 't': components[i] = SwizzleComponent::T; break;
1609 case 'T': components[i] = SwizzleComponent::UT; break;
1610 case 'b': components[i] = SwizzleComponent::B; break;
1611 case 'z': components[i] = SwizzleComponent::Z; break;
1612 case 'p': components[i] = SwizzleComponent::P; break;
1613 case 'R': components[i] = SwizzleComponent::UR; break;
1614 case 'a': components[i] = SwizzleComponent::A; break;
1615 case 'w': components[i] = SwizzleComponent::W; break;
1616 case 'q': components[i] = SwizzleComponent::Q; break;
1617 case 'B': components[i] = SwizzleComponent::UB; break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001618 default:
Brian Osmancc914522021-09-24 18:58:37 +00001619 this->error(offset,
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001620 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001621 return DSLExpression::Poison();
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001622 }
1623 }
1624 switch (length) {
1625 case 1: return dsl::Swizzle(std::move(base), components[0]);
1626 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1627 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1628 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1629 components[3]);
1630 default: SkUNREACHABLE;
1631 }
1632}
1633
Brian Osmancc914522021-09-24 18:58:37 +00001634dsl::DSLExpression DSLParser::call(int offset, dsl::DSLExpression base, ExpressionArray args) {
1635 return DSLExpression(base(std::move(args), this->position(offset)), this->position(offset));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001636}
1637
1638/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1639 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001640DSLExpression DSLParser::suffix(DSLExpression base) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001641 Token next = this->nextToken();
1642 AutoDSLDepth depth(this);
1643 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001644 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001645 }
1646 switch (next.fKind) {
1647 case Token::Kind::TK_LBRACKET: {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001648 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1649 this->error(next, "missing index in '[]'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001650 return DSLExpression::Poison();
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001651 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001652 DSLExpression index = this->expression();
1653 if (!index.hasValue()) {
1654 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001655 }
1656 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001657 DSLPossibleExpression result = base[std::move(index)];
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001658 if (!result.valid()) {
1659 result.reportErrors(this->position(next));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001660 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001661 return std::move(result);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001662 }
1663 case Token::Kind::TK_DOT: {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001664 int line = this->peek().fLine;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001665 skstd::string_view text;
1666 if (this->identifier(&text)) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001667 return this->swizzle(line, std::move(base), text);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001668 }
1669 [[fallthrough]];
1670 }
1671 case Token::Kind::TK_FLOAT_LITERAL: {
1672 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1673 // floating point literals, possibly followed by an identifier. Handle that here.
1674 skstd::string_view field = this->text(next);
1675 SkASSERT(field[0] == '.');
1676 field.remove_prefix(1);
1677 // use the next *raw* token so we don't ignore whitespace - we only care about
1678 // identifiers that directly follow the float
1679 Token id = this->nextRawToken();
1680 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001681 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
Ethan Nicholasbf4a7d52021-09-09 09:32:13 -04001682 } else if (field.empty()) {
1683 this->error(next, "expected field name or swizzle mask after '.'");
1684 return {{DSLExpression::Poison()}};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001685 }
1686 this->pushback(id);
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001687 return this->swizzle(next.fLine, std::move(base), field);
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001688 }
1689 case Token::Kind::TK_LPAREN: {
Ethan Nicholas9a1f92e2021-09-09 15:03:22 -04001690 ExpressionArray args;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001691 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1692 for (;;) {
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001693 DSLExpression expr = this->assignmentExpression();
1694 if (!expr.hasValue()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001695 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001696 }
Ethan Nicholasf62934b2021-09-20 10:18:58 -04001697 args.push_back(expr.release());
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001698 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1699 break;
1700 }
1701 }
1702 }
1703 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001704 return this->call(next.fLine, std::move(base), std::move(args));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001705 }
1706 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001707 return std::move(base)++;
1708 case Token::Kind::TK_MINUSMINUS:
1709 return std::move(base)--;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001710 default: {
1711 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001712 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001713 }
1714 }
1715}
1716
1717/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001718DSLExpression DSLParser::term() {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001719 Token t = this->peek();
1720 switch (t.fKind) {
1721 case Token::Kind::TK_IDENTIFIER: {
1722 skstd::string_view text;
1723 if (this->identifier(&text)) {
Ethan Nicholas6f20b8d2021-08-31 07:40:24 -04001724 return dsl::Symbol(text, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001725 }
1726 break;
1727 }
1728 case Token::Kind::TK_INT_LITERAL: {
1729 SKSL_INT i;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001730 if (!this->intLiteral(&i)) {
1731 i = 0;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001732 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001733 return DSLExpression(i, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001734 }
1735 case Token::Kind::TK_FLOAT_LITERAL: {
1736 SKSL_FLOAT f;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001737 if (!this->floatLiteral(&f)) {
1738 f = 0.0f;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001739 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001740 return DSLExpression(f, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001741 }
1742 case Token::Kind::TK_TRUE_LITERAL: // fall through
1743 case Token::Kind::TK_FALSE_LITERAL: {
1744 bool b;
Ethan Nicholas0459a932021-09-01 14:54:44 -04001745 SkAssertResult(this->boolLiteral(&b));
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001746 return DSLExpression(b, this->position(t));
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001747 }
1748 case Token::Kind::TK_LPAREN: {
1749 this->nextToken();
1750 AutoDSLDepth depth(this);
1751 if (!depth.increase()) {
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001752 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001753 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001754 DSLExpression result = this->expression();
1755 if (result.hasValue()) {
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001756 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1757 return result;
1758 }
1759 break;
1760 }
1761 default:
1762 this->nextToken();
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001763 this->error(t, "expected expression, but found '" + this->text(t) + "'");
Ethan Nicholasad284fe2021-09-01 10:17:48 -04001764 fEncounteredFatalError = true;
Ethan Nicholas5fad2b882021-09-27 10:39:18 -04001765 break;
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001766 }
Ethan Nicholasb7cb38f2021-09-15 08:29:14 -04001767 return {};
Ethan Nicholasdd2fdea2021-07-20 15:23:04 -04001768}
1769
1770/* INT_LITERAL */
1771bool DSLParser::intLiteral(SKSL_INT* dest) {
1772 Token t;
1773 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1774 return false;
1775 }
1776 skstd::string_view s = this->text(t);
1777 if (!SkSL::stoi(s, dest)) {
1778 this->error(t, "integer is too large: " + s);
1779 return false;
1780 }
1781 return true;
1782}
1783
1784/* FLOAT_LITERAL */
1785bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1786 Token t;
1787 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1788 return false;
1789 }
1790 skstd::string_view s = this->text(t);
1791 if (!SkSL::stod(s, dest)) {
1792 this->error(t, "floating-point value is too large: " + s);
1793 return false;
1794 }
1795 return true;
1796}
1797
1798/* TRUE_LITERAL | FALSE_LITERAL */
1799bool DSLParser::boolLiteral(bool* dest) {
1800 Token t = this->nextToken();
1801 switch (t.fKind) {
1802 case Token::Kind::TK_TRUE_LITERAL:
1803 *dest = true;
1804 return true;
1805 case Token::Kind::TK_FALSE_LITERAL:
1806 *dest = false;
1807 return true;
1808 default:
1809 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1810 return false;
1811 }
1812}
1813
1814/* IDENTIFIER */
1815bool DSLParser::identifier(skstd::string_view* dest) {
1816 Token t;
1817 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1818 *dest = this->text(t);
1819 return true;
1820 }
1821 return false;
1822}
1823
1824} // namespace SkSL
1825
1826#endif // SKSL_DSL_PARSER