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