OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/parser.h" | 5 #include "tools/gn/parser.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "tools/gn/functions.h" | 8 #include "tools/gn/functions.h" |
9 #include "tools/gn/operators.h" | 9 #include "tools/gn/operators.h" |
10 #include "tools/gn/token.h" | 10 #include "tools/gn/token.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 {&Parser::Group, NULL, -1}, // LEFT_PAREN | 67 {&Parser::Group, NULL, -1}, // LEFT_PAREN |
68 {NULL, NULL, -1}, // RIGHT_PAREN | 68 {NULL, NULL, -1}, // RIGHT_PAREN |
69 {&Parser::List, &Parser::Subscript, PRECEDENCE_CALL}, // LEFT_BRACKET | 69 {&Parser::List, &Parser::Subscript, PRECEDENCE_CALL}, // LEFT_BRACKET |
70 {NULL, NULL, -1}, // RIGHT_BRACKET | 70 {NULL, NULL, -1}, // RIGHT_BRACKET |
71 {NULL, NULL, -1}, // LEFT_BRACE | 71 {NULL, NULL, -1}, // LEFT_BRACE |
72 {NULL, NULL, -1}, // RIGHT_BRACE | 72 {NULL, NULL, -1}, // RIGHT_BRACE |
73 {NULL, NULL, -1}, // IF | 73 {NULL, NULL, -1}, // IF |
74 {NULL, NULL, -1}, // ELSE | 74 {NULL, NULL, -1}, // ELSE |
75 {&Parser::Name, &Parser::IdentifierOrCall, PRECEDENCE_CALL}, // IDENTIFIER | 75 {&Parser::Name, &Parser::IdentifierOrCall, PRECEDENCE_CALL}, // IDENTIFIER |
76 {NULL, NULL, -1}, // COMMA | 76 {NULL, NULL, -1}, // COMMA |
77 {NULL, NULL, -1}, // UNCLASSIFIED_COMMENT | 77 {NULL, NULL, -1}, // UNCLASSIFIED_COMMENT |
78 {NULL, NULL, -1}, // LINE_COMMENT | 78 {NULL, NULL, -1}, // LINE_COMMENT |
79 {NULL, NULL, -1}, // SUFFIX_COMMENT | 79 {NULL, NULL, -1}, // SUFFIX_COMMENT |
| 80 {&Parser::BlockComment, NULL, -1}, // BLOCK_COMMENT |
80 }; | 81 }; |
81 | 82 |
82 Parser::Parser(const std::vector<Token>& tokens, Err* err) | 83 Parser::Parser(const std::vector<Token>& tokens, Err* err) |
83 : err_(err), cur_(0) { | 84 : err_(err), cur_(0) { |
84 for (std::vector<Token>::const_iterator i(tokens.begin()); i != tokens.end(); | 85 for (std::vector<Token>::const_iterator i(tokens.begin()); i != tokens.end(); |
85 ++i) { | 86 ++i) { |
86 switch(i->type()) { | 87 switch(i->type()) { |
87 case Token::LINE_COMMENT: | 88 case Token::LINE_COMMENT: |
88 line_comment_tokens_.push_back(*i); | 89 line_comment_tokens_.push_back(*i); |
89 break; | 90 break; |
90 case Token::SUFFIX_COMMENT: | 91 case Token::SUFFIX_COMMENT: |
91 suffix_comment_tokens_.push_back(*i); | 92 suffix_comment_tokens_.push_back(*i); |
92 break; | 93 break; |
93 default: | 94 default: |
| 95 // Note that BLOCK_COMMENTs (top-level standalone comments) are passed |
| 96 // through the real parser. |
94 tokens_.push_back(*i); | 97 tokens_.push_back(*i); |
95 break; | 98 break; |
96 } | 99 } |
97 } | 100 } |
98 } | 101 } |
99 | 102 |
100 Parser::~Parser() { | 103 Parser::~Parser() { |
101 } | 104 } |
102 | 105 |
103 // static | 106 // static |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 } | 226 } |
224 | 227 |
225 scoped_ptr<ParseNode> Parser::Literal(Token token) { | 228 scoped_ptr<ParseNode> Parser::Literal(Token token) { |
226 return scoped_ptr<ParseNode>(new LiteralNode(token)).Pass(); | 229 return scoped_ptr<ParseNode>(new LiteralNode(token)).Pass(); |
227 } | 230 } |
228 | 231 |
229 scoped_ptr<ParseNode> Parser::Name(Token token) { | 232 scoped_ptr<ParseNode> Parser::Name(Token token) { |
230 return IdentifierOrCall(scoped_ptr<ParseNode>(), token).Pass(); | 233 return IdentifierOrCall(scoped_ptr<ParseNode>(), token).Pass(); |
231 } | 234 } |
232 | 235 |
| 236 scoped_ptr<ParseNode> Parser::BlockComment(Token token) { |
| 237 scoped_ptr<BlockCommentNode> comment(new BlockCommentNode()); |
| 238 comment->set_comment(token); |
| 239 return comment.PassAs<ParseNode>(); |
| 240 } |
| 241 |
233 scoped_ptr<ParseNode> Parser::Group(Token token) { | 242 scoped_ptr<ParseNode> Parser::Group(Token token) { |
234 scoped_ptr<ParseNode> expr = ParseExpression(); | 243 scoped_ptr<ParseNode> expr = ParseExpression(); |
235 if (has_error()) | 244 if (has_error()) |
236 return scoped_ptr<ParseNode>(); | 245 return scoped_ptr<ParseNode>(); |
237 Consume(Token::RIGHT_PAREN, "Expected ')'"); | 246 Consume(Token::RIGHT_PAREN, "Expected ')'"); |
238 return expr.Pass(); | 247 return expr.Pass(); |
239 } | 248 } |
240 | 249 |
241 scoped_ptr<ParseNode> Parser::Not(Token token) { | 250 scoped_ptr<ParseNode> Parser::Not(Token token) { |
242 scoped_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1); | 251 scoped_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1); |
243 if (has_error()) | 252 if (has_error()) |
244 return scoped_ptr<ParseNode>(); | 253 return scoped_ptr<ParseNode>(); |
245 scoped_ptr<UnaryOpNode> unary_op(new UnaryOpNode); | 254 scoped_ptr<UnaryOpNode> unary_op(new UnaryOpNode); |
246 unary_op->set_op(token); | 255 unary_op->set_op(token); |
247 unary_op->set_operand(expr.Pass()); | 256 unary_op->set_operand(expr.Pass()); |
248 return unary_op.PassAs<ParseNode>(); | 257 return unary_op.PassAs<ParseNode>(); |
249 } | 258 } |
250 | 259 |
251 scoped_ptr<ParseNode> Parser::List(Token node) { | 260 scoped_ptr<ParseNode> Parser::List(Token node) { |
252 scoped_ptr<ParseNode> list(ParseList(Token::RIGHT_BRACKET, true)); | 261 scoped_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET, true)); |
253 if (!has_error() && !at_end()) | 262 if (!has_error() && !at_end()) |
254 Consume(Token::RIGHT_BRACKET, "Expected ']'"); | 263 Consume(Token::RIGHT_BRACKET, "Expected ']'"); |
255 return list.Pass(); | 264 return list.Pass(); |
256 } | 265 } |
257 | 266 |
258 scoped_ptr<ParseNode> Parser::BinaryOperator(scoped_ptr<ParseNode> left, | 267 scoped_ptr<ParseNode> Parser::BinaryOperator(scoped_ptr<ParseNode> left, |
259 Token token) { | 268 Token token) { |
260 scoped_ptr<ParseNode> right = | 269 scoped_ptr<ParseNode> right = |
261 ParseExpression(expressions_[token.type()].precedence + 1); | 270 ParseExpression(expressions_[token.type()].precedence + 1); |
262 if (!right) { | 271 if (!right) { |
263 *err_ = | 272 *err_ = |
264 Err(token, | 273 Err(token, |
265 "Expected right hand side for '" + token.value().as_string() + "'"); | 274 "Expected right hand side for '" + token.value().as_string() + "'"); |
266 return scoped_ptr<ParseNode>(); | 275 return scoped_ptr<ParseNode>(); |
267 } | 276 } |
268 scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode); | 277 scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode); |
269 binary_op->set_op(token); | 278 binary_op->set_op(token); |
270 binary_op->set_left(left.Pass()); | 279 binary_op->set_left(left.Pass()); |
271 binary_op->set_right(right.Pass()); | 280 binary_op->set_right(right.Pass()); |
272 return binary_op.PassAs<ParseNode>(); | 281 return binary_op.PassAs<ParseNode>(); |
273 } | 282 } |
274 | 283 |
275 scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left, | 284 scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left, |
276 Token token) { | 285 Token token) { |
277 scoped_ptr<ListNode> list(new ListNode); | 286 scoped_ptr<ListNode> list(new ListNode); |
278 list->set_begin_token(token); | 287 list->set_begin_token(token); |
279 list->set_end_token(token); | 288 list->set_end_token(token); |
280 scoped_ptr<BlockNode> block; | 289 scoped_ptr<BlockNode> block; |
281 bool has_arg = false; | 290 bool has_arg = false; |
282 if (Match(Token::LEFT_PAREN)) { | 291 if (LookAhead(Token::LEFT_PAREN)) { |
| 292 Token start_token = Consume(); |
283 // Parsing a function call. | 293 // Parsing a function call. |
284 has_arg = true; | 294 has_arg = true; |
285 if (Match(Token::RIGHT_PAREN)) { | 295 if (Match(Token::RIGHT_PAREN)) { |
286 // Nothing, just an empty call. | 296 // Nothing, just an empty call. |
287 } else { | 297 } else { |
288 list = ParseList(Token::RIGHT_PAREN, false); | 298 list = ParseList(start_token, Token::RIGHT_PAREN, false); |
289 if (has_error()) | 299 if (has_error()) |
290 return scoped_ptr<ParseNode>(); | 300 return scoped_ptr<ParseNode>(); |
291 Consume(Token::RIGHT_PAREN, "Expected ')' after call"); | 301 Consume(Token::RIGHT_PAREN, "Expected ')' after call"); |
292 } | 302 } |
293 // Optionally with a scope. | 303 // Optionally with a scope. |
294 if (LookAhead(Token::LEFT_BRACE)) { | 304 if (LookAhead(Token::LEFT_BRACE)) { |
295 block = ParseBlock(); | 305 block = ParseBlock(); |
296 if (has_error()) | 306 if (has_error()) |
297 return scoped_ptr<ParseNode>(); | 307 return scoped_ptr<ParseNode>(); |
298 } | 308 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 } | 371 } |
362 | 372 |
363 scoped_ptr<AccessorNode> accessor(new AccessorNode); | 373 scoped_ptr<AccessorNode> accessor(new AccessorNode); |
364 accessor->set_base(left->AsIdentifier()->value()); | 374 accessor->set_base(left->AsIdentifier()->value()); |
365 accessor->set_member(scoped_ptr<IdentifierNode>( | 375 accessor->set_member(scoped_ptr<IdentifierNode>( |
366 static_cast<IdentifierNode*>(right.release()))); | 376 static_cast<IdentifierNode*>(right.release()))); |
367 return accessor.PassAs<ParseNode>(); | 377 return accessor.PassAs<ParseNode>(); |
368 } | 378 } |
369 | 379 |
370 // Does not Consume the start or end token. | 380 // Does not Consume the start or end token. |
371 scoped_ptr<ListNode> Parser::ParseList(Token::Type stop_before, | 381 scoped_ptr<ListNode> Parser::ParseList(Token start_token, |
| 382 Token::Type stop_before, |
372 bool allow_trailing_comma) { | 383 bool allow_trailing_comma) { |
373 scoped_ptr<ListNode> list(new ListNode); | 384 scoped_ptr<ListNode> list(new ListNode); |
374 list->set_begin_token(cur_token()); | 385 list->set_begin_token(start_token); |
375 bool just_got_comma = false; | 386 bool just_got_comma = false; |
376 bool first_time = true; | 387 bool first_time = true; |
377 while (!LookAhead(stop_before)) { | 388 while (!LookAhead(stop_before)) { |
378 if (!first_time) { | 389 if (!first_time) { |
379 if (!just_got_comma) { | 390 if (!just_got_comma) { |
380 // Require commas separate things in lists. | 391 // Require commas separate things in lists. |
381 *err_ = Err(cur_token(), "Expected comma between items."); | 392 *err_ = Err(cur_token(), "Expected comma between items."); |
382 return scoped_ptr<ListNode>(); | 393 return scoped_ptr<ListNode>(); |
383 } | 394 } |
384 } | 395 } |
385 first_time = false; | 396 first_time = false; |
386 | 397 |
387 // Why _OR? We're parsing things that are higher precedence than the , | 398 // Why _OR? We're parsing things that are higher precedence than the , |
388 // that separates the items of the list. , should appear lower than | 399 // that separates the items of the list. , should appear lower than |
389 // boolean expressions (the lowest of which is OR), but above assignments. | 400 // boolean expressions (the lowest of which is OR), but above assignments. |
390 list->append_item(ParseExpression(PRECEDENCE_OR)); | 401 list->append_item(ParseExpression(PRECEDENCE_OR)); |
391 if (has_error()) | 402 if (has_error()) |
392 return scoped_ptr<ListNode>(); | 403 return scoped_ptr<ListNode>(); |
393 if (at_end()) { | 404 if (at_end()) { |
394 *err_ = | 405 *err_ = |
395 Err(tokens_[tokens_.size() - 1], "Unexpected end of file in list."); | 406 Err(tokens_[tokens_.size() - 1], "Unexpected end of file in list."); |
396 return scoped_ptr<ListNode>(); | 407 return scoped_ptr<ListNode>(); |
397 } | 408 } |
398 just_got_comma = Match(Token::COMMA); | 409 if (list->contents().back()->AsBlockComment()) { |
| 410 // If there was a comment inside the list, we don't need a comma to the |
| 411 // next item, so pretend we got one, if we're expecting one. |
| 412 just_got_comma = allow_trailing_comma; |
| 413 } else { |
| 414 just_got_comma = Match(Token::COMMA); |
| 415 } |
399 } | 416 } |
400 if (just_got_comma && !allow_trailing_comma) { | 417 if (just_got_comma && !allow_trailing_comma) { |
401 *err_ = Err(cur_token(), "Trailing comma"); | 418 *err_ = Err(cur_token(), "Trailing comma"); |
402 return scoped_ptr<ListNode>(); | 419 return scoped_ptr<ListNode>(); |
403 } | 420 } |
404 list->set_end_token(cur_token()); | 421 list->set_end_token(cur_token()); |
405 return list.Pass(); | 422 return list.Pass(); |
406 } | 423 } |
407 | 424 |
408 scoped_ptr<ParseNode> Parser::ParseFile() { | 425 scoped_ptr<ParseNode> Parser::ParseFile() { |
(...skipping 18 matching lines...) Expand all Loading... |
427 AssignComments(file.get()); | 444 AssignComments(file.get()); |
428 | 445 |
429 return file.PassAs<ParseNode>(); | 446 return file.PassAs<ParseNode>(); |
430 } | 447 } |
431 | 448 |
432 scoped_ptr<ParseNode> Parser::ParseStatement() { | 449 scoped_ptr<ParseNode> Parser::ParseStatement() { |
433 if (LookAhead(Token::LEFT_BRACE)) { | 450 if (LookAhead(Token::LEFT_BRACE)) { |
434 return ParseBlock().PassAs<ParseNode>(); | 451 return ParseBlock().PassAs<ParseNode>(); |
435 } else if (LookAhead(Token::IF)) { | 452 } else if (LookAhead(Token::IF)) { |
436 return ParseCondition(); | 453 return ParseCondition(); |
| 454 } else if (LookAhead(Token::BLOCK_COMMENT)) { |
| 455 return BlockComment(Consume()); |
437 } else { | 456 } else { |
438 // TODO(scottmg): Is this too strict? Just drop all the testing if we want | 457 // TODO(scottmg): Is this too strict? Just drop all the testing if we want |
439 // to allow "pointless" expressions and return ParseExpression() directly. | 458 // to allow "pointless" expressions and return ParseExpression() directly. |
440 scoped_ptr<ParseNode> stmt = ParseExpression(); | 459 scoped_ptr<ParseNode> stmt = ParseExpression(); |
441 if (stmt) { | 460 if (stmt) { |
442 if (stmt->AsFunctionCall() || IsAssignment(stmt.get())) | 461 if (stmt->AsFunctionCall() || IsAssignment(stmt.get())) |
443 return stmt.Pass(); | 462 return stmt.Pass(); |
444 } | 463 } |
445 if (!has_error()) { | 464 if (!has_error()) { |
446 Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token(); | 465 Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token(); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 const std::vector<const ParseNode*>& contents = list->contents(); | 539 const std::vector<const ParseNode*>& contents = list->contents(); |
521 for (std::vector<const ParseNode*>::const_iterator i(contents.begin()); | 540 for (std::vector<const ParseNode*>::const_iterator i(contents.begin()); |
522 i != contents.end(); | 541 i != contents.end(); |
523 ++i) { | 542 ++i) { |
524 TraverseOrder(*i, pre, post); | 543 TraverseOrder(*i, pre, post); |
525 } | 544 } |
526 } else if (root->AsLiteral()) { | 545 } else if (root->AsLiteral()) { |
527 // Nothing. | 546 // Nothing. |
528 } else if (const UnaryOpNode* unaryop = root->AsUnaryOp()) { | 547 } else if (const UnaryOpNode* unaryop = root->AsUnaryOp()) { |
529 TraverseOrder(unaryop->operand(), pre, post); | 548 TraverseOrder(unaryop->operand(), pre, post); |
| 549 } else if (root->AsBlockComment()) { |
| 550 // Nothing. |
530 } else { | 551 } else { |
531 CHECK(false) << "Unhandled case in TraverseOrder."; | 552 CHECK(false) << "Unhandled case in TraverseOrder."; |
532 } | 553 } |
533 | 554 |
534 post->push_back(root); | 555 post->push_back(root); |
535 } | 556 } |
536 } | 557 } |
537 | 558 |
538 void Parser::AssignComments(ParseNode* file) { | 559 void Parser::AssignComments(ParseNode* file) { |
539 // Start by generating a pre- and post- order traversal of the tree so we | 560 // Start by generating a pre- and post- order traversal of the tree so we |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 } else { | 616 } else { |
596 break; | 617 break; |
597 } | 618 } |
598 } | 619 } |
599 | 620 |
600 // Suffix comments were assigned in reverse, so if there were multiple on | 621 // Suffix comments were assigned in reverse, so if there were multiple on |
601 // the same node, they need to be reversed. | 622 // the same node, they need to be reversed. |
602 const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix(); | 623 const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix(); |
603 } | 624 } |
604 } | 625 } |
OLD | NEW |