gn: Reduce stack memory use while parsing.

BUG=641454

Review-Url: https://codereview.chromium.org/2290713002
Cr-Original-Commit-Position: refs/heads/master@{#415181}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 9e92b9d9ef75b26947a46ed3bc2735fddc888b3f
diff --git a/tools/gn/parser.cc b/tools/gn/parser.cc
index e256d2d..76d4580 100644
--- a/tools/gn/parser.cc
+++ b/tools/gn/parser.cc
@@ -281,7 +281,9 @@
 };
 
 Parser::Parser(const std::vector<Token>& tokens, Err* err)
-    : err_(err), cur_(0) {
+    : invalid_token_(Location(), Token::INVALID, base::StringPiece()),
+      err_(err),
+      cur_(0) {
   for (const auto& token : tokens) {
     switch (token.type()) {
       case Token::LINE_COMMENT:
@@ -377,20 +379,20 @@
   return true;
 }
 
-Token Parser::Consume(Token::Type type, const char* error_message) {
+const Token& Parser::Consume(Token::Type type, const char* error_message) {
   Token::Type types[1] = { type };
   return Consume(types, 1, error_message);
 }
 
-Token Parser::Consume(Token::Type* types,
-                      size_t num_types,
-                      const char* error_message) {
+const Token& Parser::Consume(Token::Type* types,
+                             size_t num_types,
+                             const char* error_message) {
   if (has_error()) {
     // Don't overwrite current error, but make progress through tokens so that
     // a loop that's expecting a particular token will still terminate.
     if (!at_end())
       cur_++;
-    return Token(Location(), Token::INVALID, base::StringPiece());
+    return invalid_token_;
   }
   if (at_end()) {
     const char kEOFMsg[] = "I hit EOF instead.";
@@ -398,7 +400,7 @@
       *err_ = Err(Location(), error_message, kEOFMsg);
     else
       *err_ = Err(tokens_[tokens_.size() - 1], error_message, kEOFMsg);
-    return Token(Location(), Token::INVALID, base::StringPiece());
+    return invalid_token_;
   }
 
   for (size_t i = 0; i < num_types; ++i) {
@@ -406,10 +408,10 @@
       return Consume();
   }
   *err_ = Err(cur_token(), error_message);
-  return Token(Location(), Token::INVALID, base::StringPiece());
+  return invalid_token_;
 }
 
-Token Parser::Consume() {
+const Token& Parser::Consume() {
   return tokens_[cur_++];
 }
 
@@ -421,7 +423,7 @@
   if (at_end())
     return std::unique_ptr<ParseNode>();
 
-  Token token = Consume();
+  const Token& token = Consume();
   PrefixFunc prefix = expressions_[token.type()].prefix;
 
   if (prefix == nullptr) {
@@ -437,15 +439,15 @@
 
   while (!at_end() && !IsStatementBreak(cur_token().type()) &&
          precedence <= expressions_[cur_token().type()].precedence) {
-    token = Consume();
-    InfixFunc infix = expressions_[token.type()].infix;
+    const Token& next_token = Consume();
+    InfixFunc infix = expressions_[next_token.type()].infix;
     if (infix == nullptr) {
-      *err_ = Err(token,
-                  std::string("Unexpected token '") +
-                      token.value().as_string() + std::string("'"));
+      *err_ = Err(next_token, std::string("Unexpected token '") +
+                                  next_token.value().as_string() +
+                                  std::string("'"));
       return std::unique_ptr<ParseNode>();
     }
-    left = (this->*infix)(std::move(left), token);
+    left = (this->*infix)(std::move(left), next_token);
     if (has_error())
       return std::unique_ptr<ParseNode>();
   }
@@ -453,27 +455,27 @@
   return left;
 }
 
-std::unique_ptr<ParseNode> Parser::Block(Token token) {
+std::unique_ptr<ParseNode> Parser::Block(const Token& token) {
   // This entrypoint into ParseBlock means it's part of an expression and we
   // always want the result.
   return ParseBlock(token, BlockNode::RETURNS_SCOPE);
 }
 
-std::unique_ptr<ParseNode> Parser::Literal(Token token) {
+std::unique_ptr<ParseNode> Parser::Literal(const Token& token) {
   return base::WrapUnique(new LiteralNode(token));
 }
 
-std::unique_ptr<ParseNode> Parser::Name(Token token) {
+std::unique_ptr<ParseNode> Parser::Name(const Token& token) {
   return IdentifierOrCall(std::unique_ptr<ParseNode>(), token);
 }
 
-std::unique_ptr<ParseNode> Parser::BlockComment(Token token) {
+std::unique_ptr<ParseNode> Parser::BlockComment(const Token& token) {
   std::unique_ptr<BlockCommentNode> comment(new BlockCommentNode());
   comment->set_comment(token);
   return std::move(comment);
 }
 
-std::unique_ptr<ParseNode> Parser::Group(Token token) {
+std::unique_ptr<ParseNode> Parser::Group(const Token& token) {
   std::unique_ptr<ParseNode> expr = ParseExpression();
   if (has_error())
     return std::unique_ptr<ParseNode>();
@@ -481,7 +483,7 @@
   return expr;
 }
 
-std::unique_ptr<ParseNode> Parser::Not(Token token) {
+std::unique_ptr<ParseNode> Parser::Not(const Token& token) {
   std::unique_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1);
   if (has_error())
     return std::unique_ptr<ParseNode>();
@@ -496,7 +498,7 @@
   return std::move(unary_op);
 }
 
-std::unique_ptr<ParseNode> Parser::List(Token node) {
+std::unique_ptr<ParseNode> Parser::List(const Token& node) {
   std::unique_ptr<ParseNode> list(ParseList(node, Token::RIGHT_BRACKET, true));
   if (!has_error() && !at_end())
     Consume(Token::RIGHT_BRACKET, "Expected ']'");
@@ -505,7 +507,7 @@
 
 std::unique_ptr<ParseNode> Parser::BinaryOperator(
     std::unique_ptr<ParseNode> left,
-    Token token) {
+    const Token& token) {
   std::unique_ptr<ParseNode> right =
       ParseExpression(expressions_[token.type()].precedence + 1);
   if (!right) {
@@ -524,14 +526,14 @@
 
 std::unique_ptr<ParseNode> Parser::IdentifierOrCall(
     std::unique_ptr<ParseNode> left,
-    Token token) {
+    const Token& token) {
   std::unique_ptr<ListNode> list(new ListNode);
   list->set_begin_token(token);
   list->set_end(base::WrapUnique(new EndNode(token)));
   std::unique_ptr<BlockNode> block;
   bool has_arg = false;
   if (LookAhead(Token::LEFT_PAREN)) {
-    Token start_token = Consume();
+    const Token& start_token = Consume();
     // Parsing a function call.
     has_arg = true;
     if (Match(Token::RIGHT_PAREN)) {
@@ -563,7 +565,7 @@
 }
 
 std::unique_ptr<ParseNode> Parser::Assignment(std::unique_ptr<ParseNode> left,
-                                              Token token) {
+                                              const Token& token) {
   if (left->AsIdentifier() == nullptr && left->AsAccessor() == nullptr) {
     *err_ = Err(left.get(),
         "The left-hand side of an assignment must be an identifier, "
@@ -584,7 +586,7 @@
 }
 
 std::unique_ptr<ParseNode> Parser::Subscript(std::unique_ptr<ParseNode> left,
-                                             Token token) {
+                                             const Token& token) {
   // TODO: Maybe support more complex expressions like a[0][0]. This would
   // require work on the evaluator too.
   if (left->AsIdentifier() == nullptr) {
@@ -603,7 +605,7 @@
 }
 
 std::unique_ptr<ParseNode> Parser::DotOperator(std::unique_ptr<ParseNode> left,
-                                               Token token) {
+                                               const Token& token) {
   if (left->AsIdentifier() == nullptr) {
     *err_ = Err(left.get(), "May only use \".\" for identifiers.",
         "The thing on the left hand side of the dot must be an identifier\n"
@@ -627,7 +629,7 @@
 }
 
 // Does not Consume the start or end token.
-std::unique_ptr<ListNode> Parser::ParseList(Token start_token,
+std::unique_ptr<ListNode> Parser::ParseList(const Token& start_token,
                                             Token::Type stop_before,
                                             bool allow_trailing_comma) {
   std::unique_ptr<ListNode> list(new ListNode);
@@ -709,7 +711,7 @@
         return stmt;
     }
     if (!has_error()) {
-      Token token = cur_or_last_token();
+      const Token& token = cur_or_last_token();
       *err_ = Err(token, "Expecting assignment or function call.");
     }
     return std::unique_ptr<ParseNode>();
@@ -717,7 +719,7 @@
 }
 
 std::unique_ptr<BlockNode> Parser::ParseBlock(
-    Token begin_brace,
+    const Token& begin_brace,
     BlockNode::ResultMode result_mode) {
   if (has_error())
     return std::unique_ptr<BlockNode>();
diff --git a/tools/gn/parser.h b/tools/gn/parser.h
index 22acb47..69dc8cf 100644
--- a/tools/gn/parser.h
+++ b/tools/gn/parser.h
@@ -17,9 +17,9 @@
 #include "tools/gn/parse_tree.h"
 
 class Parser;
-typedef std::unique_ptr<ParseNode> (Parser::*PrefixFunc)(Token token);
+typedef std::unique_ptr<ParseNode> (Parser::*PrefixFunc)(const Token& token);
 typedef std::unique_ptr<ParseNode> (
-    Parser::*InfixFunc)(std::unique_ptr<ParseNode> left, Token token);
+    Parser::*InfixFunc)(std::unique_ptr<ParseNode> left, const Token& token);
 
 extern const char kGrammar_Help[];
 
@@ -58,29 +58,29 @@
   std::unique_ptr<ParseNode> ParseExpression(int precedence);
 
   // |PrefixFunc|s used in parsing expressions.
-  std::unique_ptr<ParseNode> Block(Token token);
-  std::unique_ptr<ParseNode> Literal(Token token);
-  std::unique_ptr<ParseNode> Name(Token token);
-  std::unique_ptr<ParseNode> Group(Token token);
-  std::unique_ptr<ParseNode> Not(Token token);
-  std::unique_ptr<ParseNode> List(Token token);
-  std::unique_ptr<ParseNode> BlockComment(Token token);
+  std::unique_ptr<ParseNode> Block(const Token& token);
+  std::unique_ptr<ParseNode> Literal(const Token& token);
+  std::unique_ptr<ParseNode> Name(const Token& token);
+  std::unique_ptr<ParseNode> Group(const Token& token);
+  std::unique_ptr<ParseNode> Not(const Token& token);
+  std::unique_ptr<ParseNode> List(const Token& token);
+  std::unique_ptr<ParseNode> BlockComment(const Token& token);
 
   // |InfixFunc|s used in parsing expressions.
   std::unique_ptr<ParseNode> BinaryOperator(std::unique_ptr<ParseNode> left,
-                                            Token token);
+                                            const Token& token);
   std::unique_ptr<ParseNode> IdentifierOrCall(std::unique_ptr<ParseNode> left,
-                                              Token token);
+                                              const Token& token);
   std::unique_ptr<ParseNode> Assignment(std::unique_ptr<ParseNode> left,
-                                        Token token);
+                                        const Token& token);
   std::unique_ptr<ParseNode> Subscript(std::unique_ptr<ParseNode> left,
-                                       Token token);
+                                       const Token& token);
   std::unique_ptr<ParseNode> DotOperator(std::unique_ptr<ParseNode> left,
-                                         Token token);
+                                         const Token& token);
 
   // Helper to parse a comma separated list, optionally allowing trailing
   // commas (allowed in [] lists, not in function calls).
-  std::unique_ptr<ListNode> ParseList(Token start_token,
+  std::unique_ptr<ListNode> ParseList(const Token& start_token,
                                       Token::Type stop_before,
                                       bool allow_trailing_comma);
 
@@ -88,7 +88,7 @@
   std::unique_ptr<ParseNode> ParseStatement();
   // Expects to be passed the token corresponding to the '{' and that the
   // current token is the one following the '{'.
-  std::unique_ptr<BlockNode> ParseBlock(Token being_brace,
+  std::unique_ptr<BlockNode> ParseBlock(const Token& begin_brace,
                                         BlockNode::ResultMode result_mode);
   std::unique_ptr<ParseNode> ParseCondition();
 
@@ -105,11 +105,11 @@
 
   bool LookAhead(Token::Type type);
   bool Match(Token::Type type);
-  Token Consume(Token::Type type, const char* error_message);
-  Token Consume(Token::Type* types,
-                size_t num_types,
-                const char* error_message);
-  Token Consume();
+  const Token& Consume(Token::Type type, const char* error_message);
+  const Token& Consume(Token::Type* types,
+                       size_t num_types,
+                       const char* error_message);
+  const Token& Consume();
 
   // Call this only if !at_end().
   const Token& cur_token() const { return tokens_[cur_]; }
@@ -128,6 +128,7 @@
 
   static ParserHelper expressions_[Token::NUM_TYPES];
 
+  Token invalid_token_;
   Err* err_;
 
   // Current index into the tokens.