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