// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef TOOLS_GN_PARSER_H_ #define TOOLS_GN_PARSER_H_ #include <map> #include <vector> #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "tools/gn/err.h" #include "tools/gn/parse_tree.h" class Parser; typedef scoped_ptr<ParseNode> (Parser::*PrefixFunc)(Token token); typedef scoped_ptr<ParseNode> (Parser::*InfixFunc)(scoped_ptr<ParseNode> left, Token token); struct ParserHelper { PrefixFunc prefix; InfixFunc infix; int precedence; }; // Parses a series of tokens. The resulting AST will refer to the tokens passed // to the input, so the tokens an the file data they refer to must outlive your // use of the ParseNode. class Parser { public: // Will return a null pointer and set the err on error. static scoped_ptr<ParseNode> Parse(const std::vector<Token>& tokens, Err* err); // Alternative to parsing that assumes the input is an expression. static scoped_ptr<ParseNode> ParseExpression(const std::vector<Token>& tokens, Err* err); scoped_ptr<ParseNode> ParseExpression(); private: // Vector must be valid for lifetime of call. Parser(const std::vector<Token>& tokens, Err* err); ~Parser(); // Parses an expression with the given precedence or higher. scoped_ptr<ParseNode> ParseExpression(int precedence); // |PrefixFunc|s used in parsing expressions. scoped_ptr<ParseNode> Literal(Token token); scoped_ptr<ParseNode> Name(Token token); scoped_ptr<ParseNode> Group(Token token); scoped_ptr<ParseNode> Not(Token token); scoped_ptr<ParseNode> List(Token token); // |InfixFunc|s used in parsing expressions. scoped_ptr<ParseNode> BinaryOperator(scoped_ptr<ParseNode> left, Token token); scoped_ptr<ParseNode> IdentifierOrCall(scoped_ptr<ParseNode> left, Token token); scoped_ptr<ParseNode> Assignment(scoped_ptr<ParseNode> left, Token token); scoped_ptr<ParseNode> Subscript(scoped_ptr<ParseNode> left, Token token); // Helper to parse a comma separated list, optionally allowing trailing // commas (allowed in [] lists, not in function calls). scoped_ptr<ListNode> ParseList(Token::Type stop_before, bool allow_trailing_comma); scoped_ptr<ParseNode> ParseFile(); scoped_ptr<ParseNode> ParseStatement(); scoped_ptr<BlockNode> ParseBlock(); scoped_ptr<ParseNode> ParseCondition(); bool IsAssignment(const ParseNode* node) const; bool IsStatementBreak(Token::Type token_type) const; 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& cur_token() const { return tokens_[cur_]; } bool done() const { return at_end() || has_error(); } bool at_end() const { return cur_ >= tokens_.size(); } bool has_error() const { return err_->has_error(); } const std::vector<Token>& tokens_; static ParserHelper expressions_[Token::NUM_TYPES]; Err* err_; // Current index into the tokens. size_t cur_; FRIEND_TEST_ALL_PREFIXES(Parser, BinaryOp); FRIEND_TEST_ALL_PREFIXES(Parser, Block); FRIEND_TEST_ALL_PREFIXES(Parser, Condition); FRIEND_TEST_ALL_PREFIXES(Parser, Expression); FRIEND_TEST_ALL_PREFIXES(Parser, FunctionCall); FRIEND_TEST_ALL_PREFIXES(Parser, List); FRIEND_TEST_ALL_PREFIXES(Parser, ParenExpression); FRIEND_TEST_ALL_PREFIXES(Parser, UnaryOp); DISALLOW_COPY_AND_ASSIGN(Parser); }; #endif // TOOLS_GN_PARSER_H_