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