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