• 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/SkSLParser.h"
9 
10 #include "include/core/SkSpan.h"
11 #include "include/private/SkSLModifiers.h"
12 #include "include/private/SkSLProgramElement.h"
13 #include "include/private/SkSLString.h"
14 #include "include/sksl/DSLBlock.h"
15 #include "include/sksl/DSLCase.h"
16 #include "include/sksl/DSLFunction.h"
17 #include "include/sksl/DSLVar.h"
18 #include "include/sksl/SkSLOperator.h"
19 #include "include/sksl/SkSLVersion.h"
20 #include "src/core/SkTHash.h"
21 #include "src/sksl/SkSLCompiler.h"
22 #include "src/sksl/SkSLConstantFolder.h"
23 #include "src/sksl/SkSLThreadContext.h"
24 #include "src/sksl/dsl/priv/DSLWriter.h"
25 #include "src/sksl/dsl/priv/DSL_priv.h"
26 #include "src/sksl/ir/SkSLExpression.h"
27 #include "src/sksl/ir/SkSLProgram.h"
28 #include "src/sksl/ir/SkSLSymbolTable.h"
29 #include "src/sksl/ir/SkSLVariable.h"
30 
31 #include <algorithm>
32 #include <climits>
33 #include <initializer_list>
34 #include <memory>
35 #include <utility>
36 #include <vector>
37 
38 using namespace SkSL::dsl;
39 
40 namespace SkSL {
41 
42 static constexpr int kMaxParseDepth = 50;
43 
parse_modifier_token(Token::Kind token)44 static int parse_modifier_token(Token::Kind token) {
45     switch (token) {
46         case Token::Kind::TK_UNIFORM:        return Modifiers::kUniform_Flag;
47         case Token::Kind::TK_CONST:          return Modifiers::kConst_Flag;
48         case Token::Kind::TK_IN:             return Modifiers::kIn_Flag;
49         case Token::Kind::TK_OUT:            return Modifiers::kOut_Flag;
50         case Token::Kind::TK_INOUT:          return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
51         case Token::Kind::TK_FLAT:           return Modifiers::kFlat_Flag;
52         case Token::Kind::TK_NOPERSPECTIVE:  return Modifiers::kNoPerspective_Flag;
53         case Token::Kind::TK_PURE:           return Modifiers::kPure_Flag;
54         case Token::Kind::TK_INLINE:         return Modifiers::kInline_Flag;
55         case Token::Kind::TK_NOINLINE:       return Modifiers::kNoInline_Flag;
56         case Token::Kind::TK_HIGHP:          return Modifiers::kHighp_Flag;
57         case Token::Kind::TK_MEDIUMP:        return Modifiers::kMediump_Flag;
58         case Token::Kind::TK_LOWP:           return Modifiers::kLowp_Flag;
59         case Token::Kind::TK_EXPORT:         return Modifiers::kExport_Flag;
60         case Token::Kind::TK_ES3:            return Modifiers::kES3_Flag;
61         case Token::Kind::TK_WORKGROUP:      return Modifiers::kWorkgroup_Flag;
62         case Token::Kind::TK_READONLY:       return Modifiers::kReadOnly_Flag;
63         case Token::Kind::TK_WRITEONLY:      return Modifiers::kWriteOnly_Flag;
64         case Token::Kind::TK_BUFFER:         return Modifiers::kBuffer_Flag;
65         default:                             return 0;
66     }
67 }
68 
69 class Parser::AutoDepth {
70 public:
AutoDepth(Parser * p)71     AutoDepth(Parser* p)
72     : fParser(p)
73     , fDepth(0) {}
74 
~AutoDepth()75     ~AutoDepth() {
76         fParser->fDepth -= fDepth;
77     }
78 
increase()79     bool increase() {
80         ++fDepth;
81         ++fParser->fDepth;
82         if (fParser->fDepth > kMaxParseDepth) {
83             fParser->error(fParser->peek(), "exceeded max parse depth");
84             fParser->fEncounteredFatalError = true;
85             return false;
86         }
87         return true;
88     }
89 
90 private:
91     Parser* fParser;
92     int fDepth;
93 };
94 
95 class Parser::AutoSymbolTable {
96 public:
AutoSymbolTable(Parser * p)97     AutoSymbolTable(Parser* p) : fParser(p) {
98         SymbolTable::Push(&fParser->symbolTable());
99     }
100 
~AutoSymbolTable()101     ~AutoSymbolTable() {
102         SymbolTable::Pop(&fParser->symbolTable());
103     }
104 
105 private:
106     Parser* fParser;
107 };
108 
Parser(Compiler * compiler,const ProgramSettings & settings,ProgramKind kind,std::string text)109 Parser::Parser(Compiler* compiler,
110                const ProgramSettings& settings,
111                ProgramKind kind,
112                std::string text)
113         : fCompiler(*compiler)
114         , fSettings(settings)
115         , fKind(kind)
116         , fText(std::make_unique<std::string>(std::move(text)))
117         , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1) {
118     fLexer.start(*fText);
119 }
120 
symbolTable()121 std::shared_ptr<SymbolTable>& Parser::symbolTable() {
122     return fCompiler.symbolTable();
123 }
124 
addToSymbolTable(DSLVarBase & var,Position pos)125 void Parser::addToSymbolTable(DSLVarBase& var, Position pos) {
126     if (SkSL::Variable* skslVar = DSLWriter::Var(var)) {
127         this->symbolTable()->addWithoutOwnership(skslVar);
128     }
129 }
130 
nextRawToken()131 Token Parser::nextRawToken() {
132     Token token;
133     if (fPushback.fKind != Token::Kind::TK_NONE) {
134         // Retrieve the token from the pushback buffer.
135         token = fPushback;
136         fPushback.fKind = Token::Kind::TK_NONE;
137     } else {
138         // Fetch a token from the lexer.
139         token = fLexer.next();
140 
141         // Some tokens are always invalid, so we detect and report them here.
142         switch (token.fKind) {
143             case Token::Kind::TK_PRIVATE_IDENTIFIER:
144                 if (ProgramConfig::AllowsPrivateIdentifiers(fKind)) {
145                     token.fKind = Token::Kind::TK_IDENTIFIER;
146                     break;
147                 }
148                 [[fallthrough]];
149 
150             case Token::Kind::TK_RESERVED:
151                 this->error(token, "name '" + std::string(this->text(token)) + "' is reserved");
152                 token.fKind = Token::Kind::TK_IDENTIFIER;  // reduces additional follow-up errors
153                 break;
154 
155             case Token::Kind::TK_BAD_OCTAL:
156                 this->error(token, "'" + std::string(this->text(token)) +
157                                    "' is not a valid octal number");
158                 break;
159 
160             default:
161                 break;
162         }
163     }
164 
165     return token;
166 }
167 
is_whitespace(Token::Kind kind)168 static bool is_whitespace(Token::Kind kind) {
169     switch (kind) {
170         case Token::Kind::TK_WHITESPACE:
171         case Token::Kind::TK_LINE_COMMENT:
172         case Token::Kind::TK_BLOCK_COMMENT:
173             return true;
174 
175         default:
176             return false;
177     }
178 }
179 
expectNewline()180 bool Parser::expectNewline() {
181     Token token = this->nextRawToken();
182     if (token.fKind == Token::Kind::TK_WHITESPACE) {
183         // The lexer doesn't distinguish newlines from other forms of whitespace, so we check
184         // for newlines by searching through the token text.
185         std::string_view tokenText = this->text(token);
186         if (tokenText.find_first_of('\r') != std::string_view::npos ||
187             tokenText.find_first_of('\n') != std::string_view::npos) {
188             return true;
189         }
190     }
191     // We didn't find a newline.
192     this->pushback(token);
193     return false;
194 }
195 
nextToken()196 Token Parser::nextToken() {
197     for (;;) {
198         Token token = this->nextRawToken();
199         if (!is_whitespace(token.fKind)) {
200             return token;
201         }
202     }
203 }
204 
pushback(Token t)205 void Parser::pushback(Token t) {
206     SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
207     fPushback = std::move(t);
208 }
209 
peek()210 Token Parser::peek() {
211     if (fPushback.fKind == Token::Kind::TK_NONE) {
212         fPushback = this->nextToken();
213     }
214     return fPushback;
215 }
216 
checkNext(Token::Kind kind,Token * result)217 bool Parser::checkNext(Token::Kind kind, Token* result) {
218     if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
219         return false;
220     }
221     Token next = this->nextToken();
222     if (next.fKind == kind) {
223         if (result) {
224             *result = next;
225         }
226         return true;
227     }
228     this->pushback(std::move(next));
229     return false;
230 }
231 
expect(Token::Kind kind,const char * expected,Token * result)232 bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
233     Token next = this->nextToken();
234     if (next.fKind == kind) {
235         if (result) {
236             *result = std::move(next);
237         }
238         return true;
239     } else {
240         this->error(next, "expected " + std::string(expected) + ", but found '" +
241                           std::string(this->text(next)) + "'");
242         this->fEncounteredFatalError = true;
243         return false;
244     }
245 }
246 
expectIdentifier(Token * result)247 bool Parser::expectIdentifier(Token* result) {
248     if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
249         return false;
250     }
251     if (this->symbolTable()->isBuiltinType(this->text(*result))) {
252         this->error(*result, "expected an identifier, but found type '" +
253                              std::string(this->text(*result)) + "'");
254         this->fEncounteredFatalError = true;
255         return false;
256     }
257     return true;
258 }
259 
checkIdentifier(Token * result)260 bool Parser::checkIdentifier(Token* result) {
261     if (!this->checkNext(Token::Kind::TK_IDENTIFIER, result)) {
262         return false;
263     }
264     if (this->symbolTable()->isBuiltinType(this->text(*result))) {
265         this->pushback(std::move(*result));
266         return false;
267     }
268     return true;
269 }
270 
text(Token token)271 std::string_view Parser::text(Token token) {
272     return std::string_view(fText->data() + token.fOffset, token.fLength);
273 }
274 
position(Token t)275 Position Parser::position(Token t) {
276     if (t.fOffset >= 0) {
277         return Position::Range(t.fOffset, t.fOffset + t.fLength);
278     } else {
279         return Position();
280     }
281 }
282 
error(Token token,std::string_view msg)283 void Parser::error(Token token, std::string_view msg) {
284     this->error(this->position(token), msg);
285 }
286 
error(Position position,std::string_view msg)287 void Parser::error(Position position, std::string_view msg) {
288     GetErrorReporter().error(position, msg);
289 }
290 
rangeFrom(Position start)291 Position Parser::rangeFrom(Position start) {
292     int offset = fPushback.fKind != Token::Kind::TK_NONE ? fPushback.fOffset
293                                                          : fLexer.getCheckpoint().fOffset;
294     return Position::Range(start.startOffset(), offset);
295 }
296 
rangeFrom(Token start)297 Position Parser::rangeFrom(Token start) {
298     return this->rangeFrom(this->position(start));
299 }
300 
301 /* declaration* END_OF_FILE */
program()302 std::unique_ptr<Program> Parser::program() {
303     ErrorReporter* errorReporter = &fCompiler.errorReporter();
304     Start(&fCompiler, fKind, fSettings);
305     SetErrorReporter(errorReporter);
306     errorReporter->setSource(*fText);
307     this->declarations();
308     std::unique_ptr<Program> result;
309     if (!GetErrorReporter().errorCount()) {
310         result = dsl::ReleaseProgram(std::move(fText));
311     }
312     errorReporter->setSource(std::string_view());
313     End();
314     return result;
315 }
316 
moduleInheritingFrom(const SkSL::Module * parent)317 std::unique_ptr<SkSL::Module> Parser::moduleInheritingFrom(const SkSL::Module* parent) {
318     ErrorReporter* errorReporter = &fCompiler.errorReporter();
319     StartModule(&fCompiler, fKind, fSettings, parent);
320     SetErrorReporter(errorReporter);
321     errorReporter->setSource(*fText);
322     this->declarations();
323     this->symbolTable()->takeOwnershipOfString(std::move(*fText));
324     auto result = std::make_unique<SkSL::Module>();
325     result->fParent = parent;
326     result->fSymbols = this->symbolTable();
327     result->fElements = std::move(ThreadContext::ProgramElements());
328     errorReporter->setSource(std::string_view());
329     End();
330     return result;
331 }
332 
declarations()333 void Parser::declarations() {
334     fEncounteredFatalError = false;
335     // Any #version directive must appear as the first thing in a file
336     if (this->peek().fKind == Token::Kind::TK_DIRECTIVE) {
337         this->directive(/*allowVersion=*/true);
338     }
339     bool done = false;
340     while (!done) {
341         switch (this->peek().fKind) {
342             case Token::Kind::TK_END_OF_FILE:
343                 done = true;
344                 break;
345             case Token::Kind::TK_DIRECTIVE:
346                 this->directive(/*allowVersion=*/false);
347                 break;
348             case Token::Kind::TK_INVALID:
349                 this->error(this->peek(), "invalid token");
350                 this->nextToken();
351                 done = true;
352                 break;
353             default:
354                 this->declaration();
355                 done = fEncounteredFatalError;
356                 break;
357         }
358     }
359 }
360 
361 /* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER NEWLINE |
362    DIRECTIVE(#version) INTLITERAL NEWLINE */
directive(bool allowVersion)363 void Parser::directive(bool allowVersion) {
364     Token start;
365     if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
366         return;
367     }
368     std::string_view text = this->text(start);
369     const bool allowExtensions = !ProgramConfig::IsRuntimeEffect(fKind);
370     if (text == "#extension" && allowExtensions) {
371         Token name;
372         if (!this->expectIdentifier(&name)) {
373             return;
374         }
375         if (!this->expect(Token::Kind::TK_COLON, "':'")) {
376             return;
377         }
378         Token behavior;
379         if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
380             return;
381         }
382         std::string_view behaviorText = this->text(behavior);
383         if (behaviorText != "disable") {
384             if (behaviorText == "require" || behaviorText == "enable" || behaviorText == "warn") {
385                 // We don't currently do anything different between require, enable, and warn
386                 dsl::AddExtension(this->text(name));
387             } else {
388                 this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
389             }
390         }
391 
392         // We expect a newline after an #extension directive.
393         if (!this->expectNewline()) {
394             this->error(start, "invalid #extension directive");
395         }
396     } else if (text == "#version") {
397         if (!allowVersion) {
398             this->error(start, "#version directive must appear before anything else");
399             return;
400         }
401         SKSL_INT version;
402         if (!this->intLiteral(&version)) {
403             return;
404         }
405         switch (version) {
406             case 100:
407                 ThreadContext::GetProgramConfig()->fRequiredSkSLVersion = Version::k100;
408                 break;
409             case 300:
410                 ThreadContext::GetProgramConfig()->fRequiredSkSLVersion = Version::k300;
411                 break;
412             default:
413                 this->error(start, "unsupported version number");
414                 return;
415         }
416         // We expect a newline after a #version directive.
417         if (!this->expectNewline()) {
418             this->error(start, "invalid #version directive");
419         }
420     } else {
421         this->error(start, "unsupported directive '" + std::string(this->text(start)) + "'");
422     }
423 }
424 
425 /* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
426    (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
declaration()427 bool Parser::declaration() {
428     Token start = this->peek();
429     if (start.fKind == Token::Kind::TK_SEMICOLON) {
430         this->nextToken();
431         this->error(start, "expected a declaration, but found ';'");
432         return false;
433     }
434     DSLModifiers modifiers = this->modifiers();
435     Token lookahead = this->peek();
436     if (lookahead.fKind == Token::Kind::TK_IDENTIFIER &&
437         !this->symbolTable()->isType(this->text(lookahead))) {
438         // we have an identifier that's not a type, could be the start of an interface block
439         return this->interfaceBlock(modifiers);
440     }
441     if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
442         this->nextToken();
443         Declare(modifiers, this->position(start));
444         return true;
445     }
446     if (lookahead.fKind == Token::Kind::TK_STRUCT) {
447         this->structVarDeclaration(this->position(start), modifiers);
448         return true;
449     }
450     DSLType type = this->type(&modifiers);
451     if (!type.hasValue()) {
452         return false;
453     }
454     Token name;
455     if (!this->expectIdentifier(&name)) {
456         return false;
457     }
458     if (this->checkNext(Token::Kind::TK_LPAREN)) {
459         return this->functionDeclarationEnd(this->position(start), modifiers, type, name);
460     } else {
461         this->globalVarDeclarationEnd(this->position(start), modifiers, type, name);
462         return true;
463     }
464 }
465 
466 /* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
functionDeclarationEnd(Position start,DSLModifiers & modifiers,DSLType type,const Token & name)467 bool Parser::functionDeclarationEnd(Position start,
468                                     DSLModifiers& modifiers,
469                                     DSLType type,
470                                     const Token& name) {
471     SkSTArray<8, DSLParameter> parameters;
472     Token lookahead = this->peek();
473     if (lookahead.fKind == Token::Kind::TK_RPAREN) {
474         // `()` means no parameters at all.
475     } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
476         // `(void)` also means no parameters at all.
477         this->nextToken();
478     } else {
479         for (;;) {
480             size_t paramIndex = parameters.size();
481             std::optional<DSLParameter> parameter = this->parameter(paramIndex);
482             if (!parameter) {
483                 return false;
484             }
485             parameters.push_back(std::move(*parameter));
486             if (!this->checkNext(Token::Kind::TK_COMMA)) {
487                 break;
488             }
489         }
490     }
491     if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
492         return false;
493     }
494     SkSTArray<8, DSLParameter*> parameterPointers;
495     parameterPointers.reserve_back(parameters.size());
496     for (DSLParameter& param : parameters) {
497         parameterPointers.push_back(&param);
498     }
499 
500     DSLFunction result(this->text(name), modifiers, type, parameterPointers,
501                        this->rangeFrom(start));
502 
503     const bool hasFunctionBody = !this->checkNext(Token::Kind::TK_SEMICOLON);
504     if (hasFunctionBody) {
505         AutoSymbolTable symbols(this);
506         for (DSLParameter* var : parameterPointers) {
507             if (!var->name().empty()) {
508                 this->addToSymbolTable(*var);
509             }
510         }
511         Token bodyStart = this->peek();
512         std::optional<DSLBlock> body = this->block();
513         if (!body) {
514             return false;
515         }
516         result.define(std::move(*body), this->rangeFrom(bodyStart));
517     } else {
518         result.prototype();
519     }
520     return true;
521 }
522 
arraySize(SKSL_INT * outResult)523 bool Parser::arraySize(SKSL_INT* outResult) {
524     // Start out with a safe value that won't generate any errors downstream
525     *outResult = 1;
526     Token next = this->peek();
527     if (next.fKind == Token::Kind::TK_RBRACKET) {
528         this->error(this->position(next), "unsized arrays are not permitted here");
529         return true;
530     }
531     DSLExpression sizeExpr = this->expression();
532     if (!sizeExpr.hasValue()) {
533         return false;
534     }
535     if (sizeExpr.isValid()) {
536         std::unique_ptr<SkSL::Expression> sizeLiteral = sizeExpr.release();
537         SKSL_INT size;
538         if (!ConstantFolder::GetConstantInt(*sizeLiteral, &size)) {
539             this->error(sizeLiteral->fPosition, "array size must be an integer");
540             return true;
541         }
542         if (size > INT32_MAX) {
543             this->error(sizeLiteral->fPosition, "array size out of bounds");
544             return true;
545         }
546         if (size <= 0) {
547             this->error(sizeLiteral->fPosition, "array size must be positive");
548             return true;
549         }
550         // Now that we've validated it, output the real value
551         *outResult = size;
552     }
553     return true;
554 }
555 
parseArrayDimensions(Position pos,DSLType * type)556 bool Parser::parseArrayDimensions(Position pos, DSLType* type) {
557     Token next;
558     while (this->checkNext(Token::Kind::TK_LBRACKET, &next)) {
559         if (this->checkNext(Token::Kind::TK_RBRACKET)) {
560             if (this->allowUnsizedArrays()) {
561                 *type = UnsizedArray(*type, this->rangeFrom(pos));
562             } else {
563                 this->error(this->rangeFrom(pos), "unsized arrays are not permitted here");
564             }
565         } else {
566             SKSL_INT size;
567             if (!this->arraySize(&size)) {
568                 return false;
569             }
570             if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
571                 return false;
572             }
573             *type = Array(*type, size, this->rangeFrom(pos));
574         }
575     }
576     return true;
577 }
578 
parseInitializer(Position pos,DSLExpression * initializer)579 bool Parser::parseInitializer(Position pos, DSLExpression* initializer) {
580     if (this->checkNext(Token::Kind::TK_EQ)) {
581         DSLExpression value = this->assignmentExpression();
582         if (!value.hasValue()) {
583             return false;
584         }
585         initializer->swap(value);
586     }
587     return true;
588 }
589 
590 /* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
591    (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
globalVarDeclarationEnd(Position pos,const dsl::DSLModifiers & mods,dsl::DSLType baseType,Token name)592 void Parser::globalVarDeclarationEnd(Position pos,
593                                      const dsl::DSLModifiers& mods,
594                                      dsl::DSLType baseType,
595                                      Token name) {
596     using namespace dsl;
597     DSLType type = baseType;
598     DSLExpression initializer;
599     if (!this->parseArrayDimensions(pos, &type)) {
600         return;
601     }
602     if (!this->parseInitializer(pos, &initializer)) {
603         return;
604     }
605     DSLGlobalVar first(mods, type, this->text(name), std::move(initializer), this->rangeFrom(pos),
606                        this->position(name));
607     Declare(first);
608     this->addToSymbolTable(first);
609 
610     while (this->checkNext(Token::Kind::TK_COMMA)) {
611         type = baseType;
612         Token identifierName;
613         if (!this->expectIdentifier(&identifierName)) {
614             return;
615         }
616         if (!this->parseArrayDimensions(pos, &type)) {
617             return;
618         }
619         DSLExpression anotherInitializer;
620         if (!this->parseInitializer(pos, &anotherInitializer)) {
621             return;
622         }
623         DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
624                           this->rangeFrom(identifierName));
625         Declare(next);
626         this->addToSymbolTable(next, this->position(identifierName));
627     }
628     this->expect(Token::Kind::TK_SEMICOLON, "';'");
629 }
630 
631 /* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
632    (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
localVarDeclarationEnd(Position pos,const dsl::DSLModifiers & mods,dsl::DSLType baseType,Token name)633 DSLStatement Parser::localVarDeclarationEnd(Position pos,
634                                             const dsl::DSLModifiers& mods,
635                                             dsl::DSLType baseType,
636                                             Token name) {
637     using namespace dsl;
638     DSLType type = baseType;
639     DSLExpression initializer;
640     if (!this->parseArrayDimensions(pos, &type)) {
641         return {};
642     }
643     if (!this->parseInitializer(pos, &initializer)) {
644         return {};
645     }
646     DSLVar first(mods, type, this->text(name), std::move(initializer), this->rangeFrom(pos),
647                  this->position(name));
648     DSLStatement result = Declare(first);
649     this->addToSymbolTable(first);
650 
651     while (this->checkNext(Token::Kind::TK_COMMA)) {
652         type = baseType;
653         Token identifierName;
654         if (!this->expectIdentifier(&identifierName)) {
655             return result;
656         }
657         if (!this->parseArrayDimensions(pos, &type)) {
658             return result;
659         }
660         DSLExpression anotherInitializer;
661         if (!this->parseInitializer(pos, &anotherInitializer)) {
662             return result;
663         }
664         DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
665                     this->rangeFrom(identifierName), this->position(identifierName));
666         DSLWriter::AddVarDeclaration(result, next);
667         this->addToSymbolTable(next, this->position(identifierName));
668     }
669     this->expect(Token::Kind::TK_SEMICOLON, "';'");
670     result.setPosition(this->rangeFrom(pos));
671     return result;
672 }
673 
674 /* (varDeclarations | expressionStatement) */
varDeclarationsOrExpressionStatement()675 DSLStatement Parser::varDeclarationsOrExpressionStatement() {
676     Token nextToken = this->peek();
677     if (nextToken.fKind == Token::Kind::TK_CONST) {
678         // Statements that begin with `const` might be variable declarations, but can't be legal
679         // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
680         return this->varDeclarations();
681     }
682 
683     if (nextToken.fKind == Token::Kind::TK_HIGHP ||
684         nextToken.fKind == Token::Kind::TK_MEDIUMP ||
685         nextToken.fKind == Token::Kind::TK_LOWP ||
686         this->symbolTable()->isType(this->text(nextToken))) {
687         // Statements that begin with a typename are most often variable declarations, but
688         // occasionally the type is part of a constructor, and these are actually expression-
689         // statements in disguise. First, attempt the common case: parse it as a vardecl.
690         Checkpoint checkpoint(this);
691         VarDeclarationsPrefix prefix;
692         if (this->varDeclarationsPrefix(&prefix)) {
693             checkpoint.accept();
694             return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
695                                                 prefix.fName);
696         }
697 
698         // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
699         // expression-statement instead.
700         checkpoint.rewind();
701     }
702     return this->expressionStatement();
703 }
704 
705 // Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
706 // statement is a variable-declaration statement, not an expression-statement.
varDeclarationsPrefix(VarDeclarationsPrefix * prefixData)707 bool Parser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
708     prefixData->fPosition = this->position(this->peek());
709     prefixData->fModifiers = this->modifiers();
710     prefixData->fType = this->type(&prefixData->fModifiers);
711     if (!prefixData->fType.hasValue()) {
712         return false;
713     }
714     return this->expectIdentifier(&prefixData->fName);
715 }
716 
717 /* modifiers type IDENTIFIER varDeclarationEnd */
varDeclarations()718 DSLStatement Parser::varDeclarations() {
719     VarDeclarationsPrefix prefix;
720     if (!this->varDeclarationsPrefix(&prefix)) {
721         return {};
722     }
723     return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
724             prefix.fName);
725 }
726 
727 /* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
structDeclaration()728 DSLType Parser::structDeclaration() {
729     Position start = this->position(this->peek());
730     if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
731         return DSLType(nullptr);
732     }
733     Token name;
734     if (!this->expectIdentifier(&name)) {
735         return DSLType(nullptr);
736     }
737     if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
738         return DSLType(nullptr);
739     }
740     AutoDepth depth(this);
741     if (!depth.increase()) {
742         return DSLType(nullptr);
743     }
744     SkTArray<DSLField> fields;
745     SkTHashSet<std::string_view> fieldNames;
746     while (!this->checkNext(Token::Kind::TK_RBRACE)) {
747         Token fieldStart = this->peek();
748         DSLModifiers modifiers = this->modifiers();
749         DSLType type = this->type(&modifiers);
750         if (!type.hasValue()) {
751             return DSLType(nullptr);
752         }
753 
754         do {
755             DSLType actualType = type;
756             Token memberName;
757             if (!this->expectIdentifier(&memberName)) {
758                 return DSLType(nullptr);
759             }
760 
761             while (this->checkNext(Token::Kind::TK_LBRACKET)) {
762                 SKSL_INT size;
763                 if (!this->arraySize(&size)) {
764                     return DSLType(nullptr);
765                 }
766                 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
767                     return DSLType(nullptr);
768                 }
769                 actualType = dsl::Array(actualType, size,
770                         this->rangeFrom(this->position(fieldStart)));
771             }
772 
773             std::string_view nameText = this->text(memberName);
774             if (!fieldNames.contains(nameText)) {
775                 fields.push_back(DSLField(modifiers,
776                                           std::move(actualType),
777                                           nameText,
778                                           this->rangeFrom(fieldStart)));
779                 fieldNames.add(nameText);
780             } else {
781                 this->error(memberName, "field '" + std::string(nameText) +
782                                         "' was already defined in the same struct ('" +
783                                         std::string(this->text(name)) + "')");
784             }
785         } while (this->checkNext(Token::Kind::TK_COMMA));
786         if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
787             return DSLType(nullptr);
788         }
789     }
790     if (fields.empty()) {
791         this->error(this->rangeFrom(start), "struct '" + std::string(this->text(name)) +
792                 "' must contain at least one field");
793     }
794     return dsl::Struct(this->text(name), SkSpan(fields), this->rangeFrom(start));
795 }
796 
797 /* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
structVarDeclaration(Position start,const DSLModifiers & modifiers)798 SkTArray<dsl::DSLGlobalVar> Parser::structVarDeclaration(Position start,
799                                                          const DSLModifiers& modifiers) {
800     DSLType type = this->structDeclaration();
801     if (!type.hasValue()) {
802         return {};
803     }
804     Token name;
805     if (this->checkIdentifier(&name)) {
806         this->globalVarDeclarationEnd(this->rangeFrom(name), modifiers, type, name);
807     } else {
808         this->expect(Token::Kind::TK_SEMICOLON, "';'");
809     }
810     return {};
811 }
812 
813 /* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
parameter(size_t paramIndex)814 std::optional<DSLParameter> Parser::parameter(size_t paramIndex) {
815     Position pos = this->position(this->peek());
816     DSLModifiers modifiers = this->modifiers();
817     DSLType type = this->type(&modifiers);
818     if (!type.hasValue()) {
819         return std::nullopt;
820     }
821     Token name;
822     std::string_view paramText;
823     Position paramPos;
824     if (this->checkIdentifier(&name)) {
825         paramText = this->text(name);
826         paramPos = this->position(name);
827     } else {
828         paramPos = this->rangeFrom(pos);
829     }
830     if (!this->parseArrayDimensions(pos, &type)) {
831         return std::nullopt;
832     }
833     return DSLParameter(modifiers, type, paramText, this->rangeFrom(pos), paramPos);
834 }
835 
836 /** EQ INT_LITERAL */
layoutInt()837 int Parser::layoutInt() {
838     if (!this->expect(Token::Kind::TK_EQ, "'='")) {
839         return -1;
840     }
841     Token resultToken;
842     if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
843         return -1;
844     }
845     std::string_view resultFrag = this->text(resultToken);
846     SKSL_INT resultValue;
847     if (!SkSL::stoi(resultFrag, &resultValue)) {
848         this->error(resultToken, "value in layout is too large: " + std::string(resultFrag));
849         return -1;
850     }
851     return resultValue;
852 }
853 
854 /** EQ IDENTIFIER */
layoutIdentifier()855 std::string_view Parser::layoutIdentifier() {
856     if (!this->expect(Token::Kind::TK_EQ, "'='")) {
857         return {};
858     }
859     Token resultToken;
860     if (!this->expectIdentifier(&resultToken)) {
861         return {};
862     }
863     return this->text(resultToken);
864 }
865 
866 /* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
layout()867 DSLLayout Parser::layout() {
868     enum class LayoutToken {
869         LOCATION,
870         OFFSET,
871         BINDING,
872         TEXTURE,
873         SAMPLER,
874         INDEX,
875         SET,
876         BUILTIN,
877         INPUT_ATTACHMENT_INDEX,
878         ORIGIN_UPPER_LEFT,
879         BLEND_SUPPORT_ALL_EQUATIONS,
880         PUSH_CONSTANT,
881         COLOR,
882         SPIRV,
883         METAL,
884         GL,
885         WGSL
886     };
887 
888     using LayoutMap = SkTHashMap<std::string_view, LayoutToken>;
889     static LayoutMap* sLayoutTokens = new LayoutMap{
890             {"location",                    LayoutToken::LOCATION},
891             {"offset",                      LayoutToken::OFFSET},
892             {"binding",                     LayoutToken::BINDING},
893             {"texture",                     LayoutToken::TEXTURE},
894             {"sampler",                     LayoutToken::SAMPLER},
895             {"index",                       LayoutToken::INDEX},
896             {"set",                         LayoutToken::SET},
897             {"builtin",                     LayoutToken::BUILTIN},
898             {"input_attachment_index",      LayoutToken::INPUT_ATTACHMENT_INDEX},
899             {"origin_upper_left",           LayoutToken::ORIGIN_UPPER_LEFT},
900             {"blend_support_all_equations", LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS},
901             {"push_constant",               LayoutToken::PUSH_CONSTANT},
902             {"color",                       LayoutToken::COLOR},
903             {"spirv",                       LayoutToken::SPIRV},
904             {"metal",                       LayoutToken::METAL},
905             {"gl",                          LayoutToken::GL},
906             {"wgsl",                        LayoutToken::WGSL},
907     };
908 
909     DSLLayout result;
910     if (this->checkNext(Token::Kind::TK_LAYOUT)) {
911         if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
912             return result;
913         }
914         for (;;) {
915             Token t = this->nextToken();
916             std::string text(this->text(t));
917             LayoutToken* found = sLayoutTokens->find(text);
918             if (found != nullptr) {
919                 switch (*found) {
920                     case LayoutToken::SPIRV:
921                         result.spirv(this->position(t));
922                         break;
923                     case LayoutToken::METAL:
924                         result.metal(this->position(t));
925                         break;
926                     case LayoutToken::GL:
927                         result.gl(this->position(t));
928                         break;
929                     case LayoutToken::WGSL:
930                         result.wgsl(this->position(t));
931                         break;
932                     case LayoutToken::ORIGIN_UPPER_LEFT:
933                         result.originUpperLeft(this->position(t));
934                         break;
935                     case LayoutToken::PUSH_CONSTANT:
936                         result.pushConstant(this->position(t));
937                         break;
938                     case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
939                         result.blendSupportAllEquations(this->position(t));
940                         break;
941                     case LayoutToken::COLOR:
942                         result.color(this->position(t));
943                         break;
944                     case LayoutToken::LOCATION:
945                         result.location(this->layoutInt(), this->position(t));
946                         break;
947                     case LayoutToken::OFFSET:
948                         result.offset(this->layoutInt(), this->position(t));
949                         break;
950                     case LayoutToken::BINDING:
951                         result.binding(this->layoutInt(), this->position(t));
952                         break;
953                     case LayoutToken::INDEX:
954                         result.index(this->layoutInt(), this->position(t));
955                         break;
956                     case LayoutToken::SET:
957                         result.set(this->layoutInt(), this->position(t));
958                         break;
959                     case LayoutToken::TEXTURE:
960                         result.texture(this->layoutInt(), this->position(t));
961                         break;
962                     case LayoutToken::SAMPLER:
963                         result.sampler(this->layoutInt(), this->position(t));
964                         break;
965                     case LayoutToken::BUILTIN:
966                         result.builtin(this->layoutInt(), this->position(t));
967                         break;
968                     case LayoutToken::INPUT_ATTACHMENT_INDEX:
969                         result.inputAttachmentIndex(this->layoutInt(), this->position(t));
970                         break;
971                 }
972             } else {
973                 this->error(t, "'" + text + "' is not a valid layout qualifier");
974             }
975             if (this->checkNext(Token::Kind::TK_RPAREN)) {
976                 break;
977             }
978             if (!this->expect(Token::Kind::TK_COMMA, "','")) {
979                 break;
980             }
981         }
982     }
983     return result;
984 }
985 
986 /* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
987             VARYING | INLINE | WORKGROUP | READONLY | WRITEONLY | BUFFER)* */
modifiers()988 DSLModifiers Parser::modifiers() {
989     int start = this->peek().fOffset;
990     DSLLayout layout = this->layout();
991     Token raw = this->nextRawToken();
992     int end = raw.fOffset;
993     if (!is_whitespace(raw.fKind)) {
994         this->pushback(raw);
995     }
996     int flags = 0;
997     for (;;) {
998         int tokenFlag = parse_modifier_token(peek().fKind);
999         if (!tokenFlag) {
1000             break;
1001         }
1002         Token modifier = this->nextToken();
1003         if (int duplicateFlags = (tokenFlag & flags)) {
1004             this->error(modifier, "'" + Modifiers::DescribeFlags(duplicateFlags) +
1005                                   "' appears more than once");
1006         }
1007         flags |= tokenFlag;
1008         end = this->position(modifier).endOffset();
1009     }
1010     return DSLModifiers(std::move(layout), flags, Position::Range(start, end));
1011 }
1012 
1013 /* ifStatement | forStatement | doStatement | whileStatement | block | expression */
statement()1014 DSLStatement Parser::statement() {
1015     Token start = this->nextToken();
1016     AutoDepth depth(this);
1017     if (!depth.increase()) {
1018         return {};
1019     }
1020     this->pushback(start);
1021     switch (start.fKind) {
1022         case Token::Kind::TK_IF:
1023             return this->ifStatement();
1024         case Token::Kind::TK_FOR:
1025             return this->forStatement();
1026         case Token::Kind::TK_DO:
1027             return this->doStatement();
1028         case Token::Kind::TK_WHILE:
1029             return this->whileStatement();
1030         case Token::Kind::TK_SWITCH:
1031             return this->switchStatement();
1032         case Token::Kind::TK_RETURN:
1033             return this->returnStatement();
1034         case Token::Kind::TK_BREAK:
1035             return this->breakStatement();
1036         case Token::Kind::TK_CONTINUE:
1037             return this->continueStatement();
1038         case Token::Kind::TK_DISCARD:
1039             return this->discardStatement();
1040         case Token::Kind::TK_LBRACE: {
1041             std::optional<DSLBlock> result = this->block();
1042             return result ? DSLStatement(std::move(*result)) : DSLStatement();
1043         }
1044         case Token::Kind::TK_SEMICOLON:
1045             this->nextToken();
1046             return DSLBlock();
1047         case Token::Kind::TK_HIGHP:
1048         case Token::Kind::TK_MEDIUMP:
1049         case Token::Kind::TK_LOWP:
1050         case Token::Kind::TK_CONST:
1051         case Token::Kind::TK_IDENTIFIER:
1052             return this->varDeclarationsOrExpressionStatement();
1053         default:
1054             return this->expressionStatement();
1055     }
1056 }
1057 
1058 /* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
type(DSLModifiers * modifiers)1059 DSLType Parser::type(DSLModifiers* modifiers) {
1060     Token type;
1061     if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
1062         return DSLType(nullptr);
1063     }
1064     if (!this->symbolTable()->isType(this->text(type))) {
1065         this->error(type, "no type named '" + std::string(this->text(type)) + "'");
1066         return DSLType::Invalid();
1067     }
1068     DSLType result(this->text(type), modifiers, this->position(type));
1069     Token bracket;
1070     while (this->checkNext(Token::Kind::TK_LBRACKET, &bracket)) {
1071         if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1072             if (this->allowUnsizedArrays()) {
1073                 result = UnsizedArray(result, this->rangeFrom(type));
1074             } else {
1075                 this->error(this->rangeFrom(bracket), "unsized arrays are not permitted here");
1076             }
1077         } else {
1078             SKSL_INT size;
1079             if (!this->arraySize(&size)) {
1080                 return DSLType(nullptr);
1081             }
1082             this->expect(Token::Kind::TK_RBRACKET, "']'");
1083             result = Array(result, size, this->rangeFrom(type));
1084         }
1085     }
1086     return result;
1087 }
1088 
1089 /* IDENTIFIER LBRACE
1090      varDeclaration+
1091    RBRACE (IDENTIFIER (LBRACKET expression RBRACKET)*)? SEMICOLON */
interfaceBlock(const dsl::DSLModifiers & modifiers)1092 bool Parser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
1093     Token typeName;
1094     if (!this->expectIdentifier(&typeName)) {
1095         return false;
1096     }
1097     if (this->peek().fKind != Token::Kind::TK_LBRACE) {
1098         // we only get into interfaceBlock if we found a top-level identifier which was not a type.
1099         // 99% of the time, the user was not actually intending to create an interface block, so
1100         // it's better to report it as an unknown type
1101         this->error(typeName, "no type named '" + std::string(this->text(typeName)) + "'");
1102         return false;
1103     }
1104     this->nextToken();
1105     SkTArray<DSLField> fields;
1106     SkTHashSet<std::string_view> fieldNames;
1107     while (!this->checkNext(Token::Kind::TK_RBRACE)) {
1108         Position fieldPos = this->position(this->peek());
1109         DSLModifiers fieldModifiers = this->modifiers();
1110         DSLType type = this->type(&fieldModifiers);
1111         if (!type.hasValue()) {
1112             return false;
1113         }
1114         do {
1115             Token fieldName;
1116             if (!this->expectIdentifier(&fieldName)) {
1117                 return false;
1118             }
1119             DSLType actualType = type;
1120             if (this->checkNext(Token::Kind::TK_LBRACKET)) {
1121                 Token sizeToken = this->peek();
1122                 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
1123                     SKSL_INT size;
1124                     if (!this->arraySize(&size)) {
1125                         return false;
1126                     }
1127                     actualType = Array(std::move(actualType), size, this->position(typeName));
1128                 } else if (this->allowUnsizedArrays()) {
1129                     actualType = UnsizedArray(std::move(actualType), this->position(typeName));
1130                 } else {
1131                     this->error(sizeToken, "unsized arrays are not permitted here");
1132                 }
1133                 this->expect(Token::Kind::TK_RBRACKET, "']'");
1134             }
1135             if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1136                 return false;
1137             }
1138 
1139             std::string_view nameText = this->text(fieldName);
1140             if (!fieldNames.contains(nameText)) {
1141                 fields.push_back(DSLField(fieldModifiers,
1142                                           std::move(actualType),
1143                                           nameText,
1144                                           this->rangeFrom(fieldPos)));
1145                 fieldNames.add(nameText);
1146             } else {
1147                 this->error(fieldName, "field '" + std::string(nameText) +
1148                                        "' was already defined in the same interface block ('" +
1149                                        std::string(this->text(typeName)) +  "')");
1150             }
1151         } while (this->checkNext(Token::Kind::TK_COMMA));
1152     }
1153     if (fields.empty()) {
1154         this->error(this->rangeFrom(typeName), "interface block '" +
1155                 std::string(this->text(typeName)) + "' must contain at least one member");
1156     }
1157     std::string_view instanceName;
1158     Token instanceNameToken;
1159     SKSL_INT size = 0;
1160     if (this->checkIdentifier(&instanceNameToken)) {
1161         instanceName = this->text(instanceNameToken);
1162         if (this->checkNext(Token::Kind::TK_LBRACKET)) {
1163             if (!this->arraySize(&size)) {
1164                 return false;
1165             }
1166             this->expect(Token::Kind::TK_RBRACKET, "']'");
1167         }
1168     }
1169     if (!fields.empty()) {
1170         dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
1171                             size, this->position(typeName));
1172     }
1173     this->expect(Token::Kind::TK_SEMICOLON, "';'");
1174     return true;
1175 }
1176 
1177 /* IF LPAREN expression RPAREN statement (ELSE statement)? */
ifStatement()1178 DSLStatement Parser::ifStatement() {
1179     Token start;
1180     if (!this->expect(Token::Kind::TK_IF, "'if'", &start)) {
1181         return {};
1182     }
1183     if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1184         return {};
1185     }
1186     DSLExpression test = this->expression();
1187     if (!test.hasValue()) {
1188         return {};
1189     }
1190     if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1191         return {};
1192     }
1193     DSLStatement ifTrue = this->statement();
1194     if (!ifTrue.hasValue()) {
1195         return {};
1196     }
1197     DSLStatement ifFalse;
1198     if (this->checkNext(Token::Kind::TK_ELSE)) {
1199         ifFalse = this->statement();
1200         if (!ifFalse.hasValue()) {
1201             return {};
1202         }
1203     }
1204     Position pos = this->rangeFrom(start);
1205     return If(std::move(test), std::move(ifTrue),
1206               ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), pos);
1207 }
1208 
1209 /* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
doStatement()1210 DSLStatement Parser::doStatement() {
1211     Token start;
1212     if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
1213         return {};
1214     }
1215     DSLStatement statement = this->statement();
1216     if (!statement.hasValue()) {
1217         return {};
1218     }
1219     if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
1220         return {};
1221     }
1222     if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1223         return {};
1224     }
1225     DSLExpression test = this->expression();
1226     if (!test.hasValue()) {
1227         return {};
1228     }
1229     if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1230         return {};
1231     }
1232     if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1233         return {};
1234     }
1235     return Do(std::move(statement), std::move(test), this->rangeFrom(start));
1236 }
1237 
1238 /* WHILE LPAREN expression RPAREN STATEMENT */
whileStatement()1239 DSLStatement Parser::whileStatement() {
1240     Token start;
1241     if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
1242         return {};
1243     }
1244     if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1245         return {};
1246     }
1247     DSLExpression test = this->expression();
1248     if (!test.hasValue()) {
1249         return {};
1250     }
1251     if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1252         return {};
1253     }
1254     DSLStatement statement = this->statement();
1255     if (!statement.hasValue()) {
1256         return {};
1257     }
1258     return While(std::move(test), std::move(statement), this->rangeFrom(start));
1259 }
1260 
1261 /* CASE expression COLON statement* */
switchCase()1262 std::optional<DSLCase> Parser::switchCase() {
1263     Token start;
1264     if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
1265         return {};
1266     }
1267     DSLExpression value = this->expression();
1268     if (!value.hasValue()) {
1269         return {};
1270     }
1271     if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1272         return {};
1273     }
1274     SkTArray<DSLStatement> statements;
1275     while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1276            this->peek().fKind != Token::Kind::TK_CASE &&
1277            this->peek().fKind != Token::Kind::TK_DEFAULT) {
1278         DSLStatement s = this->statement();
1279         if (!s.hasValue()) {
1280             return {};
1281         }
1282         statements.push_back(std::move(s));
1283     }
1284     return DSLCase(std::move(value), std::move(statements));
1285 }
1286 
1287 /* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
switchStatement()1288 DSLStatement Parser::switchStatement() {
1289     Token start;
1290     if (!this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
1291         return {};
1292     }
1293     if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1294         return {};
1295     }
1296     DSLExpression value = this->expression();
1297     if (!value.hasValue()) {
1298         return {};
1299     }
1300     if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1301         return {};
1302     }
1303     if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
1304         return {};
1305     }
1306     SkTArray<DSLCase> cases;
1307     while (this->peek().fKind == Token::Kind::TK_CASE) {
1308         std::optional<DSLCase> c = this->switchCase();
1309         if (!c) {
1310             return {};
1311         }
1312         cases.push_back(std::move(*c));
1313     }
1314     // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1315     // parts of the compiler may rely upon this assumption.
1316     if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1317         SkTArray<DSLStatement> statements;
1318         Token defaultStart;
1319         SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1320         if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1321             return {};
1322         }
1323         while (this->peek().fKind != Token::Kind::TK_RBRACE) {
1324             DSLStatement s = this->statement();
1325             if (!s.hasValue()) {
1326                 return {};
1327             }
1328             statements.push_back(std::move(s));
1329         }
1330         cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
1331     }
1332     if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
1333         return {};
1334     }
1335     Position pos = this->rangeFrom(start);
1336     return Switch(std::move(value), std::move(cases), pos);
1337 }
1338 
range_of_at_least_one_char(int start,int end)1339 static Position range_of_at_least_one_char(int start, int end) {
1340     return Position::Range(start, std::max(end, start + 1));
1341 }
1342 
1343 /* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1344    STATEMENT */
forStatement()1345 dsl::DSLStatement Parser::forStatement() {
1346     Token start;
1347     if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
1348         return {};
1349     }
1350     Token lparen;
1351     if (!this->expect(Token::Kind::TK_LPAREN, "'('", &lparen)) {
1352         return {};
1353     }
1354     AutoSymbolTable symbols(this);
1355     dsl::DSLStatement initializer;
1356     Token nextToken = this->peek();
1357     int firstSemicolonOffset;
1358     if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1359         // An empty init-statement.
1360         firstSemicolonOffset = this->nextToken().fOffset;
1361     } else {
1362         // The init-statement must be an expression or variable declaration.
1363         initializer = this->varDeclarationsOrExpressionStatement();
1364         if (!initializer.hasValue()) {
1365             return {};
1366         }
1367         firstSemicolonOffset = fLexer.getCheckpoint().fOffset - 1;
1368     }
1369     dsl::DSLExpression test;
1370     if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1371         dsl::DSLExpression testValue = this->expression();
1372         if (!testValue.hasValue()) {
1373             return {};
1374         }
1375         test.swap(testValue);
1376     }
1377     Token secondSemicolon;
1378     if (!this->expect(Token::Kind::TK_SEMICOLON, "';'", &secondSemicolon)) {
1379         return {};
1380     }
1381     dsl::DSLExpression next;
1382     if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1383         dsl::DSLExpression nextValue = this->expression();
1384         if (!nextValue.hasValue()) {
1385             return {};
1386         }
1387         next.swap(nextValue);
1388     }
1389     Token rparen;
1390     if (!this->expect(Token::Kind::TK_RPAREN, "')'", &rparen)) {
1391         return {};
1392     }
1393     dsl::DSLStatement statement = this->statement();
1394     if (!statement.hasValue()) {
1395         return {};
1396     }
1397     return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1398                test.hasValue() ? std::move(test) : DSLExpression(),
1399                next.hasValue() ? std::move(next) : DSLExpression(),
1400                std::move(statement),
1401                this->rangeFrom(start),
1402                ForLoopPositions{
1403                     range_of_at_least_one_char(lparen.fOffset + 1, firstSemicolonOffset),
1404                     range_of_at_least_one_char(firstSemicolonOffset + 1, secondSemicolon.fOffset),
1405                     range_of_at_least_one_char(secondSemicolon.fOffset + 1, rparen.fOffset)
1406                });
1407 }
1408 
1409 /* RETURN expression? SEMICOLON */
returnStatement()1410 DSLStatement Parser::returnStatement() {
1411     Token start;
1412     if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
1413         return {};
1414     }
1415     DSLExpression expression;
1416     if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1417         DSLExpression next = this->expression();
1418         if (!next.hasValue()) {
1419             return {};
1420         }
1421         expression.swap(next);
1422     }
1423     if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1424         return {};
1425     }
1426     return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1427             this->rangeFrom(start));
1428 }
1429 
1430 /* BREAK SEMICOLON */
breakStatement()1431 DSLStatement Parser::breakStatement() {
1432     Token start;
1433     if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
1434         return {};
1435     }
1436     if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1437         return {};
1438     }
1439     return Break(this->position(start));
1440 }
1441 
1442 /* CONTINUE SEMICOLON */
continueStatement()1443 DSLStatement Parser::continueStatement() {
1444     Token start;
1445     if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
1446         return {};
1447     }
1448     if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1449         return {};
1450     }
1451     return Continue(this->position(start));
1452 }
1453 
1454 /* DISCARD SEMICOLON */
discardStatement()1455 DSLStatement Parser::discardStatement() {
1456     Token start;
1457     if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
1458         return {};
1459     }
1460     if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1461         return {};
1462     }
1463     return Discard(this->position(start));
1464 }
1465 
1466 /* LBRACE statement* RBRACE */
block()1467 std::optional<DSLBlock> Parser::block() {
1468     Token start;
1469     if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1470         return std::nullopt;
1471     }
1472     AutoDepth depth(this);
1473     if (!depth.increase()) {
1474         return std::nullopt;
1475     }
1476     AutoSymbolTable symbols(this);
1477     StatementArray statements;
1478     for (;;) {
1479         switch (this->peek().fKind) {
1480             case Token::Kind::TK_RBRACE:
1481                 this->nextToken();
1482                 return DSLBlock(std::move(statements), this->symbolTable(), this->rangeFrom(start));
1483             case Token::Kind::TK_END_OF_FILE:
1484                 this->error(this->peek(), "expected '}', but found end of file");
1485                 return std::nullopt;
1486             default: {
1487                 DSLStatement statement = this->statement();
1488                 if (fEncounteredFatalError) {
1489                     return std::nullopt;
1490                 }
1491                 if (statement.hasValue()) {
1492                     statements.push_back(statement.release());
1493                 }
1494                 break;
1495             }
1496         }
1497     }
1498 }
1499 
1500 /* expression SEMICOLON */
expressionStatement()1501 DSLStatement Parser::expressionStatement() {
1502     DSLExpression expr = this->expression();
1503     if (expr.hasValue()) {
1504         if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1505             return {};
1506         }
1507         return DSLStatement(std::move(expr));
1508     }
1509     return {};
1510 }
1511 
operatorRight(Parser::AutoDepth & depth,Operator::Kind op,BinaryParseFn rightFn,DSLExpression & result)1512 bool Parser::operatorRight(Parser::AutoDepth& depth,
1513                            Operator::Kind op,
1514                            BinaryParseFn rightFn,
1515                            DSLExpression& result) {
1516     this->nextToken();
1517     if (!depth.increase()) {
1518         return false;
1519     }
1520     DSLExpression right = (this->*rightFn)();
1521     if (!right.hasValue()) {
1522         return false;
1523     }
1524     Position pos = result.position().rangeThrough(right.position());
1525     DSLExpression next = result.binary(op, std::move(right), pos);
1526     result.swap(next);
1527     return true;
1528 }
1529 
1530 /* assignmentExpression (COMMA assignmentExpression)* */
expression()1531 DSLExpression Parser::expression() {
1532     [[maybe_unused]] Token start = this->peek();
1533     DSLExpression result = this->assignmentExpression();
1534     if (!result.hasValue()) {
1535         return {};
1536     }
1537     Token t;
1538     AutoDepth depth(this);
1539     while (this->peek().fKind == Token::Kind::TK_COMMA) {
1540         if (!operatorRight(depth, Operator::Kind::COMMA, &Parser::assignmentExpression,
1541                 result)) {
1542             return {};
1543         }
1544     }
1545     SkASSERTF(result.position().valid(), "Expression %s has invalid position",
1546             result.description().c_str());
1547     SkASSERTF(result.position().startOffset() == this->position(start).startOffset(),
1548             "Expected %s to start at %d (first token: '%.*s'), but it has range %d-%d\n",
1549             result.description().c_str(), this->position(start).startOffset(),
1550             (int)this->text(start).length(), this->text(start).data(),
1551             result.position().startOffset(), result.position().endOffset());
1552     return result;
1553 }
1554 
1555 /* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1556    BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1557    assignmentExpression)*
1558  */
assignmentExpression()1559 DSLExpression Parser::assignmentExpression() {
1560     AutoDepth depth(this);
1561     DSLExpression result = this->ternaryExpression();
1562     if (!result.hasValue()) {
1563         return {};
1564     }
1565     for (;;) {
1566         switch (this->peek().fKind) {
1567             case Token::Kind::TK_EQ:
1568                 if (!operatorRight(depth, Operator::Kind::EQ, &Parser::assignmentExpression,
1569                         result)) {
1570                     return {};
1571                 }
1572                 break;
1573             case Token::Kind::TK_STAREQ:
1574                 if (!operatorRight(depth, Operator::Kind::STAREQ, &Parser::assignmentExpression,
1575                         result)) {
1576                     return {};
1577                 }
1578                 break;
1579             case Token::Kind::TK_SLASHEQ:
1580                 if (!operatorRight(depth, Operator::Kind::SLASHEQ, &Parser::assignmentExpression,
1581                         result)) {
1582                     return {};
1583                 }
1584                 break;
1585             case Token::Kind::TK_PERCENTEQ:
1586                 if (!operatorRight(depth, Operator::Kind::PERCENTEQ,
1587                         &Parser::assignmentExpression, result)) {
1588                     return {};
1589                 }
1590                 break;
1591             case Token::Kind::TK_PLUSEQ:
1592                 if (!operatorRight(depth, Operator::Kind::PLUSEQ, &Parser::assignmentExpression,
1593                         result)) {
1594                     return {};
1595                 }
1596                 break;
1597             case Token::Kind::TK_MINUSEQ:
1598                 if (!operatorRight(depth, Operator::Kind::MINUSEQ, &Parser::assignmentExpression,
1599                         result)) {
1600                     return {};
1601                 }
1602                 break;
1603             case Token::Kind::TK_SHLEQ:
1604                 if (!operatorRight(depth, Operator::Kind::SHLEQ, &Parser::assignmentExpression,
1605                         result)) {
1606                     return {};
1607                 }
1608                 break;
1609             case Token::Kind::TK_SHREQ:
1610                 if (!operatorRight(depth, Operator::Kind::SHREQ, &Parser::assignmentExpression,
1611                         result)) {
1612                     return {};
1613                 }
1614                 break;
1615             case Token::Kind::TK_BITWISEANDEQ:
1616                 if (!operatorRight(depth, Operator::Kind::BITWISEANDEQ,
1617                         &Parser::assignmentExpression, result)) {
1618                     return {};
1619                 }
1620                 break;
1621             case Token::Kind::TK_BITWISEXOREQ:
1622                 if (!operatorRight(depth, Operator::Kind::BITWISEXOREQ,
1623                         &Parser::assignmentExpression, result)) {
1624                     return {};
1625                 }
1626                 break;
1627             case Token::Kind::TK_BITWISEOREQ:
1628                 if (!operatorRight(depth, Operator::Kind::BITWISEOREQ,
1629                         &Parser::assignmentExpression, result)) {
1630                     return {};
1631                 }
1632                 break;
1633             default:
1634                 return result;
1635         }
1636     }
1637 }
1638 
1639 /* logicalOrExpression ('?' expression ':' assignmentExpression)? */
ternaryExpression()1640 DSLExpression Parser::ternaryExpression() {
1641     DSLExpression base = this->logicalOrExpression();
1642     if (!base.hasValue()) {
1643         return {};
1644     }
1645     if (!this->checkNext(Token::Kind::TK_QUESTION)) {
1646         return base;
1647     }
1648     AutoDepth depth(this);
1649     if (!depth.increase()) {
1650         return {};
1651     }
1652     DSLExpression trueExpr = this->expression();
1653     if (!trueExpr.hasValue()) {
1654         return {};
1655     }
1656     if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1657         return {};
1658     }
1659     DSLExpression falseExpr = this->assignmentExpression();
1660     if (!falseExpr.hasValue()) {
1661         return {};
1662     }
1663     Position pos = base.position().rangeThrough(falseExpr.position());
1664     return Select(std::move(base), std::move(trueExpr), std::move(falseExpr), pos);
1665 }
1666 
1667 /* logicalXorExpression (LOGICALOR logicalXorExpression)* */
logicalOrExpression()1668 DSLExpression Parser::logicalOrExpression() {
1669     AutoDepth depth(this);
1670     DSLExpression result = this->logicalXorExpression();
1671     if (!result.hasValue()) {
1672         return {};
1673     }
1674     while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1675         if (!operatorRight(depth, Operator::Kind::LOGICALOR, &Parser::logicalXorExpression,
1676                 result)) {
1677             return {};
1678         }
1679     }
1680     return result;
1681 }
1682 
1683 /* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
logicalXorExpression()1684 DSLExpression Parser::logicalXorExpression() {
1685     AutoDepth depth(this);
1686     DSLExpression result = this->logicalAndExpression();
1687     if (!result.hasValue()) {
1688         return {};
1689     }
1690     while (this->peek().fKind == Token::Kind::TK_LOGICALXOR) {
1691         if (!operatorRight(depth, Operator::Kind::LOGICALXOR, &Parser::logicalAndExpression,
1692                 result)) {
1693             return {};
1694         }
1695     }
1696     return result;
1697 }
1698 
1699 /* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
logicalAndExpression()1700 DSLExpression Parser::logicalAndExpression() {
1701     AutoDepth depth(this);
1702     DSLExpression result = this->bitwiseOrExpression();
1703     if (!result.hasValue()) {
1704         return {};
1705     }
1706     while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1707         if (!operatorRight(depth, Operator::Kind::LOGICALAND, &Parser::bitwiseOrExpression,
1708                 result)) {
1709             return {};
1710         }
1711     }
1712     return result;
1713 }
1714 
1715 /* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
bitwiseOrExpression()1716 DSLExpression Parser::bitwiseOrExpression() {
1717     AutoDepth depth(this);
1718     DSLExpression result = this->bitwiseXorExpression();
1719     if (!result.hasValue()) {
1720         return {};
1721     }
1722     while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1723         if (!operatorRight(depth, Operator::Kind::BITWISEOR, &Parser::bitwiseXorExpression,
1724                 result)) {
1725             return {};
1726         }
1727     }
1728     return result;
1729 }
1730 
1731 /* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
bitwiseXorExpression()1732 DSLExpression Parser::bitwiseXorExpression() {
1733     AutoDepth depth(this);
1734     DSLExpression result = this->bitwiseAndExpression();
1735     if (!result.hasValue()) {
1736         return {};
1737     }
1738     while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1739         if (!operatorRight(depth, Operator::Kind::BITWISEXOR, &Parser::bitwiseAndExpression,
1740                 result)) {
1741             return {};
1742         }
1743     }
1744     return result;
1745 }
1746 
1747 /* equalityExpression (BITWISEAND equalityExpression)* */
bitwiseAndExpression()1748 DSLExpression Parser::bitwiseAndExpression() {
1749     AutoDepth depth(this);
1750     DSLExpression result = this->equalityExpression();
1751     if (!result.hasValue()) {
1752         return {};
1753     }
1754     while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1755         if (!operatorRight(depth, Operator::Kind::BITWISEAND, &Parser::equalityExpression,
1756                 result)) {
1757             return {};
1758         }
1759     }
1760     return result;
1761 }
1762 
1763 /* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
equalityExpression()1764 DSLExpression Parser::equalityExpression() {
1765     AutoDepth depth(this);
1766     DSLExpression result = this->relationalExpression();
1767     if (!result.hasValue()) {
1768         return {};
1769     }
1770     for (;;) {
1771         switch (this->peek().fKind) {
1772             case Token::Kind::TK_EQEQ:
1773                 if (!operatorRight(depth, Operator::Kind::EQEQ, &Parser::relationalExpression,
1774                         result)) {
1775                     return {};
1776                 }
1777                 break;
1778             case Token::Kind::TK_NEQ:
1779                 if (!operatorRight(depth, Operator::Kind::NEQ, &Parser::relationalExpression,
1780                         result)) {
1781                     return {};
1782                 }
1783                 break;
1784             default: return result;
1785         }
1786     }
1787 }
1788 
1789 /* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
relationalExpression()1790 DSLExpression Parser::relationalExpression() {
1791     AutoDepth depth(this);
1792     DSLExpression result = this->shiftExpression();
1793     if (!result.hasValue()) {
1794         return {};
1795     }
1796     for (;;) {
1797         switch (this->peek().fKind) {
1798             case Token::Kind::TK_LT:
1799                 if (!operatorRight(depth, Operator::Kind::LT, &Parser::shiftExpression,
1800                         result)) {
1801                     return {};
1802                 }
1803                 break;
1804             case Token::Kind::TK_GT:
1805                 if (!operatorRight(depth, Operator::Kind::GT, &Parser::shiftExpression,
1806                         result)) {
1807                     return {};
1808                 }
1809                 break;
1810             case Token::Kind::TK_LTEQ:
1811                 if (!operatorRight(depth, Operator::Kind::LTEQ, &Parser::shiftExpression,
1812                         result)) {
1813                     return {};
1814                 }
1815                 break;
1816             case Token::Kind::TK_GTEQ:
1817                 if (!operatorRight(depth, Operator::Kind::GTEQ, &Parser::shiftExpression,
1818                         result)) {
1819                     return {};
1820                 }
1821                 break;
1822             default:
1823                 return result;
1824         }
1825     }
1826 }
1827 
1828 /* additiveExpression ((SHL | SHR) additiveExpression)* */
shiftExpression()1829 DSLExpression Parser::shiftExpression() {
1830     AutoDepth depth(this);
1831     DSLExpression result = this->additiveExpression();
1832     if (!result.hasValue()) {
1833         return {};
1834     }
1835     for (;;) {
1836         switch (this->peek().fKind) {
1837             case Token::Kind::TK_SHL:
1838                 if (!operatorRight(depth, Operator::Kind::SHL, &Parser::additiveExpression,
1839                         result)) {
1840                     return {};
1841                 }
1842                 break;
1843             case Token::Kind::TK_SHR:
1844                 if (!operatorRight(depth, Operator::Kind::SHR, &Parser::additiveExpression,
1845                         result)) {
1846                     return {};
1847                 }
1848                 break;
1849             default:
1850                 return result;
1851         }
1852     }
1853 }
1854 
1855 /* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
additiveExpression()1856 DSLExpression Parser::additiveExpression() {
1857     AutoDepth depth(this);
1858     DSLExpression result = this->multiplicativeExpression();
1859     if (!result.hasValue()) {
1860         return {};
1861     }
1862     for (;;) {
1863         switch (this->peek().fKind) {
1864             case Token::Kind::TK_PLUS:
1865                 if (!operatorRight(depth, Operator::Kind::PLUS,
1866                         &Parser::multiplicativeExpression, result)) {
1867                     return {};
1868                 }
1869                 break;
1870             case Token::Kind::TK_MINUS:
1871                 if (!operatorRight(depth, Operator::Kind::MINUS,
1872                         &Parser::multiplicativeExpression, result)) {
1873                     return {};
1874                 }
1875                 break;
1876             default:
1877                 return result;
1878         }
1879     }
1880 }
1881 
1882 /* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
multiplicativeExpression()1883 DSLExpression Parser::multiplicativeExpression() {
1884     AutoDepth depth(this);
1885     DSLExpression result = this->unaryExpression();
1886     if (!result.hasValue()) {
1887         return {};
1888     }
1889     for (;;) {
1890         switch (this->peek().fKind) {
1891             case Token::Kind::TK_STAR:
1892                 if (!operatorRight(depth, Operator::Kind::STAR, &Parser::unaryExpression,
1893                         result)) {
1894                     return {};
1895                 }
1896                 break;
1897             case Token::Kind::TK_SLASH:
1898                 if (!operatorRight(depth, Operator::Kind::SLASH, &Parser::unaryExpression,
1899                         result)) {
1900                     return {};
1901                 }
1902                 break;
1903             case Token::Kind::TK_PERCENT:
1904                 if (!operatorRight(depth, Operator::Kind::PERCENT, &Parser::unaryExpression,
1905                         result)) {
1906                     return {};
1907                 }
1908                 break;
1909             default: return result;
1910         }
1911     }
1912 }
1913 
1914 /* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
unaryExpression()1915 DSLExpression Parser::unaryExpression() {
1916     AutoDepth depth(this);
1917     Token start = this->peek();
1918     switch (start.fKind) {
1919         case Token::Kind::TK_PLUS:
1920         case Token::Kind::TK_MINUS:
1921         case Token::Kind::TK_LOGICALNOT:
1922         case Token::Kind::TK_BITWISENOT:
1923         case Token::Kind::TK_PLUSPLUS:
1924         case Token::Kind::TK_MINUSMINUS: {
1925             this->nextToken();
1926             if (!depth.increase()) {
1927                 return {};
1928             }
1929             DSLExpression expr = this->unaryExpression();
1930             if (!expr.hasValue()) {
1931                 return {};
1932             }
1933             Position p = Position::Range(start.fOffset, expr.position().endOffset());
1934             switch (start.fKind) {
1935                 case Token::Kind::TK_PLUS:       return expr.prefix(Operator::Kind::PLUS, p);
1936                 case Token::Kind::TK_MINUS:      return expr.prefix(Operator::Kind::MINUS, p);
1937                 case Token::Kind::TK_LOGICALNOT: return expr.prefix(Operator::Kind::LOGICALNOT, p);
1938                 case Token::Kind::TK_BITWISENOT: return expr.prefix(Operator::Kind::BITWISENOT, p);
1939                 case Token::Kind::TK_PLUSPLUS:   return expr.prefix(Operator::Kind::PLUSPLUS, p);
1940                 case Token::Kind::TK_MINUSMINUS: return expr.prefix(Operator::Kind::MINUSMINUS, p);
1941                 default: SkUNREACHABLE;
1942             }
1943         }
1944         default:
1945             return this->postfixExpression();
1946     }
1947 }
1948 
1949 /* term suffix* */
postfixExpression()1950 DSLExpression Parser::postfixExpression() {
1951     AutoDepth depth(this);
1952     DSLExpression result = this->term();
1953     if (!result.hasValue()) {
1954         return {};
1955     }
1956     for (;;) {
1957         Token t = this->peek();
1958         switch (t.fKind) {
1959             case Token::Kind::TK_FLOAT_LITERAL:
1960                 if (this->text(t)[0] != '.') {
1961                     return result;
1962                 }
1963                 [[fallthrough]];
1964             case Token::Kind::TK_LBRACKET:
1965             case Token::Kind::TK_DOT:
1966             case Token::Kind::TK_LPAREN:
1967             case Token::Kind::TK_PLUSPLUS:
1968             case Token::Kind::TK_MINUSMINUS: {
1969                 if (!depth.increase()) {
1970                     return {};
1971                 }
1972                 DSLExpression next = this->suffix(std::move(result));
1973                 if (!next.hasValue()) {
1974                     return {};
1975                 }
1976                 result.swap(next);
1977                 break;
1978             }
1979             default:
1980                 return result;
1981         }
1982     }
1983 }
1984 
swizzle(Position pos,DSLExpression base,std::string_view swizzleMask,Position maskPos)1985 DSLExpression Parser::swizzle(Position pos,
1986                               DSLExpression base,
1987                               std::string_view swizzleMask,
1988                               Position maskPos) {
1989     SkASSERT(swizzleMask.length() > 0);
1990     if (!base.type().isVector() && !base.type().isScalar()) {
1991         return base.field(swizzleMask, pos);
1992     }
1993     int length = swizzleMask.length();
1994     SkSL::SwizzleComponent::Type components[4];
1995     for (int i = 0; i < length; ++i) {
1996         if (i >= 4) {
1997             Position errorPos = maskPos.valid() ? Position::Range(maskPos.startOffset() + 4,
1998                                                                   maskPos.endOffset())
1999                                                 : pos;
2000             this->error(errorPos, "too many components in swizzle mask");
2001             return DSLExpression::Poison(pos);
2002         }
2003         switch (swizzleMask[i]) {
2004             case '0': components[i] = SwizzleComponent::ZERO; break;
2005             case '1': components[i] = SwizzleComponent::ONE;  break;
2006             case 'r': components[i] = SwizzleComponent::R;    break;
2007             case 'x': components[i] = SwizzleComponent::X;    break;
2008             case 's': components[i] = SwizzleComponent::S;    break;
2009             case 'L': components[i] = SwizzleComponent::UL;   break;
2010             case 'g': components[i] = SwizzleComponent::G;    break;
2011             case 'y': components[i] = SwizzleComponent::Y;    break;
2012             case 't': components[i] = SwizzleComponent::T;    break;
2013             case 'T': components[i] = SwizzleComponent::UT;   break;
2014             case 'b': components[i] = SwizzleComponent::B;    break;
2015             case 'z': components[i] = SwizzleComponent::Z;    break;
2016             case 'p': components[i] = SwizzleComponent::P;    break;
2017             case 'R': components[i] = SwizzleComponent::UR;   break;
2018             case 'a': components[i] = SwizzleComponent::A;    break;
2019             case 'w': components[i] = SwizzleComponent::W;    break;
2020             case 'q': components[i] = SwizzleComponent::Q;    break;
2021             case 'B': components[i] = SwizzleComponent::UB;   break;
2022             default: {
2023                 Position componentPos = Position::Range(maskPos.startOffset() + i,
2024                         maskPos.startOffset() + i + 1);
2025                 this->error(componentPos, String::printf("invalid swizzle component '%c'",
2026                         swizzleMask[i]).c_str());
2027                 return DSLExpression::Poison(pos);
2028             }
2029         }
2030     }
2031     switch (length) {
2032         case 1: return dsl::Swizzle(std::move(base), components[0], pos, maskPos);
2033         case 2: return dsl::Swizzle(std::move(base), components[0], components[1], pos, maskPos);
2034         case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
2035                                     pos, maskPos);
2036         case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
2037                                     components[3], pos, maskPos);
2038         default: SkUNREACHABLE;
2039     }
2040 }
2041 
call(Position pos,dsl::DSLExpression base,ExpressionArray args)2042 dsl::DSLExpression Parser::call(Position pos, dsl::DSLExpression base, ExpressionArray args) {
2043     return base(std::move(args), pos);
2044 }
2045 
2046 /* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
2047    PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
suffix(DSLExpression base)2048 DSLExpression Parser::suffix(DSLExpression base) {
2049     Token next = this->nextToken();
2050     AutoDepth depth(this);
2051     if (!depth.increase()) {
2052         return {};
2053     }
2054     switch (next.fKind) {
2055         case Token::Kind::TK_LBRACKET: {
2056             if (this->checkNext(Token::Kind::TK_RBRACKET)) {
2057                 this->error(this->rangeFrom(next), "missing index in '[]'");
2058                 return DSLExpression::Poison(this->rangeFrom(base.position()));
2059             }
2060             DSLExpression index = this->expression();
2061             if (!index.hasValue()) {
2062                 return {};
2063             }
2064             this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
2065             return base.index(std::move(index), this->rangeFrom(base.position()));
2066         }
2067         case Token::Kind::TK_DOT: {
2068             std::string_view text;
2069             if (this->identifier(&text)) {
2070                 Position pos = this->rangeFrom(base.position());
2071                 return this->swizzle(pos, std::move(base), text,
2072                         this->rangeFrom(this->position(next).after()));
2073             }
2074             [[fallthrough]];
2075         }
2076         case Token::Kind::TK_FLOAT_LITERAL: {
2077             // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
2078             // floating point literals, possibly followed by an identifier. Handle that here.
2079             std::string_view field = this->text(next);
2080             SkASSERT(field[0] == '.');
2081             field.remove_prefix(1);
2082             // use the next *raw* token so we don't ignore whitespace - we only care about
2083             // identifiers that directly follow the float
2084             Position pos = this->rangeFrom(base.position());
2085             Position start = this->position(next);
2086             // skip past the "."
2087             start = Position::Range(start.startOffset() + 1, start.endOffset());
2088             Position maskPos = this->rangeFrom(start);
2089             Token id = this->nextRawToken();
2090             if (id.fKind == Token::Kind::TK_IDENTIFIER) {
2091                 pos = this->rangeFrom(base.position());
2092                 maskPos = this->rangeFrom(start);
2093                 return this->swizzle(pos, std::move(base), std::string(field) +
2094                         std::string(this->text(id)), maskPos);
2095             } else if (field.empty()) {
2096                 this->error(pos, "expected field name or swizzle mask after '.'");
2097                 return {{DSLExpression::Poison(pos)}};
2098             }
2099             this->pushback(id);
2100             return this->swizzle(pos, std::move(base), field, maskPos);
2101         }
2102         case Token::Kind::TK_LPAREN: {
2103             ExpressionArray args;
2104             if (this->peek().fKind != Token::Kind::TK_RPAREN) {
2105                 for (;;) {
2106                     DSLExpression expr = this->assignmentExpression();
2107                     if (!expr.hasValue()) {
2108                         return {};
2109                     }
2110                     args.push_back(expr.release());
2111                     if (!this->checkNext(Token::Kind::TK_COMMA)) {
2112                         break;
2113                     }
2114                 }
2115             }
2116             this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
2117             Position pos = this->rangeFrom(base.position());
2118             return this->call(pos, std::move(base), std::move(args));
2119         }
2120         case Token::Kind::TK_PLUSPLUS:
2121             return base.postfix(Operator::Kind::PLUSPLUS, this->rangeFrom(base.position()));
2122         case Token::Kind::TK_MINUSMINUS:
2123             return base.postfix(Operator::Kind::MINUSMINUS, this->rangeFrom(base.position()));
2124         default: {
2125             this->error(next, "expected expression suffix, but found '" +
2126                               std::string(this->text(next)) + "'");
2127             return {};
2128         }
2129     }
2130 }
2131 
2132 /* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
term()2133 DSLExpression Parser::term() {
2134     Token t = this->peek();
2135     switch (t.fKind) {
2136         case Token::Kind::TK_IDENTIFIER: {
2137             std::string_view text;
2138             if (this->identifier(&text)) {
2139                 Position pos = this->position(t);
2140                 return DSLExpression(fCompiler.convertIdentifier(pos, text), pos);
2141             }
2142             break;
2143         }
2144         case Token::Kind::TK_INT_LITERAL: {
2145             SKSL_INT i;
2146             if (!this->intLiteral(&i)) {
2147                 i = 0;
2148             }
2149             return DSLExpression(i, this->position(t));
2150         }
2151         case Token::Kind::TK_FLOAT_LITERAL: {
2152             SKSL_FLOAT f;
2153             if (!this->floatLiteral(&f)) {
2154                 f = 0.0f;
2155             }
2156             return DSLExpression(f, this->position(t));
2157         }
2158         case Token::Kind::TK_TRUE_LITERAL: // fall through
2159         case Token::Kind::TK_FALSE_LITERAL: {
2160             bool b;
2161             SkAssertResult(this->boolLiteral(&b));
2162             return DSLExpression(b, this->position(t));
2163         }
2164         case Token::Kind::TK_LPAREN: {
2165             this->nextToken();
2166             AutoDepth depth(this);
2167             if (!depth.increase()) {
2168                 return {};
2169             }
2170             DSLExpression result = this->expression();
2171             if (result.hasValue()) {
2172                 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
2173                 result.setPosition(this->rangeFrom(this->position(t)));
2174                 return result;
2175             }
2176             break;
2177         }
2178         default:
2179             this->nextToken();
2180             this->error(t, "expected expression, but found '" + std::string(this->text(t)) + "'");
2181             fEncounteredFatalError = true;
2182             break;
2183     }
2184     return {};
2185 }
2186 
2187 /* INT_LITERAL */
intLiteral(SKSL_INT * dest)2188 bool Parser::intLiteral(SKSL_INT* dest) {
2189     Token t;
2190     if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
2191         return false;
2192     }
2193     std::string_view s = this->text(t);
2194     if (!SkSL::stoi(s, dest)) {
2195         this->error(t, "integer is too large: " + std::string(s));
2196         return false;
2197     }
2198     return true;
2199 }
2200 
2201 /* FLOAT_LITERAL */
floatLiteral(SKSL_FLOAT * dest)2202 bool Parser::floatLiteral(SKSL_FLOAT* dest) {
2203     Token t;
2204     if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
2205         return false;
2206     }
2207     std::string_view s = this->text(t);
2208     if (!SkSL::stod(s, dest)) {
2209         this->error(t, "floating-point value is too large: " + std::string(s));
2210         return false;
2211     }
2212     return true;
2213 }
2214 
2215 /* TRUE_LITERAL | FALSE_LITERAL */
boolLiteral(bool * dest)2216 bool Parser::boolLiteral(bool* dest) {
2217     Token t = this->nextToken();
2218     switch (t.fKind) {
2219         case Token::Kind::TK_TRUE_LITERAL:
2220             *dest = true;
2221             return true;
2222         case Token::Kind::TK_FALSE_LITERAL:
2223             *dest = false;
2224             return true;
2225         default:
2226             this->error(t, "expected 'true' or 'false', but found '" +
2227                            std::string(this->text(t)) + "'");
2228             return false;
2229     }
2230 }
2231 
2232 /* IDENTIFIER */
identifier(std::string_view * dest)2233 bool Parser::identifier(std::string_view* dest) {
2234     Token t;
2235     if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
2236         *dest = this->text(t);
2237         return true;
2238     }
2239     return false;
2240 }
2241 
2242 }  // namespace SkSL
2243