Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkSLParser.cpp
Go to the documentation of this file.
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
9
10#include "include/core/SkSpan.h"
15#include "src/core/SkTHash.h"
22#include "src/sksl/SkSLString.h"
45#include "src/sksl/ir/SkSLNop.h"
63
64#include <algorithm>
65#include <climits>
66#include <initializer_list>
67#include <memory>
68#include <utility>
69#include <vector>
70
71using namespace skia_private;
72
73namespace SkSL {
74
75static constexpr int kMaxParseDepth = 50;
76
102
104public:
105 AutoDepth(Parser* p) : fParser(p), fDepth(0) {}
106
108 fParser->fDepth -= fDepth;
109 }
110
111 bool increase() {
112 ++fDepth;
113 ++fParser->fDepth;
114 if (fParser->fDepth > kMaxParseDepth) {
115 fParser->error(fParser->peek(), "exceeded max parse depth");
116 fParser->fEncounteredFatalError = true;
117 return false;
118 }
119 return true;
120 }
121
122private:
123 Parser* fParser;
124 int fDepth;
125};
126
128public:
129 AutoSymbolTable(Parser* p, std::unique_ptr<SymbolTable>* newSymbolTable, bool enable = true) {
130 if (enable) {
131 fParser = p;
132 SymbolTable*& ctxSymbols = this->contextSymbolTable();
133 *newSymbolTable = std::make_unique<SymbolTable>(ctxSymbols, ctxSymbols->isBuiltin());
134 ctxSymbols = newSymbolTable->get();
135 }
136 }
137
139 if (fParser) {
140 SymbolTable*& ctxSymbols = this->contextSymbolTable();
141 ctxSymbols = ctxSymbols->fParent;
142 }
143 }
144
145private:
146 SymbolTable*& contextSymbolTable() { return fParser->fCompiler.context().fSymbolTable; }
147
148 Parser* fParser = nullptr;
149};
150
152public:
153 Checkpoint(Parser* p) : fParser(p) {
154 Context& context = fParser->fCompiler.context();
155 fPushbackCheckpoint = fParser->fPushback;
156 fLexerCheckpoint = fParser->fLexer.getCheckpoint();
157 fOldErrorReporter = context.fErrors;
158 fOldEncounteredFatalError = fParser->fEncounteredFatalError;
159 SkASSERT(fOldErrorReporter);
160 context.setErrorReporter(&fErrorReporter);
161 }
162
164 SkASSERTF(!fOldErrorReporter, "Checkpoint was not accepted or rewound before destruction");
165 }
166
167 void accept() {
168 this->restoreErrorReporter();
169 // Parser errors should have been fatal, but we can encounter other errors like type
170 // mismatches despite accepting the parse. Forward those messages to the actual error
171 // handler now.
172 fErrorReporter.forwardErrors(fParser);
173 }
174
175 void rewind() {
176 this->restoreErrorReporter();
177 fParser->fPushback = fPushbackCheckpoint;
178 fParser->fLexer.rewindToCheckpoint(fLexerCheckpoint);
179 fParser->fEncounteredFatalError = fOldEncounteredFatalError;
180 }
181
182private:
183 class ForwardingErrorReporter : public ErrorReporter {
184 public:
185 void handleError(std::string_view msg, Position pos) override {
186 fErrors.push_back({std::string(msg), pos});
187 }
188
189 void forwardErrors(Parser* parser) {
190 for (const Error& error : fErrors) {
191 parser->error(error.fPos, error.fMsg);
192 }
193 }
194
195 private:
196 struct Error {
197 std::string fMsg;
198 Position fPos;
199 };
200
202 };
203
204 void restoreErrorReporter() {
205 SkASSERT(fOldErrorReporter);
206 fParser->fCompiler.context().setErrorReporter(fOldErrorReporter);
207 fOldErrorReporter = nullptr;
208 }
209
210 Parser* fParser;
211 Token fPushbackCheckpoint;
212 SkSL::Lexer::Checkpoint fLexerCheckpoint;
213 ForwardingErrorReporter fErrorReporter;
214 ErrorReporter* fOldErrorReporter;
215 bool fOldEncounteredFatalError;
216};
217
219 const ProgramSettings& settings,
220 ProgramKind kind,
221 std::unique_ptr<std::string> text)
222 : fCompiler(*compiler)
223 , fSettings(settings)
224 , fKind(kind)
225 , fText(std::move(text))
226 , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1) {
227 fLexer.start(*fText);
228}
229
230Parser::~Parser() = default;
231
232SymbolTable* Parser::symbolTable() {
233 return fCompiler.symbolTable();
234}
235
236Token Parser::nextRawToken() {
237 Token token;
238 if (fPushback.fKind != Token::Kind::TK_NONE) {
239 // Retrieve the token from the pushback buffer.
240 token = fPushback;
241 fPushback.fKind = Token::Kind::TK_NONE;
242 } else {
243 // Fetch a token from the lexer.
244 token = fLexer.next();
245
246 // Some tokens are always invalid, so we detect and report them here.
247 switch (token.fKind) {
251 break;
252 }
253 [[fallthrough]];
254
256 this->error(token, "name '" + std::string(this->text(token)) + "' is reserved");
257 token.fKind = Token::Kind::TK_IDENTIFIER; // reduces additional follow-up errors
258 break;
259
261 this->error(token, "'" + std::string(this->text(token)) +
262 "' is not a valid octal number");
263 break;
264
265 default:
266 break;
267 }
268 }
269
270 return token;
271}
272
273static bool is_whitespace(Token::Kind kind) {
274 switch (kind) {
278 return true;
279
280 default:
281 return false;
282 }
283}
284
285bool Parser::expectNewline() {
286 Token token = this->nextRawToken();
287 if (token.fKind == Token::Kind::TK_WHITESPACE) {
288 // The lexer doesn't distinguish newlines from other forms of whitespace, so we check
289 // for newlines by searching through the token text.
290 std::string_view tokenText = this->text(token);
291 if (tokenText.find_first_of('\r') != std::string_view::npos ||
292 tokenText.find_first_of('\n') != std::string_view::npos) {
293 return true;
294 }
295 }
296 // We didn't find a newline.
297 this->pushback(token);
298 return false;
299}
300
301Token Parser::nextToken() {
302 for (;;) {
303 Token token = this->nextRawToken();
304 if (!is_whitespace(token.fKind)) {
305 return token;
306 }
307 }
308}
309
310void Parser::pushback(Token t) {
311 SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
312 fPushback = t;
313}
314
315Token Parser::peek() {
316 if (fPushback.fKind == Token::Kind::TK_NONE) {
317 fPushback = this->nextToken();
318 }
319 return fPushback;
320}
321
322bool Parser::checkNext(Token::Kind kind, Token* result) {
323 if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
324 return false;
325 }
326 Token next = this->nextToken();
327 if (next.fKind == kind) {
328 if (result) {
329 *result = next;
330 }
331 return true;
332 }
333 this->pushback(next);
334 return false;
335}
336
337bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
338 Token next = this->nextToken();
339 if (next.fKind == kind) {
340 if (result) {
341 *result = next;
342 }
343 return true;
344 } else {
345 this->error(next, "expected " + std::string(expected) + ", but found '" +
346 std::string(this->text(next)) + "'");
347 this->fEncounteredFatalError = true;
348 return false;
349 }
350}
351
352bool Parser::expectIdentifier(Token* result) {
353 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
354 return false;
355 }
356 if (this->symbolTable()->isBuiltinType(this->text(*result))) {
357 this->error(*result, "expected an identifier, but found type '" +
358 std::string(this->text(*result)) + "'");
359 this->fEncounteredFatalError = true;
360 return false;
361 }
362 return true;
363}
364
365bool Parser::checkIdentifier(Token* result) {
366 if (!this->checkNext(Token::Kind::TK_IDENTIFIER, result)) {
367 return false;
368 }
369 if (this->symbolTable()->isBuiltinType(this->text(*result))) {
370 this->pushback(*result);
371 return false;
372 }
373 return true;
374}
375
376std::string_view Parser::text(Token token) {
377 return std::string_view(fText->data() + token.fOffset, token.fLength);
378}
379
381 if (t.fOffset >= 0) {
382 return Position::Range(t.fOffset, t.fOffset + t.fLength);
383 } else {
384 return Position();
385 }
386}
387
388void Parser::error(Token token, std::string_view msg) {
389 this->error(this->position(token), msg);
390}
391
392void Parser::error(Position position, std::string_view msg) {
393 fCompiler.context().fErrors->error(position, msg);
394}
395
396Position Parser::rangeFrom(Position start) {
397 int offset = fPushback.fKind != Token::Kind::TK_NONE ? fPushback.fOffset
398 : fLexer.getCheckpoint().fOffset;
399 return Position::Range(start.startOffset(), offset);
400}
401
402Position Parser::rangeFrom(Token start) {
403 return this->rangeFrom(this->position(start));
404}
405
406/* declaration* END_OF_FILE */
407std::unique_ptr<Program> Parser::programInheritingFrom(const SkSL::Module* module) {
408 this->declarations();
409 std::unique_ptr<Program> result;
410 if (fCompiler.errorReporter().errorCount() == 0) {
411 result = fCompiler.releaseProgram(std::move(fText), std::move(fProgramElements));
412 } else {
413 fProgramElements.clear();
414 }
415 return result;
416}
417
418std::unique_ptr<SkSL::Module> Parser::moduleInheritingFrom(const SkSL::Module* parentModule) {
419 this->declarations();
420 this->symbolTable()->takeOwnershipOfString(std::move(*fText));
421 auto result = std::make_unique<SkSL::Module>();
422 result->fParent = parentModule;
423 result->fSymbols = std::move(fCompiler.fGlobalSymbols);
424 result->fElements = std::move(fProgramElements);
425 return result;
426}
427
428void Parser::declarations() {
429 fEncounteredFatalError = false;
430
431 // If the program is 8MB or longer (Position::kMaxOffset), error reporting goes off the rails.
432 // At any rate, there's no good reason for a program to be this long.
433 if (fText->size() >= Position::kMaxOffset) {
434 this->error(Position(), "program is too large");
435 return;
436 }
437
438 // Any #version directive must appear as the first thing in a file
439 if (this->peek().fKind == Token::Kind::TK_DIRECTIVE) {
440 this->directive(/*allowVersion=*/true);
441 }
442
443 while (!fEncounteredFatalError) {
444 // We should always be at global scope when processing top-level declarations.
445 SkASSERT(fCompiler.context().fSymbolTable == fCompiler.globalSymbols());
446
447 switch (this->peek().fKind) {
449 return;
450
452 this->error(this->peek(), "invalid token");
453 return;
454
456 this->directive(/*allowVersion=*/false);
457 break;
458
459 default:
460 this->declaration();
461 break;
462 }
463 }
464}
465
466/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER NEWLINE */
467void Parser::extensionDirective(Position start) {
468 Token name;
469 if (!this->expectIdentifier(&name)) {
470 return;
471 }
472 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
473 return;
474 }
475 Token behavior;
476 if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
477 return;
478 }
479 // We expect a newline immediately after `#extension name : behavior`.
480 if (this->expectNewline()) {
481 std::unique_ptr<SkSL::Extension> ext = Extension::Convert(fCompiler.context(),
482 this->rangeFrom(start),
483 this->text(name),
484 this->text(behavior));
485 if (ext) {
486 fProgramElements.push_back(std::move(ext));
487 }
488 } else {
489 this->error(start, "invalid #extension directive");
490 }
491}
492
493/* DIRECTIVE(#version) INTLITERAL NEWLINE */
494void Parser::versionDirective(Position start, bool allowVersion) {
495 if (!allowVersion) {
496 this->error(start, "#version directive must appear before anything else");
497 return;
498 }
500 if (!this->intLiteral(&version)) {
501 return;
502 }
503 switch (version) {
504 case 100:
506 break;
507 case 300:
509 break;
510 default:
511 this->error(start, "unsupported version number");
512 return;
513 }
514 // We expect a newline after a #version directive.
515 if (!this->expectNewline()) {
516 this->error(start, "invalid #version directive");
517 }
518}
519
520/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER NEWLINE |
521 DIRECTIVE(#version) INTLITERAL NEWLINE */
522void Parser::directive(bool allowVersion) {
523 Token start;
524 if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
525 return;
526 }
527 std::string_view text = this->text(start);
528 if (text == "#extension") {
529 return this->extensionDirective(this->position(start));
530 }
531 if (text == "#version") {
532 return this->versionDirective(this->position(start), allowVersion);
533 }
534 this->error(start, "unsupported directive '" + std::string(this->text(start)) + "'");
535}
536
537bool Parser::modifiersDeclarationEnd(const SkSL::Modifiers& mods) {
538 std::unique_ptr<ModifiersDeclaration> decl = ModifiersDeclaration::Convert(fCompiler.context(),
539 mods);
540 if (!decl) {
541 return false;
542 }
543 fProgramElements.push_back(std::move(decl));
544 return true;
545}
546
547/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
548 (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
549bool Parser::declaration() {
550 Token start = this->peek();
551 if (start.fKind == Token::Kind::TK_SEMICOLON) {
552 this->nextToken();
553 this->error(start, "expected a declaration, but found ';'");
554 return false;
555 }
556 Modifiers modifiers = this->modifiers();
557 Token lookahead = this->peek();
558 if (lookahead.fKind == Token::Kind::TK_IDENTIFIER &&
559 !this->symbolTable()->isType(this->text(lookahead))) {
560 // we have an identifier that's not a type, could be the start of an interface block
561 return this->interfaceBlock(modifiers);
562 }
563 if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
564 this->nextToken();
565 return this->modifiersDeclarationEnd(modifiers);
566 }
567 if (lookahead.fKind == Token::Kind::TK_STRUCT) {
568 this->structVarDeclaration(this->position(start), modifiers);
569 return true;
570 }
571 const Type* type = this->type(&modifiers);
572 if (!type) {
573 return false;
574 }
575 Token name;
576 if (!this->expectIdentifier(&name)) {
577 return false;
578 }
579 if (this->checkNext(Token::Kind::TK_LPAREN)) {
580 return this->functionDeclarationEnd(this->position(start), modifiers, type, name);
581 } else {
582 this->globalVarDeclarationEnd(this->position(start), modifiers, type, name);
583 return true;
584 }
585}
586
587/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
588bool Parser::functionDeclarationEnd(Position start,
589 Modifiers& modifiers,
590 const Type* returnType,
591 const Token& name) {
592 Token lookahead = this->peek();
593 bool validParams = true;
595 if (lookahead.fKind == Token::Kind::TK_RPAREN) {
596 // `()` means no parameters at all.
597 } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
598 // `(void)` also means no parameters at all.
599 this->nextToken();
600 } else {
601 for (;;) {
602 std::unique_ptr<SkSL::Variable> param;
603 if (!this->parameter(&param)) {
604 return false;
605 }
606 validParams = validParams && param;
607 parameters.push_back(std::move(param));
608 if (!this->checkNext(Token::Kind::TK_COMMA)) {
609 break;
610 }
611 }
612 }
613 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
614 return false;
615 }
616
617 SkSL::FunctionDeclaration* decl = nullptr;
618 if (validParams) {
620 this->rangeFrom(start),
621 modifiers,
622 this->text(name),
623 std::move(parameters),
624 start,
625 returnType);
626 }
627
628 if (this->checkNext(Token::Kind::TK_SEMICOLON)) {
629 return this->prototypeFunction(decl);
630 } else {
631 return this->defineFunction(decl);
632 }
633}
634
635bool Parser::prototypeFunction(SkSL::FunctionDeclaration* decl) {
636 if (!decl) {
637 return false;
638 }
639 fProgramElements.push_back(std::make_unique<SkSL::FunctionPrototype>(
640 decl->fPosition, decl, fCompiler.context().fConfig->fIsBuiltinCode));
641 return true;
642}
643
644bool Parser::defineFunction(SkSL::FunctionDeclaration* decl) {
645 const Context& context = fCompiler.context();
646 Token bodyStart = this->peek();
647
648 std::unique_ptr<SymbolTable> symbolTable;
649 std::unique_ptr<Statement> body;
650 {
651 // Create a symbol table for the function which includes the parameters.
652 AutoSymbolTable symbols(this, &symbolTable);
653 if (decl) {
654 for (Variable* param : decl->parameters()) {
655 symbolTable->addWithoutOwnership(fCompiler.context(), param);
656 }
657 }
658
659 // Parse the function body.
660 body = this->block(/*introduceNewScope=*/false, /*adoptExistingSymbolTable=*/&symbolTable);
661 }
662
663 // If there was a problem with the declarations or body, don't actually create a definition.
664 if (!decl || !body) {
665 return false;
666 }
667
668 std::unique_ptr<SkSL::Statement> block = std::move(body);
669 SkASSERT(block->is<Block>());
670 Position pos = this->rangeFrom(bodyStart);
671 block->fPosition = pos;
672
673 std::unique_ptr<FunctionDefinition> function = FunctionDefinition::Convert(context,
674 pos,
675 *decl,
676 std::move(block),
677 /*builtin=*/false);
678 if (!function) {
679 return false;
680 }
681 decl->setDefinition(function.get());
682 fProgramElements.push_back(std::move(function));
683 return true;
684}
685
686bool Parser::arraySize(SKSL_INT* outResult) {
687 // Start out with a safe value that won't generate any errors downstream
688 *outResult = 1;
689 Token next = this->peek();
690 if (next.fKind == Token::Kind::TK_RBRACKET) {
691 this->error(this->position(next), "unsized arrays are not permitted here");
692 return true;
693 }
694 std::unique_ptr<Expression> sizeLiteral = this->expression();
695 if (!sizeLiteral) {
696 return false;
697 }
698 if (!sizeLiteral->is<Poison>()) {
700 if (!ConstantFolder::GetConstantInt(*sizeLiteral, &size)) {
701 this->error(sizeLiteral->fPosition, "array size must be an integer");
702 return true;
703 }
704 if (size > INT32_MAX) {
705 this->error(sizeLiteral->fPosition, "array size out of bounds");
706 return true;
707 }
708 if (size <= 0) {
709 this->error(sizeLiteral->fPosition, "array size must be positive");
710 return true;
711 }
712 // Now that we've validated it, output the real value
713 *outResult = size;
714 }
715 return true;
716}
717
718const Type* Parser::arrayType(const Type* base, int count, Position pos) {
719 const Context& context = fCompiler.context();
720 count = base->convertArraySize(context, pos, pos, count);
721 if (!count) {
722 return context.fTypes.fPoison.get();
723 }
724 return this->symbolTable()->addArrayDimension(fCompiler.context(), base, count);
725}
726
727const Type* Parser::unsizedArrayType(const Type* base, Position pos) {
728 const Context& context = fCompiler.context();
729 if (!base->checkIfUsableInArray(context, pos)) {
730 return context.fTypes.fPoison.get();
731 }
732 return this->symbolTable()->addArrayDimension(fCompiler.context(), base,
734}
735
736bool Parser::parseArrayDimensions(Position pos, const Type** type) {
737 Token next;
738 while (this->checkNext(Token::Kind::TK_LBRACKET, &next)) {
739 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
740 if (this->allowUnsizedArrays()) {
741 *type = this->unsizedArrayType(*type, this->rangeFrom(pos));
742 } else {
743 this->error(this->rangeFrom(pos), "unsized arrays are not permitted here");
744 }
745 } else {
747 if (!this->arraySize(&size)) {
748 return false;
749 }
750 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
751 return false;
752 }
753 *type = this->arrayType(*type, size, this->rangeFrom(pos));
754 }
755 }
756 return true;
757}
758
759bool Parser::parseInitializer(Position pos, std::unique_ptr<Expression>* initializer) {
760 if (this->checkNext(Token::Kind::TK_EQ)) {
761 *initializer = this->assignmentExpression();
762 return *initializer != nullptr;
763 }
764 return true;
765}
766
767void Parser::addGlobalVarDeclaration(std::unique_ptr<VarDeclaration> decl) {
768 if (decl) {
769 fProgramElements.push_back(std::make_unique<SkSL::GlobalVarDeclaration>(std::move(decl)));
770 }
771}
772
773/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
774 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
775void Parser::globalVarDeclarationEnd(Position pos,
776 const Modifiers& mods,
777 const Type* baseType,
778 Token name) {
779 const Type* type = baseType;
780 std::unique_ptr<Expression> initializer;
781 if (!this->parseArrayDimensions(pos, &type)) {
782 return;
783 }
784 if (!this->parseInitializer(pos, &initializer)) {
785 return;
786 }
787 this->addGlobalVarDeclaration(VarDeclaration::Convert(fCompiler.context(),
788 this->rangeFrom(pos),
789 mods,
790 *type,
791 this->position(name),
792 this->text(name),
794 std::move(initializer)));
795 while (this->checkNext(Token::Kind::TK_COMMA)) {
796 type = baseType;
797 Token identifierName;
798 if (!this->expectIdentifier(&identifierName)) {
799 return;
800 }
801 if (!this->parseArrayDimensions(pos, &type)) {
802 return;
803 }
804 std::unique_ptr<Expression> anotherInitializer;
805 if (!this->parseInitializer(pos, &anotherInitializer)) {
806 return;
807 }
808 this->addGlobalVarDeclaration(VarDeclaration::Convert(fCompiler.context(),
809 this->rangeFrom(identifierName),
810 mods,
811 *type,
812 this->position(identifierName),
813 this->text(identifierName),
815 std::move(anotherInitializer)));
816 }
817 this->expect(Token::Kind::TK_SEMICOLON, "';'");
818}
819
820/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
821 (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
822std::unique_ptr<Statement> Parser::localVarDeclarationEnd(Position pos,
823 const Modifiers& mods,
824 const Type* baseType,
825 Token name) {
826 const Type* type = baseType;
827 std::unique_ptr<Expression> initializer;
828 if (!this->parseArrayDimensions(pos, &type)) {
829 return nullptr;
830 }
831 if (!this->parseInitializer(pos, &initializer)) {
832 return nullptr;
833 }
834 std::unique_ptr<Statement> result = VarDeclaration::Convert(fCompiler.context(),
835 this->rangeFrom(pos),
836 mods,
837 *type,
838 this->position(name),
839 this->text(name),
841 std::move(initializer));
842 for (;;) {
843 if (!this->checkNext(Token::Kind::TK_COMMA)) {
844 this->expect(Token::Kind::TK_SEMICOLON, "';'");
845 break;
846 }
847 type = baseType;
848 Token identifierName;
849 if (!this->expectIdentifier(&identifierName)) {
850 break;
851 }
852 if (!this->parseArrayDimensions(pos, &type)) {
853 break;
854 }
855 std::unique_ptr<Expression> anotherInitializer;
856 if (!this->parseInitializer(pos, &anotherInitializer)) {
857 break;
858 }
859 std::unique_ptr<Statement> next = VarDeclaration::Convert(fCompiler.context(),
860 this->rangeFrom(identifierName),
861 mods,
862 *type,
863 this->position(identifierName),
864 this->text(identifierName),
866 std::move(anotherInitializer));
867
868 result = Block::MakeCompoundStatement(std::move(result), std::move(next));
869 }
870 pos = this->rangeFrom(pos);
871 return this->statementOrNop(pos, std::move(result));
872}
873
874/* (varDeclarations | expressionStatement) */
875std::unique_ptr<Statement> Parser::varDeclarationsOrExpressionStatement() {
876 Token nextToken = this->peek();
877 if (nextToken.fKind == Token::Kind::TK_CONST) {
878 // Statements that begin with `const` might be variable declarations, but can't be legal
879 // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
880 return this->varDeclarations();
881 }
882
883 if (nextToken.fKind == Token::Kind::TK_HIGHP ||
884 nextToken.fKind == Token::Kind::TK_MEDIUMP ||
885 nextToken.fKind == Token::Kind::TK_LOWP ||
886 this->symbolTable()->isType(this->text(nextToken))) {
887 // Statements that begin with a typename are most often variable declarations, but
888 // occasionally the type is part of a constructor, and these are actually expression-
889 // statements in disguise. First, attempt the common case: parse it as a vardecl.
890 Checkpoint checkpoint(this);
891 VarDeclarationsPrefix prefix;
892 if (this->varDeclarationsPrefix(&prefix)) {
893 checkpoint.accept();
894 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
895 prefix.fName);
896 }
897
898 // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
899 // expression-statement instead.
900 checkpoint.rewind();
901 }
902 return this->expressionStatement();
903}
904
905// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
906// statement is a variable-declaration statement, not an expression-statement.
907bool Parser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
908 prefixData->fPosition = this->position(this->peek());
909 prefixData->fModifiers = this->modifiers();
910 prefixData->fType = this->type(&prefixData->fModifiers);
911 if (!prefixData->fType) {
912 return false;
913 }
914 return this->expectIdentifier(&prefixData->fName);
915}
916
917/* modifiers type IDENTIFIER varDeclarationEnd */
918std::unique_ptr<Statement> Parser::varDeclarations() {
919 VarDeclarationsPrefix prefix;
920 if (!this->varDeclarationsPrefix(&prefix)) {
921 return nullptr;
922 }
923 return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
924 prefix.fName);
925}
926
927/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
928const Type* Parser::structDeclaration() {
929 AutoDepth depth(this);
930 Position start = this->position(this->peek());
931 if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
932 return nullptr;
933 }
934 Token name;
935 if (!this->expectIdentifier(&name)) {
936 return nullptr;
937 }
938 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
939 return nullptr;
940 }
941 if (!depth.increase()) {
942 return nullptr;
943 }
944 TArray<SkSL::Field> fields;
945 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
946 Token fieldStart = this->peek();
947 Modifiers modifiers = this->modifiers();
948 const Type* type = this->type(&modifiers);
949 if (!type) {
950 return nullptr;
951 }
952
953 do {
954 const Type* actualType = type;
955 Token memberName;
956 if (!this->expectIdentifier(&memberName)) {
957 return nullptr;
958 }
959
960 while (this->checkNext(Token::Kind::TK_LBRACKET)) {
962 if (!this->arraySize(&size)) {
963 return nullptr;
964 }
965 if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
966 return nullptr;
967 }
968 actualType = this->arrayType(actualType, size,
969 this->rangeFrom(this->position(fieldStart)));
970 }
971
972 fields.push_back(SkSL::Field(this->rangeFrom(fieldStart),
973 modifiers.fLayout,
974 modifiers.fFlags,
975 this->text(memberName),
976 actualType));
977 } while (this->checkNext(Token::Kind::TK_COMMA));
978
979 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
980 return nullptr;
981 }
982 }
983 std::unique_ptr<SkSL::StructDefinition> def = StructDefinition::Convert(fCompiler.context(),
984 this->rangeFrom(start),
985 this->text(name),
986 std::move(fields));
987 if (!def) {
988 return nullptr;
989 }
990
991 const Type* result = &def->type();
992 fProgramElements.push_back(std::move(def));
993 return result;
994}
995
996/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
997void Parser::structVarDeclaration(Position start, const Modifiers& modifiers) {
998 const Type* type = this->structDeclaration();
999 if (!type) {
1000 return;
1001 }
1002 Token name;
1003 if (this->checkIdentifier(&name)) {
1004 this->globalVarDeclarationEnd(this->rangeFrom(name), modifiers, type, name);
1005 } else {
1006 this->expect(Token::Kind::TK_SEMICOLON, "';'");
1007 }
1008}
1009
1010/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
1011bool Parser::parameter(std::unique_ptr<SkSL::Variable>* outParam) {
1012 Position pos = this->position(this->peek());
1013 Modifiers modifiers = this->modifiers();
1014 const Type* type = this->type(&modifiers);
1015 if (!type) {
1016 return false;
1017 }
1018 Token name;
1019 std::string_view nameText;
1020 Position namePos;
1021 if (this->checkIdentifier(&name)) {
1022 nameText = this->text(name);
1023 namePos = this->position(name);
1024 } else {
1025 namePos = this->rangeFrom(pos);
1026 }
1027 if (!this->parseArrayDimensions(pos, &type)) {
1028 return false;
1029 }
1030 *outParam = SkSL::Variable::Convert(fCompiler.context(),
1031 this->rangeFrom(pos),
1032 modifiers.fPosition,
1033 modifiers.fLayout,
1034 modifiers.fFlags,
1035 type,
1036 namePos,
1037 nameText,
1039 return true;
1040}
1041
1042/** EQ INT_LITERAL */
1043int Parser::layoutInt() {
1044 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
1045 return -1;
1046 }
1047 Token resultToken;
1048 if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
1049 return -1;
1050 }
1051 std::string_view resultFrag = this->text(resultToken);
1052 SKSL_INT resultValue;
1053 if (!SkSL::stoi(resultFrag, &resultValue)) {
1054 this->error(resultToken, "value in layout is too large: " + std::string(resultFrag));
1055 return -1;
1056 }
1057 return resultValue;
1058}
1059
1060/** EQ IDENTIFIER */
1061std::string_view Parser::layoutIdentifier() {
1062 if (!this->expect(Token::Kind::TK_EQ, "'='")) {
1063 return {};
1064 }
1065 Token resultToken;
1066 if (!this->expectIdentifier(&resultToken)) {
1067 return {};
1068 }
1069 return this->text(resultToken);
1070}
1071
1072/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
1073SkSL::Layout Parser::layout() {
1075 static SkNoDestructor<LayoutMap> sLayoutTokens(LayoutMap{
1076 {"location", SkSL::LayoutFlag::kLocation},
1077 {"offset", SkSL::LayoutFlag::kOffset},
1078 {"binding", SkSL::LayoutFlag::kBinding},
1079 {"texture", SkSL::LayoutFlag::kTexture},
1080 {"sampler", SkSL::LayoutFlag::kSampler},
1081 {"index", SkSL::LayoutFlag::kIndex},
1082 {"set", SkSL::LayoutFlag::kSet},
1083 {"builtin", SkSL::LayoutFlag::kBuiltin},
1084 {"input_attachment_index", SkSL::LayoutFlag::kInputAttachmentIndex},
1085 {"origin_upper_left", SkSL::LayoutFlag::kOriginUpperLeft},
1086 {"blend_support_all_equations", SkSL::LayoutFlag::kBlendSupportAllEquations},
1087 {"push_constant", SkSL::LayoutFlag::kPushConstant},
1088 {"color", SkSL::LayoutFlag::kColor},
1089 {"vulkan", SkSL::LayoutFlag::kVulkan},
1090 {"metal", SkSL::LayoutFlag::kMetal},
1091 {"webgpu", SkSL::LayoutFlag::kWebGPU},
1092 {"direct3d", SkSL::LayoutFlag::kDirect3D},
1093 {"rgba8", SkSL::LayoutFlag::kRGBA8},
1094 {"rgba32f", SkSL::LayoutFlag::kRGBA32F},
1095 {"r32f", SkSL::LayoutFlag::kR32F},
1096 {"local_size_x", SkSL::LayoutFlag::kLocalSizeX},
1097 {"local_size_y", SkSL::LayoutFlag::kLocalSizeY},
1098 {"local_size_z", SkSL::LayoutFlag::kLocalSizeZ},
1099 });
1100
1101 Layout result;
1102 if (this->checkNext(Token::Kind::TK_LAYOUT) &&
1103 this->expect(Token::Kind::TK_LPAREN, "'('")) {
1104
1105 for (;;) {
1106 Token t = this->nextToken();
1107 std::string_view text = this->text(t);
1108 SkSL::LayoutFlag* found = sLayoutTokens->find(text);
1109
1110 if (!found) {
1111 this->error(t, "'" + std::string(text) + "' is not a valid layout qualifier");
1112 } else {
1113 if (result.fFlags & *found) {
1114 this->error(t, "layout qualifier '" + std::string(text) +
1115 "' appears more than once");
1116 }
1117
1118 result.fFlags |= *found;
1119
1120 switch (*found) {
1122 result.fLocation = this->layoutInt();
1123 break;
1125 result.fOffset = this->layoutInt();
1126 break;
1128 result.fBinding = this->layoutInt();
1129 break;
1131 result.fIndex = this->layoutInt();
1132 break;
1134 result.fSet = this->layoutInt();
1135 break;
1137 result.fTexture = this->layoutInt();
1138 break;
1140 result.fSampler = this->layoutInt();
1141 break;
1143 result.fBuiltin = this->layoutInt();
1144 break;
1146 result.fInputAttachmentIndex = this->layoutInt();
1147 break;
1149 result.fLocalSizeX = this->layoutInt();
1150 break;
1152 result.fLocalSizeY = this->layoutInt();
1153 break;
1155 result.fLocalSizeZ = this->layoutInt();
1156 break;
1157 default:
1158 break;
1159 }
1160 }
1161 if (this->checkNext(Token::Kind::TK_RPAREN)) {
1162 break;
1163 }
1164 if (!this->expect(Token::Kind::TK_COMMA, "','")) {
1165 break;
1166 }
1167 }
1168 }
1169 return result;
1170}
1171
1172/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
1173 VARYING | INLINE | WORKGROUP | READONLY | WRITEONLY | BUFFER)* */
1174Modifiers Parser::modifiers() {
1175 int start = this->peek().fOffset;
1176 SkSL::Layout layout = this->layout();
1177 Token raw = this->nextRawToken();
1178 int end = raw.fOffset;
1179 if (!is_whitespace(raw.fKind)) {
1180 this->pushback(raw);
1181 }
1182 ModifierFlags flags = ModifierFlag::kNone;
1183 for (;;) {
1184 ModifierFlags tokenFlag = parse_modifier_token(peek().fKind);
1185 if (tokenFlag == ModifierFlag::kNone) {
1186 break;
1187 }
1188 Token modifier = this->nextToken();
1189 if (ModifierFlags duplicateFlags = (tokenFlag & flags)) {
1190 this->error(modifier, "'" + duplicateFlags.description() + "' appears more than once");
1191 }
1192 flags |= tokenFlag;
1193 end = this->position(modifier).endOffset();
1194 }
1195 return Modifiers{Position::Range(start, end), layout, flags};
1196}
1197
1198std::unique_ptr<Statement> Parser::statementOrNop(Position pos, std::unique_ptr<Statement> stmt) {
1199 if (!stmt) {
1200 stmt = Nop::Make();
1201 }
1202 if (pos.valid() && !stmt->position().valid()) {
1203 stmt->setPosition(pos);
1204 }
1205 return stmt;
1206}
1207
1208/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
1209std::unique_ptr<Statement> Parser::statement(bool bracesIntroduceNewScope) {
1210 AutoDepth depth(this);
1211 if (!depth.increase()) {
1212 return nullptr;
1213 }
1214 switch (this->peek().fKind) {
1215 case Token::Kind::TK_IF:
1216 return this->ifStatement();
1218 return this->forStatement();
1219 case Token::Kind::TK_DO:
1220 return this->doStatement();
1222 return this->whileStatement();
1224 return this->switchStatement();
1226 return this->returnStatement();
1228 return this->breakStatement();
1230 return this->continueStatement();
1232 return this->discardStatement();
1234 return this->block(bracesIntroduceNewScope, /*adoptExistingSymbolTable=*/nullptr);
1236 this->nextToken();
1237 return Nop::Make();
1239 return this->varDeclarations();
1244 return this->varDeclarationsOrExpressionStatement();
1245 default:
1246 return this->expressionStatement();
1247 }
1248}
1249
1250const Type* Parser::findType(Position pos,
1251 Modifiers* modifiers,
1252 std::string_view name) {
1253 const Context& context = fCompiler.context();
1254 const Symbol* symbol = this->symbolTable()->find(name);
1255 if (!symbol) {
1256 this->error(pos, "no symbol named '" + std::string(name) + "'");
1257 return context.fTypes.fPoison.get();
1258 }
1259 if (!symbol->is<Type>()) {
1260 this->error(pos, "symbol '" + std::string(name) + "' is not a type");
1261 return context.fTypes.fPoison.get();
1262 }
1263 const SkSL::Type* type = &symbol->as<Type>();
1264 if (!context.fConfig->fIsBuiltinCode) {
1265 if (!TypeReference::VerifyType(context, type, pos)) {
1266 return context.fTypes.fPoison.get();
1267 }
1268 }
1269 Position qualifierRange = modifiers->fPosition;
1270 if (qualifierRange.startOffset() == qualifierRange.endOffset()) {
1271 qualifierRange = this->rangeFrom(qualifierRange);
1272 }
1273 return modifiers ? type->applyQualifiers(context, &modifiers->fFlags, qualifierRange)
1274 : type;
1275}
1276
1277/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
1278const Type* Parser::type(Modifiers* modifiers) {
1279 Token type;
1280 if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
1281 return nullptr;
1282 }
1283 if (!this->symbolTable()->isType(this->text(type))) {
1284 this->error(type, "no type named '" + std::string(this->text(type)) + "'");
1285 return fCompiler.context().fTypes.fInvalid.get();
1286 }
1287 const Type* result = this->findType(this->position(type), modifiers, this->text(type));
1288 if (result->isInterfaceBlock()) {
1289 // SkSL puts interface blocks into the symbol table, but they aren't general-purpose types;
1290 // you can't use them to declare a variable type or a function return type.
1291 this->error(type, "expected a type, found '" + std::string(this->text(type)) + "'");
1292 return fCompiler.context().fTypes.fInvalid.get();
1293 }
1294 Token bracket;
1295 while (this->checkNext(Token::Kind::TK_LBRACKET, &bracket)) {
1296 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1297 if (this->allowUnsizedArrays()) {
1298 result = this->unsizedArrayType(result, this->rangeFrom(type));
1299 } else {
1300 this->error(this->rangeFrom(bracket), "unsized arrays are not permitted here");
1301 }
1302 } else {
1303 SKSL_INT size;
1304 if (!this->arraySize(&size)) {
1305 return nullptr;
1306 }
1307 this->expect(Token::Kind::TK_RBRACKET, "']'");
1308 result = this->arrayType(result, size, this->rangeFrom(type));
1309 }
1310 }
1311 return result;
1312}
1313
1314/* IDENTIFIER LBRACE
1315 varDeclaration+
1316 RBRACE (IDENTIFIER (LBRACKET expression RBRACKET)*)? SEMICOLON */
1317bool Parser::interfaceBlock(const Modifiers& modifiers) {
1318 Token typeName;
1319 if (!this->expectIdentifier(&typeName)) {
1320 return false;
1321 }
1322 if (this->peek().fKind != Token::Kind::TK_LBRACE) {
1323 // we only get into interfaceBlock if we found a top-level identifier which was not a type.
1324 // 99% of the time, the user was not actually intending to create an interface block, so
1325 // it's better to report it as an unknown type
1326 this->error(typeName, "no type named '" + std::string(this->text(typeName)) + "'");
1327 return false;
1328 }
1329 this->nextToken();
1330 TArray<SkSL::Field> fields;
1331 while (!this->checkNext(Token::Kind::TK_RBRACE)) {
1332 Position fieldPos = this->position(this->peek());
1333 Modifiers fieldModifiers = this->modifiers();
1334 const Type* type = this->type(&fieldModifiers);
1335 if (!type) {
1336 return false;
1337 }
1338 do {
1339 Token fieldName;
1340 if (!this->expectIdentifier(&fieldName)) {
1341 return false;
1342 }
1343 const Type* actualType = type;
1344 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
1345 Token sizeToken = this->peek();
1346 if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
1347 SKSL_INT size;
1348 if (!this->arraySize(&size)) {
1349 return false;
1350 }
1351 actualType = this->arrayType(actualType, size, this->position(typeName));
1352 } else if (this->allowUnsizedArrays()) {
1353 actualType = this->unsizedArrayType(actualType, this->position(typeName));
1354 } else {
1355 this->error(sizeToken, "unsized arrays are not permitted here");
1356 }
1357 this->expect(Token::Kind::TK_RBRACKET, "']'");
1358 }
1359 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1360 return false;
1361 }
1362
1363 fields.push_back(SkSL::Field(this->rangeFrom(fieldPos),
1364 fieldModifiers.fLayout,
1365 fieldModifiers.fFlags,
1366 this->text(fieldName),
1367 actualType));
1368 } while (this->checkNext(Token::Kind::TK_COMMA));
1369 }
1370 std::string_view instanceName;
1371 Token instanceNameToken;
1372 SKSL_INT size = 0;
1373 if (this->checkIdentifier(&instanceNameToken)) {
1374 instanceName = this->text(instanceNameToken);
1375 if (this->checkNext(Token::Kind::TK_LBRACKET)) {
1376 if (!this->arraySize(&size)) {
1377 return false;
1378 }
1379 this->expect(Token::Kind::TK_RBRACKET, "']'");
1380 }
1381 }
1382 this->expect(Token::Kind::TK_SEMICOLON, "';'");
1383
1384 if (std::unique_ptr<SkSL::InterfaceBlock> ib = InterfaceBlock::Convert(fCompiler.context(),
1385 this->position(typeName),
1386 modifiers,
1387 this->text(typeName),
1388 std::move(fields),
1389 instanceName,
1390 size)) {
1391 fProgramElements.push_back(std::move(ib));
1392 return true;
1393 }
1394 return false;
1395}
1396
1397/* IF LPAREN expression RPAREN statement (ELSE statement)? */
1398std::unique_ptr<Statement> Parser::ifStatement() {
1399 Token start;
1400 if (!this->expect(Token::Kind::TK_IF, "'if'", &start)) {
1401 return nullptr;
1402 }
1403 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1404 return nullptr;
1405 }
1406 std::unique_ptr<Expression> test = this->expression();
1407 if (!test) {
1408 return nullptr;
1409 }
1410 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1411 return nullptr;
1412 }
1413 std::unique_ptr<Statement> ifTrue = this->statement();
1414 if (!ifTrue) {
1415 return nullptr;
1416 }
1417 std::unique_ptr<Statement> ifFalse;
1418 if (this->checkNext(Token::Kind::TK_ELSE)) {
1419 ifFalse = this->statement();
1420 if (!ifFalse) {
1421 return nullptr;
1422 }
1423 }
1424 Position pos = this->rangeFrom(start);
1425 return this->statementOrNop(pos, IfStatement::Convert(fCompiler.context(),
1426 pos,
1427 std::move(test),
1428 std::move(ifTrue),
1429 std::move(ifFalse)));
1430}
1431
1432/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
1433std::unique_ptr<Statement> Parser::doStatement() {
1434 Token start;
1435 if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
1436 return nullptr;
1437 }
1438 std::unique_ptr<Statement> statement = this->statement();
1439 if (!statement) {
1440 return nullptr;
1441 }
1442 if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
1443 return nullptr;
1444 }
1445 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1446 return nullptr;
1447 }
1448 std::unique_ptr<Expression> test = this->expression();
1449 if (!test) {
1450 return nullptr;
1451 }
1452 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1453 return nullptr;
1454 }
1455 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1456 return nullptr;
1457 }
1458 Position pos = this->rangeFrom(start);
1459 return this->statementOrNop(pos, DoStatement::Convert(fCompiler.context(), pos,
1460 std::move(statement), std::move(test)));
1461}
1462
1463/* WHILE LPAREN expression RPAREN STATEMENT */
1464std::unique_ptr<Statement> Parser::whileStatement() {
1465 Token start;
1466 if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
1467 return nullptr;
1468 }
1469 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1470 return nullptr;
1471 }
1472 std::unique_ptr<Expression> test = this->expression();
1473 if (!test) {
1474 return nullptr;
1475 }
1476 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1477 return nullptr;
1478 }
1479 std::unique_ptr<Statement> statement = this->statement();
1480 if (!statement) {
1481 return nullptr;
1482 }
1483 Position pos = this->rangeFrom(start);
1484 return this->statementOrNop(pos, ForStatement::ConvertWhile(fCompiler.context(), pos,
1485 std::move(test),
1486 std::move(statement)));
1487}
1488
1489/* COLON statement* */
1490bool Parser::switchCaseBody(ExpressionArray* values,
1491 StatementArray* caseBlocks,
1492 std::unique_ptr<Expression> caseValue) {
1493 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1494 return false;
1495 }
1496 StatementArray statements;
1497 while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1498 this->peek().fKind != Token::Kind::TK_CASE &&
1499 this->peek().fKind != Token::Kind::TK_DEFAULT) {
1500 std::unique_ptr<Statement> s = this->statement();
1501 if (!s) {
1502 return false;
1503 }
1504 statements.push_back(std::move(s));
1505 }
1506 values->push_back(std::move(caseValue));
1507 caseBlocks->push_back(SkSL::Block::Make(Position(), std::move(statements),
1508 Block::Kind::kUnbracedBlock));
1509 return true;
1510}
1511
1512/* CASE expression COLON statement* */
1513bool Parser::switchCase(ExpressionArray* values, StatementArray* caseBlocks) {
1514 Token start;
1515 if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
1516 return false;
1517 }
1518 std::unique_ptr<Expression> caseValue = this->expression();
1519 if (!caseValue) {
1520 return false;
1521 }
1522 return this->switchCaseBody(values, caseBlocks, std::move(caseValue));
1523}
1524
1525/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
1526std::unique_ptr<Statement> Parser::switchStatement() {
1527 Token start;
1528 if (!this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
1529 return nullptr;
1530 }
1531 if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1532 return nullptr;
1533 }
1534 std::unique_ptr<Expression> value = this->expression();
1535 if (!value) {
1536 return nullptr;
1537 }
1538 if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1539 return nullptr;
1540 }
1541 if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
1542 return nullptr;
1543 }
1544
1545 std::unique_ptr<SymbolTable> symbolTable;
1546 ExpressionArray values;
1547 StatementArray caseBlocks;
1548 {
1549 // Keeping a tight scope around AutoSymbolTable is important here. SwitchStatement::Convert
1550 // may end up creating a new symbol table if the HoistSwitchVarDeclarationsAtTopLevel
1551 // transform is used. We want ~AutoSymbolTable to happen first, so it can restore the
1552 // context's active symbol table to the enclosing block instead of the switch's inner block.
1553 AutoSymbolTable symbols(this, &symbolTable);
1554
1555 while (this->peek().fKind == Token::Kind::TK_CASE) {
1556 if (!this->switchCase(&values, &caseBlocks)) {
1557 return nullptr;
1558 }
1559 }
1560 // Requiring `default:` to be last (in defiance of C and GLSL) was a deliberate decision.
1561 // Other parts of the compiler are allowed to rely upon this assumption.
1562 if (this->checkNext(Token::Kind::TK_DEFAULT)) {
1563 if (!this->switchCaseBody(&values, &caseBlocks, /*value=*/nullptr)) {
1564 return nullptr;
1565 }
1566 }
1567 if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
1568 return nullptr;
1569 }
1570 }
1571
1572 Position pos = this->rangeFrom(start);
1573 return this->statementOrNop(pos, SwitchStatement::Convert(fCompiler.context(), pos,
1574 std::move(value),
1575 std::move(values),
1576 std::move(caseBlocks),
1577 std::move(symbolTable)));
1578}
1579
1581 return Position::Range(start, std::max(end, start + 1));
1582}
1583
1584/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1585 STATEMENT */
1586std::unique_ptr<Statement> Parser::forStatement() {
1587 Token start;
1588 if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
1589 return nullptr;
1590 }
1591 Token lparen;
1592 if (!this->expect(Token::Kind::TK_LPAREN, "'('", &lparen)) {
1593 return nullptr;
1594 }
1595 std::unique_ptr<SymbolTable> symbolTable;
1596 std::unique_ptr<Statement> initializer;
1597 std::unique_ptr<Expression> test;
1598 std::unique_ptr<Expression> next;
1599 std::unique_ptr<Statement> statement;
1600 int firstSemicolonOffset;
1601 Token secondSemicolon;
1602 Token rparen;
1603 {
1604 AutoSymbolTable symbols(this, &symbolTable);
1605
1606 Token nextToken = this->peek();
1607 if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1608 // An empty init-statement.
1609 firstSemicolonOffset = this->nextToken().fOffset;
1610 } else {
1611 // The init-statement must be an expression or variable declaration.
1612 initializer = this->varDeclarationsOrExpressionStatement();
1613 if (!initializer) {
1614 return nullptr;
1615 }
1616 firstSemicolonOffset = fLexer.getCheckpoint().fOffset - 1;
1617 }
1618 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1619 test = this->expression();
1620 if (!test) {
1621 return nullptr;
1622 }
1623 }
1624 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'", &secondSemicolon)) {
1625 return nullptr;
1626 }
1627 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1628 next = this->expression();
1629 if (!next) {
1630 return nullptr;
1631 }
1632 }
1633 if (!this->expect(Token::Kind::TK_RPAREN, "')'", &rparen)) {
1634 return nullptr;
1635 }
1636 statement = this->statement(/*bracesIntroduceNewScope=*/false);
1637 if (!statement) {
1638 return nullptr;
1639 }
1640 }
1641 Position pos = this->rangeFrom(start);
1642 ForLoopPositions loopPositions{
1643 range_of_at_least_one_char(lparen.fOffset + 1, firstSemicolonOffset),
1644 range_of_at_least_one_char(firstSemicolonOffset + 1, secondSemicolon.fOffset),
1645 range_of_at_least_one_char(secondSemicolon.fOffset + 1, rparen.fOffset),
1646 };
1647 return this->statementOrNop(pos, ForStatement::Convert(fCompiler.context(), pos, loopPositions,
1648 std::move(initializer),
1649 std::move(test),
1650 std::move(next),
1651 std::move(statement),
1652 std::move(symbolTable)));
1653}
1654
1655/* RETURN expression? SEMICOLON */
1656std::unique_ptr<Statement> Parser::returnStatement() {
1657 Token start;
1658 if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
1659 return nullptr;
1660 }
1661 std::unique_ptr<Expression> expression;
1662 if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1663 expression = this->expression();
1664 if (!expression) {
1665 return nullptr;
1666 }
1667 }
1668 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1669 return nullptr;
1670 }
1671 // We do not check for errors, or coerce the value to the correct type, until the return
1672 // statement is actually added to a function. (This is done in FunctionDefinition::Convert.)
1673 return ReturnStatement::Make(this->rangeFrom(start), std::move(expression));
1674}
1675
1676/* BREAK SEMICOLON */
1677std::unique_ptr<Statement> Parser::breakStatement() {
1678 Token start;
1679 if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
1680 return nullptr;
1681 }
1682 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1683 return nullptr;
1684 }
1685 return SkSL::BreakStatement::Make(this->position(start));
1686}
1687
1688/* CONTINUE SEMICOLON */
1689std::unique_ptr<Statement> Parser::continueStatement() {
1690 Token start;
1691 if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
1692 return nullptr;
1693 }
1694 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1695 return nullptr;
1696 }
1697 return SkSL::ContinueStatement::Make(this->position(start));
1698}
1699
1700/* DISCARD SEMICOLON */
1701std::unique_ptr<Statement> Parser::discardStatement() {
1702 Token start;
1703 if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
1704 return nullptr;
1705 }
1706 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1707 return nullptr;
1708 }
1709 Position pos = this->position(start);
1710 return this->statementOrNop(pos, SkSL::DiscardStatement::Convert(fCompiler.context(), pos));
1711}
1712
1713/* LBRACE statement* RBRACE */
1714std::unique_ptr<Statement> Parser::block(bool introduceNewScope,
1715 std::unique_ptr<SymbolTable>* adoptExistingSymbolTable) {
1716 // We can't introduce a new scope _and_ adopt an existing symbol table.
1717 SkASSERT(!(introduceNewScope && adoptExistingSymbolTable));
1718
1719 AutoDepth depth(this);
1720 Token start;
1721 if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1722 return nullptr;
1723 }
1724 if (!depth.increase()) {
1725 return nullptr;
1726 }
1727
1728 std::unique_ptr<SymbolTable> newSymbolTable;
1729 std::unique_ptr<SymbolTable>* symbolTableToUse =
1730 adoptExistingSymbolTable ? adoptExistingSymbolTable : &newSymbolTable;
1731
1732 StatementArray statements;
1733 {
1734 AutoSymbolTable symbols(this, symbolTableToUse, /*enable=*/introduceNewScope);
1735
1736 // Consume statements until we reach the closing brace.
1737 for (;;) {
1738 Token::Kind tokenKind = this->peek().fKind;
1739 if (tokenKind == Token::Kind::TK_RBRACE) {
1740 this->nextToken();
1741 break;
1742 }
1743 if (tokenKind == Token::Kind::TK_END_OF_FILE) {
1744 this->error(this->peek(), "expected '}', but found end of file");
1745 return nullptr;
1746 }
1747 if (std::unique_ptr<Statement> statement = this->statement()) {
1748 statements.push_back(std::move(statement));
1749 }
1750 if (fEncounteredFatalError) {
1751 return nullptr;
1752 }
1753 }
1754 }
1755 return SkSL::Block::MakeBlock(this->rangeFrom(start),
1756 std::move(statements),
1757 Block::Kind::kBracedScope,
1758 std::move(*symbolTableToUse));
1759}
1760
1761/* expression SEMICOLON */
1762std::unique_ptr<Statement> Parser::expressionStatement() {
1763 std::unique_ptr<Expression> expr = this->expression();
1764 if (!expr) {
1765 return nullptr;
1766 }
1767 if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1768 return nullptr;
1769 }
1770 Position pos = expr->position();
1771 return this->statementOrNop(pos, SkSL::ExpressionStatement::Convert(fCompiler.context(),
1772 std::move(expr)));
1773}
1774
1775std::unique_ptr<Expression> Parser::poison(Position pos) {
1776 return Poison::Make(pos, fCompiler.context());
1777}
1778
1779std::unique_ptr<Expression> Parser::expressionOrPoison(Position pos,
1780 std::unique_ptr<Expression> expr) {
1781 if (!expr) {
1782 // If no expression was passed in, create a poison expression.
1783 expr = this->poison(pos);
1784 }
1785 // If a valid position was passed in, it must match the expression's position.
1786 SkASSERTF(!pos.valid() || expr->position() == pos,
1787 "expected expression position (%d-%d), but received (%d-%d)",
1788 pos.startOffset(),
1789 pos.endOffset(),
1790 expr->position().startOffset(),
1791 expr->position().endOffset());
1792 return expr;
1793}
1794
1795bool Parser::operatorRight(Parser::AutoDepth& depth,
1796 Operator::Kind op,
1797 BinaryParseFn rightFn,
1798 std::unique_ptr<Expression>& expr) {
1799 this->nextToken();
1800 if (!depth.increase()) {
1801 return false;
1802 }
1803 std::unique_ptr<Expression> right = (this->*rightFn)();
1804 if (!right) {
1805 return false;
1806 }
1807 Position pos = expr->position().rangeThrough(right->position());
1808 expr = this->expressionOrPoison(pos, BinaryExpression::Convert(fCompiler.context(), pos,
1809 std::move(expr), op,
1810 std::move(right)));
1811 return true;
1812}
1813
1814/* assignmentExpression (COMMA assignmentExpression)* */
1815std::unique_ptr<Expression> Parser::expression() {
1816 AutoDepth depth(this);
1817 [[maybe_unused]] Token start = this->peek();
1818 std::unique_ptr<Expression> result = this->assignmentExpression();
1819 if (!result) {
1820 return nullptr;
1821 }
1822 while (this->peek().fKind == Token::Kind::TK_COMMA) {
1823 if (!this->operatorRight(depth, Operator::Kind::COMMA, &Parser::assignmentExpression,
1824 result)) {
1825 return nullptr;
1826 }
1827 }
1828 SkASSERTF(result->position().valid(), "Expression %s has invalid position",
1829 result->description().c_str());
1830 SkASSERTF(result->position().startOffset() == this->position(start).startOffset(),
1831 "Expected %s to start at %d (first token: '%.*s'), but it has range %d-%d\n",
1832 result->description().c_str(), this->position(start).startOffset(),
1833 (int)this->text(start).length(), this->text(start).data(),
1834 result->position().startOffset(), result->position().endOffset());
1835 return result;
1836}
1837
1838/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1839 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1840 assignmentExpression)*
1841 */
1842std::unique_ptr<Expression> Parser::assignmentExpression() {
1843 AutoDepth depth(this);
1844 std::unique_ptr<Expression> result = this->ternaryExpression();
1845 if (!result) {
1846 return nullptr;
1847 }
1848 for (;;) {
1849 Operator::Kind op;
1850 switch (this->peek().fKind) {
1851 case Token::Kind::TK_EQ: op = Operator::Kind::EQ; break;
1852 case Token::Kind::TK_STAREQ: op = Operator::Kind::STAREQ; break;
1853 case Token::Kind::TK_SLASHEQ: op = Operator::Kind::SLASHEQ; break;
1854 case Token::Kind::TK_PERCENTEQ: op = Operator::Kind::PERCENTEQ; break;
1855 case Token::Kind::TK_PLUSEQ: op = Operator::Kind::PLUSEQ; break;
1856 case Token::Kind::TK_MINUSEQ: op = Operator::Kind::MINUSEQ; break;
1857 case Token::Kind::TK_SHLEQ: op = Operator::Kind::SHLEQ; break;
1858 case Token::Kind::TK_SHREQ: op = Operator::Kind::SHREQ; break;
1859 case Token::Kind::TK_BITWISEANDEQ: op = Operator::Kind::BITWISEANDEQ; break;
1860 case Token::Kind::TK_BITWISEXOREQ: op = Operator::Kind::BITWISEXOREQ; break;
1861 case Token::Kind::TK_BITWISEOREQ: op = Operator::Kind::BITWISEOREQ; break;
1862 default: return result;
1863 }
1864 if (!this->operatorRight(depth, op, &Parser::assignmentExpression, result)) {
1865 return nullptr;
1866 }
1867 }
1868}
1869
1870/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1871std::unique_ptr<Expression> Parser::ternaryExpression() {
1872 AutoDepth depth(this);
1873 std::unique_ptr<Expression> base = this->logicalOrExpression();
1874 if (!base) {
1875 return nullptr;
1876 }
1877 if (!this->checkNext(Token::Kind::TK_QUESTION)) {
1878 return base;
1879 }
1880 if (!depth.increase()) {
1881 return nullptr;
1882 }
1883 std::unique_ptr<Expression> trueExpr = this->expression();
1884 if (!trueExpr) {
1885 return nullptr;
1886 }
1887 if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1888 return nullptr;
1889 }
1890 std::unique_ptr<Expression> falseExpr = this->assignmentExpression();
1891 if (!falseExpr) {
1892 return nullptr;
1893 }
1894 Position pos = base->position().rangeThrough(falseExpr->position());
1895 return this->expressionOrPoison(pos, TernaryExpression::Convert(fCompiler.context(),
1896 pos, std::move(base),
1897 std::move(trueExpr),
1898 std::move(falseExpr)));
1899}
1900
1901/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1902std::unique_ptr<Expression> Parser::logicalOrExpression() {
1903 AutoDepth depth(this);
1904 std::unique_ptr<Expression> result = this->logicalXorExpression();
1905 if (!result) {
1906 return nullptr;
1907 }
1908 while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1909 if (!this->operatorRight(depth, Operator::Kind::LOGICALOR, &Parser::logicalXorExpression,
1910 result)) {
1911 return nullptr;
1912 }
1913 }
1914 return result;
1915}
1916
1917/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1918std::unique_ptr<Expression> Parser::logicalXorExpression() {
1919 AutoDepth depth(this);
1920 std::unique_ptr<Expression> result = this->logicalAndExpression();
1921 if (!result) {
1922 return nullptr;
1923 }
1924 while (this->peek().fKind == Token::Kind::TK_LOGICALXOR) {
1925 if (!this->operatorRight(depth, Operator::Kind::LOGICALXOR, &Parser::logicalAndExpression,
1926 result)) {
1927 return nullptr;
1928 }
1929 }
1930 return result;
1931}
1932
1933/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1934std::unique_ptr<Expression> Parser::logicalAndExpression() {
1935 AutoDepth depth(this);
1936 std::unique_ptr<Expression> result = this->bitwiseOrExpression();
1937 if (!result) {
1938 return nullptr;
1939 }
1940 while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1941 if (!this->operatorRight(depth, Operator::Kind::LOGICALAND, &Parser::bitwiseOrExpression,
1942 result)) {
1943 return nullptr;
1944 }
1945 }
1946 return result;
1947}
1948
1949/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1950std::unique_ptr<Expression> Parser::bitwiseOrExpression() {
1951 AutoDepth depth(this);
1952 std::unique_ptr<Expression> result = this->bitwiseXorExpression();
1953 if (!result) {
1954 return nullptr;
1955 }
1956 while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1957 if (!this->operatorRight(depth, Operator::Kind::BITWISEOR, &Parser::bitwiseXorExpression,
1958 result)) {
1959 return nullptr;
1960 }
1961 }
1962 return result;
1963}
1964
1965/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1966std::unique_ptr<Expression> Parser::bitwiseXorExpression() {
1967 AutoDepth depth(this);
1968 std::unique_ptr<Expression> result = this->bitwiseAndExpression();
1969 if (!result) {
1970 return nullptr;
1971 }
1972 while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1973 if (!this->operatorRight(depth, Operator::Kind::BITWISEXOR, &Parser::bitwiseAndExpression,
1974 result)) {
1975 return nullptr;
1976 }
1977 }
1978 return result;
1979}
1980
1981/* equalityExpression (BITWISEAND equalityExpression)* */
1982std::unique_ptr<Expression> Parser::bitwiseAndExpression() {
1983 AutoDepth depth(this);
1984 std::unique_ptr<Expression> result = this->equalityExpression();
1985 if (!result) {
1986 return nullptr;
1987 }
1988 while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1989 if (!this->operatorRight(depth, Operator::Kind::BITWISEAND, &Parser::equalityExpression,
1990 result)) {
1991 return nullptr;
1992 }
1993 }
1994 return result;
1995}
1996
1997/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1998std::unique_ptr<Expression> Parser::equalityExpression() {
1999 AutoDepth depth(this);
2000 std::unique_ptr<Expression> result = this->relationalExpression();
2001 if (!result) {
2002 return nullptr;
2003 }
2004 for (;;) {
2005 Operator::Kind op;
2006 switch (this->peek().fKind) {
2007 case Token::Kind::TK_EQEQ: op = Operator::Kind::EQEQ; break;
2008 case Token::Kind::TK_NEQ: op = Operator::Kind::NEQ; break;
2009 default: return result;
2010 }
2011 if (!this->operatorRight(depth, op, &Parser::relationalExpression, result)) {
2012 return nullptr;
2013 }
2014 }
2015}
2016
2017/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
2018std::unique_ptr<Expression> Parser::relationalExpression() {
2019 AutoDepth depth(this);
2020 std::unique_ptr<Expression> result = this->shiftExpression();
2021 if (!result) {
2022 return nullptr;
2023 }
2024 for (;;) {
2025 Operator::Kind op;
2026 switch (this->peek().fKind) {
2027 case Token::Kind::TK_LT: op = Operator::Kind::LT; break;
2028 case Token::Kind::TK_GT: op = Operator::Kind::GT; break;
2029 case Token::Kind::TK_LTEQ: op = Operator::Kind::LTEQ; break;
2030 case Token::Kind::TK_GTEQ: op = Operator::Kind::GTEQ; break;
2031 default: return result;
2032 }
2033 if (!this->operatorRight(depth, op, &Parser::shiftExpression, result)) {
2034 return nullptr;
2035 }
2036 }
2037}
2038
2039/* additiveExpression ((SHL | SHR) additiveExpression)* */
2040std::unique_ptr<Expression> Parser::shiftExpression() {
2041 AutoDepth depth(this);
2042 std::unique_ptr<Expression> result = this->additiveExpression();
2043 if (!result) {
2044 return nullptr;
2045 }
2046 for (;;) {
2047 Operator::Kind op;
2048 switch (this->peek().fKind) {
2049 case Token::Kind::TK_SHL: op = Operator::Kind::SHL; break;
2050 case Token::Kind::TK_SHR: op = Operator::Kind::SHR; break;
2051 default: return result;
2052 }
2053 if (!this->operatorRight(depth, op, &Parser::additiveExpression, result)) {
2054 return nullptr;
2055 }
2056 }
2057}
2058
2059/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
2060std::unique_ptr<Expression> Parser::additiveExpression() {
2061 AutoDepth depth(this);
2062 std::unique_ptr<Expression> result = this->multiplicativeExpression();
2063 if (!result) {
2064 return nullptr;
2065 }
2066 for (;;) {
2067 Operator::Kind op;
2068 switch (this->peek().fKind) {
2069 case Token::Kind::TK_PLUS: op = Operator::Kind::PLUS; break;
2070 case Token::Kind::TK_MINUS: op = Operator::Kind::MINUS; break;
2071 default: return result;
2072 }
2073 if (!this->operatorRight(depth, op, &Parser::multiplicativeExpression, result)) {
2074 return nullptr;
2075 }
2076 }
2077}
2078
2079/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
2080std::unique_ptr<Expression> Parser::multiplicativeExpression() {
2081 AutoDepth depth(this);
2082 std::unique_ptr<Expression> result = this->unaryExpression();
2083 if (!result) {
2084 return nullptr;
2085 }
2086 for (;;) {
2087 Operator::Kind op;
2088 switch (this->peek().fKind) {
2089 case Token::Kind::TK_STAR: op = Operator::Kind::STAR; break;
2090 case Token::Kind::TK_SLASH: op = Operator::Kind::SLASH; break;
2091 case Token::Kind::TK_PERCENT: op = Operator::Kind::PERCENT; break;
2092 default: return result;
2093 }
2094 if (!this->operatorRight(depth, op, &Parser::unaryExpression, result)) {
2095 return nullptr;
2096 }
2097 }
2098}
2099
2100/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
2101std::unique_ptr<Expression> Parser::unaryExpression() {
2102 AutoDepth depth(this);
2103 Operator::Kind op;
2104 Token start = this->peek();
2105 switch (start.fKind) {
2106 case Token::Kind::TK_PLUS: op = Operator::Kind::PLUS; break;
2107 case Token::Kind::TK_MINUS: op = Operator::Kind::MINUS; break;
2108 case Token::Kind::TK_LOGICALNOT: op = Operator::Kind::LOGICALNOT; break;
2109 case Token::Kind::TK_BITWISENOT: op = Operator::Kind::BITWISENOT; break;
2110 case Token::Kind::TK_PLUSPLUS: op = Operator::Kind::PLUSPLUS; break;
2111 case Token::Kind::TK_MINUSMINUS: op = Operator::Kind::MINUSMINUS; break;
2112 default: return this->postfixExpression();
2113 }
2114 this->nextToken();
2115 if (!depth.increase()) {
2116 return nullptr;
2117 }
2118 std::unique_ptr<Expression> expr = this->unaryExpression();
2119 if (!expr) {
2120 return nullptr;
2121 }
2122 Position pos = Position::Range(start.fOffset, expr->position().endOffset());
2123 return this->expressionOrPoison(pos, PrefixExpression::Convert(fCompiler.context(),
2124 pos, op, std::move(expr)));
2125}
2126
2127/* term suffix* */
2128std::unique_ptr<Expression> Parser::postfixExpression() {
2129 AutoDepth depth(this);
2130 std::unique_ptr<Expression> result = this->term();
2131 if (!result) {
2132 return nullptr;
2133 }
2134 for (;;) {
2135 Token t = this->peek();
2136 switch (t.fKind) {
2138 if (this->text(t)[0] != '.') {
2139 return result;
2140 }
2141 [[fallthrough]];
2147 if (!depth.increase()) {
2148 return nullptr;
2149 }
2150 result = this->suffix(std::move(result));
2151 if (!result) {
2152 return nullptr;
2153 }
2154 break;
2155 }
2156 default:
2157 return result;
2158 }
2159 }
2160}
2161
2162std::unique_ptr<Expression> Parser::swizzle(Position pos,
2163 std::unique_ptr<Expression> base,
2164 std::string_view swizzleMask,
2165 Position maskPos) {
2166 SkASSERT(!swizzleMask.empty());
2167 if (!base->type().isVector() && !base->type().isScalar()) {
2168 return this->expressionOrPoison(pos, FieldAccess::Convert(fCompiler.context(), pos,
2169 std::move(base), swizzleMask));
2170
2171 }
2172 return this->expressionOrPoison(pos, Swizzle::Convert(fCompiler.context(), pos, maskPos,
2173 std::move(base), swizzleMask));
2174}
2175
2176std::unique_ptr<Expression> Parser::call(Position pos,
2177 std::unique_ptr<Expression> base,
2178 ExpressionArray args) {
2179 return this->expressionOrPoison(pos, SkSL::FunctionCall::Convert(fCompiler.context(), pos,
2180 std::move(base),
2181 std::move(args)));
2182}
2183
2184/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
2185 PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
2186std::unique_ptr<Expression> Parser::suffix(std::unique_ptr<Expression> base) {
2187 AutoDepth depth(this);
2188 Token next = this->nextToken();
2189 if (!depth.increase()) {
2190 return nullptr;
2191 }
2192 switch (next.fKind) {
2194 if (this->checkNext(Token::Kind::TK_RBRACKET)) {
2195 this->error(this->rangeFrom(next), "missing index in '[]'");
2196 return this->poison(this->rangeFrom(base->position()));
2197 }
2198 std::unique_ptr<Expression> index = this->expression();
2199 if (!index) {
2200 return nullptr;
2201 }
2202 this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
2203
2204 Position pos = this->rangeFrom(base->position());
2205 return this->expressionOrPoison(pos, IndexExpression::Convert(fCompiler.context(), pos,
2206 std::move(base),
2207 std::move(index)));
2208 }
2209 case Token::Kind::TK_DOT: {
2210 std::string_view text;
2211 if (this->identifier(&text)) {
2212 Position pos = this->rangeFrom(base->position());
2213 return this->swizzle(pos, std::move(base), text,
2214 this->rangeFrom(this->position(next).after()));
2215 }
2216 [[fallthrough]];
2217 }
2219 // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
2220 // floating point literals, possibly followed by an identifier. Handle that here.
2221 std::string_view field = this->text(next);
2222 SkASSERT(field[0] == '.');
2223 field.remove_prefix(1);
2224 // use the next *raw* token so we don't ignore whitespace - we only care about
2225 // identifiers that directly follow the float
2226 Position pos = this->rangeFrom(base->position());
2227 Position start = this->position(next);
2228 // skip past the "."
2229 start = Position::Range(start.startOffset() + 1, start.endOffset());
2230 Position maskPos = this->rangeFrom(start);
2231 Token id = this->nextRawToken();
2232 if (id.fKind == Token::Kind::TK_IDENTIFIER) {
2233 pos = this->rangeFrom(base->position());
2234 maskPos = this->rangeFrom(start);
2235 return this->swizzle(pos,
2236 std::move(base),
2237 std::string(field) + std::string(this->text(id)),
2238 maskPos);
2239 }
2240 if (field.empty()) {
2241 this->error(pos, "expected field name or swizzle mask after '.'");
2242 return this->poison(pos);
2243 }
2244 this->pushback(id);
2245 return this->swizzle(pos, std::move(base), field, maskPos);
2246 }
2248 ExpressionArray args;
2249 if (this->peek().fKind != Token::Kind::TK_RPAREN) {
2250 for (;;) {
2251 std::unique_ptr<Expression> expr = this->assignmentExpression();
2252 if (!expr) {
2253 return nullptr;
2254 }
2255 args.push_back(std::move(expr));
2256 if (!this->checkNext(Token::Kind::TK_COMMA)) {
2257 break;
2258 }
2259 }
2260 }
2261 this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
2262 Position pos = this->rangeFrom(base->position());
2263 return this->call(pos, std::move(base), std::move(args));
2264 }
2268 ? Operator::Kind::PLUSPLUS
2269 : Operator::Kind::MINUSMINUS;
2270 Position pos = this->rangeFrom(base->position());
2271 return this->expressionOrPoison(pos, PostfixExpression::Convert(fCompiler.context(),
2272 pos, std::move(base),
2273 op));
2274 }
2275 default: {
2276 this->error(next, "expected expression suffix, but found '" +
2277 std::string(this->text(next)) + "'");
2278 return nullptr;
2279 }
2280 }
2281}
2282
2283/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
2284std::unique_ptr<Expression> Parser::term() {
2285 AutoDepth depth(this);
2286 Token t = this->peek();
2287 switch (t.fKind) {
2289 std::string_view text;
2290 if (this->identifier(&text)) {
2291 Position pos = this->position(t);
2292 return this->expressionOrPoison(
2293 pos,
2294 this->symbolTable()->instantiateSymbolRef(fCompiler.context(), text, pos));
2295 }
2296 break;
2297 }
2299 SKSL_INT i;
2300 if (!this->intLiteral(&i)) {
2301 i = 0;
2302 }
2303 Position pos = this->position(t);
2304 return this->expressionOrPoison(pos, SkSL::Literal::MakeInt(fCompiler.context(),
2305 pos, i));
2306 }
2308 SKSL_FLOAT f;
2309 if (!this->floatLiteral(&f)) {
2310 f = 0.0f;
2311 }
2312 Position pos = this->position(t);
2313 return this->expressionOrPoison(pos, SkSL::Literal::MakeFloat(fCompiler.context(),
2314 pos, f));
2315 }
2316 case Token::Kind::TK_TRUE_LITERAL: // fall through
2318 bool b;
2319 SkAssertResult(this->boolLiteral(&b));
2320 Position pos = this->position(t);
2321 return this->expressionOrPoison(pos, SkSL::Literal::MakeBool(fCompiler.context(),
2322 pos, b));
2323 }
2325 this->nextToken();
2326 if (!depth.increase()) {
2327 return nullptr;
2328 }
2329 std::unique_ptr<Expression> result = this->expression();
2330 if (result != nullptr) {
2331 this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
2332 result->setPosition(this->rangeFrom(this->position(t)));
2333 return result;
2334 }
2335 break;
2336 }
2337 default:
2338 this->nextToken();
2339 this->error(t, "expected expression, but found '" + std::string(this->text(t)) + "'");
2340 fEncounteredFatalError = true;
2341 break;
2342 }
2343 return nullptr;
2344}
2345
2346/* INT_LITERAL */
2347bool Parser::intLiteral(SKSL_INT* dest) {
2348 Token t;
2349 if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
2350 return false;
2351 }
2352 std::string_view s = this->text(t);
2353 if (!SkSL::stoi(s, dest)) {
2354 this->error(t, "integer is too large: " + std::string(s));
2355 return false;
2356 }
2357 return true;
2358}
2359
2360/* FLOAT_LITERAL */
2361bool Parser::floatLiteral(SKSL_FLOAT* dest) {
2362 Token t;
2363 if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
2364 return false;
2365 }
2366 std::string_view s = this->text(t);
2367 if (!SkSL::stod(s, dest)) {
2368 this->error(t, "floating-point value is too large: " + std::string(s));
2369 return false;
2370 }
2371 return true;
2372}
2373
2374/* TRUE_LITERAL | FALSE_LITERAL */
2375bool Parser::boolLiteral(bool* dest) {
2376 Token t = this->nextToken();
2377 switch (t.fKind) {
2379 *dest = true;
2380 return true;
2382 *dest = false;
2383 return true;
2384 default:
2385 this->error(t, "expected 'true' or 'false', but found '" +
2386 std::string(this->text(t)) + "'");
2387 return false;
2388 }
2389}
2390
2391/* IDENTIFIER */
2392bool Parser::identifier(std::string_view* dest) {
2393 Token t;
2394 if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
2395 *dest = this->text(t);
2396 return true;
2397 }
2398 return false;
2399}
2400
2401} // namespace SkSL
#define test(name)
static struct Initializer initializer
int count
SkPoint pos
static float next(float f)
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition SkAssert.h:117
static bool right(const SkPoint &p0, const SkPoint &p1)
int64_t SKSL_INT
Definition SkSLDefines.h:16
float SKSL_FLOAT
Definition SkSLDefines.h:17
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, std::unique_ptr< Expression > left, Operator op, std::unique_ptr< Expression > right)
static std::unique_ptr< Block > MakeBlock(Position pos, StatementArray statements, Kind kind=Kind::kBracedScope, std::unique_ptr< SymbolTable > symbols=nullptr)
Definition SkSLBlock.cpp:59
static std::unique_ptr< Statement > Make(Position pos)
const std::unique_ptr< Type > fInvalid
Context & context() const
SymbolTable * symbolTable()
ErrorReporter & errorReporter()
SymbolTable * globalSymbols()
static bool GetConstantInt(const Expression &value, SKSL_INT *out)
const BuiltinTypes & fTypes
Definition SkSLContext.h:30
void setErrorReporter(ErrorReporter *e)
Definition SkSLContext.h:38
ErrorReporter * fErrors
Definition SkSLContext.h:36
SymbolTable * fSymbolTable
Definition SkSLContext.h:48
ProgramConfig * fConfig
Definition SkSLContext.h:33
static std::unique_ptr< Statement > Make(Position pos)
static std::unique_ptr< Statement > Convert(const Context &context, Position pos)
static std::unique_ptr< Statement > Convert(const Context &context, Position pos, std::unique_ptr< Statement > stmt, std::unique_ptr< Expression > test)
void error(Position position, std::string_view msg)
static std::unique_ptr< Statement > Convert(const Context &context, std::unique_ptr< Expression > expr)
static std::unique_ptr< Extension > Convert(const Context &context, Position pos, std::string_view name, std::string_view behaviorText)
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, std::unique_ptr< Expression > base, std::string_view field)
static std::unique_ptr< Statement > ConvertWhile(const Context &context, Position pos, std::unique_ptr< Expression > test, std::unique_ptr< Statement > statement)
static std::unique_ptr< Statement > Convert(const Context &context, Position pos, ForLoopPositions forLoopPositions, std::unique_ptr< Statement > initializer, std::unique_ptr< Expression > test, std::unique_ptr< Expression > next, std::unique_ptr< Statement > statement, std::unique_ptr< SymbolTable > symbolTable)
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, const FunctionDeclaration &function, ExpressionArray arguments)
void setDefinition(const FunctionDefinition *definition)
static FunctionDeclaration * Convert(const Context &context, Position pos, const Modifiers &modifiers, std::string_view name, skia_private::TArray< std::unique_ptr< Variable > > parameters, Position returnTypePos, const Type *returnType)
static std::unique_ptr< FunctionDefinition > Convert(const Context &context, Position pos, const FunctionDeclaration &function, std::unique_ptr< Statement > body, bool builtin)
Position fPosition
Definition SkSLIRNode.h:109
static std::unique_ptr< Statement > Convert(const Context &context, Position pos, std::unique_ptr< Expression > test, std::unique_ptr< Statement > ifTrue, std::unique_ptr< Statement > ifFalse)
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, std::unique_ptr< Expression > base, std::unique_ptr< Expression > index)
static std::unique_ptr< InterfaceBlock > Convert(const Context &context, Position pos, const Modifiers &modifiers, std::string_view typeName, skia_private::TArray< Field > fields, std::string_view varName, int arraySize)
Checkpoint getCheckpoint() const
Definition SkSLLexer.h:136
void rewindToCheckpoint(Checkpoint checkpoint)
Definition SkSLLexer.h:138
void start(std::string_view text)
Definition SkSLLexer.h:125
Token next()
static std::unique_ptr< Literal > MakeInt(const Context &context, Position pos, SKSL_INT value)
Definition SkSLLiteral.h:54
static std::unique_ptr< Literal > MakeBool(const Context &context, Position pos, bool value)
Definition SkSLLiteral.h:69
static std::unique_ptr< Literal > MakeFloat(const Context &context, Position pos, float value)
Definition SkSLLiteral.h:43
static std::unique_ptr< ModifiersDeclaration > Convert(const Context &context, const Modifiers &modifiers)
static std::unique_ptr< Statement > Make()
Definition SkSLNop.h:26
OperatorKind Kind
AutoSymbolTable(Parser *p, std::unique_ptr< SymbolTable > *newSymbolTable, bool enable=true)
Position position(Token token)
std::string_view text(Token token)
Parser(Compiler *compiler, const ProgramSettings &settings, ProgramKind kind, std::unique_ptr< std::string > text)
std::unique_ptr< Program > programInheritingFrom(const Module *module)
std::unique_ptr< Module > moduleInheritingFrom(const Module *parentModule)
static std::unique_ptr< Expression > Make(Position pos, const Context &context)
Definition SkSLPoison.h:21
static constexpr int kMaxOffset
static Position Range(int startOffset, int endOffset)
int endOffset() const
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, std::unique_ptr< Expression > base, Operator op)
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, Operator op, std::unique_ptr< Expression > base)
static std::unique_ptr< Statement > Make(Position pos, std::unique_ptr< Expression > expression)
static std::unique_ptr< StructDefinition > Convert(const Context &context, Position pos, std::string_view name, skia_private::TArray< Field > fields)
static std::unique_ptr< Statement > Convert(const Context &context, Position pos, std::unique_ptr< Expression > value, ExpressionArray caseValues, StatementArray caseStatements, std::unique_ptr< SymbolTable > symbolTable)
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, Position maskPos, std::unique_ptr< Expression > base, ComponentArray inComponents)
const std::string * takeOwnershipOfString(std::string n)
SymbolTable * fParent
bool isBuiltin() const
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, std::unique_ptr< Expression > test, std::unique_ptr< Expression > ifTrue, std::unique_ptr< Expression > ifFalse)
static bool VerifyType(const Context &context, const SkSL::Type *type, Position pos)
static constexpr int kUnsizedArray
Definition SkSLType.h:99
const T & as() const
Definition SkSLType.h:210
static std::unique_ptr< VarDeclaration > Convert(const Context &context, Position overallPos, const Modifiers &modifiers, const Type &type, Position namePos, std::string_view name, VariableStorage storage, std::unique_ptr< Expression > value)
static std::unique_ptr< Variable > Convert(const Context &context, Position pos, Position modifiersPos, const Layout &layout, ModifierFlags flags, const Type *type, Position namePos, std::string_view name, Storage storage)
static bool b
struct MyStruct s
FlutterSemanticsFlag flags
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
Dart_NativeFunction function
Definition fuchsia.cc:51
const char * name
Definition fuchsia.cc:50
std::u16string text
bool stod(std::string_view s, SKSL_FLOAT *value)
static Position range_of_at_least_one_char(int start, int end)
static ModifierFlags parse_modifier_token(Token::Kind token)
skia_private::STArray< 2, std::unique_ptr< Statement > > StatementArray
Definition SkSLDefines.h:34
bool stoi(std::string_view s, SKSL_INT *value)
static bool is_whitespace(Token::Kind kind)
LayoutFlag
Definition SkSLLayout.h:20
static constexpr int kMaxParseDepth
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
Definition ref_ptr.h:256
dest
Definition zip.py:79
Point offset
std::unique_ptr< SymbolTable > fSymbols
static bool AllowsPrivateIdentifiers(ProgramKind kind)
SkSL::Version fRequiredSkSLVersion
int32_t fOffset
Definition SkSLLexer.h:119
int32_t fLength
Definition SkSLLexer.h:120