Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Side by Side Diff: src/sksl/SkSLParser.cpp

Issue 1984363002: initial checkin of SkSL compiler (Closed) Base URL: https://skia.googlesource.com/skia@master
Patch Set: documentation and cleanups Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 Google Inc.
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 "stdio.h"
9 #include "SkSLParser.h"
10 #include "SkSLToken.h"
11
12 #define register
13 #ifdef __clang__
14 #pragma clang diagnostic push
15 #pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
16 #endif
17 #include "lex.sksl.c"
18 #ifdef __clang__
19 #pragma clang diagnostic pop
20 #endif
21 #undef register
22
23 #include "ast/SkSLASTBinaryExpression.h"
24 #include "ast/SkSLASTBlock.h"
25 #include "ast/SkSLASTBoolLiteral.h"
26 #include "ast/SkSLASTBreakStatement.h"
27 #include "ast/SkSLASTCallSuffix.h"
28 #include "ast/SkSLASTContinueStatement.h"
29 #include "ast/SkSLASTDiscardStatement.h"
30 #include "ast/SkSLASTDoStatement.h"
31 #include "ast/SkSLASTExpression.h"
32 #include "ast/SkSLASTExpressionStatement.h"
33 #include "ast/SkSLASTExtension.h"
34 #include "ast/SkSLASTFieldSuffix.h"
35 #include "ast/SkSLASTFloatLiteral.h"
36 #include "ast/SkSLASTForStatement.h"
37 #include "ast/SkSLASTFunction.h"
38 #include "ast/SkSLASTIdentifier.h"
39 #include "ast/SkSLASTIfStatement.h"
40 #include "ast/SkSLASTIndexSuffix.h"
41 #include "ast/SkSLASTInterfaceBlock.h"
42 #include "ast/SkSLASTIntLiteral.h"
43 #include "ast/SkSLASTParameter.h"
44 #include "ast/SkSLASTPrefixExpression.h"
45 #include "ast/SkSLASTReturnStatement.h"
46 #include "ast/SkSLASTStatement.h"
47 #include "ast/SkSLASTSuffixExpression.h"
48 #include "ast/SkSLASTTernaryExpression.h"
49 #include "ast/SkSLASTType.h"
50 #include "ast/SkSLASTVarDeclaration.h"
51 #include "ast/SkSLASTVarDeclarationStatement.h"
52 #include "ast/SkSLASTWhileStatement.h"
53 #include "ir/SkSLSymbolTable.h"
54
55 namespace SkSL {
56
57 Parser::Parser(std::string text, std::shared_ptr<SymbolTable> types, ErrorReport er& errors)
58 : fPushback(Position(-1, -1), Token::INVALID_TOKEN, std::string(""))
59 , fTypes(types)
60 , fErrors(errors) {
61 fBuffer = sksl_scan_string(text.c_str());
62 yylineno = 1;
63
64 if (false) {
65 // avoid unused warning
66 yyunput(0, nullptr);
67 }
68 }
69
70 Parser::~Parser() {
71 sksl_delete_buffer(fBuffer);
72 }
73
74 Token Parser::nextToken() {
75 if (fPushback.fKind != Token::INVALID_TOKEN) {
76 Token result = fPushback;
77 fPushback.fKind = Token::INVALID_TOKEN;
78 fPushback.fText = std::string("");
79 return result;
80 }
81 int token = sksllex();
82 return Token(Position(yylineno, -1), (Token::Kind) token,
83 token == Token::END_OF_FILE ? "<end of file>" : std::string(sks ltext));
84 }
85
86 void Parser::pushback(Token t) {
87 fPushback = t;
88 }
89
90 Token Parser::peek() {
91 fPushback = this->nextToken();
92 return fPushback;
93 }
94
95 bool Parser::expect(Token::Kind kind, std::string expected, Token* result) {
96 Token next = this->nextToken();
97 if (next.fKind == kind) {
98 if (result != nullptr) {
99 *result = next;
100 }
101 return true;
102 } else {
103 this->error(next.fPosition, "expected " + expected + ", but found '" +
104 next.fText + "'");
105 return false;
106 }
107 }
108
109 void Parser::error(Position p, std::string msg) {
110 fErrors.error(p, msg);
111 }
112
113 /* (precision | directive | declaration)* END_OF_FILE */
114 std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
115 std::vector<std::unique_ptr<ASTDeclaration>> result;
116 for (;;) {
117 switch (this->peek().fKind) {
118 case Token::END_OF_FILE:
119 return result;
120 case Token::PRECISION:
121 this->precision();
122 break;
123 case Token::DIRECTIVE: {
124 std::unique_ptr<ASTDeclaration> decl = this->directive();
125 if (decl != nullptr) {
126 result.push_back(std::move(decl));
127 }
128 break;
129 }
130 default: {
131 std::unique_ptr<ASTDeclaration> decl = this->declaration();
132 if (decl == nullptr) {
133 return result;
134 }
135 result.push_back(std::move(decl));
136 }
137 }
138 }
139 }
140
141 /* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
142 void Parser::precision() {
143 if (!this->expect(Token::PRECISION, "'precision'")) {
144 return;
145 }
146 Token p = this->nextToken();
147 switch (p.fKind) {
148 case Token::LOWP: // fall through
149 case Token::MEDIUMP: // fall through
150 case Token::HIGHP:
151 break;
152 default:
153 this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', bu t found '" +
154 p.fText + "'");
155 return;
156 }
157 if (this->type() == nullptr) {
158 return;
159 }
160 this->expect(Token::SEMICOLON, "';'");
161 }
162
163 /* DIRECTIVE(#version) INT_LITERAL | DIRECTIVE(#extension) IDENTIFIER COLON IDEN TIFIER */
164 std::unique_ptr<ASTDeclaration> Parser::directive() {
165 Token start;
166 if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
167 return nullptr;
168 }
169 if (start.fText == "#version") {
170 this->expect(Token::INT_LITERAL, "a version number");
171 return nullptr;
172 } else if (start.fText == "#extension") {
173 Token name;
174 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
175 return nullptr;
176 }
177 if (!this->expect(Token::COLON, "':'")) {
178 return nullptr;
179 }
180 // FIXME: need to start paying attention to this token
181 if (!this->expect(Token::IDENTIFIER, "an identifier")) {
182 return nullptr;
183 }
184 return std::unique_ptr<ASTDeclaration>(new ASTExtension(start.fPosition, name.fText));
185 } else {
186 this->error(start.fPosition, "unsupport directive '" + start.fText + "'" );
187 return nullptr;
188 }
189 }
190
191 /* modifiers (type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN (blo ck | SEMICOLON)) |
192 SEMICOLON) | interfaceBlock) */
193 std::unique_ptr<ASTDeclaration> Parser::declaration() {
194 ASTModifiers modifiers = this->modifiers();
195 Token lookahead = this->peek();
196 if (lookahead.fKind == Token::IDENTIFIER && !this->isType(lookahead.fText)) {
197 // we have an identifier that's not a type, could be the start of an int erface block
198 return this->interfaceBlock(modifiers);
199 }
200 std::unique_ptr<ASTType> type(this->type());
201 if (!type) {
202 return nullptr;
203 }
204 if (type->fKind == ASTType::kStruct_Kind && peek().fKind == Token::SEMICOLON ) {
205 this->nextToken();
206 std::vector<std::string> names;
207 std::vector<std::vector<std::unique_ptr<ASTExpression>>> sizes;
208 std::vector<std::unique_ptr<ASTExpression>> values;
209 return std::unique_ptr<ASTVarDeclaration>(new ASTVarDeclaration(std::mov e(modifiers),
210 std::mov e(type),
211 names,
212 std::mov e(sizes),
213 std::mov e(values)));
214 }
215 Token name;
216 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
217 return nullptr;
218 }
219 if (!modifiers.fBits && this->peek().fKind == Token::LPAREN) {
220 this->nextToken();
221 std::vector<std::unique_ptr<ASTParameter>> parameters;
222 while (this->peek().fKind != Token::RPAREN) {
223 if (parameters.size() > 0) {
224 if (!this->expect(Token::COMMA, "','")) {
225 return nullptr;
226 }
227 }
228 std::unique_ptr<ASTParameter> parameter = this->parameter();
229 if (!parameter) {
230 return nullptr;
231 }
232 parameters.push_back(std::move(parameter));
233 }
234 this->nextToken();
235 std::unique_ptr<ASTBlock> body;
236 if (this->peek().fKind == Token::SEMICOLON) {
237 this->nextToken();
238 } else {
239 body = this->block();
240 if (!body) {
241 return nullptr;
242 }
243 }
244 return std::unique_ptr<ASTDeclaration>(new ASTFunction(name.fPosition, s td::move(type),
245 name.fText, std::mo ve(parameters),
246 std::move(body)));
247 } else {
248 return this->varDeclarationEnd(modifiers, std::move(type), name.fText);
249 }
250 }
251
252 /* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
253 std::unique_ptr<ASTType> Parser::structDeclaration() {
254 if (!this->expect(Token::STRUCT, "'struct'")) {
255 return nullptr;
256 }
257 Token name;
258 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
259 return nullptr;
260 }
261 if (!this->expect(Token::LBRACE, "'{'")) {
262 return nullptr;
263 }
264 std::vector<Type::Field> fields;
265 while (this->peek().fKind != Token::RBRACE) {
266 std::unique_ptr<ASTVarDeclaration> decl = this->varDeclaration();
267 if (decl == nullptr) {
268 return nullptr;
269 }
270 for (size_t i = 0; i < decl->fNames.size(); i++) {
271 std::shared_ptr<Type> type = std::static_pointer_cast<Type>(
272 (*fTypes) [d ecl->fType->fName]);
273 for (int j = (int) decl->fSizes[i].size() - 1; j >= 0; j--) {
274 if (decl->fSizes[i][j]->fKind == ASTExpression::kInt_Kind) {
275 this->error(decl->fPosition, "array size in struct field mus t be a constant");
276 }
277 uint64_t columns = ((ASTIntLiteral&) *decl->fSizes[i][j]).fValue ;
278 std::string name = type->name() + "[" + to_string(columns) + "]" ;
279 type = std::shared_ptr<Type>(new Type(name, Type::kArray_Kind, t ype,
280 (int) columns));
281 }
282 fields.push_back(Type::Field(decl->fModifiers, decl->fNames[i], type ));
283 if (decl->fValues[i] != nullptr) {
284 this->error(decl->fPosition, "initializers are not permitted on struct fields");
285 }
286 }
287 }
288 if (!this->expect(Token::RBRACE, "'}'")) {
289 return nullptr;
290 }
291 std::shared_ptr<Type> type(new Type(name.fText, fields));
292 (*fTypes).add(type->fName, type);
293 return std::unique_ptr<ASTType>(new ASTType(name.fPosition, type->fName,
294 ASTType::kStruct_Kind));
295 }
296
297 /* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
298 std::unique_ptr<ASTParameter> Parser::parameter() {
299 ASTModifiers modifiers = this->modifiers();
300 std::unique_ptr<ASTType> type = this->type();
301 if (!type) {
302 return nullptr;
303 }
304 Token name;
305 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
306 return nullptr;
307 }
308 std::vector<int> sizes;
309 while (this->peek().fKind == Token::LBRACKET) {
310 this->nextToken();
311 Token sizeToken;
312 if (!this->expect(Token::INT_LITERAL, "a non-negative integer", &sizeTok en)) {
313 return nullptr;
314 }
315 sizes.push_back(SkSL::stoi(sizeToken.fText));
316 if (!this->expect(Token::RBRACKET, "']'")) {
317 return nullptr;
318 }
319 }
320 return std::unique_ptr<ASTParameter>(new ASTParameter(name.fPosition, modifi ers,
321 std::move(type), name. fText, sizes));
322 }
323
324 static int read_layout_int(Parser* parser) {
325 if (!parser->expect(Token::EQ, "'='")) {
326 return -1;
327 }
328 Token resultToken;
329 if (parser->expect(Token::INT_LITERAL, "a non-negative integer", &resultToke n)) {
330 return SkSL::stoi(resultToken.fText);
331 }
332 return -1;
333 }
334
335 /* LAYOUT LPAREN IDENTIFIER EQ INT_LITERAL (COMMA IDENTIFIER EQ INT_LITERAL)*
336 RPAREN */
337 ASTLayout Parser::layout() {
338 int location = -1;
339 int binding = -1;
340 int index = -1;
341 int set = -1;
342 int builtin = -1;
343 if (this->peek().fKind == Token::LAYOUT) {
344 this->nextToken();
345 if (!this->expect(Token::LPAREN, "'('")) {
346 return ASTLayout(location, binding, index, set, builtin);
347 }
348 for (;;) {
349 Token t = this->nextToken();
350 if (t.fText == "location") {
351 location = read_layout_int(this);
352 } else if (t.fText == "binding") {
353 binding = read_layout_int(this);
354 } else if (t.fText == "index") {
355 index = read_layout_int(this);
356 } else if (t.fText == "set") {
357 set = read_layout_int(this);
358 } else if (t.fText == "builtin") {
359 builtin = read_layout_int(this);
360 } else {
361 this->error(t.fPosition, ("'" + t.fText +
362 "' is not a valid layout qualifier").c _str());
363 }
364 if (this->peek().fKind == Token::RPAREN) {
365 this->nextToken();
366 break;
367 }
368 if (!this->expect(Token::COMMA, "','")) {
369 break;
370 }
371 }
372 }
373 return ASTLayout(location, binding, index, set, builtin);
374 }
375
376 /* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP |
377 MEDIUMP | HIGHP)* */
378 ASTModifiers Parser::modifiers() {
379 ASTLayout layout = this->layout();
380 int bits = 0;
381 for (;;) {
382 // TODO: handle duplicate / incompatible bits
383 switch (peek().fKind) {
384 case Token::UNIFORM:
385 this->nextToken();
386 bits |= ASTModifiers::kUniform_Bit;
387 break;
388 case Token::CONST:
389 this->nextToken();
390 bits |= ASTModifiers::kConst_Bit;
391 break;
392 case Token::IN:
393 this->nextToken();
394 bits |= ASTModifiers::kIn_Bit;
395 break;
396 case Token::OUT:
397 this->nextToken();
398 bits |= ASTModifiers::kOut_Bit;
399 break;
400 case Token::INOUT:
401 this->nextToken();
402 bits |= ASTModifiers::kIn_Bit;
403 bits |= ASTModifiers::kOut_Bit;
404 break;
405 case Token::LOWP:
406 this->nextToken();
407 bits |= ASTModifiers::kLowp_Bit;
408 break;
409 case Token::MEDIUMP:
410 this->nextToken();
411 bits |= ASTModifiers::kMediump_Bit;
412 break;
413 case Token::HIGHP:
414 this->nextToken();
415 bits |= ASTModifiers::kHighp_Bit;
416 break;
417 default:
418 return ASTModifiers(layout, bits);
419 }
420 }
421 }
422
423 /* ifStatement | forStatement | doStatement | whileStatement | block | expressio n */
424 std::unique_ptr<ASTStatement> Parser::statement() {
425 Token start = this->peek();
426 switch (start.fKind) {
427 case Token::IF:
428 return this->ifStatement();
429 case Token::FOR:
430 return this->forStatement();
431 case Token::DO:
432 return this->doStatement();
433 case Token::WHILE:
434 return this->whileStatement();
435 case Token::RETURN:
436 return this->returnStatement();
437 case Token::BREAK:
438 return this->breakStatement();
439 case Token::CONTINUE:
440 return this->continueStatement();
441 case Token::DISCARD:
442 return this->discardStatement();
443 case Token::LBRACE:
444 return this->block();
445 case Token::SEMICOLON:
446 this->nextToken();
447 return std::unique_ptr<ASTStatement>(new ASTBlock(start.fPosition,
448 std::vector<std::unique_ptr<ASTS tatement>>()));
449 case Token::CONST: // fall through
450 case Token::HIGHP: // fall through
451 case Token::MEDIUMP: // fall through
452 case Token::LOWP:
453 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatement(
454 this- >varDeclaration()));
455 case Token::IDENTIFIER:
456 if (this->isType(start.fText)) {
457 return std::unique_ptr<ASTStatement>(new ASTVarDeclarationStatem ent(
458 this- >varDeclaration()));
459 }
460 // fall through
461 default:
462 return this->expressionStatement();
463 }
464 }
465
466 /* IDENTIFIER(type) | structDeclaration */
467 std::unique_ptr<ASTType> Parser::type() {
468 if (this->peek().fKind == Token::STRUCT) {
469 return this->structDeclaration();
470 }
471 Token type;
472 if (!this->expect(Token::IDENTIFIER, "a type", &type)) {
473 return nullptr;
474 }
475 if (!this->isType(type.fText)) {
476 this->error(type.fPosition, ("no type named '" + type.fText + "'").c_str ());
477 return nullptr;
478 }
479 return std::unique_ptr<ASTType>(new ASTType(type.fPosition, type.fText,
480 ASTType::kIdentifier_Kind));
481 }
482
483 /* IDENTIFIER LBRACE varDeclaration* RBRACE */
484 std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(ASTModifiers mods) {
485 Token name;
486 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
487 return nullptr;
488 }
489 if (peek().fKind != Token::LBRACE) {
490 // we only get into interfaceBlock if we found a top-level identifier wh ich was not a type.
491 // 99% of the time, the user was not actually intending to create an int erface block, so
492 // it's better to report it as an unknown type
493 this->error(name.fPosition, "no type named '" + name.fText + "'");
494 }
495 this->nextToken();
496 std::vector<std::unique_ptr<ASTVarDeclaration>> decls;
497 while (this->peek().fKind != Token::RBRACE) {
498 std::unique_ptr<ASTVarDeclaration> decl = this->varDeclaration();
499 if (decl == nullptr) {
500 return nullptr;
501 }
502 decls.push_back(std::move(decl));
503 }
504 this->nextToken();
505 std::string valueName;
506 if (this->peek().fKind == Token::IDENTIFIER) {
507 valueName = this->nextToken().fText;
508 }
509 this->expect(Token::SEMICOLON, "';'");
510 return std::unique_ptr<ASTDeclaration>(new ASTInterfaceBlock(name.fPosition, mods,
511 name.fText, val ueName,
512 std::move(decls )));
513 }
514
515 /* (LBRACKET expression? RBRACKET)* (EQ expression)? (COMMA IDENTIFER
516 (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */
517 std::unique_ptr<ASTVarDeclaration> Parser::varDeclarationEnd(ASTModifiers mods,
518 std::unique_ptr<AST Type> type,
519 std::string name) {
520 std::vector<std::string> names;
521 std::vector<std::vector<std::unique_ptr<ASTExpression>>> sizes;
522 names.push_back(name);
523 std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
524 while (this->peek().fKind == Token::LBRACKET) {
525 this->nextToken();
526 if (this->peek().fKind == Token::RBRACKET) {
527 this->nextToken();
528 currentVarSizes.push_back(nullptr);
529 }
530 else {
531 std::unique_ptr<ASTExpression> size(this->expression());
532 if (!size) {
533 return nullptr;
534 }
535 currentVarSizes.push_back(std::move(size));
536 if (!this->expect(Token::RBRACKET, "']'")) {
537 return nullptr;
538 }
539 }
540 }
541 sizes.push_back(std::move(currentVarSizes));
542 std::vector<std::unique_ptr<ASTExpression>> values;
543 if (this->peek().fKind == Token::EQ) {
544 this->nextToken();
545 std::unique_ptr<ASTExpression> value(this->expression());
546 if (!value) {
547 return nullptr;
548 }
549 values.push_back(std::move(value));
550 } else {
551 values.push_back(nullptr);
552 }
553 while (this->peek().fKind == Token::COMMA) {
554 this->nextToken();
555 Token name;
556 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
557 return nullptr;
558 }
559 names.push_back(name.fText);
560 currentVarSizes.clear();
561 while (this->peek().fKind == Token::LBRACKET) {
562 this->nextToken();
563 if (this->peek().fKind == Token::RBRACKET) {
564 this->nextToken();
565 currentVarSizes.push_back(nullptr);
566 }
567 else {
568 std::unique_ptr<ASTExpression> size(this->expression());
569 if (!size) {
570 return nullptr;
571 }
572 currentVarSizes.push_back(std::move(size));
573 if (!this->expect(Token::RBRACKET, "']'")) {
574 return nullptr;
575 }
576 }
577 }
578 sizes.push_back(std::move(currentVarSizes));
579 if (this->peek().fKind == Token::EQ) {
580 this->nextToken();
581 std::unique_ptr<ASTExpression> value(this->expression());
582 if (!value) {
583 return nullptr;
584 }
585 values.push_back(std::move(value));
586 } else {
587 values.push_back(nullptr);
588 }
589 }
590 if (!this->expect(Token::SEMICOLON, "';'")) {
591 return nullptr;
592 }
593 return std::unique_ptr<ASTVarDeclaration>(new ASTVarDeclaration(std::move(mo ds),
594 std::move(ty pe),
595 names,
596 std::move(si zes),
597 std::move(va lues)));
598 }
599
600 /* modifiers type IDENTIFIER (EQ expression)? (COMMA IDENTIFER (EQ expression)?) * SEMICOLON */
601 std::unique_ptr<ASTVarDeclaration> Parser::varDeclaration() {
602 ASTModifiers modifiers = this->modifiers();
603 std::unique_ptr<ASTType> type(this->type());
604 if (!type) {
605 return nullptr;
606 }
607 Token name;
608 if (!this->expect(Token::IDENTIFIER, "an identifier", &name)) {
609 return nullptr;
610 }
611 return this->varDeclarationEnd(std::move(modifiers), std::move(type), name.f Text);
612 }
613
614 /* IF LPAREN expression RPAREN statement (ELSE statement)? */
615 std::unique_ptr<ASTIfStatement> Parser::ifStatement() {
616 Token start;
617 if (!this->expect(Token::IF, "'if'", &start)) {
618 return nullptr;
619 }
620 if (!this->expect(Token::LPAREN, "'('")) {
621 return nullptr;
622 }
623 std::unique_ptr<ASTExpression> test(this->expression());
624 if (test == nullptr) {
625 return nullptr;
626 }
627 if (!this->expect(Token::RPAREN, "')'")) {
628 return nullptr;
629 }
630 std::unique_ptr<ASTStatement> ifTrue(this->statement());
631 if (ifTrue == nullptr) {
632 return nullptr;
633 }
634 std::unique_ptr<ASTStatement> ifFalse;
635 if (this->peek().fKind == Token::ELSE) {
636 this->nextToken();
637 ifFalse = this->statement();
638 if (!ifFalse) {
639 return nullptr;
640 }
641 }
642 return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, s td::move(test),
643 std::move(ifTrue),
644 std::move(ifFalse) ));
645 }
646
647 /* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
648 std::unique_ptr<ASTDoStatement> Parser::doStatement() {
649 Token start;
650 if (!this->expect(Token::DO, "'do'", &start)) {
651 return nullptr;
652 }
653 std::unique_ptr<ASTStatement> statement(this->statement());
654 if (statement == nullptr) {
655 return nullptr;
656 }
657 if (!this->expect(Token::WHILE, "'while'")) {
658 return nullptr;
659 }
660 if (!this->expect(Token::LPAREN, "'('")) {
661 return nullptr;
662 }
663 std::unique_ptr<ASTExpression> test(this->expression());
664 if (test == nullptr) {
665 return nullptr;
666 }
667 if (!this->expect(Token::RPAREN, "')'")) {
668 return nullptr;
669 }
670 if (!this->expect(Token::SEMICOLON, "';'")) {
671 return nullptr;
672 }
673 return std::unique_ptr<ASTDoStatement>(new ASTDoStatement(start.fPosition,
674 std::move(test),
675 std::move(statemen t)));
676 }
677
678 /* WHILE LPAREN expression RPAREN STATEMENT */
679 std::unique_ptr<ASTWhileStatement> Parser::whileStatement() {
680 Token start;
681 if (!this->expect(Token::WHILE, "'while'", &start)) {
682 return nullptr;
683 }
684 if (!this->expect(Token::LPAREN, "'('")) {
685 return nullptr;
686 }
687 std::unique_ptr<ASTExpression> test(this->expression());
688 if (test == nullptr) {
689 return nullptr;
690 }
691 if (!this->expect(Token::RPAREN, "')'")) {
692 return nullptr;
693 }
694 std::unique_ptr<ASTStatement> statement(this->statement());
695 if (statement == nullptr) {
696 return nullptr;
697 }
698 return std::unique_ptr<ASTWhileStatement>(new ASTWhileStatement(start.fPosit ion,
699 std::move(te st),
700 std::move(st atement)));
701 }
702
703 /* RETURN expression? SEMICOLON */
704 std::unique_ptr<ASTReturnStatement> Parser::returnStatement() {
705 Token start;
706 if (!this->expect(Token::RETURN, "'return'", &start)) {
707 return nullptr;
708 }
709 std::unique_ptr<ASTExpression> expression;
710 if (this->peek().fKind != Token::SEMICOLON) {
711 expression = this->expression();
712 if (!expression) {
713 return nullptr;
714 }
715 }
716 if (!this->expect(Token::SEMICOLON, "';'")) {
717 return nullptr;
718 }
719 return std::unique_ptr<ASTReturnStatement>(new ASTReturnStatement(start.fPos ition,
720 std::move( expression)));
721 }
722
723 /* BREAK SEMICOLON */
724 std::unique_ptr<ASTBreakStatement> Parser::breakStatement() {
725 Token start;
726 if (!this->expect(Token::BREAK, "'break'", &start)) {
727 return nullptr;
728 }
729 if (!this->expect(Token::SEMICOLON, "';'")) {
730 return nullptr;
731 }
732 return std::unique_ptr<ASTBreakStatement>(new ASTBreakStatement(start.fPosit ion));
733 }
734
735 /* CONTINUE SEMICOLON */
736 std::unique_ptr<ASTContinueStatement> Parser::continueStatement() {
737 Token start;
738 if (!this->expect(Token::CONTINUE, "'continue'", &start)) {
739 return nullptr;
740 }
741 if (!this->expect(Token::SEMICOLON, "';'")) {
742 return nullptr;
743 }
744 return std::unique_ptr<ASTContinueStatement>(new ASTContinueStatement(start. fPosition));
745 }
746
747 /* DISCARD SEMICOLON */
748 std::unique_ptr<ASTDiscardStatement> Parser::discardStatement() {
749 Token start;
750 if (!this->expect(Token::DISCARD, "'continue'", &start)) {
751 return nullptr;
752 }
753 if (!this->expect(Token::SEMICOLON, "';'")) {
754 return nullptr;
755 }
756 return std::unique_ptr<ASTDiscardStatement>(new ASTDiscardStatement(start.fP osition));
757 }
758
759 bool Parser::isType(std::string name) {
760 return (*fTypes)[name] != nullptr;
761 }
762
763 /* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expres sion? RPAREN
764 STATEMENT */
765 std::unique_ptr<ASTForStatement> Parser::forStatement() {
766 Token start;
767 if (!this->expect(Token::FOR, "'for'", &start)) {
768 return nullptr;
769 }
770 if (!this->expect(Token::LPAREN, "'('")) {
771 return nullptr;
772 }
773 std::unique_ptr<ASTStatement> initializer;
774 Token nextToken = this->peek();
775 switch (nextToken.fKind) {
776 case Token::SEMICOLON:
777 break;
778 case Token::CONST:
779 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclarationSta tement(
780 this- >varDeclaration()));
781 break;
782 case Token::IDENTIFIER:
783 if (this->isType(nextToken.fText)) {
784 initializer = std::unique_ptr<ASTStatement>(new ASTVarDeclaratio nStatement(
785 this- >varDeclaration()));
786 break;
787 }
788 // fall through
789 default:
790 initializer = this->expressionStatement();
791 }
792 std::unique_ptr<ASTExpression> test;
793 if (this->peek().fKind != Token::SEMICOLON) {
794 test = this->expression();
795 if (!test) {
796 return nullptr;
797 }
798 }
799 if (!this->expect(Token::SEMICOLON, "';'")) {
800 return nullptr;
801 }
802 std::unique_ptr<ASTExpression> next;
803 if (this->peek().fKind != Token::SEMICOLON) {
804 next = this->expression();
805 if (!next) {
806 return nullptr;
807 }
808 }
809 if (!this->expect(Token::RPAREN, "')'")) {
810 return nullptr;
811 }
812 std::unique_ptr<ASTStatement> statement(this->statement());
813 if (statement == nullptr) {
814 return nullptr;
815 }
816 return std::unique_ptr<ASTForStatement>(new ASTForStatement(start.fPosition,
817 std::move(initia lizer),
818 std::move(test), std::move(next),
819 std::move(statem ent)));
820 }
821
822 /* LBRACE statement* RBRACE */
823 std::unique_ptr<ASTBlock> Parser::block() {
824 Token start;
825 if (!this->expect(Token::LBRACE, "'{'", &start)) {
826 return nullptr;
827 }
828 std::vector<std::unique_ptr<ASTStatement>> statements;
829 for (;;) {
830 switch (this->peek().fKind) {
831 case Token::RBRACE:
832 this->nextToken();
833 return std::unique_ptr<ASTBlock>(new ASTBlock(start.fPosition,
834 std::move(statemen ts)));
835 case Token::END_OF_FILE:
836 this->error(this->peek().fPosition, "expected '}', but found end of file");
837 return nullptr;
838 default: {
839 std::unique_ptr<ASTStatement> statement = this->statement();
840 if (statement == nullptr) {
841 return nullptr;
842 }
843 statements.push_back(std::move(statement));
844 }
845 }
846 }
847 }
848
849 /* expression SEMICOLON */
850 std::unique_ptr<ASTExpressionStatement> Parser::expressionStatement() {
851 std::unique_ptr<ASTExpression> expr = this->expression();
852 if (expr) {
853 if (this->expect(Token::SEMICOLON, "';'")) {
854 ASTExpressionStatement* result = new ASTExpressionStatement(std::mov e(expr));
855 return std::unique_ptr<ASTExpressionStatement>(result);
856 }
857 }
858 return nullptr;
859 }
860
861 /* assignmentExpression */
862 std::unique_ptr<ASTExpression> Parser::expression() {
863 return this->assignmentExpression();
864 }
865
866 /* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
867 BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOG ICALOREQ)
868 assignmentExpression)*
869 */
870 std::unique_ptr<ASTExpression> Parser::assignmentExpression() {
871 std::unique_ptr<ASTExpression> result = this->ternaryExpression();
872 if (!result) {
873 return nullptr;
874 }
875 for (;;) {
876 switch (this->peek().fKind) {
877 case Token::EQ: // fall through
878 case Token::STAREQ: // fall through
879 case Token::SLASHEQ: // fall through
880 case Token::PERCENTEQ: // fall through
881 case Token::PLUSEQ: // fall through
882 case Token::MINUSEQ: // fall through
883 case Token::SHLEQ: // fall through
884 case Token::SHREQ: // fall through
885 case Token::BITWISEANDEQ: // fall through
886 case Token::BITWISEXOREQ: // fall through
887 case Token::BITWISEOREQ: // fall through
888 case Token::LOGICALANDEQ: // fall through
889 case Token::LOGICALXOREQ: // fall through
890 case Token::LOGICALOREQ: {
891 Token t = this->nextToken();
892 std::unique_ptr<ASTExpression> right = this->assignmentExpressio n();
893 if (right == nullptr) {
894 return nullptr;
895 }
896 result = std::unique_ptr<ASTExpression>(new ASTBinaryExpression( std::move(result),
897 t,
898 std::move(right)));
899 }
900 default:
901 return result;
902 }
903 }
904 }
905
906 /* logicalOrExpression ('?' expression ':' assignmentExpression)? */
907 std::unique_ptr<ASTExpression> Parser::ternaryExpression() {
908 std::unique_ptr<ASTExpression> result = this->logicalOrExpression();
909 if (result == nullptr) {
910 return nullptr;
911 }
912 if (this->peek().fKind == Token::QUESTION) {
913 Token question = this->nextToken();
914 std::unique_ptr<ASTExpression> trueExpr = this->expression();
915 if (trueExpr == nullptr) {
916 return nullptr;
917 }
918 if (this->expect(Token::COLON, "':'")) {
919 std::unique_ptr<ASTExpression> falseExpr = this->assignmentExpressio n();
920 return std::unique_ptr<ASTExpression>(new ASTTernaryExpression(std:: move(result),
921 std:: move(trueExpr),
922 std:: move(falseExpr)));
923 }
924 return nullptr;
925 }
926 return result;
927 }
928
929 /* logicalXorExpression (LOGICALOR logicalXorExpression)* */
930 std::unique_ptr<ASTExpression> Parser::logicalOrExpression() {
931 std::unique_ptr<ASTExpression> result = this->logicalXorExpression();
932 if (result == nullptr) {
933 return nullptr;
934 }
935 while (this->peek().fKind == Token::LOGICALOR) {
936 Token t = this->nextToken();
937 std::unique_ptr<ASTExpression> right = this->logicalXorExpression();
938 if (right == nullptr) {
939 return nullptr;
940 }
941 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(rig ht)));
942 }
943 return result;
944 }
945
946 /* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
947 std::unique_ptr<ASTExpression> Parser::logicalXorExpression() {
948 std::unique_ptr<ASTExpression> result = this->logicalAndExpression();
949 if (result == nullptr) {
950 return nullptr;
951 }
952 while (this->peek().fKind == Token::LOGICALXOR) {
953 Token t = this->nextToken();
954 std::unique_ptr<ASTExpression> right = this->logicalAndExpression();
955 if (right == nullptr) {
956 return nullptr;
957 }
958 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(rig ht)));
959 }
960 return result;
961 }
962
963 /* bitwiseXorExpression (LOGICALAND bitwiseXorExpression)* */
964 std::unique_ptr<ASTExpression> Parser::logicalAndExpression() {
965 std::unique_ptr<ASTExpression> result = this->bitwiseOrExpression();
966 if (result == nullptr) {
967 return nullptr;
968 }
969 while (this->peek().fKind == Token::LOGICALAND) {
970 Token t = this->nextToken();
971 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
972 if (right == nullptr) {
973 return nullptr;
974 }
975 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(rig ht)));
976 }
977 return result;
978 }
979
980 /* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
981 std::unique_ptr<ASTExpression> Parser::bitwiseOrExpression() {
982 std::unique_ptr<ASTExpression> result = this->bitwiseXorExpression();
983 if (result == nullptr) {
984 return nullptr;
985 }
986 while (this->peek().fKind == Token::BITWISEOR) {
987 Token t = this->nextToken();
988 std::unique_ptr<ASTExpression> right = this->bitwiseXorExpression();
989 if (right == nullptr) {
990 return nullptr;
991 }
992 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(rig ht)));
993 }
994 return result;
995 }
996
997 /* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
998 std::unique_ptr<ASTExpression> Parser::bitwiseXorExpression() {
999 std::unique_ptr<ASTExpression> result = this->bitwiseAndExpression();
1000 if (result == nullptr) {
1001 return nullptr;
1002 }
1003 while (this->peek().fKind == Token::BITWISEXOR) {
1004 Token t = this->nextToken();
1005 std::unique_ptr<ASTExpression> right = this->bitwiseAndExpression();
1006 if (right == nullptr) {
1007 return nullptr;
1008 }
1009 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(rig ht)));
1010 }
1011 return result;
1012 }
1013
1014 /* equalityExpression (BITWISEAND equalityExpression)* */
1015 std::unique_ptr<ASTExpression> Parser::bitwiseAndExpression() {
1016 std::unique_ptr<ASTExpression> result = this->equalityExpression();
1017 if (result == nullptr) {
1018 return nullptr;
1019 }
1020 while (this->peek().fKind == Token::BITWISEAND) {
1021 Token t = this->nextToken();
1022 std::unique_ptr<ASTExpression> right = this->equalityExpression();
1023 if (right == nullptr) {
1024 return nullptr;
1025 }
1026 result.reset(new ASTBinaryExpression(std::move(result), t, std::move(rig ht)));
1027 }
1028 return result;
1029 }
1030
1031 /* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1032 std::unique_ptr<ASTExpression> Parser::equalityExpression() {
1033 std::unique_ptr<ASTExpression> result = this->relationalExpression();
1034 if (result == nullptr) {
1035 return nullptr;
1036 }
1037 for (;;) {
1038 switch (this->peek().fKind) {
1039 case Token::EQEQ: // fall through
1040 case Token::NEQ: {
1041 Token t = this->nextToken();
1042 std::unique_ptr<ASTExpression> right = this->relationalExpressio n();
1043 if (right == nullptr) {
1044 return nullptr;
1045 }
1046 result.reset(new ASTBinaryExpression(std::move(result), t, std:: move(right)));
1047 break;
1048 }
1049 default:
1050 return result;
1051 }
1052 }
1053 }
1054
1055 /* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1056 std::unique_ptr<ASTExpression> Parser::relationalExpression() {
1057 std::unique_ptr<ASTExpression> result = this->shiftExpression();
1058 if (result == nullptr) {
1059 return nullptr;
1060 }
1061 for (;;) {
1062 switch (this->peek().fKind) {
1063 case Token::LT: // fall through
1064 case Token::GT: // fall through
1065 case Token::LTEQ: // fall through
1066 case Token::GTEQ: {
1067 Token t = this->nextToken();
1068 std::unique_ptr<ASTExpression> right = this->shiftExpression();
1069 if (right == nullptr) {
1070 return nullptr;
1071 }
1072 result.reset(new ASTBinaryExpression(std::move(result), t, std:: move(right)));
1073 break;
1074 }
1075 default:
1076 return result;
1077 }
1078 }
1079 }
1080
1081 /* additiveExpression ((SHL | SHR) additiveExpression)* */
1082 std::unique_ptr<ASTExpression> Parser::shiftExpression() {
1083 std::unique_ptr<ASTExpression> result = this->additiveExpression();
1084 if (result == nullptr) {
1085 return nullptr;
1086 }
1087 for (;;) {
1088 switch (this->peek().fKind) {
1089 case Token::SHL: // fall through
1090 case Token::SHR: {
1091 Token t = this->nextToken();
1092 std::unique_ptr<ASTExpression> right = this->additiveExpression( );
1093 if (right == nullptr) {
1094 return nullptr;
1095 }
1096 result.reset(new ASTBinaryExpression(std::move(result), t, std:: move(right)));
1097 break;
1098 }
1099 default:
1100 return result;
1101 }
1102 }
1103 }
1104
1105 /* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1106 std::unique_ptr<ASTExpression> Parser::additiveExpression() {
1107 std::unique_ptr<ASTExpression> result = this->multiplicativeExpression();
1108 if (result == nullptr) {
1109 return nullptr;
1110 }
1111 for (;;) {
1112 switch (this->peek().fKind) {
1113 case Token::PLUS: // fall through
1114 case Token::MINUS: {
1115 Token t = this->nextToken();
1116 std::unique_ptr<ASTExpression> right = this->multiplicativeExpre ssion();
1117 if (right == nullptr) {
1118 return nullptr;
1119 }
1120 result.reset(new ASTBinaryExpression(std::move(result), t, std:: move(right)));
1121 break;
1122 }
1123 default:
1124 return result;
1125 }
1126 }
1127 }
1128
1129 /* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1130 std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
1131 std::unique_ptr<ASTExpression> result = this->unaryExpression();
1132 if (result == nullptr) {
1133 return nullptr;
1134 }
1135 for (;;) {
1136 switch (this->peek().fKind) {
1137 case Token::STAR: // fall through
1138 case Token::SLASH: // fall through
1139 case Token::PERCENT: {
1140 Token t = this->nextToken();
1141 std::unique_ptr<ASTExpression> right = this->unaryExpression();
1142 if (right == nullptr) {
1143 return nullptr;
1144 }
1145 result.reset(new ASTBinaryExpression(std::move(result), t, std:: move(right)));
1146 break;
1147 }
1148 default:
1149 return result;
1150 }
1151 }
1152 }
1153
1154 /* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpress ion */
1155 std::unique_ptr<ASTExpression> Parser::unaryExpression() {
1156 switch (this->peek().fKind) {
1157 case Token::PLUS: // fall through
1158 case Token::MINUS: // fall through
1159 case Token::NOT: // fall through
1160 case Token::PLUSPLUS: // fall through
1161 case Token::MINUSMINUS: {
1162 Token t = this->nextToken();
1163 std::unique_ptr<ASTExpression> expr = this->unaryExpression();
1164 if (expr == nullptr) {
1165 return nullptr;
1166 }
1167 return std::unique_ptr<ASTExpression>(new ASTPrefixExpression(t, std ::move(expr)));
1168 }
1169 default:
1170 return this->postfixExpression();
1171 }
1172 }
1173
1174 /* term suffix* */
1175 std::unique_ptr<ASTExpression> Parser::postfixExpression() {
1176 std::unique_ptr<ASTExpression> result = this->term();
1177 if (result == nullptr) {
1178 return nullptr;
1179 }
1180 for (;;) {
1181 switch (this->peek().fKind) {
1182 case Token::LBRACKET: // fall through
1183 case Token::DOT: // fall through
1184 case Token::LPAREN: // fall through
1185 case Token::PLUSPLUS: // fall through
1186 case Token::MINUSMINUS: {
1187 std::unique_ptr<ASTSuffix> s = this->suffix();
1188 if (s == nullptr) {
1189 return nullptr;
1190 }
1191 result.reset(new ASTSuffixExpression(std::move(result), std::mov e(s)));
1192 break;
1193 }
1194 default:
1195 return result;
1196 }
1197 }
1198 }
1199
1200 /* LBRACKET expression RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
1201 PLUSPLUS | MINUSMINUS */
1202 std::unique_ptr<ASTSuffix> Parser::suffix() {
1203 Token next = this->nextToken();
1204 switch (next.fKind) {
1205 case Token::LBRACKET: {
1206 std::unique_ptr<ASTExpression> e = this->expression();
1207 if (e == nullptr) {
1208 return nullptr;
1209 }
1210 this->expect(Token::RBRACKET, "']' to complete array access expressi on");
1211 return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(std::move(e)));
1212 }
1213 case Token::DOT: {
1214 Position pos = this->peek().fPosition;
1215 std::string text;
1216 if (this->identifier(&text)) {
1217 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, text)) ;
1218 }
1219 return nullptr;
1220 }
1221 case Token::LPAREN: {
1222 std::vector<std::unique_ptr<ASTExpression>> parameters;
1223 if (this->peek().fKind != Token::RPAREN) {
1224 for (;;) {
1225 std::unique_ptr<ASTExpression> expr = this->expression();
1226 if (expr == nullptr) {
1227 return nullptr;
1228 }
1229 parameters.push_back(std::move(expr));
1230 if (this->peek().fKind != Token::COMMA) {
1231 break;
1232 }
1233 this->nextToken();
1234 }
1235 }
1236 this->expect(Token::RPAREN, "')' to complete function parameters");
1237 return std::unique_ptr<ASTSuffix>(new ASTCallSuffix(next.fPosition,
1238 std::move(parame ters)));
1239 }
1240 case Token::PLUSPLUS:
1241 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1242 ASTSuffix::kPostIncr ement_Kind));
1243 case Token::MINUSMINUS:
1244 return std::unique_ptr<ASTSuffix>(new ASTSuffix(next.fPosition,
1245 ASTSuffix::kPostDecr ement_Kind));
1246 default: {
1247 this->error(next.fPosition, "expected expression suffix, but found '" + next.fText +
1248 "'\n");
1249 return nullptr;
1250 }
1251 }
1252 }
1253
1254 /* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1255 std::unique_ptr<ASTExpression> Parser::term() {
1256 std::unique_ptr<ASTExpression> result;
1257 Token t = this->peek();
1258 switch (t.fKind) {
1259 case Token::IDENTIFIER: {
1260 std::string text;
1261 if (this->identifier(&text)) {
1262 result.reset(new ASTIdentifier(t.fPosition, text));
1263 }
1264 break;
1265 }
1266 case Token::INT_LITERAL: {
1267 int64_t i;
1268 if (this->intLiteral(&i)) {
1269 result.reset(new ASTIntLiteral(t.fPosition, i));
1270 }
1271 break;
1272 }
1273 case Token::FLOAT_LITERAL: {
1274 double f;
1275 if (this->floatLiteral(&f)) {
1276 result.reset(new ASTFloatLiteral(t.fPosition, f));
1277 }
1278 break;
1279 }
1280 case Token::TRUE_LITERAL: // fall through
1281 case Token::FALSE_LITERAL: {
1282 bool b;
1283 if (this->boolLiteral(&b)) {
1284 result.reset(new ASTBoolLiteral(t.fPosition, b));
1285 }
1286 break;
1287 }
1288 case Token::LPAREN: {
1289 this->nextToken();
1290 result = this->expression();
1291 if (result) {
1292 this->expect(Token::RPAREN, "')' to complete expression");
1293 }
1294 break;
1295 }
1296 default:
1297 this->nextToken();
1298 this->error(t.fPosition, "expected expression, but found '" + t.fTe xt + "'\n");
1299 result = nullptr;
1300 }
1301 return result;
1302 }
1303
1304 /* INT_LITERAL */
1305 bool Parser::intLiteral(int64_t* dest) {
1306 Token t;
1307 if (this->expect(Token::INT_LITERAL, "integer literal", &t)) {
1308 *dest = SkSL::stol(t.fText);
1309 return true;
1310 }
1311 return false;
1312 }
1313
1314 /* FLOAT_LITERAL */
1315 bool Parser::floatLiteral(double* dest) {
1316 Token t;
1317 if (this->expect(Token::FLOAT_LITERAL, "float literal", &t)) {
1318 *dest = SkSL::stod(t.fText);
1319 return true;
1320 }
1321 return false;
1322 }
1323
1324 /* TRUE_LITERAL | FALSE_LITERAL */
1325 bool Parser::boolLiteral(bool* dest) {
1326 Token t = this->nextToken();
1327 switch (t.fKind) {
1328 case Token::TRUE_LITERAL:
1329 *dest = true;
1330 return true;
1331 case Token::FALSE_LITERAL:
1332 *dest = false;
1333 return true;
1334 default:
1335 this->error(t.fPosition, "expected 'true' or 'false', but found '" + t.fText + "'\n");
1336 return false;
1337 }
1338 }
1339
1340 /* IDENTIFIER */
1341 bool Parser::identifier(std::string* dest) {
1342 Token t;
1343 if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
1344 *dest = t.fText;
1345 return true;
1346 }
1347 return false;
1348 }
1349
1350 } // namespace
OLDNEW
« src/gpu/vk/GrVkGpu.h ('K') | « src/sksl/SkSLParser.h ('k') | src/sksl/SkSLPosition.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698