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