1 /*
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"
12 #include "src/sksl/SkSLConstantFolder.h"
13 #include "src/sksl/SkSLThreadContext.h"
14 #include "src/sksl/dsl/priv/DSLWriter.h"
15 #include "src/sksl/dsl/priv/DSL_priv.h"
16 #include <memory>
17
18 using namespace SkSL::dsl;
19
20 namespace SkSL {
21
22 static constexpr int kMaxParseDepth = 50;
23
parse_modifier_token(Token::Kind token)24 static 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;
36 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;
39 case Token::Kind::TK_ES3: return Modifiers::kES3_Flag;
40 #ifdef SKSL_EXT
41 case Token::Kind::TK_READONLY: return Modifiers::kReadOnly_Flag;
42 case Token::Kind::TK_WRITEONLY: return Modifiers::kWriteOnly_Flag;
43 case Token::Kind::TK_BUFFER: return Modifiers::kBuffer_Flag;
44 #endif
45 default: return 0;
46 }
47 }
48
49 class AutoDSLDepth {
50 public:
AutoDSLDepth(DSLParser * p)51 AutoDSLDepth(DSLParser* p)
52 : fParser(p)
53 , fDepth(0) {}
54
~AutoDSLDepth()55 ~AutoDSLDepth() {
56 fParser->fDepth -= fDepth;
57 }
58
increase()59 bool increase() {
60 ++fDepth;
61 ++fParser->fDepth;
62 if (fParser->fDepth > kMaxParseDepth) {
63 fParser->error(fParser->peek(), String("exceeded max parse depth"));
64 return false;
65 }
66 return true;
67 }
68
69 private:
70 DSLParser* fParser;
71 int fDepth;
72 };
73
74 class AutoDSLSymbolTable {
75 public:
AutoDSLSymbolTable()76 AutoDSLSymbolTable() {
77 dsl::PushSymbolTable();
78 }
79
~AutoDSLSymbolTable()80 ~AutoDSLSymbolTable() {
81 dsl::PopSymbolTable();
82 }
83 };
84
85 std::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
86
InitLayoutMap()87 void DSLParser::InitLayoutMap() {
88 layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
89 #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
90 TOKEN(LOCATION, "location");
91 TOKEN(OFFSET, "offset");
92 TOKEN(BINDING, "binding");
93 TOKEN(INDEX, "index");
94 TOKEN(SET, "set");
95 TOKEN(BUILTIN, "builtin");
96 TOKEN(INPUT_ATTACHMENT_INDEX, "input_attachment_index");
97 TOKEN(ORIGIN_UPPER_LEFT, "origin_upper_left");
98 TOKEN(BLEND_SUPPORT_ALL_EQUATIONS, "blend_support_all_equations");
99 TOKEN(PUSH_CONSTANT, "push_constant");
100 TOKEN(SRGB_UNPREMUL, "srgb_unpremul");
101 #ifdef SKSL_EXT
102 TOKEN(CONSTANT_ID, "constant_id");
103 #endif
104 #undef TOKEN
105 }
106
DSLParser(Compiler * compiler,const ProgramSettings & settings,ProgramKind kind,String text)107 DSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
108 String text)
109 : fCompiler(*compiler)
110 , fSettings(settings)
111 , fKind(kind)
112 , fText(std::make_unique<String>(std::move(text)))
113 , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1, /*line=*/-1) {
114 // We don't want to have to worry about manually releasing all of the objects in the event that
115 // an error occurs
116 fSettings.fAssertDSLObjectsReleased = false;
117 // We manage our symbol tables manually, so no need for name mangling
118 fSettings.fDSLMangling = false;
119 fLexer.start(*fText);
120 static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
121 (void) layoutMapInitialized;
122 }
123
nextRawToken()124 Token DSLParser::nextRawToken() {
125 if (fPushback.fKind != Token::Kind::TK_NONE) {
126 Token result = fPushback;
127 fPushback.fKind = Token::Kind::TK_NONE;
128 return result;
129 }
130 return fLexer.next();
131 }
132
nextToken()133 Token DSLParser::nextToken() {
134 for (;;) {
135 Token token = this->nextRawToken();
136 switch (token.fKind) {
137 case Token::Kind::TK_WHITESPACE:
138 case Token::Kind::TK_LINE_COMMENT:
139 case Token::Kind::TK_BLOCK_COMMENT:
140 continue;
141
142 case Token::Kind::TK_RESERVED:
143 this->error(token, "'" + this->text(token) + "' is a reserved word");
144 token.fKind = Token::Kind::TK_IDENTIFIER;
145 [[fallthrough]];
146
147 default:
148 return token;
149 }
150 }
151 }
152
pushback(Token t)153 void DSLParser::pushback(Token t) {
154 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
155 fPushback = std::move(t);
156 }
157
peek()158 Token DSLParser::peek() {
159 if (fPushback.fKind == Token::Kind::TK_NONE) {
160 fPushback = this->nextToken();
161 }
162 return fPushback;
163 }
164
checkNext(Token::Kind kind,Token * result)165 bool DSLParser::checkNext(Token::Kind kind, Token* result) {
166 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
167 return false;
168 }
169 Token next = this->nextToken();
170 if (next.fKind == kind) {
171 if (result) {
172 *result = next;
173 }
174 return true;
175 }
176 this->pushback(std::move(next));
177 return false;
178 }
179
expect(Token::Kind kind,const char * expected,Token * result)180 bool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
181 Token next = this->nextToken();
182 if (next.fKind == kind) {
183 if (result) {
184 *result = std::move(next);
185 }
186 return true;
187 } else {
188 this->error(next, "expected " + String(expected) + ", but found '" +
189 this->text(next) + "'");
190 this->fEncounteredFatalError = true;
191 return false;
192 }
193 }
194
expectIdentifier(Token * result)195 bool DSLParser::expectIdentifier(Token* result) {
196 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
197 return false;
198 }
199 if (IsBuiltinType(this->text(*result))) {
200 this->error(*result, "expected an identifier, but found type '" +
201 this->text(*result) + "'");
202 this->fEncounteredFatalError = true;
203 return false;
204 }
205 return true;
206 }
207
text(Token token)208 skstd::string_view DSLParser::text(Token token) {
209 return skstd::string_view(fText->data() + token.fOffset, token.fLength);
210 }
211
position(Token t)212 PositionInfo DSLParser::position(Token t) {
213 return this->position(t.fLine);
214 }
215
position(int line)216 PositionInfo DSLParser::position(int line) {
217 return PositionInfo("<unknown>", line);
218 }
219
error(Token token,String msg)220 void DSLParser::error(Token token, String msg) {
221 this->error(token.fLine, msg);
222 }
223
error(int line,String msg)224 void DSLParser::error(int line, String msg) {
225 GetErrorReporter().error(msg.c_str(), this->position(line));
226 }
227
228 /* declaration* END_OF_FILE */
program()229 std::unique_ptr<Program> DSLParser::program() {
230 ErrorReporter* errorReporter = &fCompiler.errorReporter();
231 Start(&fCompiler, fKind, fSettings);
232 SetErrorReporter(errorReporter);
233 errorReporter->setSource(fText->c_str());
234 this->declarations();
235 std::unique_ptr<Program> result;
236 if (!GetErrorReporter().errorCount()) {
237 result = dsl::ReleaseProgram(std::move(fText));
238 }
239 errorReporter->setSource(nullptr);
240 End();
241 return result;
242 }
243
moduleInheritingFrom(SkSL::ParsedModule baseModule)244 SkSL::LoadedModule DSLParser::moduleInheritingFrom(SkSL::ParsedModule baseModule) {
245 ErrorReporter* errorReporter = &fCompiler.errorReporter();
246 StartModule(&fCompiler, fKind, fSettings, std::move(baseModule));
247 SetErrorReporter(errorReporter);
248 errorReporter->setSource(fText->c_str());
249 this->declarations();
250 CurrentSymbolTable()->takeOwnershipOfString(std::move(*fText));
251 SkSL::LoadedModule result{ fKind, CurrentSymbolTable(),
252 std::move(ThreadContext::ProgramElements()) };
253 errorReporter->setSource(nullptr);
254 End();
255 return result;
256 }
257
declarations()258 void DSLParser::declarations() {
259 fEncounteredFatalError = false;
260 bool done = false;
261 while (!done) {
262 switch (this->peek().fKind) {
263 case Token::Kind::TK_END_OF_FILE:
264 done = true;
265 break;
266 case Token::Kind::TK_DIRECTIVE:
267 this->directive();
268 break;
269 case Token::Kind::TK_INVALID: {
270 this->nextToken();
271 this->error(this->peek(), String("invalid token"));
272 done = true;
273 break;
274 }
275 default:
276 this->declaration();
277 done = fEncounteredFatalError;
278 break;
279 }
280 }
281 }
282
283 /* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
directive()284 void DSLParser::directive() {
285 Token start;
286 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
287 return;
288 }
289 skstd::string_view text = this->text(start);
290 if (text == "#extension") {
291 Token name;
292 if (!this->expectIdentifier(&name)) {
293 return;
294 }
295 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
296 return;
297 }
298 Token behavior;
299 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
300 return;
301 }
302 skstd::string_view behaviorText = this->text(behavior);
303 if (behaviorText == "disable") {
304 return;
305 }
306 if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
307 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
308 }
309 // We don't currently do anything different between require, enable, and warn
310 dsl::AddExtension(this->text(name));
311 } else {
312 this->error(start, "unsupported directive '" + this->text(start) + "'");
313 }
314 }
315
316 /* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
317 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
declaration()318 bool DSLParser::declaration() {
319 Token lookahead = this->peek();
320 switch (lookahead.fKind) {
321 case Token::Kind::TK_SEMICOLON:
322 this->nextToken();
323 this->error(lookahead, "expected a declaration, but found ';'");
324 return false;
325 default:
326 break;
327 }
328 DSLModifiers modifiers = this->modifiers();
329 lookahead = this->peek();
330 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
331 // we have an identifier that's not a type, could be the start of an interface block
332 return this->interfaceBlock(modifiers);
333 }
334 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
335 this->nextToken();
336 Declare(modifiers, position(lookahead));
337 return true;
338 }
339 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
340 this->structVarDeclaration(modifiers);
341 return true;
342 }
343 skstd::optional<DSLType> type = this->type(&modifiers);
344 if (!type) {
345 return false;
346 }
347 Token name;
348 if (!this->expectIdentifier(&name)) {
349 return false;
350 }
351 if (this->checkNext(Token::Kind::TK_LPAREN)) {
352 return this->functionDeclarationEnd(modifiers, *type, name);
353 } else {
354 this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
355 return true;
356 }
357 }
358
359 /* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
functionDeclarationEnd(const DSLModifiers & modifiers,DSLType type,const Token & name)360 bool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
361 DSLType type,
362 const Token& name) {
363 SkTArray<DSLWrapper<DSLParameter>> parameters;
364 Token lookahead = this->peek();
365 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
366 // `()` means no parameters at all.
367 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
368 // `(void)` also means no parameters at all.
369 this->nextToken();
370 } else {
371 for (;;) {
372 skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
373 if (!parameter) {
374 return false;
375 }
376 parameters.push_back(std::move(*parameter));
377 if (!this->checkNext(Token::Kind::TK_COMMA)) {
378 break;
379 }
380 }
381 }
382 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
383 return false;
384 }
385 SkTArray<DSLParameter*> parameterPointers;
386 for (DSLWrapper<DSLParameter>& param : parameters) {
387 parameterPointers.push_back(¶m.get());
388 }
389 DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
390 if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
391 AutoDSLSymbolTable symbols;
392 for (DSLParameter* var : parameterPointers) {
393 AddToSymbolTable(*var);
394 }
395 skstd::optional<DSLBlock> body = this->block();
396 if (!body) {
397 return false;
398 }
399 result.define(std::move(*body), this->position(name));
400 }
401 return true;
402 }
403
arraySize()404 SKSL_INT DSLParser::arraySize() {
405 DSLExpression sizeExpr = this->expression();
406 if (!sizeExpr.isValid()) {
407 return 1;
408 }
409 std::unique_ptr<SkSL::Expression> sizeLiteral = sizeExpr.release();
410 SKSL_INT size;
411 if (!ConstantFolder::GetConstantInt(*sizeLiteral, &size)) {
412 this->error(sizeLiteral->fLine, "array size must be an integer");
413 return 1;
414 }
415 if (size > INT32_MAX) {
416 this->error(sizeLiteral->fLine, "array size out of bounds");
417 return 1;
418 }
419 if (size <= 0) {
420 this->error(sizeLiteral->fLine, "array size must be positive");
421 return 1;
422 }
423 return size;
424 }
425
parseArrayDimensions(int line,DSLType * type)426 bool DSLParser::parseArrayDimensions(int line, DSLType* type) {
427 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
428 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
429 #ifdef SKSL_EXT
430 *type = UnsizedArray(*type, this->position(line));
431 #else
432 this->error(line, "expected array dimension");
433 #endif
434 } else {
435 *type = Array(*type, this->arraySize(), this->position(line));
436 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
437 return false;
438 }
439 }
440 }
441 return true;
442 }
443
parseInitializer(int line,DSLExpression * initializer)444 bool DSLParser::parseInitializer(int line, DSLExpression* initializer) {
445 if (this->checkNext(Token::Kind::TK_EQ)) {
446 DSLExpression value = this->assignmentExpression();
447 if (!value.hasValue()) {
448 return false;
449 }
450 initializer->swap(value);
451 }
452 return true;
453 }
454
455 /* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
456 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
globalVarDeclarationEnd(PositionInfo pos,const dsl::DSLModifiers & mods,dsl::DSLType baseType,skstd::string_view name)457 void DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
458 dsl::DSLType baseType, skstd::string_view name) {
459 using namespace dsl;
460 int line = this->peek().fLine;
461 DSLType type = baseType;
462 DSLExpression initializer;
463 if (!this->parseArrayDimensions(line, &type)) {
464 return;
465 }
466 if (!this->parseInitializer(line, &initializer)) {
467 return;
468 }
469 DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
470 Declare(first);
471 AddToSymbolTable(first);
472
473 while (this->checkNext(Token::Kind::TK_COMMA)) {
474 type = baseType;
475 Token identifierName;
476 if (!this->expectIdentifier(&identifierName)) {
477 return;
478 }
479 if (!this->parseArrayDimensions(line, &type)) {
480 return;
481 }
482 DSLExpression anotherInitializer;
483 if (!this->parseInitializer(line, &anotherInitializer)) {
484 return;
485 }
486 DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
487 this->position(line));
488 Declare(next);
489 AddToSymbolTable(next, this->position(identifierName));
490 }
491 this->expect(Token::Kind::TK_SEMICOLON, "';'");
492 }
493
494 /* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
495 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
localVarDeclarationEnd(PositionInfo pos,const dsl::DSLModifiers & mods,dsl::DSLType baseType,skstd::string_view name)496 DSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
497 dsl::DSLType baseType, skstd::string_view name) {
498 using namespace dsl;
499 int line = this->peek().fLine;
500 DSLType type = baseType;
501 DSLExpression initializer;
502 if (!this->parseArrayDimensions(line, &type)) {
503 return {};
504 }
505 if (!this->parseInitializer(line, &initializer)) {
506 return {};
507 }
508 DSLVar first(mods, type, name, std::move(initializer), pos);
509 DSLStatement result = Declare(first);
510 AddToSymbolTable(first);
511
512 while (this->checkNext(Token::Kind::TK_COMMA)) {
513 type = baseType;
514 Token identifierName;
515 if (!this->expectIdentifier(&identifierName)) {
516 return result;
517 }
518 if (!this->parseArrayDimensions(line, &type)) {
519 return result;
520 }
521 DSLExpression anotherInitializer;
522 if (!this->parseInitializer(line, &anotherInitializer)) {
523 return result;
524 }
525 DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
526 this->position(line));
527 DSLWriter::AddVarDeclaration(result, next);
528 AddToSymbolTable(next, this->position(identifierName));
529 }
530 this->expect(Token::Kind::TK_SEMICOLON, "';'");
531 return result;
532 }
533
534 /* (varDeclarations | expressionStatement) */
varDeclarationsOrExpressionStatement()535 DSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
536 Token nextToken = this->peek();
537 if (nextToken.fKind == Token::Kind::TK_CONST) {
538 // Statements that begin with `const` might be variable declarations, but can't be legal
539 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
540 return this->varDeclarations();
541 }
542
543 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
544 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
545 nextToken.fKind == Token::Kind::TK_LOWP ||
546 IsType(this->text(nextToken))) {
547 // Statements that begin with a typename are most often variable declarations, but
548 // occasionally the type is part of a constructor, and these are actually expression-
549 // statements in disguise. First, attempt the common case: parse it as a vardecl.
550 Checkpoint checkpoint(this);
551 VarDeclarationsPrefix prefix;
552 if (this->varDeclarationsPrefix(&prefix)) {
553 checkpoint.accept();
554 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
555 this->text(prefix.fName));
556 }
557
558 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
559 // expression-statement instead.
560 checkpoint.rewind();
561 }
562 return this->expressionStatement();
563 }
564
565 // Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
566 // statement is a variable-declaration statement, not an expression-statement.
varDeclarationsPrefix(VarDeclarationsPrefix * prefixData)567 bool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
568 prefixData->fPosition = this->position(this->peek());
569 prefixData->fModifiers = this->modifiers();
570 skstd::optional<DSLType> type = this->type(&prefixData->fModifiers);
571 if (!type) {
572 return false;
573 }
574 prefixData->fType = *type;
575 return this->expectIdentifier(&prefixData->fName);
576 }
577
578 /* modifiers type IDENTIFIER varDeclarationEnd */
varDeclarations()579 DSLStatement DSLParser::varDeclarations() {
580 VarDeclarationsPrefix prefix;
581 if (!this->varDeclarationsPrefix(&prefix)) {
582 return {};
583 }
584 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
585 this->text(prefix.fName));
586 }
587
588 /* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
structDeclaration()589 skstd::optional<DSLType> DSLParser::structDeclaration() {
590 AutoDSLDepth depth(this);
591 if (!depth.increase()) {
592 return skstd::nullopt;
593 }
594 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
595 return skstd::nullopt;
596 }
597 Token name;
598 if (!this->expectIdentifier(&name)) {
599 return skstd::nullopt;
600 }
601 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
602 return skstd::nullopt;
603 }
604 SkTArray<DSLField> fields;
605 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
606 DSLModifiers modifiers = this->modifiers();
607 skstd::optional<DSLType> type = this->type(&modifiers);
608 if (!type) {
609 return skstd::nullopt;
610 }
611
612 do {
613 DSLType actualType = *type;
614 Token memberName;
615 if (!this->expectIdentifier(&memberName)) {
616 return skstd::nullopt;
617 }
618
619 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
620 actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
621 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
622 return skstd::nullopt;
623 }
624 }
625 fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
626 this->position(memberName)));
627 } while (this->checkNext(Token::Kind::TK_COMMA));
628 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
629 return skstd::nullopt;
630 }
631 }
632 if (fields.empty()) {
633 this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
634 }
635 return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
636 }
637
638 /* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
structVarDeclaration(const DSLModifiers & modifiers)639 SkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
640 skstd::optional<DSLType> type = this->structDeclaration();
641 if (!type) {
642 return {};
643 }
644 Token name;
645 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
646 this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
647 this->text(name));
648 } else {
649 this->expect(Token::Kind::TK_SEMICOLON, "';'");
650 }
651 return {};
652 }
653
654 /* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
parameter()655 skstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
656 DSLModifiers modifiers = this->modifiers();
657 skstd::optional<DSLType> type = this->type(&modifiers);
658 if (!type) {
659 return skstd::nullopt;
660 }
661 Token name;
662 if (!this->expectIdentifier(&name)) {
663 return skstd::nullopt;
664 }
665 if (!this->parseArrayDimensions(name.fLine, &type.value())) {
666 return skstd::nullopt;
667 }
668 return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
669 }
670
671 /** EQ INT_LITERAL */
layoutInt()672 int 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 */
layoutIdentifier()690 skstd::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 */
layout()702 DSLLayout 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:
715 result.originUpperLeft(this->position(t));
716 break;
717 case LayoutToken::PUSH_CONSTANT:
718 result.pushConstant(this->position(t));
719 break;
720 case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
721 result.blendSupportAllEquations(this->position(t));
722 break;
723 case LayoutToken::SRGB_UNPREMUL:
724 result.srgbUnpremul(this->position(t));
725 break;
726 case LayoutToken::LOCATION:
727 result.location(this->layoutInt(), this->position(t));
728 break;
729 case LayoutToken::OFFSET:
730 result.offset(this->layoutInt(), this->position(t));
731 break;
732 case LayoutToken::BINDING:
733 result.binding(this->layoutInt(), this->position(t));
734 break;
735 case LayoutToken::INDEX:
736 result.index(this->layoutInt(), this->position(t));
737 break;
738 case LayoutToken::SET:
739 result.set(this->layoutInt(), this->position(t));
740 break;
741 case LayoutToken::BUILTIN:
742 result.builtin(this->layoutInt(), this->position(t));
743 break;
744 case LayoutToken::INPUT_ATTACHMENT_INDEX:
745 result.inputAttachmentIndex(this->layoutInt(), this->position(t));
746 break;
747 #ifdef SKSL_EXT
748 case LayoutToken::CONSTANT_ID:
749 result.constant_id(this->layoutInt(), this->position(t));
750 break;
751 #endif
752 default:
753 this->error(t, "'" + text + "' is not a valid layout qualifier");
754 break;
755 }
756 } else {
757 this->error(t, "'" + text + "' is not a valid layout qualifier");
758 }
759 if (this->checkNext(Token::Kind::TK_RPAREN)) {
760 break;
761 }
762 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
763 break;
764 }
765 }
766 }
767 return result;
768 }
769
770 /* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
771 VARYING | INLINE)* */
modifiers()772 DSLModifiers DSLParser::modifiers() {
773 DSLLayout layout = this->layout();
774 int flags = 0;
775 for (;;) {
776 // TODO(ethannicholas): handle duplicate / incompatible flags
777 int tokenFlag = parse_modifier_token(peek().fKind);
778 if (!tokenFlag) {
779 break;
780 }
781 flags |= tokenFlag;
782 this->nextToken();
783 }
784 return DSLModifiers(std::move(layout), flags);
785 }
786
787 /* ifStatement | forStatement | doStatement | whileStatement | block | expression */
statement()788 DSLStatement DSLParser::statement() {
789 Token start = this->nextToken();
790 AutoDSLDepth depth(this);
791 if (!depth.increase()) {
792 return {};
793 }
794 this->pushback(start);
795 switch (start.fKind) {
796 case Token::Kind::TK_IF: // fall through
797 case Token::Kind::TK_STATIC_IF:
798 return this->ifStatement();
799 case Token::Kind::TK_FOR:
800 return this->forStatement();
801 case Token::Kind::TK_DO:
802 return this->doStatement();
803 case Token::Kind::TK_WHILE:
804 return this->whileStatement();
805 case Token::Kind::TK_SWITCH: // fall through
806 case Token::Kind::TK_STATIC_SWITCH:
807 return this->switchStatement();
808 case Token::Kind::TK_RETURN:
809 return this->returnStatement();
810 case Token::Kind::TK_BREAK:
811 return this->breakStatement();
812 case Token::Kind::TK_CONTINUE:
813 return this->continueStatement();
814 case Token::Kind::TK_DISCARD:
815 return this->discardStatement();
816 case Token::Kind::TK_LBRACE: {
817 skstd::optional<DSLBlock> result = this->block();
818 return result ? DSLStatement(std::move(*result)) : DSLStatement();
819 }
820 case Token::Kind::TK_SEMICOLON:
821 this->nextToken();
822 return dsl::Block();
823 case Token::Kind::TK_HIGHP:
824 case Token::Kind::TK_MEDIUMP:
825 case Token::Kind::TK_LOWP:
826 case Token::Kind::TK_CONST:
827 case Token::Kind::TK_IDENTIFIER:
828 return this->varDeclarationsOrExpressionStatement();
829 default:
830 return this->expressionStatement();
831 }
832 }
833
834 /* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
type(DSLModifiers * modifiers)835 skstd::optional<DSLType> DSLParser::type(DSLModifiers* modifiers) {
836 Token type;
837 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
838 return skstd::nullopt;
839 }
840 if (!IsType(this->text(type))) {
841 this->error(type, ("no type named '" + this->text(type) + "'").c_str());
842 return skstd::nullopt;
843 }
844 DSLType result(this->text(type), modifiers, this->position(type));
845 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
846 if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
847 result = Array(result, this->arraySize(), this->position(type));
848 } else {
849 this->error(this->peek(), "expected array dimension");
850 }
851 this->expect(Token::Kind::TK_RBRACKET, "']'");
852 }
853 return result;
854 }
855
856 /* IDENTIFIER LBRACE
857 varDeclaration+
858 RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
interfaceBlock(const dsl::DSLModifiers & modifiers)859 bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
860 Token typeName;
861 if (!this->expectIdentifier(&typeName)) {
862 return false;
863 }
864 if (peek().fKind != Token::Kind::TK_LBRACE) {
865 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
866 // 99% of the time, the user was not actually intending to create an interface block, so
867 // it's better to report it as an unknown type
868 this->error(typeName, "no type named '" + this->text(typeName) + "'");
869 return false;
870 }
871 this->nextToken();
872 SkTArray<dsl::Field> fields;
873 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
874 DSLModifiers fieldModifiers = this->modifiers();
875 skstd::optional<dsl::DSLType> type = this->type(&fieldModifiers);
876 if (!type) {
877 return false;
878 }
879 do {
880 Token fieldName;
881 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
882 return false;
883 }
884 DSLType actualType = *type;
885 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
886 Token sizeToken = this->peek();
887 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
888 actualType = Array(std::move(actualType), this->arraySize(),
889 this->position(typeName));
890 } else {
891 #ifdef SKSL_EXT
892 actualType = UnsizedArray(std::move(actualType), this->position(typeName));
893 #else
894 this->error(sizeToken, "unsized arrays are not permitted");
895 #endif
896 }
897 this->expect(Token::Kind::TK_RBRACKET, "']'");
898 }
899 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
900 return false;
901 }
902 fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
903 this->text(fieldName), this->position(fieldName)));
904 }
905 while (this->checkNext(Token::Kind::TK_COMMA));
906 }
907 skstd::string_view instanceName;
908 Token instanceNameToken;
909 SKSL_INT arraySize = 0;
910 if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
911 instanceName = this->text(instanceNameToken);
912 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
913 arraySize = this->arraySize();
914 this->expect(Token::Kind::TK_RBRACKET, "']'");
915 }
916 }
917 this->expect(Token::Kind::TK_SEMICOLON, "';'");
918 if (fields.empty()) {
919 this->error(typeName, "interface block '" + this->text(typeName) +
920 "' must contain at least one member");
921 } else {
922 dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
923 arraySize, this->position(typeName));
924 }
925 return true;
926 }
927
928 /* IF LPAREN expression RPAREN statement (ELSE statement)? */
ifStatement()929 DSLStatement DSLParser::ifStatement() {
930 Token start;
931 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
932 if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
933 return {};
934 }
935 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
936 return {};
937 }
938 DSLExpression test = this->expression();
939 if (!test.hasValue()) {
940 return {};
941 }
942 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
943 return {};
944 }
945 DSLStatement ifTrue = this->statement();
946 if (!ifTrue.hasValue()) {
947 return {};
948 }
949 DSLStatement ifFalse;
950 if (this->checkNext(Token::Kind::TK_ELSE)) {
951 ifFalse = this->statement();
952 if (!ifFalse.hasValue()) {
953 return {};
954 }
955 }
956 if (isStatic) {
957 return StaticIf(std::move(test), std::move(ifTrue),
958 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
959 } else {
960 return If(std::move(test), std::move(ifTrue),
961 ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
962 }
963 }
964
965 /* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
doStatement()966 DSLStatement DSLParser::doStatement() {
967 Token start;
968 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
969 return {};
970 }
971 DSLStatement statement = this->statement();
972 if (!statement.hasValue()) {
973 return {};
974 }
975 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
976 return {};
977 }
978 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
979 return {};
980 }
981 DSLExpression test = this->expression();
982 if (!test.hasValue()) {
983 return {};
984 }
985 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
986 return {};
987 }
988 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
989 return {};
990 }
991 return Do(std::move(statement), std::move(test), this->position(start));
992 }
993
994 /* WHILE LPAREN expression RPAREN STATEMENT */
whileStatement()995 DSLStatement DSLParser::whileStatement() {
996 Token start;
997 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
998 return {};
999 }
1000 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1001 return {};
1002 }
1003 DSLExpression test = this->expression();
1004 if (!test.hasValue()) {
1005 return {};
1006 }
1007 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1008 return {};
1009 }
1010 DSLStatement statement = this->statement();
1011 if (!statement.hasValue()) {
1012 return {};
1013 }
1014 return While(std::move(test), std::move(statement), this->position(start));
1015 }
1016
1017 /* CASE expression COLON statement* */
switchCase()1018 skstd::optional<DSLCase> DSLParser::switchCase() {
1019 Token start;
1020 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
1021 return {};
1022 }
1023 DSLExpression value = this->expression();
1024 if (!value.hasValue()) {
1025 return {};
1026 }
1027 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1028 return {};
1029 }
1030 SkTArray<DSLStatement> statements;
1031 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1032 this->peek().fKind != Token::Kind::TK_CASE &&
1033 this->peek().fKind != Token::Kind::TK_DEFAULT) {
1034 DSLStatement s = this->statement();
1035 if (!s.hasValue()) {
1036 return {};
1037 }
1038 statements.push_back(std::move(s));
1039 }
1040 return DSLCase(std::move(value), std::move(statements));
1041 }
1042
1043 /* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
switchStatement()1044 DSLStatement DSLParser::switchStatement() {
1045 Token start;
1046 bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1047 if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
1048 return {};
1049 }
1050 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1051 return {};
1052 }
1053 DSLExpression value = this->expression();
1054 if (!value.hasValue()) {
1055 return {};
1056 }
1057 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1058 return {};
1059 }
1060 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
1061 return {};
1062 }
1063 SkTArray<DSLCase> cases;
1064 while (this->peek().fKind == Token::Kind::TK_CASE) {
1065 skstd::optional<DSLCase> c = this->switchCase();
1066 if (!c) {
1067 return {};
1068 }
1069 cases.push_back(std::move(*c));
1070 }
1071 // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1072 // parts of the compiler may rely upon this assumption.
1073 if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1074 SkTArray<DSLStatement> statements;
1075 Token defaultStart;
1076 SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1077 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1078 return {};
1079 }
1080 while (this->peek().fKind != Token::Kind::TK_RBRACE) {
1081 DSLStatement s = this->statement();
1082 if (!s.hasValue()) {
1083 return {};
1084 }
1085 statements.push_back(std::move(s));
1086 }
1087 cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
1088 }
1089 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
1090 return {};
1091 }
1092 if (isStatic) {
1093 return StaticSwitch(std::move(value), std::move(cases), this->position(start));
1094 } else {
1095 return Switch(std::move(value), std::move(cases), this->position(start));
1096 }
1097 }
1098
1099 /* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1100 STATEMENT */
forStatement()1101 dsl::DSLStatement DSLParser::forStatement() {
1102 Token start;
1103 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
1104 return {};
1105 }
1106 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1107 return {};
1108 }
1109 AutoDSLSymbolTable symbols;
1110 dsl::DSLStatement initializer;
1111 Token nextToken = this->peek();
1112 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1113 // An empty init-statement.
1114 this->nextToken();
1115 } else {
1116 // The init-statement must be an expression or variable declaration.
1117 initializer = this->varDeclarationsOrExpressionStatement();
1118 if (!initializer.hasValue()) {
1119 return {};
1120 }
1121 }
1122 dsl::DSLExpression test;
1123 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1124 dsl::DSLExpression testValue = this->expression();
1125 if (!testValue.hasValue()) {
1126 return {};
1127 }
1128 test.swap(testValue);
1129 }
1130 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1131 return {};
1132 }
1133 dsl::DSLExpression next;
1134 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1135 dsl::DSLExpression nextValue = this->expression();
1136 if (!nextValue.hasValue()) {
1137 return {};
1138 }
1139 next.swap(nextValue);
1140 }
1141 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1142 return {};
1143 }
1144 dsl::DSLStatement statement = this->statement();
1145 if (!statement.hasValue()) {
1146 return {};
1147 }
1148 return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1149 test.hasValue() ? std::move(test) : DSLExpression(),
1150 next.hasValue() ? std::move(next) : DSLExpression(),
1151 std::move(statement),
1152 this->position(start));
1153 }
1154
1155 /* RETURN expression? SEMICOLON */
returnStatement()1156 DSLStatement DSLParser::returnStatement() {
1157 Token start;
1158 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
1159 return {};
1160 }
1161 DSLExpression expression;
1162 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1163 DSLExpression next = this->expression();
1164 if (!next.hasValue()) {
1165 return {};
1166 }
1167 expression.swap(next);
1168 }
1169 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1170 return {};
1171 }
1172 return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1173 this->position(start));
1174 }
1175
1176 /* BREAK SEMICOLON */
breakStatement()1177 DSLStatement DSLParser::breakStatement() {
1178 Token start;
1179 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
1180 return {};
1181 }
1182 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1183 return {};
1184 }
1185 return Break(this->position(start));
1186 }
1187
1188 /* CONTINUE SEMICOLON */
continueStatement()1189 DSLStatement DSLParser::continueStatement() {
1190 Token start;
1191 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
1192 return {};
1193 }
1194 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1195 return {};
1196 }
1197 return Continue(this->position(start));
1198 }
1199
1200 /* DISCARD SEMICOLON */
discardStatement()1201 DSLStatement DSLParser::discardStatement() {
1202 Token start;
1203 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
1204 return {};
1205 }
1206 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1207 return {};
1208 }
1209 return Discard(this->position(start));
1210 }
1211
1212 /* LBRACE statement* RBRACE */
block()1213 skstd::optional<DSLBlock> DSLParser::block() {
1214 Token start;
1215 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1216 return skstd::nullopt;
1217 }
1218 AutoDSLDepth depth(this);
1219 if (!depth.increase()) {
1220 return skstd::nullopt;
1221 }
1222 AutoDSLSymbolTable symbols;
1223 StatementArray statements;
1224 for (;;) {
1225 switch (this->peek().fKind) {
1226 case Token::Kind::TK_RBRACE:
1227 this->nextToken();
1228 return DSLBlock(std::move(statements), CurrentSymbolTable());
1229 case Token::Kind::TK_END_OF_FILE:
1230 this->error(this->peek(), "expected '}', but found end of file");
1231 return skstd::nullopt;
1232 default: {
1233 DSLStatement statement = this->statement();
1234 if (!statement.hasValue()) {
1235 return skstd::nullopt;
1236 }
1237 statements.push_back(statement.release());
1238 break;
1239 }
1240 }
1241 }
1242 }
1243
1244 /* expression SEMICOLON */
expressionStatement()1245 DSLStatement DSLParser::expressionStatement() {
1246 DSLExpression expr = this->expression();
1247 if (expr.hasValue()) {
1248 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1249 return {};
1250 }
1251 return DSLStatement(std::move(expr));
1252 }
1253 return {};
1254 }
1255
1256 /* assignmentExpression (COMMA assignmentExpression)* */
expression()1257 DSLExpression DSLParser::expression() {
1258 DSLExpression result = this->assignmentExpression();
1259 if (!result.hasValue()) {
1260 return {};
1261 }
1262 Token t;
1263 AutoDSLDepth depth(this);
1264 while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1265 if (!depth.increase()) {
1266 return {};
1267 }
1268 DSLExpression right = this->assignmentExpression();
1269 if (!right.hasValue()) {
1270 return {};
1271 }
1272 DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1273 result.swap(next);
1274 }
1275 return result;
1276 }
1277
1278 #define OPERATOR_RIGHT(op, exprType) \
1279 do { \
1280 this->nextToken(); \
1281 if (!depth.increase()) { \
1282 return {}; \
1283 } \
1284 DSLExpression right = this->exprType(); \
1285 if (!right.hasValue()) { \
1286 return {}; \
1287 } \
1288 DSLExpression next = std::move(result) op std::move(right); \
1289 result.swap(next); \
1290 } while (false)
1291
1292 /* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1293 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1294 assignmentExpression)*
1295 */
assignmentExpression()1296 DSLExpression DSLParser::assignmentExpression() {
1297 AutoDSLDepth depth(this);
1298 DSLExpression result = this->ternaryExpression();
1299 if (!result.hasValue()) {
1300 return {};
1301 }
1302 for (;;) {
1303 switch (this->peek().fKind) {
1304 case Token::Kind::TK_EQ: OPERATOR_RIGHT(=, assignmentExpression); break;
1305 case Token::Kind::TK_STAREQ: OPERATOR_RIGHT(*=, assignmentExpression); break;
1306 case Token::Kind::TK_SLASHEQ: OPERATOR_RIGHT(/=, assignmentExpression); break;
1307 case Token::Kind::TK_PERCENTEQ: OPERATOR_RIGHT(%=, assignmentExpression); break;
1308 case Token::Kind::TK_PLUSEQ: OPERATOR_RIGHT(+=, assignmentExpression); break;
1309 case Token::Kind::TK_MINUSEQ: OPERATOR_RIGHT(-=, assignmentExpression); break;
1310 case Token::Kind::TK_SHLEQ: OPERATOR_RIGHT(<<=, assignmentExpression); break;
1311 case Token::Kind::TK_SHREQ: OPERATOR_RIGHT(>>=, assignmentExpression); break;
1312 case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=, assignmentExpression); break;
1313 case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=, assignmentExpression); break;
1314 case Token::Kind::TK_BITWISEOREQ: OPERATOR_RIGHT(|=, assignmentExpression); break;
1315 default:
1316 return result;
1317 }
1318 }
1319 }
1320
1321 /* logicalOrExpression ('?' expression ':' assignmentExpression)? */
ternaryExpression()1322 DSLExpression DSLParser::ternaryExpression() {
1323 AutoDSLDepth depth(this);
1324 DSLExpression base = this->logicalOrExpression();
1325 if (!base.hasValue()) {
1326 return {};
1327 }
1328 if (this->checkNext(Token::Kind::TK_QUESTION)) {
1329 if (!depth.increase()) {
1330 return {};
1331 }
1332 DSLExpression trueExpr = this->expression();
1333 if (!trueExpr.hasValue()) {
1334 return {};
1335 }
1336 if (this->expect(Token::Kind::TK_COLON, "':'")) {
1337 DSLExpression falseExpr = this->assignmentExpression();
1338 if (!falseExpr.hasValue()) {
1339 return {};
1340 }
1341 return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
1342 }
1343 return {};
1344 }
1345 return base;
1346 }
1347
1348 /* logicalXorExpression (LOGICALOR logicalXorExpression)* */
logicalOrExpression()1349 DSLExpression DSLParser::logicalOrExpression() {
1350 AutoDSLDepth depth(this);
1351 DSLExpression result = this->logicalXorExpression();
1352 if (!result.hasValue()) {
1353 return {};
1354 }
1355 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1356 OPERATOR_RIGHT(||, logicalXorExpression);
1357 }
1358 return result;
1359 }
1360
1361 /* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
logicalXorExpression()1362 DSLExpression DSLParser::logicalXorExpression() {
1363 AutoDSLDepth depth(this);
1364 DSLExpression result = this->logicalAndExpression();
1365 if (!result.hasValue()) {
1366 return {};
1367 }
1368 while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1369 if (!depth.increase()) {
1370 return {};
1371 }
1372 DSLExpression right = this->logicalAndExpression();
1373 if (!right.hasValue()) {
1374 return {};
1375 }
1376 DSLExpression next = LogicalXor(std::move(result), std::move(right));
1377 result.swap(next);
1378 }
1379 return result;
1380 }
1381
1382 /* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
logicalAndExpression()1383 DSLExpression DSLParser::logicalAndExpression() {
1384 AutoDSLDepth depth(this);
1385 DSLExpression result = this->bitwiseOrExpression();
1386 if (!result.hasValue()) {
1387 return {};
1388 }
1389 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1390 OPERATOR_RIGHT(&&, bitwiseOrExpression);
1391 }
1392 return result;
1393 }
1394
1395 /* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
bitwiseOrExpression()1396 DSLExpression DSLParser::bitwiseOrExpression() {
1397 AutoDSLDepth depth(this);
1398 DSLExpression result = this->bitwiseXorExpression();
1399 if (!result.hasValue()) {
1400 return {};
1401 }
1402 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1403 OPERATOR_RIGHT(|, bitwiseXorExpression);
1404 }
1405 return result;
1406 }
1407
1408 /* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
bitwiseXorExpression()1409 DSLExpression DSLParser::bitwiseXorExpression() {
1410 AutoDSLDepth depth(this);
1411 DSLExpression result = this->bitwiseAndExpression();
1412 if (!result.hasValue()) {
1413 return {};
1414 }
1415 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1416 OPERATOR_RIGHT(^, bitwiseAndExpression);
1417 }
1418 return result;
1419 }
1420
1421 /* equalityExpression (BITWISEAND equalityExpression)* */
bitwiseAndExpression()1422 DSLExpression DSLParser::bitwiseAndExpression() {
1423 AutoDSLDepth depth(this);
1424 DSLExpression result = this->equalityExpression();
1425 if (!result.hasValue()) {
1426 return {};
1427 }
1428 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1429 OPERATOR_RIGHT(&, equalityExpression);
1430 }
1431 return result;
1432 }
1433
1434 /* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
equalityExpression()1435 DSLExpression DSLParser::equalityExpression() {
1436 AutoDSLDepth depth(this);
1437 DSLExpression result = this->relationalExpression();
1438 if (!result.hasValue()) {
1439 return {};
1440 }
1441 for (;;) {
1442 switch (this->peek().fKind) {
1443 case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1444 case Token::Kind::TK_NEQ: OPERATOR_RIGHT(!=, relationalExpression); break;
1445 default: return result;
1446 }
1447 }
1448 }
1449
1450 /* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
relationalExpression()1451 DSLExpression DSLParser::relationalExpression() {
1452 AutoDSLDepth depth(this);
1453 DSLExpression result = this->shiftExpression();
1454 if (!result.hasValue()) {
1455 return {};
1456 }
1457 for (;;) {
1458 switch (this->peek().fKind) {
1459 case Token::Kind::TK_LT: OPERATOR_RIGHT(<, shiftExpression); break;
1460 case Token::Kind::TK_GT: OPERATOR_RIGHT(>, shiftExpression); break;
1461 case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1462 case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1463 default: return result;
1464 }
1465 }
1466 }
1467
1468 /* additiveExpression ((SHL | SHR) additiveExpression)* */
shiftExpression()1469 DSLExpression DSLParser::shiftExpression() {
1470 AutoDSLDepth depth(this);
1471 DSLExpression result = this->additiveExpression();
1472 if (!result.hasValue()) {
1473 return {};
1474 }
1475 for (;;) {
1476 switch (this->peek().fKind) {
1477 case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1478 case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1479 default: return result;
1480 }
1481 }
1482 }
1483
1484 /* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
additiveExpression()1485 DSLExpression DSLParser::additiveExpression() {
1486 AutoDSLDepth depth(this);
1487 DSLExpression result = this->multiplicativeExpression();
1488 if (!result.hasValue()) {
1489 return {};
1490 }
1491 for (;;) {
1492 switch (this->peek().fKind) {
1493 case Token::Kind::TK_PLUS: OPERATOR_RIGHT(+, multiplicativeExpression); break;
1494 case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1495 default: return result;
1496 }
1497 }
1498 }
1499
1500 /* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
multiplicativeExpression()1501 DSLExpression DSLParser::multiplicativeExpression() {
1502 AutoDSLDepth depth(this);
1503 DSLExpression result = this->unaryExpression();
1504 if (!result.hasValue()) {
1505 return {};
1506 }
1507 for (;;) {
1508 switch (this->peek().fKind) {
1509 case Token::Kind::TK_STAR: OPERATOR_RIGHT(*, unaryExpression); break;
1510 case Token::Kind::TK_SLASH: OPERATOR_RIGHT(/, unaryExpression); break;
1511 case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1512 default: return result;
1513 }
1514 }
1515 }
1516
1517 /* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
unaryExpression()1518 DSLExpression DSLParser::unaryExpression() {
1519 AutoDSLDepth depth(this);
1520 Token next = this->peek();
1521 switch (next.fKind) {
1522 case Token::Kind::TK_PLUS:
1523 case Token::Kind::TK_MINUS:
1524 case Token::Kind::TK_LOGICALNOT:
1525 case Token::Kind::TK_BITWISENOT:
1526 case Token::Kind::TK_PLUSPLUS:
1527 case Token::Kind::TK_MINUSMINUS: {
1528 if (!depth.increase()) {
1529 return {};
1530 }
1531 this->nextToken();
1532 DSLExpression expr = this->unaryExpression();
1533 if (!expr.hasValue()) {
1534 return {};
1535 }
1536 switch (next.fKind) {
1537 case Token::Kind::TK_PLUS: return {{ +std::move(expr)}};
1538 case Token::Kind::TK_MINUS: return {{ -std::move(expr)}};
1539 case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1540 case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1541 case Token::Kind::TK_PLUSPLUS: return {{++std::move(expr)}};
1542 case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
1543 default: SkUNREACHABLE;
1544 }
1545 }
1546 default:
1547 return this->postfixExpression();
1548 }
1549 }
1550
1551 /* term suffix* */
postfixExpression()1552 DSLExpression DSLParser::postfixExpression() {
1553 AutoDSLDepth depth(this);
1554 DSLExpression result = this->term();
1555 if (!result.hasValue()) {
1556 return {};
1557 }
1558 for (;;) {
1559 Token t = this->peek();
1560 switch (t.fKind) {
1561 case Token::Kind::TK_FLOAT_LITERAL:
1562 if (this->text(t)[0] != '.') {
1563 return result;
1564 }
1565 [[fallthrough]];
1566 case Token::Kind::TK_LBRACKET:
1567 case Token::Kind::TK_DOT:
1568 case Token::Kind::TK_LPAREN:
1569 case Token::Kind::TK_PLUSPLUS:
1570 case Token::Kind::TK_MINUSMINUS: {
1571 if (!depth.increase()) {
1572 return {};
1573 }
1574 DSLExpression next = this->suffix(std::move(result));
1575 if (!next.hasValue()) {
1576 return {};
1577 }
1578 result.swap(next);
1579 break;
1580 }
1581 default:
1582 return result;
1583 }
1584 }
1585 }
1586
swizzle(int line,DSLExpression base,skstd::string_view swizzleMask)1587 DSLExpression DSLParser::swizzle(int line, DSLExpression base,
1588 skstd::string_view swizzleMask) {
1589 SkASSERT(swizzleMask.length() > 0);
1590 if (!base.type().isVector() && !base.type().isScalar()) {
1591 return base.field(swizzleMask, this->position(line));
1592 }
1593 int length = swizzleMask.length();
1594 SkSL::SwizzleComponent::Type components[4];
1595 for (int i = 0; i < length; ++i) {
1596 if (i >= 4) {
1597 this->error(line, "too many components in swizzle mask");
1598 return DSLExpression::Poison();
1599 }
1600 switch (swizzleMask[i]) {
1601 case '0': components[i] = SwizzleComponent::ZERO; break;
1602 case '1': components[i] = SwizzleComponent::ONE; break;
1603 case 'r': components[i] = SwizzleComponent::R; break;
1604 case 'x': components[i] = SwizzleComponent::X; break;
1605 case 's': components[i] = SwizzleComponent::S; break;
1606 case 'L': components[i] = SwizzleComponent::UL; break;
1607 case 'g': components[i] = SwizzleComponent::G; break;
1608 case 'y': components[i] = SwizzleComponent::Y; break;
1609 case 't': components[i] = SwizzleComponent::T; break;
1610 case 'T': components[i] = SwizzleComponent::UT; break;
1611 case 'b': components[i] = SwizzleComponent::B; break;
1612 case 'z': components[i] = SwizzleComponent::Z; break;
1613 case 'p': components[i] = SwizzleComponent::P; break;
1614 case 'R': components[i] = SwizzleComponent::UR; break;
1615 case 'a': components[i] = SwizzleComponent::A; break;
1616 case 'w': components[i] = SwizzleComponent::W; break;
1617 case 'q': components[i] = SwizzleComponent::Q; break;
1618 case 'B': components[i] = SwizzleComponent::UB; break;
1619 default:
1620 this->error(line,
1621 String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
1622 return DSLExpression::Poison();
1623 }
1624 }
1625 switch (length) {
1626 case 1: return dsl::Swizzle(std::move(base), components[0]);
1627 case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1628 case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1629 case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1630 components[3]);
1631 default: SkUNREACHABLE;
1632 }
1633 }
1634
call(int line,dsl::DSLExpression base,ExpressionArray args)1635 dsl::DSLExpression DSLParser::call(int line, dsl::DSLExpression base, ExpressionArray args) {
1636 return DSLExpression(base(std::move(args), this->position(line)), this->position(line));
1637 }
1638
1639 /* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1640 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
suffix(DSLExpression base)1641 DSLExpression DSLParser::suffix(DSLExpression base) {
1642 Token next = this->nextToken();
1643 AutoDSLDepth depth(this);
1644 if (!depth.increase()) {
1645 return {};
1646 }
1647 switch (next.fKind) {
1648 case Token::Kind::TK_LBRACKET: {
1649 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1650 this->error(next, "missing index in '[]'");
1651 return DSLExpression::Poison();
1652 }
1653 DSLExpression index = this->expression();
1654 if (!index.hasValue()) {
1655 return {};
1656 }
1657 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
1658 DSLPossibleExpression result = base[std::move(index)];
1659 if (!result.valid()) {
1660 result.reportErrors(this->position(next));
1661 }
1662 return std::move(result);
1663 }
1664 case Token::Kind::TK_DOT: {
1665 int line = this->peek().fLine;
1666 skstd::string_view text;
1667 if (this->identifier(&text)) {
1668 return this->swizzle(line, std::move(base), text);
1669 }
1670 [[fallthrough]];
1671 }
1672 case Token::Kind::TK_FLOAT_LITERAL: {
1673 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1674 // floating point literals, possibly followed by an identifier. Handle that here.
1675 skstd::string_view field = this->text(next);
1676 SkASSERT(field[0] == '.');
1677 field.remove_prefix(1);
1678 // use the next *raw* token so we don't ignore whitespace - we only care about
1679 // identifiers that directly follow the float
1680 Token id = this->nextRawToken();
1681 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
1682 return this->swizzle(next.fLine, std::move(base), field + this->text(id));
1683 } else if (field.empty()) {
1684 this->error(next, "expected field name or swizzle mask after '.'");
1685 return {{DSLExpression::Poison()}};
1686 }
1687 this->pushback(id);
1688 return this->swizzle(next.fLine, std::move(base), field);
1689 }
1690 case Token::Kind::TK_LPAREN: {
1691 ExpressionArray args;
1692 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1693 for (;;) {
1694 DSLExpression expr = this->assignmentExpression();
1695 if (!expr.hasValue()) {
1696 return {};
1697 }
1698 args.push_back(expr.release());
1699 if (!this->checkNext(Token::Kind::TK_COMMA)) {
1700 break;
1701 }
1702 }
1703 }
1704 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
1705 return this->call(next.fLine, std::move(base), std::move(args));
1706 }
1707 case Token::Kind::TK_PLUSPLUS:
1708 return std::move(base)++;
1709 case Token::Kind::TK_MINUSMINUS:
1710 return std::move(base)--;
1711 default: {
1712 this->error(next, "expected expression suffix, but found '" + this->text(next) + "'");
1713 return {};
1714 }
1715 }
1716 }
1717
1718 /* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
term()1719 DSLExpression DSLParser::term() {
1720 Token t = this->peek();
1721 switch (t.fKind) {
1722 case Token::Kind::TK_IDENTIFIER: {
1723 skstd::string_view text;
1724 if (this->identifier(&text)) {
1725 return dsl::Symbol(text, this->position(t));
1726 }
1727 break;
1728 }
1729 case Token::Kind::TK_INT_LITERAL: {
1730 SKSL_INT i;
1731 if (!this->intLiteral(&i)) {
1732 i = 0;
1733 }
1734 return DSLExpression(i, this->position(t));
1735 }
1736 case Token::Kind::TK_FLOAT_LITERAL: {
1737 SKSL_FLOAT f;
1738 if (!this->floatLiteral(&f)) {
1739 f = 0.0f;
1740 }
1741 return DSLExpression(f, this->position(t));
1742 }
1743 case Token::Kind::TK_TRUE_LITERAL: // fall through
1744 case Token::Kind::TK_FALSE_LITERAL: {
1745 bool b;
1746 SkAssertResult(this->boolLiteral(&b));
1747 return DSLExpression(b, this->position(t));
1748 }
1749 case Token::Kind::TK_LPAREN: {
1750 this->nextToken();
1751 AutoDSLDepth depth(this);
1752 if (!depth.increase()) {
1753 return {};
1754 }
1755 DSLExpression result = this->expression();
1756 if (result.hasValue()) {
1757 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1758 return result;
1759 }
1760 break;
1761 }
1762 default:
1763 this->nextToken();
1764 this->error(t, "expected expression, but found '" + this->text(t) + "'");
1765 fEncounteredFatalError = true;
1766 break;
1767 }
1768 return {};
1769 }
1770
1771 /* INT_LITERAL */
intLiteral(SKSL_INT * dest)1772 bool DSLParser::intLiteral(SKSL_INT* dest) {
1773 Token t;
1774 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1775 return false;
1776 }
1777 skstd::string_view s = this->text(t);
1778 if (!SkSL::stoi(s, dest)) {
1779 this->error(t, "integer is too large: " + s);
1780 return false;
1781 }
1782 return true;
1783 }
1784
1785 /* FLOAT_LITERAL */
floatLiteral(SKSL_FLOAT * dest)1786 bool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1787 Token t;
1788 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1789 return false;
1790 }
1791 skstd::string_view s = this->text(t);
1792 if (!SkSL::stod(s, dest)) {
1793 this->error(t, "floating-point value is too large: " + s);
1794 return false;
1795 }
1796 return true;
1797 }
1798
1799 /* TRUE_LITERAL | FALSE_LITERAL */
boolLiteral(bool * dest)1800 bool DSLParser::boolLiteral(bool* dest) {
1801 Token t = this->nextToken();
1802 switch (t.fKind) {
1803 case Token::Kind::TK_TRUE_LITERAL:
1804 *dest = true;
1805 return true;
1806 case Token::Kind::TK_FALSE_LITERAL:
1807 *dest = false;
1808 return true;
1809 default:
1810 this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1811 return false;
1812 }
1813 }
1814
1815 /* IDENTIFIER */
identifier(skstd::string_view * dest)1816 bool DSLParser::identifier(skstd::string_view* dest) {
1817 Token t;
1818 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1819 *dest = this->text(t);
1820 return true;
1821 }
1822 return false;
1823 }
1824
1825 } // namespace SkSL
1826