Home | History | Annotate | Download | only in gn
      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
      3 // found in the LICENSE file.
      4 
      5 #include "tools/gn/parser.h"
      6 
      7 #include "base/logging.h"
      8 #include "tools/gn/functions.h"
      9 #include "tools/gn/operators.h"
     10 #include "tools/gn/token.h"
     11 
     12 // grammar:
     13 //
     14 // file       := (statement)*
     15 // statement  := block | if | assignment
     16 // block      := '{' statement* '}'
     17 // if         := 'if' '(' expr ')' statement [ else ]
     18 // else       := 'else' (if | statement)*
     19 // assignment := ident {'=' | '+=' | '-='} expr
     20 
     21 enum Precedence {
     22   PRECEDENCE_ASSIGNMENT = 1,  // Lowest precedence.
     23   PRECEDENCE_OR = 2,
     24   PRECEDENCE_AND = 3,
     25   PRECEDENCE_EQUALITY = 4,
     26   PRECEDENCE_RELATION = 5,
     27   PRECEDENCE_SUM = 6,
     28   PRECEDENCE_PREFIX = 7,
     29   PRECEDENCE_CALL = 8,
     30   PRECEDENCE_DOT = 9,         // Highest precedence.
     31 };
     32 
     33 // The top-level for blocks/ifs is recursive descent, the expression parser is
     34 // a Pratt parser. The basic idea there is to have the precedences (and
     35 // associativities) encoded relative to each other and only parse up until you
     36 // hit something of that precedence. There's a dispatch table in expressions_
     37 // at the top of parser.cc that describes how each token dispatches if it's
     38 // seen as either a prefix or infix operator, and if it's infix, what its
     39 // precedence is.
     40 //
     41 // Refs:
     42 // - http://javascript.crockford.com/tdop/tdop.html
     43 // - http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
     44 
     45 // Indexed by Token::Type.
     46 ParserHelper Parser::expressions_[] = {
     47   {NULL, NULL, -1},                                             // INVALID
     48   {&Parser::Literal, NULL, -1},                                 // INTEGER
     49   {&Parser::Literal, NULL, -1},                                 // STRING
     50   {&Parser::Literal, NULL, -1},                                 // TRUE_TOKEN
     51   {&Parser::Literal, NULL, -1},                                 // FALSE_TOKEN
     52   {NULL, &Parser::Assignment, PRECEDENCE_ASSIGNMENT},           // EQUAL
     53   {NULL, &Parser::BinaryOperator, PRECEDENCE_SUM},              // PLUS
     54   {NULL, &Parser::BinaryOperator, PRECEDENCE_SUM},              // MINUS
     55   {NULL, &Parser::Assignment, PRECEDENCE_ASSIGNMENT},           // PLUS_EQUALS
     56   {NULL, &Parser::Assignment, PRECEDENCE_ASSIGNMENT},           // MINUS_EQUALS
     57   {NULL, &Parser::BinaryOperator, PRECEDENCE_EQUALITY},         // EQUAL_EQUAL
     58   {NULL, &Parser::BinaryOperator, PRECEDENCE_EQUALITY},         // NOT_EQUAL
     59   {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // LESS_EQUAL
     60   {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // GREATER_EQUAL
     61   {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // LESS_THAN
     62   {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // GREATER_THAN
     63   {NULL, &Parser::BinaryOperator, PRECEDENCE_AND},              // BOOLEAN_AND
     64   {NULL, &Parser::BinaryOperator, PRECEDENCE_OR},               // BOOLEAN_OR
     65   {&Parser::Not, NULL, -1},                                     // BANG
     66   {NULL, &Parser::DotOperator, PRECEDENCE_DOT},                 // DOT
     67   {&Parser::Group, NULL, -1},                                   // LEFT_PAREN
     68   {NULL, NULL, -1},                                             // RIGHT_PAREN
     69   {&Parser::List, &Parser::Subscript, PRECEDENCE_CALL},         // LEFT_BRACKET
     70   {NULL, NULL, -1},                                             // RIGHT_BRACKET
     71   {NULL, NULL, -1},                                             // LEFT_BRACE
     72   {NULL, NULL, -1},                                             // RIGHT_BRACE
     73   {NULL, NULL, -1},                                             // IF
     74   {NULL, NULL, -1},                                             // ELSE
     75   {&Parser::Name, &Parser::IdentifierOrCall, PRECEDENCE_CALL},  // IDENTIFIER
     76   {NULL, NULL, -1},                                             // COMMA
     77   {NULL, NULL, -1},                   // UNCLASSIFIED_COMMENT
     78   {NULL, NULL, -1},                   // LINE_COMMENT
     79   {NULL, NULL, -1},                   // SUFFIX_COMMENT
     80   {&Parser::BlockComment, NULL, -1},  // BLOCK_COMMENT
     81 };
     82 
     83 Parser::Parser(const std::vector<Token>& tokens, Err* err)
     84     : err_(err), cur_(0) {
     85   for (std::vector<Token>::const_iterator i(tokens.begin()); i != tokens.end();
     86        ++i) {
     87     switch(i->type()) {
     88       case Token::LINE_COMMENT:
     89         line_comment_tokens_.push_back(*i);
     90         break;
     91       case Token::SUFFIX_COMMENT:
     92         suffix_comment_tokens_.push_back(*i);
     93         break;
     94       default:
     95         // Note that BLOCK_COMMENTs (top-level standalone comments) are passed
     96         // through the real parser.
     97         tokens_.push_back(*i);
     98         break;
     99     }
    100   }
    101 }
    102 
    103 Parser::~Parser() {
    104 }
    105 
    106 // static
    107 scoped_ptr<ParseNode> Parser::Parse(const std::vector<Token>& tokens,
    108                                     Err* err) {
    109   Parser p(tokens, err);
    110   return p.ParseFile().PassAs<ParseNode>();
    111 }
    112 
    113 // static
    114 scoped_ptr<ParseNode> Parser::ParseExpression(const std::vector<Token>& tokens,
    115                                               Err* err) {
    116   Parser p(tokens, err);
    117   return p.ParseExpression().Pass();
    118 }
    119 
    120 bool Parser::IsAssignment(const ParseNode* node) const {
    121   return node && node->AsBinaryOp() &&
    122          (node->AsBinaryOp()->op().type() == Token::EQUAL ||
    123           node->AsBinaryOp()->op().type() == Token::PLUS_EQUALS ||
    124           node->AsBinaryOp()->op().type() == Token::MINUS_EQUALS);
    125 }
    126 
    127 bool Parser::IsStatementBreak(Token::Type token_type) const {
    128   switch (token_type) {
    129     case Token::IDENTIFIER:
    130     case Token::LEFT_BRACE:
    131     case Token::RIGHT_BRACE:
    132     case Token::IF:
    133     case Token::ELSE:
    134       return true;
    135     default:
    136       return false;
    137   }
    138 }
    139 
    140 bool Parser::LookAhead(Token::Type type) {
    141   if (at_end())
    142     return false;
    143   return cur_token().type() == type;
    144 }
    145 
    146 bool Parser::Match(Token::Type type) {
    147   if (!LookAhead(type))
    148     return false;
    149   Consume();
    150   return true;
    151 }
    152 
    153 Token Parser::Consume(Token::Type type, const char* error_message) {
    154   Token::Type types[1] = { type };
    155   return Consume(types, 1, error_message);
    156 }
    157 
    158 Token Parser::Consume(Token::Type* types,
    159                       size_t num_types,
    160                       const char* error_message) {
    161   if (has_error()) {
    162     // Don't overwrite current error, but make progress through tokens so that
    163     // a loop that's expecting a particular token will still terminate.
    164     cur_++;
    165     return Token(Location(), Token::INVALID, base::StringPiece());
    166   }
    167   if (at_end()) {
    168     const char kEOFMsg[] = "I hit EOF instead.";
    169     if (tokens_.empty())
    170       *err_ = Err(Location(), error_message, kEOFMsg);
    171     else
    172       *err_ = Err(tokens_[tokens_.size() - 1], error_message, kEOFMsg);
    173     return Token(Location(), Token::INVALID, base::StringPiece());
    174   }
    175 
    176   for (size_t i = 0; i < num_types; ++i) {
    177     if (cur_token().type() == types[i])
    178       return tokens_[cur_++];
    179   }
    180   *err_ = Err(cur_token(), error_message);
    181   return Token(Location(), Token::INVALID, base::StringPiece());
    182 }
    183 
    184 Token Parser::Consume() {
    185   return tokens_[cur_++];
    186 }
    187 
    188 scoped_ptr<ParseNode> Parser::ParseExpression() {
    189   return ParseExpression(0);
    190 }
    191 
    192 scoped_ptr<ParseNode> Parser::ParseExpression(int precedence) {
    193   if (at_end())
    194     return scoped_ptr<ParseNode>();
    195 
    196   Token token = Consume();
    197   PrefixFunc prefix = expressions_[token.type()].prefix;
    198 
    199   if (prefix == NULL) {
    200     *err_ = Err(token,
    201                 std::string("Unexpected token '") + token.value().as_string() +
    202                     std::string("'"));
    203     return scoped_ptr<ParseNode>();
    204   }
    205 
    206   scoped_ptr<ParseNode> left = (this->*prefix)(token);
    207   if (has_error())
    208     return left.Pass();
    209 
    210   while (!at_end() && !IsStatementBreak(cur_token().type()) &&
    211          precedence <= expressions_[cur_token().type()].precedence) {
    212     token = Consume();
    213     InfixFunc infix = expressions_[token.type()].infix;
    214     if (infix == NULL) {
    215       *err_ = Err(token,
    216                   std::string("Unexpected token '") +
    217                       token.value().as_string() + std::string("'"));
    218       return scoped_ptr<ParseNode>();
    219     }
    220     left = (this->*infix)(left.Pass(), token);
    221     if (has_error())
    222       return scoped_ptr<ParseNode>();
    223   }
    224 
    225   return left.Pass();
    226 }
    227 
    228 scoped_ptr<ParseNode> Parser::Literal(Token token) {
    229   return scoped_ptr<ParseNode>(new LiteralNode(token)).Pass();
    230 }
    231 
    232 scoped_ptr<ParseNode> Parser::Name(Token token) {
    233   return IdentifierOrCall(scoped_ptr<ParseNode>(), token).Pass();
    234 }
    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 
    242 scoped_ptr<ParseNode> Parser::Group(Token token) {
    243   scoped_ptr<ParseNode> expr = ParseExpression();
    244   if (has_error())
    245     return scoped_ptr<ParseNode>();
    246   Consume(Token::RIGHT_PAREN, "Expected ')'");
    247   return expr.Pass();
    248 }
    249 
    250 scoped_ptr<ParseNode> Parser::Not(Token token) {
    251   scoped_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1);
    252   if (has_error())
    253     return scoped_ptr<ParseNode>();
    254   scoped_ptr<UnaryOpNode> unary_op(new UnaryOpNode);
    255   unary_op->set_op(token);
    256   unary_op->set_operand(expr.Pass());
    257   return unary_op.PassAs<ParseNode>();
    258 }
    259 
    260 scoped_ptr<ParseNode> Parser::List(Token node) {
    261   scoped_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET, true));
    262   if (!has_error() && !at_end())
    263     Consume(Token::RIGHT_BRACKET, "Expected ']'");
    264   return list.Pass();
    265 }
    266 
    267 scoped_ptr<ParseNode> Parser::BinaryOperator(scoped_ptr<ParseNode> left,
    268                                              Token token) {
    269   scoped_ptr<ParseNode> right =
    270       ParseExpression(expressions_[token.type()].precedence + 1);
    271   if (!right) {
    272     *err_ =
    273         Err(token,
    274             "Expected right hand side for '" + token.value().as_string() + "'");
    275     return scoped_ptr<ParseNode>();
    276   }
    277   scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode);
    278   binary_op->set_op(token);
    279   binary_op->set_left(left.Pass());
    280   binary_op->set_right(right.Pass());
    281   return binary_op.PassAs<ParseNode>();
    282 }
    283 
    284 scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left,
    285                                                Token token) {
    286   scoped_ptr<ListNode> list(new ListNode);
    287   list->set_begin_token(token);
    288   list->set_end_token(token);
    289   scoped_ptr<BlockNode> block;
    290   bool has_arg = false;
    291   if (LookAhead(Token::LEFT_PAREN)) {
    292     Token start_token = Consume();
    293     // Parsing a function call.
    294     has_arg = true;
    295     if (Match(Token::RIGHT_PAREN)) {
    296       // Nothing, just an empty call.
    297     } else {
    298       list = ParseList(start_token, Token::RIGHT_PAREN, false);
    299       if (has_error())
    300         return scoped_ptr<ParseNode>();
    301       Consume(Token::RIGHT_PAREN, "Expected ')' after call");
    302     }
    303     // Optionally with a scope.
    304     if (LookAhead(Token::LEFT_BRACE)) {
    305       block = ParseBlock();
    306       if (has_error())
    307         return scoped_ptr<ParseNode>();
    308     }
    309   }
    310 
    311   if (!left && !has_arg) {
    312     // Not a function call, just a standalone identifier.
    313     return scoped_ptr<ParseNode>(new IdentifierNode(token)).Pass();
    314   }
    315   scoped_ptr<FunctionCallNode> func_call(new FunctionCallNode);
    316   func_call->set_function(token);
    317   func_call->set_args(list.Pass());
    318   if (block)
    319     func_call->set_block(block.Pass());
    320   return func_call.PassAs<ParseNode>();
    321 }
    322 
    323 scoped_ptr<ParseNode> Parser::Assignment(scoped_ptr<ParseNode> left,
    324                                          Token token) {
    325   if (left->AsIdentifier() == NULL) {
    326     *err_ = Err(left.get(), "Left-hand side of assignment must be identifier.");
    327     return scoped_ptr<ParseNode>();
    328   }
    329   scoped_ptr<ParseNode> value = ParseExpression(PRECEDENCE_ASSIGNMENT);
    330   scoped_ptr<BinaryOpNode> assign(new BinaryOpNode);
    331   assign->set_op(token);
    332   assign->set_left(left.Pass());
    333   assign->set_right(value.Pass());
    334   return assign.PassAs<ParseNode>();
    335 }
    336 
    337 scoped_ptr<ParseNode> Parser::Subscript(scoped_ptr<ParseNode> left,
    338                                         Token token) {
    339   // TODO: Maybe support more complex expressions like a[0][0]. This would
    340   // require work on the evaluator too.
    341   if (left->AsIdentifier() == NULL) {
    342     *err_ = Err(left.get(), "May only subscript identifiers.",
    343         "The thing on the left hand side of the [] must be an identifier\n"
    344         "and not an expression. If you need this, you'll have to assign the\n"
    345         "value to a temporary before subscripting. Sorry.");
    346     return scoped_ptr<ParseNode>();
    347   }
    348   scoped_ptr<ParseNode> value = ParseExpression();
    349   Consume(Token::RIGHT_BRACKET, "Expecting ']' after subscript.");
    350   scoped_ptr<AccessorNode> accessor(new AccessorNode);
    351   accessor->set_base(left->AsIdentifier()->value());
    352   accessor->set_index(value.Pass());
    353   return accessor.PassAs<ParseNode>();
    354 }
    355 
    356 scoped_ptr<ParseNode> Parser::DotOperator(scoped_ptr<ParseNode> left,
    357                                           Token token) {
    358   if (left->AsIdentifier() == NULL) {
    359     *err_ = Err(left.get(), "May only use \".\" for identifiers.",
    360         "The thing on the left hand side of the dot must be an identifier\n"
    361         "and not an expression. If you need this, you'll have to assign the\n"
    362         "value to a temporary first. Sorry.");
    363     return scoped_ptr<ParseNode>();
    364   }
    365 
    366   scoped_ptr<ParseNode> right = ParseExpression(PRECEDENCE_DOT);
    367   if (!right || !right->AsIdentifier()) {
    368     *err_ = Err(token, "Expected identifier for right-hand-side of \".\"",
    369         "Good: a.cookies\nBad: a.42\nLooks good but still bad: a.cookies()");
    370     return scoped_ptr<ParseNode>();
    371   }
    372 
    373   scoped_ptr<AccessorNode> accessor(new AccessorNode);
    374   accessor->set_base(left->AsIdentifier()->value());
    375   accessor->set_member(scoped_ptr<IdentifierNode>(
    376       static_cast<IdentifierNode*>(right.release())));
    377   return accessor.PassAs<ParseNode>();
    378 }
    379 
    380 // Does not Consume the start or end token.
    381 scoped_ptr<ListNode> Parser::ParseList(Token start_token,
    382                                        Token::Type stop_before,
    383                                        bool allow_trailing_comma) {
    384   scoped_ptr<ListNode> list(new ListNode);
    385   list->set_begin_token(start_token);
    386   bool just_got_comma = false;
    387   bool first_time = true;
    388   while (!LookAhead(stop_before)) {
    389     if (!first_time) {
    390       if (!just_got_comma) {
    391         // Require commas separate things in lists.
    392         *err_ = Err(cur_token(), "Expected comma between items.");
    393         return scoped_ptr<ListNode>();
    394       }
    395     }
    396     first_time = false;
    397 
    398     // Why _OR? We're parsing things that are higher precedence than the ,
    399     // that separates the items of the list. , should appear lower than
    400     // boolean expressions (the lowest of which is OR), but above assignments.
    401     list->append_item(ParseExpression(PRECEDENCE_OR));
    402     if (has_error())
    403       return scoped_ptr<ListNode>();
    404     if (at_end()) {
    405       *err_ =
    406           Err(tokens_[tokens_.size() - 1], "Unexpected end of file in list.");
    407       return scoped_ptr<ListNode>();
    408     }
    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     }
    416   }
    417   if (just_got_comma && !allow_trailing_comma) {
    418     *err_ = Err(cur_token(), "Trailing comma");
    419     return scoped_ptr<ListNode>();
    420   }
    421   list->set_end_token(cur_token());
    422   return list.Pass();
    423 }
    424 
    425 scoped_ptr<ParseNode> Parser::ParseFile() {
    426   scoped_ptr<BlockNode> file(new BlockNode(false));
    427   for (;;) {
    428     if (at_end())
    429       break;
    430     scoped_ptr<ParseNode> statement = ParseStatement();
    431     if (!statement)
    432       break;
    433     file->append_statement(statement.Pass());
    434   }
    435   if (!at_end() && !has_error())
    436     *err_ = Err(cur_token(), "Unexpected here, should be newline.");
    437   if (has_error())
    438     return scoped_ptr<ParseNode>();
    439 
    440   // TODO(scottmg): If this is measurably expensive, it could be done only
    441   // when necessary (when reformatting, or during tests). Comments are
    442   // separate from the parse tree at this point, so downstream code can remain
    443   // ignorant of them.
    444   AssignComments(file.get());
    445 
    446   return file.PassAs<ParseNode>();
    447 }
    448 
    449 scoped_ptr<ParseNode> Parser::ParseStatement() {
    450   if (LookAhead(Token::LEFT_BRACE)) {
    451     return ParseBlock().PassAs<ParseNode>();
    452   } else if (LookAhead(Token::IF)) {
    453     return ParseCondition();
    454   } else if (LookAhead(Token::BLOCK_COMMENT)) {
    455     return BlockComment(Consume());
    456   } else {
    457     // TODO(scottmg): Is this too strict? Just drop all the testing if we want
    458     // to allow "pointless" expressions and return ParseExpression() directly.
    459     scoped_ptr<ParseNode> stmt = ParseExpression();
    460     if (stmt) {
    461       if (stmt->AsFunctionCall() || IsAssignment(stmt.get()))
    462         return stmt.Pass();
    463     }
    464     if (!has_error()) {
    465       Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token();
    466       *err_ = Err(token, "Expecting assignment or function call.");
    467     }
    468     return scoped_ptr<ParseNode>();
    469   }
    470 }
    471 
    472 scoped_ptr<BlockNode> Parser::ParseBlock() {
    473   Token begin_token =
    474       Consume(Token::LEFT_BRACE, "Expected '{' to start a block.");
    475   if (has_error())
    476     return scoped_ptr<BlockNode>();
    477   scoped_ptr<BlockNode> block(new BlockNode(true));
    478   block->set_begin_token(begin_token);
    479 
    480   for (;;) {
    481     if (LookAhead(Token::RIGHT_BRACE)) {
    482       block->set_end_token(Consume());
    483       break;
    484     }
    485 
    486     scoped_ptr<ParseNode> statement = ParseStatement();
    487     if (!statement)
    488       return scoped_ptr<BlockNode>();
    489     block->append_statement(statement.Pass());
    490   }
    491   return block.Pass();
    492 }
    493 
    494 scoped_ptr<ParseNode> Parser::ParseCondition() {
    495   scoped_ptr<ConditionNode> condition(new ConditionNode);
    496   condition->set_if_token(Consume(Token::IF, "Expected 'if'"));
    497   Consume(Token::LEFT_PAREN, "Expected '(' after 'if'.");
    498   condition->set_condition(ParseExpression());
    499   if (IsAssignment(condition->condition()))
    500     *err_ = Err(condition->condition(), "Assignment not allowed in 'if'.");
    501   Consume(Token::RIGHT_PAREN, "Expected ')' after condition of 'if'.");
    502   condition->set_if_true(ParseBlock().Pass());
    503   if (Match(Token::ELSE))
    504     condition->set_if_false(ParseStatement().Pass());
    505   if (has_error())
    506     return scoped_ptr<ParseNode>();
    507   return condition.PassAs<ParseNode>();
    508 }
    509 
    510 void Parser::TraverseOrder(const ParseNode* root,
    511                            std::vector<const ParseNode*>* pre,
    512                            std::vector<const ParseNode*>* post) {
    513   if (root) {
    514     pre->push_back(root);
    515 
    516     if (const AccessorNode* accessor = root->AsAccessor()) {
    517       TraverseOrder(accessor->index(), pre, post);
    518       TraverseOrder(accessor->member(), pre, post);
    519     } else if (const BinaryOpNode* binop = root->AsBinaryOp()) {
    520       TraverseOrder(binop->left(), pre, post);
    521       TraverseOrder(binop->right(), pre, post);
    522     } else if (const BlockNode* block = root->AsBlock()) {
    523       const std::vector<ParseNode*>& statements = block->statements();
    524       for (std::vector<ParseNode*>::const_iterator i(statements.begin());
    525           i != statements.end();
    526           ++i) {
    527         TraverseOrder(*i, pre, post);
    528       }
    529     } else if (const ConditionNode* condition = root->AsConditionNode()) {
    530       TraverseOrder(condition->condition(), pre, post);
    531       TraverseOrder(condition->if_true(), pre, post);
    532       TraverseOrder(condition->if_false(), pre, post);
    533     } else if (const FunctionCallNode* func_call = root->AsFunctionCall()) {
    534       TraverseOrder(func_call->args(), pre, post);
    535       TraverseOrder(func_call->block(), pre, post);
    536     } else if (root->AsIdentifier()) {
    537       // Nothing.
    538     } else if (const ListNode* list = root->AsList()) {
    539       const std::vector<const ParseNode*>& contents = list->contents();
    540       for (std::vector<const ParseNode*>::const_iterator i(contents.begin());
    541           i != contents.end();
    542           ++i) {
    543         TraverseOrder(*i, pre, post);
    544       }
    545     } else if (root->AsLiteral()) {
    546       // Nothing.
    547     } else if (const UnaryOpNode* unaryop = root->AsUnaryOp()) {
    548       TraverseOrder(unaryop->operand(), pre, post);
    549     } else if (root->AsBlockComment()) {
    550       // Nothing.
    551     } else {
    552       CHECK(false) << "Unhandled case in TraverseOrder.";
    553     }
    554 
    555     post->push_back(root);
    556   }
    557 }
    558 
    559 void Parser::AssignComments(ParseNode* file) {
    560   // Start by generating a pre- and post- order traversal of the tree so we
    561   // can determine what's before and after comments.
    562   std::vector<const ParseNode*> pre;
    563   std::vector<const ParseNode*> post;
    564   TraverseOrder(file, &pre, &post);
    565 
    566   // Assign line comments to syntax immediately following.
    567   int cur_comment = 0;
    568   for (std::vector<const ParseNode*>::const_iterator i = pre.begin();
    569        i != pre.end();
    570        ++i) {
    571     const Location& start = (*i)->GetRange().begin();
    572     while (cur_comment < static_cast<int>(line_comment_tokens_.size())) {
    573       if (start.byte() >= line_comment_tokens_[cur_comment].location().byte()) {
    574         const_cast<ParseNode*>(*i)->comments_mutable()->append_before(
    575             line_comment_tokens_[cur_comment]);
    576         ++cur_comment;
    577       } else {
    578         break;
    579       }
    580     }
    581   }
    582 
    583   // Remaining line comments go at end of file.
    584   for (; cur_comment < static_cast<int>(line_comment_tokens_.size());
    585        ++cur_comment)
    586     file->comments_mutable()->append_after(line_comment_tokens_[cur_comment]);
    587 
    588   // Assign suffix to syntax immediately before.
    589   cur_comment = static_cast<int>(suffix_comment_tokens_.size() - 1);
    590   for (std::vector<const ParseNode*>::const_reverse_iterator i = post.rbegin();
    591        i != post.rend();
    592        ++i) {
    593     // Don't assign suffix comments to the function call or list, but instead
    594     // to the last thing inside.
    595     if ((*i)->AsFunctionCall() || (*i)->AsList())
    596       continue;
    597 
    598     const Location& start = (*i)->GetRange().begin();
    599     const Location& end = (*i)->GetRange().end();
    600 
    601     // Don't assign suffix comments to something that starts on an earlier
    602     // line, so that in:
    603     //
    604     // sources = [ "a",
    605     //     "b" ] # comment
    606     //
    607     // it's attached to "b", not sources = [ ... ].
    608     if (start.line_number() != end.line_number())
    609       continue;
    610 
    611     while (cur_comment >= 0) {
    612       if (end.byte() <= suffix_comment_tokens_[cur_comment].location().byte()) {
    613         const_cast<ParseNode*>(*i)->comments_mutable()->append_suffix(
    614             suffix_comment_tokens_[cur_comment]);
    615         --cur_comment;
    616       } else {
    617         break;
    618       }
    619     }
    620 
    621     // Suffix comments were assigned in reverse, so if there were multiple on
    622     // the same node, they need to be reversed.
    623     const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix();
    624   }
    625 }
    626