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

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

Powered by Google App Engine
This is Rietveld 408576698