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