| // 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 <stddef.h> |
| |
| #include <map> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/gtest_prod_util.h" |
| #include "gn/err.h" |
| #include "gn/parse_tree.h" |
| |
| extern const char kGrammar_Help[]; |
| |
| struct ParserHelper; |
| |
| // 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 std::unique_ptr<ParseNode> Parse(const std::vector<Token>& tokens, |
| Err* err); |
| |
| // Alternative to parsing that assumes the input is an expression. |
| static std::unique_ptr<ParseNode> ParseExpression( |
| const std::vector<Token>& tokens, |
| Err* err); |
| |
| // Alternative to parsing that assumes the input is a literal value. |
| static std::unique_ptr<ParseNode> ParseValue(const std::vector<Token>& tokens, |
| Err* err); |
| |
| private: |
| // Vector must be valid for lifetime of call. |
| Parser(const std::vector<Token>& tokens, Err* err); |
| ~Parser(); |
| |
| std::unique_ptr<ParseNode> ParseExpression(); |
| |
| // Parses an expression with the given precedence or higher. |
| std::unique_ptr<ParseNode> ParseExpression(int precedence); |
| |
| // |PrefixFunc|s used in parsing expressions. |
| 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, |
| const Token& token); |
| std::unique_ptr<ParseNode> IdentifierOrCall(std::unique_ptr<ParseNode> left, |
| const Token& token); |
| std::unique_ptr<ParseNode> Assignment(std::unique_ptr<ParseNode> left, |
| const Token& token); |
| std::unique_ptr<ParseNode> Subscript(std::unique_ptr<ParseNode> left, |
| const Token& token); |
| std::unique_ptr<ParseNode> DotOperator(std::unique_ptr<ParseNode> left, |
| 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(const Token& start_token, |
| Token::Type stop_before, |
| bool allow_trailing_comma); |
| |
| std::unique_ptr<ParseNode> ParseFile(); |
| 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(const Token& begin_brace, |
| BlockNode::ResultMode result_mode); |
| std::unique_ptr<ParseNode> ParseCondition(); |
| |
| // Generates a pre- and post-order traversal of the tree. |
| void TraverseOrder(const ParseNode* root, |
| std::vector<const ParseNode*>* pre, |
| std::vector<const ParseNode*>* post); |
| |
| // Attach comments to nearby syntax. |
| void AssignComments(ParseNode* file); |
| |
| bool IsAssignment(const ParseNode* node) const; |
| bool IsStatementBreak(Token::Type token_type) const; |
| |
| bool LookAhead(Token::Type type); |
| bool Match(Token::Type type); |
| 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_]; } |
| |
| const Token& cur_or_last_token() const { |
| return at_end() ? tokens_[tokens_.size() - 1] : cur_token(); |
| } |
| |
| bool done() const { return at_end() || has_error(); } |
| bool at_end() const { return cur_ >= tokens_.size(); } |
| bool has_error() const { return err_->has_error(); } |
| |
| std::vector<Token> tokens_; |
| std::vector<Token> line_comment_tokens_; |
| std::vector<Token> suffix_comment_tokens_; |
| |
| static ParserHelper expressions_[Token::NUM_TYPES]; |
| |
| Token invalid_token_; |
| 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); |
| |
| Parser(const Parser&) = delete; |
| Parser& operator=(const Parser&) = delete; |
| }; |
| |
| using PrefixFunc = std::unique_ptr<ParseNode> (Parser::*)(const Token& token); |
| using InfixFunc = std::unique_ptr<ParseNode> ( |
| Parser::*)(std::unique_ptr<ParseNode> left, const Token& token); |
| |
| struct ParserHelper { |
| PrefixFunc prefix; |
| InfixFunc infix; |
| |
| // Used only for infix operators. |
| int precedence; |
| }; |
| |
| // Renders parse subtree as a formatted text, indenting by the given number of |
| // spaces. |
| void RenderToText(const base::Value& node, |
| int indent_level, |
| std::ostringstream& os); |
| |
| #endif // TOOLS_GN_PARSER_H_ |