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