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 namespace {
     13 
     14 // Returns true if the two tokens are on the same line. We assume they're in
     15 // the same file.
     16 bool IsSameLine(const Token& a, const Token& b) {
     17   DCHECK(a.location().file() == b.location().file());
     18   return a.location().line_number() == b.location().line_number();
     19 }
     20 
     21 }  // namespace
     22 
     23 Parser::Parser(const std::vector<Token>& tokens, Err* err)
     24     : tokens_(tokens),
     25       err_(err),
     26       cur_(0) {
     27 }
     28 
     29 Parser::~Parser() {
     30 }
     31 
     32 // static
     33 scoped_ptr<ParseNode> Parser::Parse(const std::vector<Token>& tokens,
     34                                     Err* err) {
     35   Parser p(tokens, err);
     36   return p.ParseBlock(false).PassAs<ParseNode>();
     37 }
     38 
     39 // static
     40 scoped_ptr<ParseNode> Parser::ParseExpression(const std::vector<Token>& tokens,
     41                                               Err* err) {
     42   Parser p(tokens, err);
     43   return p.ParseExpression().Pass();
     44 }
     45 
     46 bool Parser::IsToken(Token::Type type, char* str) const {
     47   if (at_end())
     48     return false;
     49   return cur_token().type() == type || cur_token().value() == str;
     50 }
     51 
     52 scoped_ptr<AccessorNode> Parser::ParseAccessor() {
     53   scoped_ptr<AccessorNode> accessor(new AccessorNode);
     54 
     55   DCHECK(cur_token().type() == Token::IDENTIFIER);
     56   accessor->set_base(cur_token());
     57   cur_++;  // Skip identifier.
     58   cur_++;  // Skip "[" (we know this exists because the existance of this
     59            // token is how the caller knows it's an accessor.
     60 
     61   if (at_end()) {
     62     *err_ = MakeEOFError("Got EOF when looking for list index.");
     63     return scoped_ptr<AccessorNode>();
     64   }
     65 
     66   // Get the expression.
     67   scoped_ptr<ParseNode> expr = ParseExpression().Pass();
     68   if (has_error())
     69     return scoped_ptr<AccessorNode>();
     70   if (at_end()) {
     71     *err_ = MakeEOFError("Got EOF when looking for list accessor ]");
     72     return scoped_ptr<AccessorNode>();
     73   }
     74   accessor->set_index(expr.Pass());
     75 
     76   // Skip over "]"
     77   if (!cur_token().IsScoperEqualTo("]")) {
     78     *err_ = Err(cur_token(), "Expecting ]",
     79                "You started a list access but didn't terminate it, and instead "
     80                "I fould this\nstupid thing.");
     81     return scoped_ptr<AccessorNode>();
     82   }
     83   cur_++;
     84 
     85   return accessor.Pass();
     86 }
     87 
     88 // Blocks at the file scope don't need {} so we have the option to ignore
     89 // them. When need_braces is set, we'll expect a begin an end brace.
     90 //
     91 // block := "{" block_contents "}"
     92 // block_contents := (expression | conditional | block)*
     93 scoped_ptr<BlockNode> Parser::ParseBlock(bool need_braces) {
     94   scoped_ptr<BlockNode> block(new BlockNode(true));
     95 
     96   // Eat initial { if necessary.
     97   const Token* opening_curly_brace;
     98   if (need_braces) {
     99     if (at_end()) {
    100       *err_ = MakeEOFError("Got EOF when looking for { for block.",
    101                            "It should have been after here.");
    102       return scoped_ptr<BlockNode>();
    103     } else if(!IsScopeBeginScoper(cur_token())) {
    104       *err_ = Err(cur_token(), "Expecting { instead of this thing.",
    105                   "THOU SHALT USE CURLY BRACES FOR ALL BLOCKS.");
    106       return scoped_ptr<BlockNode>();
    107     }
    108     opening_curly_brace = &cur_token();
    109     block->set_begin_token(opening_curly_brace);
    110     cur_++;
    111   }
    112 
    113   // Loop until EOF or end brace found.
    114   while (!at_end() && !IsScopeEndScoper(cur_token())) {
    115     if (cur_token().IsIdentifierEqualTo("if")) {
    116       // Conditional.
    117       block->append_statement(ParseCondition().PassAs<ParseNode>());
    118     } else if (IsScopeBeginScoper(cur_token())) {
    119       // Nested block.
    120       block->append_statement(ParseBlock(true).PassAs<ParseNode>());
    121     } else {
    122       // Everything else is an expression.
    123       block->append_statement(ParseExpression().PassAs<ParseNode>());
    124     }
    125     if (has_error())
    126       return scoped_ptr<BlockNode>();
    127   }
    128 
    129   // Eat the ending "}" if necessary.
    130   if (need_braces) {
    131     if (at_end() || !IsScopeEndScoper(cur_token())) {
    132       *err_ = Err(*opening_curly_brace, "Expecting }",
    133                   "I ran headlong into the end of the file looking for the "
    134                   "closing brace\ncorresponding to this one.");
    135       return scoped_ptr<BlockNode>();
    136     }
    137     block->set_end_token(&cur_token());
    138     cur_++;  // Skip past "}".
    139   }
    140 
    141   return block.Pass();
    142 }
    143 
    144 // conditional := "if (" expression ")" block [else_conditional]
    145 // else_conditional := ("else" block) | ("else" conditional)
    146 scoped_ptr<ConditionNode> Parser::ParseCondition() {
    147   scoped_ptr<ConditionNode> cond(new ConditionNode);
    148 
    149   // Skip past "if".
    150   const Token& if_token = cur_token();
    151   cond->set_if_token(if_token);
    152   DCHECK(if_token.IsIdentifierEqualTo("if"));
    153   cur_++;
    154 
    155   if (at_end() || !IsFunctionCallArgBeginScoper(cur_token())) {
    156     *err_ = Err(if_token, "Expecting \"(\" after \"if\"",
    157                 "Did you think this was Python or something?");
    158     return scoped_ptr<ConditionNode>();
    159   }
    160 
    161   // Skip over (.
    162   const Token& open_paren_token = cur_token();
    163   cur_++;
    164   if (at_end()) {
    165     *err_ = Err(if_token, "Unexpected EOF inside if condition");
    166     return scoped_ptr<ConditionNode>();
    167   }
    168 
    169   // Condition inside ().
    170   cond->set_condition(ParseExpression().Pass());
    171   if (has_error())
    172     return scoped_ptr<ConditionNode>();
    173 
    174   if (at_end() || !IsFunctionCallArgEndScoper(cur_token())) {
    175     *err_ = Err(open_paren_token, "Expecting \")\" for \"if\" condition",
    176                 "You didn't finish the thought you started here.");
    177     return scoped_ptr<ConditionNode>();
    178   }
    179   cur_++;  // Skip over )
    180 
    181   // Contents of {}.
    182   cond->set_if_true(ParseBlock(true).Pass());
    183   if (has_error())
    184     return scoped_ptr<ConditionNode>();
    185 
    186   // Optional "else" at the end.
    187   if (!at_end() && cur_token().IsIdentifierEqualTo("else")) {
    188     cur_++;
    189 
    190     // The else may be followed by an if or a block.
    191     if (at_end()) {
    192       *err_ = MakeEOFError("Ran into end of file after \"else\".",
    193                            "else, WHAT?!?!?");
    194       return scoped_ptr<ConditionNode>();
    195     }
    196     if (cur_token().IsIdentifierEqualTo("if")) {
    197       // "else if() {"
    198       cond->set_if_false(ParseCondition().PassAs<ParseNode>());
    199     } else if (IsScopeBeginScoper(cur_token())) {
    200       // "else {"
    201       cond->set_if_false(ParseBlock(true).PassAs<ParseNode>());
    202     } else {
    203       // else <anything else>
    204       *err_ = Err(cur_token(), "Expected \"if\" or \"{\" after \"else\".",
    205                   "This is neither of those things.");
    206       return scoped_ptr<ConditionNode>();
    207     }
    208   }
    209 
    210   if (has_error())
    211     return scoped_ptr<ConditionNode>();
    212   return cond.Pass();
    213 }
    214 
    215 // expression := paren_expression | accessor | identifier | literal |
    216 //               funccall | unary_expression | binary_expression
    217 //
    218 // accessor := identifier <non-newline-whitespace>* "[" expression "]"
    219 //
    220 // The "non-newline-whitespace is used to differentiate between this case:
    221 //   a[1]
    222 // and this one:
    223 //   a
    224 //   [1]
    225 // The second one is kind of stupid (since it does nothing with the values)
    226 // but is still legal.
    227 scoped_ptr<ParseNode> Parser::ParseExpression() {
    228   scoped_ptr<ParseNode> expr = ParseExpressionExceptBinaryOperators();
    229   if (has_error())
    230     return scoped_ptr<ParseNode>();
    231 
    232   // That may have hit EOF, in which case we can't have any binary operators.
    233   if (at_end())
    234     return expr.Pass();
    235 
    236   // TODO(brettw) handle operator precidence!
    237   // Gobble up all subsequent expressions as long as there are binary
    238   // operators.
    239 
    240   if (IsBinaryOperator(cur_token())) {
    241     scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode);
    242     binary_op->set_left(expr.Pass());
    243     const Token& operator_token = cur_token();
    244     binary_op->set_op(operator_token);
    245     cur_++;
    246     if (at_end()) {
    247       *err_ = Err(operator_token, "Unexpected EOF in expression.",
    248                   "I was looking for the right-hand-side of this operator.");
    249       return scoped_ptr<ParseNode>();
    250     }
    251     binary_op->set_right(ParseExpression().Pass());
    252     if (has_error())
    253       return scoped_ptr<ParseNode>();
    254     return binary_op.PassAs<ParseNode>();
    255   }
    256 
    257   return expr.Pass();
    258 }
    259 
    260 
    261 // This internal one does not handle binary operators, since it requires
    262 // looking at the "next" thing. The regular ParseExpression above handles it.
    263 scoped_ptr<ParseNode> Parser::ParseExpressionExceptBinaryOperators() {
    264   if (at_end())
    265     return scoped_ptr<ParseNode>();
    266 
    267   const Token& token = cur_token();
    268 
    269   // Unary expression.
    270   if (IsUnaryOperator(token))
    271     return ParseUnaryOp().PassAs<ParseNode>();
    272 
    273   // Parenthesized expressions.
    274   if (token.IsScoperEqualTo("("))
    275     return ParseParenExpression();
    276 
    277   // Function calls.
    278   if (token.type() == Token::IDENTIFIER) {
    279     if (has_next_token() && IsFunctionCallArgBeginScoper(next_token()))
    280       return ParseFunctionCall().PassAs<ParseNode>();
    281   }
    282 
    283   // Lists.
    284   if (token.IsScoperEqualTo("[")) {
    285     return ParseList(Token(Location(), Token::SCOPER, "["),
    286                      Token(Location(), Token::SCOPER, "]")).PassAs<ParseNode>();
    287   }
    288 
    289   // Literals.
    290   if (token.type() == Token::STRING || token.type() == Token::INTEGER) {
    291     cur_++;
    292     return scoped_ptr<ParseNode>(new LiteralNode(token));
    293   }
    294 
    295   // Accessors.
    296   if (token.type() == Token::IDENTIFIER &&
    297       has_next_token() && next_token().IsScoperEqualTo("[") &&
    298       IsSameLine(token, next_token())) {
    299     return ParseAccessor().PassAs<ParseNode>();
    300   }
    301 
    302   // Identifiers.
    303   if (token.type() == Token::IDENTIFIER) {
    304     cur_++;
    305     return scoped_ptr<ParseNode>(new IdentifierNode(token));
    306   }
    307 
    308   // Handle errors.
    309   if (token.type() == Token::SEPARATOR) {
    310     *err_ = Err(token, "Unexpected comma.",
    311                 "You can't put a comma here, it must be in list separating "
    312                 "complete\nthoughts.");
    313   } else if (IsScopeBeginScoper(token)) {
    314     *err_ = Err(token, "Unexpected token.",
    315                 "You can't put a \"{\" scope here, it must be in a block.");
    316   } else {
    317     *err_ = Err(token, "Unexpected token.",
    318                 "I was really hoping for something else here and you let me down.");
    319   }
    320   return scoped_ptr<ParseNode>();
    321 }
    322 
    323 // function_call := identifier "(" list_contents ")"
    324 //                  [<non-newline-whitespace>* block]
    325 scoped_ptr<FunctionCallNode> Parser::ParseFunctionCall() {
    326   scoped_ptr<FunctionCallNode> func(new FunctionCallNode);
    327 
    328   const Token& function_token = cur_token();
    329   func->set_function(function_token);
    330 
    331   // This function should only get called when we know we have a function,
    332   // which only happens when there is a paren following the name. Skip past it.
    333   DCHECK(has_next_token());
    334   cur_++;  // Skip past function name to (.
    335   const Token& open_paren_token = cur_token();
    336   DCHECK(IsFunctionCallArgBeginScoper(open_paren_token));
    337 
    338   if (at_end()) {
    339     *err_ = Err(open_paren_token, "Unexpected EOF for function call.",
    340                 "You didn't finish the thought you started here.");
    341     return scoped_ptr<FunctionCallNode>();
    342   }
    343 
    344   // Arguments.
    345   func->set_args(ParseList(Token(Location(), Token::SCOPER, "("),
    346                            Token(Location(), Token::SCOPER, ")")));
    347   if (has_error())
    348     return scoped_ptr<FunctionCallNode>();
    349 
    350   // Optional {} after function call for certain functions. The "{" must be on
    351   // the same line as the ")" to disambiguate the case of a function followed
    352   // by a random block just used for scoping purposes.
    353   if (!at_end() && IsScopeBeginScoper(cur_token())) {
    354     const Token& args_end_token = tokens_[cur_ - 1];
    355     DCHECK(args_end_token.IsScoperEqualTo(")"));
    356     if (IsSameLine(args_end_token, cur_token()))
    357       func->set_block(ParseBlock(true).Pass());
    358   }
    359 
    360   if (has_error())
    361     return scoped_ptr<FunctionCallNode>();
    362   return func.Pass();
    363 }
    364 
    365 // list := "[" expression* "]"
    366 // list_contents := [(expression ",")* expression [","]]
    367 //
    368 // The list_contents is also used in function calls surrounded by parens, so
    369 // this function takes the tokens that are expected to surround the list.
    370 scoped_ptr<ListNode> Parser::ParseList(const Token& expected_begin,
    371                                        const Token& expected_end) {
    372   scoped_ptr<ListNode> list(new ListNode);
    373 
    374   const Token& open_bracket_token = cur_token();
    375   list->set_begin_token(open_bracket_token);
    376   cur_++;  // Skip "[" or "(".
    377 
    378   bool need_separator = false;
    379   while(true) {
    380     if (at_end()) {
    381       *err_ = Err(open_bracket_token, "EOF found when parsing list.",
    382                   "I expected a \"" + expected_end.value().as_string() +
    383                   "\" corresponding to this one.");
    384       return scoped_ptr<ListNode>();
    385     }
    386     if (cur_token().type() == expected_end.type() &&
    387         cur_token().value() == expected_end.value()) {
    388       list->set_end_token(cur_token());
    389       cur_++;
    390       break;
    391     }
    392 
    393     if (need_separator) {
    394       DCHECK(!list->contents().empty());
    395       LocationRange prev_item_range =
    396           list->contents().at(list->contents().size() - 1)->GetRange();
    397       *err_ = Err(prev_item_range.end(),
    398                   "Need comma separating items in list.",
    399                   "You probably need a comma after this thingy.");
    400       err_->AppendRange(prev_item_range);
    401       return scoped_ptr<ListNode>();
    402     }
    403     scoped_ptr<ParseNode> expr = ParseExpression().Pass();
    404     if (has_error())
    405       return scoped_ptr<ListNode>();
    406     list->append_item(expr.Pass());
    407 
    408     need_separator = true;
    409     if (!at_end()) {
    410       // Skip over the separator, marking that we found it.
    411       if (cur_token().type() == Token::SEPARATOR) {
    412         cur_++;
    413         need_separator = false;
    414       }
    415     }
    416   }
    417   return list.Pass();
    418 }
    419 
    420 // paren_expression := "(" expression ")"
    421 scoped_ptr<ParseNode> Parser::ParseParenExpression() {
    422   const Token& open_paren_token = cur_token();
    423   cur_++;  // Skip over (
    424 
    425   scoped_ptr<ParseNode> ret = ParseExpression();
    426   if (has_error())
    427     return scoped_ptr<ParseNode>();
    428 
    429   if (at_end()) {
    430     *err_ = Err(open_paren_token, "EOF found when parsing expression.",
    431                 "I was looking for a \")\" corresponding to this one.");
    432     return scoped_ptr<ParseNode>();
    433   }
    434   if (!cur_token().IsScoperEqualTo(")")) {
    435     *err_ = Err(open_paren_token, "Expected \")\" for expression",
    436                 "I was looking for a \")\" corresponding to this one.");
    437     return scoped_ptr<ParseNode>();
    438   }
    439   cur_++;  // Skip over )
    440   return ret.Pass();
    441 }
    442 
    443 // unary_expression := "!" expression
    444 scoped_ptr<UnaryOpNode> Parser::ParseUnaryOp() {
    445   scoped_ptr<UnaryOpNode> unary(new UnaryOpNode);
    446 
    447   DCHECK(!at_end() && IsUnaryOperator(cur_token()));
    448   const Token& op_token = cur_token();
    449   unary->set_op(op_token);
    450   cur_++;
    451 
    452   if (at_end()) {
    453     *err_ = Err(op_token, "Expected expression.",
    454                 "This operator needs something to operate on.");
    455     return scoped_ptr<UnaryOpNode>();
    456   }
    457   unary->set_operand(ParseExpression().Pass());
    458   if (has_error())
    459     return scoped_ptr<UnaryOpNode>();
    460   return unary.Pass();
    461 }
    462 
    463 Err Parser::MakeEOFError(const std::string& message,
    464                          const std::string& help) const {
    465   if (tokens_.empty())
    466     return Err(Location(NULL, 1, 1), message, help);
    467 
    468   const Token& last = tokens_[tokens_.size() - 1];
    469   return Err(last, message, help);
    470 }
    471