| 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 <utility> |
| 8 |
| 7 #include "base/logging.h" | 9 #include "base/logging.h" |
| 8 #include "tools/gn/functions.h" | 10 #include "tools/gn/functions.h" |
| 9 #include "tools/gn/operators.h" | 11 #include "tools/gn/operators.h" |
| 10 #include "tools/gn/token.h" | 12 #include "tools/gn/token.h" |
| 11 | 13 |
| 12 const char kGrammar_Help[] = | 14 const char kGrammar_Help[] = |
| 13 "GN build language grammar\n" | 15 "GN build language grammar\n" |
| 14 "\n" | 16 "\n" |
| 15 "Tokens\n" | 17 "Tokens\n" |
| 16 "\n" | 18 "\n" |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 | 210 |
| 209 // static | 211 // static |
| 210 scoped_ptr<ParseNode> Parser::ParseExpression(const std::vector<Token>& tokens, | 212 scoped_ptr<ParseNode> Parser::ParseExpression(const std::vector<Token>& tokens, |
| 211 Err* err) { | 213 Err* err) { |
| 212 Parser p(tokens, err); | 214 Parser p(tokens, err); |
| 213 scoped_ptr<ParseNode> expr = p.ParseExpression(); | 215 scoped_ptr<ParseNode> expr = p.ParseExpression(); |
| 214 if (!p.at_end() && !err->has_error()) { | 216 if (!p.at_end() && !err->has_error()) { |
| 215 *err = Err(p.cur_token(), "Trailing garbage"); | 217 *err = Err(p.cur_token(), "Trailing garbage"); |
| 216 return nullptr; | 218 return nullptr; |
| 217 } | 219 } |
| 218 return expr.Pass(); | 220 return expr; |
| 219 } | 221 } |
| 220 | 222 |
| 221 // static | 223 // static |
| 222 scoped_ptr<ParseNode> Parser::ParseValue(const std::vector<Token>& tokens, | 224 scoped_ptr<ParseNode> Parser::ParseValue(const std::vector<Token>& tokens, |
| 223 Err* err) { | 225 Err* err) { |
| 224 for (const Token& token : tokens) { | 226 for (const Token& token : tokens) { |
| 225 switch (token.type()) { | 227 switch (token.type()) { |
| 226 case Token::INTEGER: | 228 case Token::INTEGER: |
| 227 case Token::STRING: | 229 case Token::STRING: |
| 228 case Token::TRUE_TOKEN: | 230 case Token::TRUE_TOKEN: |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 | 323 |
| 322 if (prefix == nullptr) { | 324 if (prefix == nullptr) { |
| 323 *err_ = Err(token, | 325 *err_ = Err(token, |
| 324 std::string("Unexpected token '") + token.value().as_string() + | 326 std::string("Unexpected token '") + token.value().as_string() + |
| 325 std::string("'")); | 327 std::string("'")); |
| 326 return scoped_ptr<ParseNode>(); | 328 return scoped_ptr<ParseNode>(); |
| 327 } | 329 } |
| 328 | 330 |
| 329 scoped_ptr<ParseNode> left = (this->*prefix)(token); | 331 scoped_ptr<ParseNode> left = (this->*prefix)(token); |
| 330 if (has_error()) | 332 if (has_error()) |
| 331 return left.Pass(); | 333 return left; |
| 332 | 334 |
| 333 while (!at_end() && !IsStatementBreak(cur_token().type()) && | 335 while (!at_end() && !IsStatementBreak(cur_token().type()) && |
| 334 precedence <= expressions_[cur_token().type()].precedence) { | 336 precedence <= expressions_[cur_token().type()].precedence) { |
| 335 token = Consume(); | 337 token = Consume(); |
| 336 InfixFunc infix = expressions_[token.type()].infix; | 338 InfixFunc infix = expressions_[token.type()].infix; |
| 337 if (infix == nullptr) { | 339 if (infix == nullptr) { |
| 338 *err_ = Err(token, | 340 *err_ = Err(token, |
| 339 std::string("Unexpected token '") + | 341 std::string("Unexpected token '") + |
| 340 token.value().as_string() + std::string("'")); | 342 token.value().as_string() + std::string("'")); |
| 341 return scoped_ptr<ParseNode>(); | 343 return scoped_ptr<ParseNode>(); |
| 342 } | 344 } |
| 343 left = (this->*infix)(left.Pass(), token); | 345 left = (this->*infix)(std::move(left), token); |
| 344 if (has_error()) | 346 if (has_error()) |
| 345 return scoped_ptr<ParseNode>(); | 347 return scoped_ptr<ParseNode>(); |
| 346 } | 348 } |
| 347 | 349 |
| 348 return left.Pass(); | 350 return left; |
| 349 } | 351 } |
| 350 | 352 |
| 351 scoped_ptr<ParseNode> Parser::Literal(Token token) { | 353 scoped_ptr<ParseNode> Parser::Literal(Token token) { |
| 352 return make_scoped_ptr(new LiteralNode(token)); | 354 return make_scoped_ptr(new LiteralNode(token)); |
| 353 } | 355 } |
| 354 | 356 |
| 355 scoped_ptr<ParseNode> Parser::Name(Token token) { | 357 scoped_ptr<ParseNode> Parser::Name(Token token) { |
| 356 return IdentifierOrCall(scoped_ptr<ParseNode>(), token).Pass(); | 358 return IdentifierOrCall(scoped_ptr<ParseNode>(), token); |
| 357 } | 359 } |
| 358 | 360 |
| 359 scoped_ptr<ParseNode> Parser::BlockComment(Token token) { | 361 scoped_ptr<ParseNode> Parser::BlockComment(Token token) { |
| 360 scoped_ptr<BlockCommentNode> comment(new BlockCommentNode()); | 362 scoped_ptr<BlockCommentNode> comment(new BlockCommentNode()); |
| 361 comment->set_comment(token); | 363 comment->set_comment(token); |
| 362 return comment.Pass(); | 364 return std::move(comment); |
| 363 } | 365 } |
| 364 | 366 |
| 365 scoped_ptr<ParseNode> Parser::Group(Token token) { | 367 scoped_ptr<ParseNode> Parser::Group(Token token) { |
| 366 scoped_ptr<ParseNode> expr = ParseExpression(); | 368 scoped_ptr<ParseNode> expr = ParseExpression(); |
| 367 if (has_error()) | 369 if (has_error()) |
| 368 return scoped_ptr<ParseNode>(); | 370 return scoped_ptr<ParseNode>(); |
| 369 Consume(Token::RIGHT_PAREN, "Expected ')'"); | 371 Consume(Token::RIGHT_PAREN, "Expected ')'"); |
| 370 return expr.Pass(); | 372 return expr; |
| 371 } | 373 } |
| 372 | 374 |
| 373 scoped_ptr<ParseNode> Parser::Not(Token token) { | 375 scoped_ptr<ParseNode> Parser::Not(Token token) { |
| 374 scoped_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1); | 376 scoped_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1); |
| 375 if (has_error()) | 377 if (has_error()) |
| 376 return scoped_ptr<ParseNode>(); | 378 return scoped_ptr<ParseNode>(); |
| 377 if (!expr) { | 379 if (!expr) { |
| 378 if (!has_error()) | 380 if (!has_error()) |
| 379 *err_ = Err(token, "Expected right-hand side for '!'."); | 381 *err_ = Err(token, "Expected right-hand side for '!'."); |
| 380 return scoped_ptr<ParseNode>(); | 382 return scoped_ptr<ParseNode>(); |
| 381 } | 383 } |
| 382 scoped_ptr<UnaryOpNode> unary_op(new UnaryOpNode); | 384 scoped_ptr<UnaryOpNode> unary_op(new UnaryOpNode); |
| 383 unary_op->set_op(token); | 385 unary_op->set_op(token); |
| 384 unary_op->set_operand(expr.Pass()); | 386 unary_op->set_operand(std::move(expr)); |
| 385 return unary_op.Pass(); | 387 return std::move(unary_op); |
| 386 } | 388 } |
| 387 | 389 |
| 388 scoped_ptr<ParseNode> Parser::List(Token node) { | 390 scoped_ptr<ParseNode> Parser::List(Token node) { |
| 389 scoped_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET, true)); | 391 scoped_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET, true)); |
| 390 if (!has_error() && !at_end()) | 392 if (!has_error() && !at_end()) |
| 391 Consume(Token::RIGHT_BRACKET, "Expected ']'"); | 393 Consume(Token::RIGHT_BRACKET, "Expected ']'"); |
| 392 return list.Pass(); | 394 return list; |
| 393 } | 395 } |
| 394 | 396 |
| 395 scoped_ptr<ParseNode> Parser::BinaryOperator(scoped_ptr<ParseNode> left, | 397 scoped_ptr<ParseNode> Parser::BinaryOperator(scoped_ptr<ParseNode> left, |
| 396 Token token) { | 398 Token token) { |
| 397 scoped_ptr<ParseNode> right = | 399 scoped_ptr<ParseNode> right = |
| 398 ParseExpression(expressions_[token.type()].precedence + 1); | 400 ParseExpression(expressions_[token.type()].precedence + 1); |
| 399 if (!right) { | 401 if (!right) { |
| 400 if (!has_error()) { | 402 if (!has_error()) { |
| 401 *err_ = Err(token, "Expected right-hand side for '" + | 403 *err_ = Err(token, "Expected right-hand side for '" + |
| 402 token.value().as_string() + "'"); | 404 token.value().as_string() + "'"); |
| 403 } | 405 } |
| 404 return scoped_ptr<ParseNode>(); | 406 return scoped_ptr<ParseNode>(); |
| 405 } | 407 } |
| 406 scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode); | 408 scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode); |
| 407 binary_op->set_op(token); | 409 binary_op->set_op(token); |
| 408 binary_op->set_left(left.Pass()); | 410 binary_op->set_left(std::move(left)); |
| 409 binary_op->set_right(right.Pass()); | 411 binary_op->set_right(std::move(right)); |
| 410 return binary_op.Pass(); | 412 return std::move(binary_op); |
| 411 } | 413 } |
| 412 | 414 |
| 413 scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left, | 415 scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left, |
| 414 Token token) { | 416 Token token) { |
| 415 scoped_ptr<ListNode> list(new ListNode); | 417 scoped_ptr<ListNode> list(new ListNode); |
| 416 list->set_begin_token(token); | 418 list->set_begin_token(token); |
| 417 list->set_end(make_scoped_ptr(new EndNode(token))); | 419 list->set_end(make_scoped_ptr(new EndNode(token))); |
| 418 scoped_ptr<BlockNode> block; | 420 scoped_ptr<BlockNode> block; |
| 419 bool has_arg = false; | 421 bool has_arg = false; |
| 420 if (LookAhead(Token::LEFT_PAREN)) { | 422 if (LookAhead(Token::LEFT_PAREN)) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 432 // Optionally with a scope. | 434 // Optionally with a scope. |
| 433 if (LookAhead(Token::LEFT_BRACE)) { | 435 if (LookAhead(Token::LEFT_BRACE)) { |
| 434 block = ParseBlock(); | 436 block = ParseBlock(); |
| 435 if (has_error()) | 437 if (has_error()) |
| 436 return scoped_ptr<ParseNode>(); | 438 return scoped_ptr<ParseNode>(); |
| 437 } | 439 } |
| 438 } | 440 } |
| 439 | 441 |
| 440 if (!left && !has_arg) { | 442 if (!left && !has_arg) { |
| 441 // Not a function call, just a standalone identifier. | 443 // Not a function call, just a standalone identifier. |
| 442 return scoped_ptr<ParseNode>(new IdentifierNode(token)).Pass(); | 444 return scoped_ptr<ParseNode>(new IdentifierNode(token)); |
| 443 } | 445 } |
| 444 scoped_ptr<FunctionCallNode> func_call(new FunctionCallNode); | 446 scoped_ptr<FunctionCallNode> func_call(new FunctionCallNode); |
| 445 func_call->set_function(token); | 447 func_call->set_function(token); |
| 446 func_call->set_args(list.Pass()); | 448 func_call->set_args(std::move(list)); |
| 447 if (block) | 449 if (block) |
| 448 func_call->set_block(block.Pass()); | 450 func_call->set_block(std::move(block)); |
| 449 return func_call.Pass(); | 451 return std::move(func_call); |
| 450 } | 452 } |
| 451 | 453 |
| 452 scoped_ptr<ParseNode> Parser::Assignment(scoped_ptr<ParseNode> left, | 454 scoped_ptr<ParseNode> Parser::Assignment(scoped_ptr<ParseNode> left, |
| 453 Token token) { | 455 Token token) { |
| 454 if (left->AsIdentifier() == nullptr) { | 456 if (left->AsIdentifier() == nullptr) { |
| 455 *err_ = Err(left.get(), "Left-hand side of assignment must be identifier."); | 457 *err_ = Err(left.get(), "Left-hand side of assignment must be identifier."); |
| 456 return scoped_ptr<ParseNode>(); | 458 return scoped_ptr<ParseNode>(); |
| 457 } | 459 } |
| 458 scoped_ptr<ParseNode> value = ParseExpression(PRECEDENCE_ASSIGNMENT); | 460 scoped_ptr<ParseNode> value = ParseExpression(PRECEDENCE_ASSIGNMENT); |
| 459 if (!value) { | 461 if (!value) { |
| 460 if (!has_error()) | 462 if (!has_error()) |
| 461 *err_ = Err(token, "Expected right-hand side for assignment."); | 463 *err_ = Err(token, "Expected right-hand side for assignment."); |
| 462 return scoped_ptr<ParseNode>(); | 464 return scoped_ptr<ParseNode>(); |
| 463 } | 465 } |
| 464 scoped_ptr<BinaryOpNode> assign(new BinaryOpNode); | 466 scoped_ptr<BinaryOpNode> assign(new BinaryOpNode); |
| 465 assign->set_op(token); | 467 assign->set_op(token); |
| 466 assign->set_left(left.Pass()); | 468 assign->set_left(std::move(left)); |
| 467 assign->set_right(value.Pass()); | 469 assign->set_right(std::move(value)); |
| 468 return assign.Pass(); | 470 return std::move(assign); |
| 469 } | 471 } |
| 470 | 472 |
| 471 scoped_ptr<ParseNode> Parser::Subscript(scoped_ptr<ParseNode> left, | 473 scoped_ptr<ParseNode> Parser::Subscript(scoped_ptr<ParseNode> left, |
| 472 Token token) { | 474 Token token) { |
| 473 // TODO: Maybe support more complex expressions like a[0][0]. This would | 475 // TODO: Maybe support more complex expressions like a[0][0]. This would |
| 474 // require work on the evaluator too. | 476 // require work on the evaluator too. |
| 475 if (left->AsIdentifier() == nullptr) { | 477 if (left->AsIdentifier() == nullptr) { |
| 476 *err_ = Err(left.get(), "May only subscript identifiers.", | 478 *err_ = Err(left.get(), "May only subscript identifiers.", |
| 477 "The thing on the left hand side of the [] must be an identifier\n" | 479 "The thing on the left hand side of the [] must be an identifier\n" |
| 478 "and not an expression. If you need this, you'll have to assign the\n" | 480 "and not an expression. If you need this, you'll have to assign the\n" |
| 479 "value to a temporary before subscripting. Sorry."); | 481 "value to a temporary before subscripting. Sorry."); |
| 480 return scoped_ptr<ParseNode>(); | 482 return scoped_ptr<ParseNode>(); |
| 481 } | 483 } |
| 482 scoped_ptr<ParseNode> value = ParseExpression(); | 484 scoped_ptr<ParseNode> value = ParseExpression(); |
| 483 Consume(Token::RIGHT_BRACKET, "Expecting ']' after subscript."); | 485 Consume(Token::RIGHT_BRACKET, "Expecting ']' after subscript."); |
| 484 scoped_ptr<AccessorNode> accessor(new AccessorNode); | 486 scoped_ptr<AccessorNode> accessor(new AccessorNode); |
| 485 accessor->set_base(left->AsIdentifier()->value()); | 487 accessor->set_base(left->AsIdentifier()->value()); |
| 486 accessor->set_index(value.Pass()); | 488 accessor->set_index(std::move(value)); |
| 487 return accessor.Pass(); | 489 return std::move(accessor); |
| 488 } | 490 } |
| 489 | 491 |
| 490 scoped_ptr<ParseNode> Parser::DotOperator(scoped_ptr<ParseNode> left, | 492 scoped_ptr<ParseNode> Parser::DotOperator(scoped_ptr<ParseNode> left, |
| 491 Token token) { | 493 Token token) { |
| 492 if (left->AsIdentifier() == nullptr) { | 494 if (left->AsIdentifier() == nullptr) { |
| 493 *err_ = Err(left.get(), "May only use \".\" for identifiers.", | 495 *err_ = Err(left.get(), "May only use \".\" for identifiers.", |
| 494 "The thing on the left hand side of the dot must be an identifier\n" | 496 "The thing on the left hand side of the dot must be an identifier\n" |
| 495 "and not an expression. If you need this, you'll have to assign the\n" | 497 "and not an expression. If you need this, you'll have to assign the\n" |
| 496 "value to a temporary first. Sorry."); | 498 "value to a temporary first. Sorry."); |
| 497 return scoped_ptr<ParseNode>(); | 499 return scoped_ptr<ParseNode>(); |
| 498 } | 500 } |
| 499 | 501 |
| 500 scoped_ptr<ParseNode> right = ParseExpression(PRECEDENCE_DOT); | 502 scoped_ptr<ParseNode> right = ParseExpression(PRECEDENCE_DOT); |
| 501 if (!right || !right->AsIdentifier()) { | 503 if (!right || !right->AsIdentifier()) { |
| 502 *err_ = Err(token, "Expected identifier for right-hand-side of \".\"", | 504 *err_ = Err(token, "Expected identifier for right-hand-side of \".\"", |
| 503 "Good: a.cookies\nBad: a.42\nLooks good but still bad: a.cookies()"); | 505 "Good: a.cookies\nBad: a.42\nLooks good but still bad: a.cookies()"); |
| 504 return scoped_ptr<ParseNode>(); | 506 return scoped_ptr<ParseNode>(); |
| 505 } | 507 } |
| 506 | 508 |
| 507 scoped_ptr<AccessorNode> accessor(new AccessorNode); | 509 scoped_ptr<AccessorNode> accessor(new AccessorNode); |
| 508 accessor->set_base(left->AsIdentifier()->value()); | 510 accessor->set_base(left->AsIdentifier()->value()); |
| 509 accessor->set_member(scoped_ptr<IdentifierNode>( | 511 accessor->set_member(scoped_ptr<IdentifierNode>( |
| 510 static_cast<IdentifierNode*>(right.release()))); | 512 static_cast<IdentifierNode*>(right.release()))); |
| 511 return accessor.Pass(); | 513 return std::move(accessor); |
| 512 } | 514 } |
| 513 | 515 |
| 514 // Does not Consume the start or end token. | 516 // Does not Consume the start or end token. |
| 515 scoped_ptr<ListNode> Parser::ParseList(Token start_token, | 517 scoped_ptr<ListNode> Parser::ParseList(Token start_token, |
| 516 Token::Type stop_before, | 518 Token::Type stop_before, |
| 517 bool allow_trailing_comma) { | 519 bool allow_trailing_comma) { |
| 518 scoped_ptr<ListNode> list(new ListNode); | 520 scoped_ptr<ListNode> list(new ListNode); |
| 519 list->set_begin_token(start_token); | 521 list->set_begin_token(start_token); |
| 520 bool just_got_comma = false; | 522 bool just_got_comma = false; |
| 521 bool first_time = true; | 523 bool first_time = true; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 546 just_got_comma = allow_trailing_comma; | 548 just_got_comma = allow_trailing_comma; |
| 547 } else { | 549 } else { |
| 548 just_got_comma = Match(Token::COMMA); | 550 just_got_comma = Match(Token::COMMA); |
| 549 } | 551 } |
| 550 } | 552 } |
| 551 if (just_got_comma && !allow_trailing_comma) { | 553 if (just_got_comma && !allow_trailing_comma) { |
| 552 *err_ = Err(cur_token(), "Trailing comma"); | 554 *err_ = Err(cur_token(), "Trailing comma"); |
| 553 return scoped_ptr<ListNode>(); | 555 return scoped_ptr<ListNode>(); |
| 554 } | 556 } |
| 555 list->set_end(make_scoped_ptr(new EndNode(cur_token()))); | 557 list->set_end(make_scoped_ptr(new EndNode(cur_token()))); |
| 556 return list.Pass(); | 558 return list; |
| 557 } | 559 } |
| 558 | 560 |
| 559 scoped_ptr<ParseNode> Parser::ParseFile() { | 561 scoped_ptr<ParseNode> Parser::ParseFile() { |
| 560 scoped_ptr<BlockNode> file(new BlockNode); | 562 scoped_ptr<BlockNode> file(new BlockNode); |
| 561 for (;;) { | 563 for (;;) { |
| 562 if (at_end()) | 564 if (at_end()) |
| 563 break; | 565 break; |
| 564 scoped_ptr<ParseNode> statement = ParseStatement(); | 566 scoped_ptr<ParseNode> statement = ParseStatement(); |
| 565 if (!statement) | 567 if (!statement) |
| 566 break; | 568 break; |
| 567 file->append_statement(statement.Pass()); | 569 file->append_statement(std::move(statement)); |
| 568 } | 570 } |
| 569 if (!at_end() && !has_error()) | 571 if (!at_end() && !has_error()) |
| 570 *err_ = Err(cur_token(), "Unexpected here, should be newline."); | 572 *err_ = Err(cur_token(), "Unexpected here, should be newline."); |
| 571 if (has_error()) | 573 if (has_error()) |
| 572 return scoped_ptr<ParseNode>(); | 574 return scoped_ptr<ParseNode>(); |
| 573 | 575 |
| 574 // TODO(scottmg): If this is measurably expensive, it could be done only | 576 // TODO(scottmg): If this is measurably expensive, it could be done only |
| 575 // when necessary (when reformatting, or during tests). Comments are | 577 // when necessary (when reformatting, or during tests). Comments are |
| 576 // separate from the parse tree at this point, so downstream code can remain | 578 // separate from the parse tree at this point, so downstream code can remain |
| 577 // ignorant of them. | 579 // ignorant of them. |
| 578 AssignComments(file.get()); | 580 AssignComments(file.get()); |
| 579 | 581 |
| 580 return file.Pass(); | 582 return std::move(file); |
| 581 } | 583 } |
| 582 | 584 |
| 583 scoped_ptr<ParseNode> Parser::ParseStatement() { | 585 scoped_ptr<ParseNode> Parser::ParseStatement() { |
| 584 if (LookAhead(Token::IF)) { | 586 if (LookAhead(Token::IF)) { |
| 585 return ParseCondition(); | 587 return ParseCondition(); |
| 586 } else if (LookAhead(Token::BLOCK_COMMENT)) { | 588 } else if (LookAhead(Token::BLOCK_COMMENT)) { |
| 587 return BlockComment(Consume()); | 589 return BlockComment(Consume()); |
| 588 } else { | 590 } else { |
| 589 // TODO(scottmg): Is this too strict? Just drop all the testing if we want | 591 // TODO(scottmg): Is this too strict? Just drop all the testing if we want |
| 590 // to allow "pointless" expressions and return ParseExpression() directly. | 592 // to allow "pointless" expressions and return ParseExpression() directly. |
| 591 scoped_ptr<ParseNode> stmt = ParseExpression(); | 593 scoped_ptr<ParseNode> stmt = ParseExpression(); |
| 592 if (stmt) { | 594 if (stmt) { |
| 593 if (stmt->AsFunctionCall() || IsAssignment(stmt.get())) | 595 if (stmt->AsFunctionCall() || IsAssignment(stmt.get())) |
| 594 return stmt.Pass(); | 596 return stmt; |
| 595 } | 597 } |
| 596 if (!has_error()) { | 598 if (!has_error()) { |
| 597 Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token(); | 599 Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token(); |
| 598 *err_ = Err(token, "Expecting assignment or function call."); | 600 *err_ = Err(token, "Expecting assignment or function call."); |
| 599 } | 601 } |
| 600 return scoped_ptr<ParseNode>(); | 602 return scoped_ptr<ParseNode>(); |
| 601 } | 603 } |
| 602 } | 604 } |
| 603 | 605 |
| 604 scoped_ptr<BlockNode> Parser::ParseBlock() { | 606 scoped_ptr<BlockNode> Parser::ParseBlock() { |
| 605 Token begin_token = | 607 Token begin_token = |
| 606 Consume(Token::LEFT_BRACE, "Expected '{' to start a block."); | 608 Consume(Token::LEFT_BRACE, "Expected '{' to start a block."); |
| 607 if (has_error()) | 609 if (has_error()) |
| 608 return scoped_ptr<BlockNode>(); | 610 return scoped_ptr<BlockNode>(); |
| 609 scoped_ptr<BlockNode> block(new BlockNode); | 611 scoped_ptr<BlockNode> block(new BlockNode); |
| 610 block->set_begin_token(begin_token); | 612 block->set_begin_token(begin_token); |
| 611 | 613 |
| 612 for (;;) { | 614 for (;;) { |
| 613 if (LookAhead(Token::RIGHT_BRACE)) { | 615 if (LookAhead(Token::RIGHT_BRACE)) { |
| 614 block->set_end(make_scoped_ptr(new EndNode(Consume()))); | 616 block->set_end(make_scoped_ptr(new EndNode(Consume()))); |
| 615 break; | 617 break; |
| 616 } | 618 } |
| 617 | 619 |
| 618 scoped_ptr<ParseNode> statement = ParseStatement(); | 620 scoped_ptr<ParseNode> statement = ParseStatement(); |
| 619 if (!statement) | 621 if (!statement) |
| 620 return scoped_ptr<BlockNode>(); | 622 return scoped_ptr<BlockNode>(); |
| 621 block->append_statement(statement.Pass()); | 623 block->append_statement(std::move(statement)); |
| 622 } | 624 } |
| 623 return block.Pass(); | 625 return block; |
| 624 } | 626 } |
| 625 | 627 |
| 626 scoped_ptr<ParseNode> Parser::ParseCondition() { | 628 scoped_ptr<ParseNode> Parser::ParseCondition() { |
| 627 scoped_ptr<ConditionNode> condition(new ConditionNode); | 629 scoped_ptr<ConditionNode> condition(new ConditionNode); |
| 628 condition->set_if_token(Consume(Token::IF, "Expected 'if'")); | 630 condition->set_if_token(Consume(Token::IF, "Expected 'if'")); |
| 629 Consume(Token::LEFT_PAREN, "Expected '(' after 'if'."); | 631 Consume(Token::LEFT_PAREN, "Expected '(' after 'if'."); |
| 630 condition->set_condition(ParseExpression()); | 632 condition->set_condition(ParseExpression()); |
| 631 if (IsAssignment(condition->condition())) | 633 if (IsAssignment(condition->condition())) |
| 632 *err_ = Err(condition->condition(), "Assignment not allowed in 'if'."); | 634 *err_ = Err(condition->condition(), "Assignment not allowed in 'if'."); |
| 633 Consume(Token::RIGHT_PAREN, "Expected ')' after condition of 'if'."); | 635 Consume(Token::RIGHT_PAREN, "Expected ')' after condition of 'if'."); |
| 634 condition->set_if_true(ParseBlock().Pass()); | 636 condition->set_if_true(ParseBlock()); |
| 635 if (Match(Token::ELSE)) { | 637 if (Match(Token::ELSE)) { |
| 636 if (LookAhead(Token::LEFT_BRACE)) { | 638 if (LookAhead(Token::LEFT_BRACE)) { |
| 637 condition->set_if_false(ParseBlock().Pass()); | 639 condition->set_if_false(ParseBlock()); |
| 638 } else if (LookAhead(Token::IF)) { | 640 } else if (LookAhead(Token::IF)) { |
| 639 condition->set_if_false(ParseStatement().Pass()); | 641 condition->set_if_false(ParseStatement()); |
| 640 } else { | 642 } else { |
| 641 *err_ = Err(cur_token(), "Expected '{' or 'if' after 'else'."); | 643 *err_ = Err(cur_token(), "Expected '{' or 'if' after 'else'."); |
| 642 return scoped_ptr<ParseNode>(); | 644 return scoped_ptr<ParseNode>(); |
| 643 } | 645 } |
| 644 } | 646 } |
| 645 if (has_error()) | 647 if (has_error()) |
| 646 return scoped_ptr<ParseNode>(); | 648 return scoped_ptr<ParseNode>(); |
| 647 return condition.Pass(); | 649 return std::move(condition); |
| 648 } | 650 } |
| 649 | 651 |
| 650 void Parser::TraverseOrder(const ParseNode* root, | 652 void Parser::TraverseOrder(const ParseNode* root, |
| 651 std::vector<const ParseNode*>* pre, | 653 std::vector<const ParseNode*>* pre, |
| 652 std::vector<const ParseNode*>* post) { | 654 std::vector<const ParseNode*>* post) { |
| 653 if (root) { | 655 if (root) { |
| 654 pre->push_back(root); | 656 pre->push_back(root); |
| 655 | 657 |
| 656 if (const AccessorNode* accessor = root->AsAccessor()) { | 658 if (const AccessorNode* accessor = root->AsAccessor()) { |
| 657 TraverseOrder(accessor->index(), pre, post); | 659 TraverseOrder(accessor->index(), pre, post); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 break; | 753 break; |
| 752 } | 754 } |
| 753 } | 755 } |
| 754 | 756 |
| 755 // Suffix comments were assigned in reverse, so if there were multiple on | 757 // Suffix comments were assigned in reverse, so if there were multiple on |
| 756 // the same node, they need to be reversed. | 758 // the same node, they need to be reversed. |
| 757 if ((*i)->comments() && !(*i)->comments()->suffix().empty()) | 759 if ((*i)->comments() && !(*i)->comments()->suffix().empty()) |
| 758 const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix(); | 760 const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix(); |
| 759 } | 761 } |
| 760 } | 762 } |
| OLD | NEW |