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