|  | // Copyright 2014 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_PARSE_TREE_H_ | 
|  | #define TOOLS_GN_PARSE_TREE_H_ | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/values.h" | 
|  | #include "tools/gn/err.h" | 
|  | #include "tools/gn/token.h" | 
|  | #include "tools/gn/value.h" | 
|  |  | 
|  | class AccessorNode; | 
|  | class BinaryOpNode; | 
|  | class BlockCommentNode; | 
|  | class BlockNode; | 
|  | class ConditionNode; | 
|  | class EndNode; | 
|  | class FunctionCallNode; | 
|  | class IdentifierNode; | 
|  | class ListNode; | 
|  | class LiteralNode; | 
|  | class Scope; | 
|  | class UnaryOpNode; | 
|  |  | 
|  | // Dictionary keys used for JSON-formatted tree dump. | 
|  | extern const char kJsonNodeChild[]; | 
|  | extern const char kJsonNodeType[]; | 
|  | extern const char kJsonNodeValue[]; | 
|  | extern const char kJsonBeforeComment[]; | 
|  | extern const char kJsonSuffixComment[]; | 
|  | extern const char kJsonAfterComment[]; | 
|  |  | 
|  | class Comments { | 
|  | public: | 
|  | Comments(); | 
|  | virtual ~Comments(); | 
|  |  | 
|  | const std::vector<Token>& before() const { return before_; } | 
|  | void append_before(Token c) { before_.push_back(c); } | 
|  | void clear_before() { before_.clear(); } | 
|  |  | 
|  | const std::vector<Token>& suffix() const { return suffix_; } | 
|  | void append_suffix(Token c) { suffix_.push_back(c); } | 
|  | // Reverse the order of the suffix comments. When walking the tree in | 
|  | // post-order we append suffix comments in reverse order, so this fixes them | 
|  | // up. | 
|  | void ReverseSuffix(); | 
|  |  | 
|  | const std::vector<Token>& after() const { return after_; } | 
|  | void append_after(Token c) { after_.push_back(c); } | 
|  |  | 
|  | private: | 
|  | // Whole line comments before the expression. | 
|  | std::vector<Token> before_; | 
|  |  | 
|  | // End-of-line comments after this expression. | 
|  | std::vector<Token> suffix_; | 
|  |  | 
|  | // For top-level expressions only, after_ lists whole-line comments | 
|  | // following the expression. | 
|  | std::vector<Token> after_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(Comments); | 
|  | }; | 
|  |  | 
|  | // ParseNode ------------------------------------------------------------------- | 
|  |  | 
|  | // A node in the AST. | 
|  | class ParseNode { | 
|  | public: | 
|  | ParseNode(); | 
|  | virtual ~ParseNode(); | 
|  |  | 
|  | virtual const AccessorNode* AsAccessor() const; | 
|  | virtual const BinaryOpNode* AsBinaryOp() const; | 
|  | virtual const BlockCommentNode* AsBlockComment() const; | 
|  | virtual const BlockNode* AsBlock() const; | 
|  | virtual const ConditionNode* AsConditionNode() const; | 
|  | virtual const EndNode* AsEnd() const; | 
|  | virtual const FunctionCallNode* AsFunctionCall() const; | 
|  | virtual const IdentifierNode* AsIdentifier() const; | 
|  | virtual const ListNode* AsList() const; | 
|  | virtual const LiteralNode* AsLiteral() const; | 
|  | virtual const UnaryOpNode* AsUnaryOp() const; | 
|  |  | 
|  | virtual Value Execute(Scope* scope, Err* err) const = 0; | 
|  |  | 
|  | virtual LocationRange GetRange() const = 0; | 
|  |  | 
|  | // Returns an error with the given messages and the range set to something | 
|  | // that indicates this node. | 
|  | virtual Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const = 0; | 
|  |  | 
|  | // Generates a representation of this node in base::Value, to be used for | 
|  | // exporting the tree as a JSON or formatted text with indents. | 
|  | virtual base::Value GetJSONNode() const = 0; | 
|  |  | 
|  | const Comments* comments() const { return comments_.get(); } | 
|  | Comments* comments_mutable(); | 
|  |  | 
|  | protected: | 
|  | // Helper functions for GetJSONNode. Creates and fills a Value object with | 
|  | // given type (and value). | 
|  | base::Value CreateJSONNode(const char* type) const; | 
|  | base::Value CreateJSONNode(const char* type, const base::StringPiece& value) | 
|  | const; | 
|  |  | 
|  | private: | 
|  | // Helper function for CreateJSONNode. | 
|  | void AddCommentsJSONNodes(base::Value* out_value) const; | 
|  |  | 
|  | std::unique_ptr<Comments> comments_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ParseNode); | 
|  | }; | 
|  |  | 
|  | // AccessorNode ---------------------------------------------------------------- | 
|  |  | 
|  | // Access an array or scope element. | 
|  | // | 
|  | // Currently, such values are only read-only. In that you can do: | 
|  | //   a = obj1.a | 
|  | //   b = obj2[0] | 
|  | // But not | 
|  | //   obj1.a = 5 | 
|  | //   obj2[0] = 6 | 
|  | // | 
|  | // In the current design where the dot operator is used only for templates, we | 
|  | // explicitly don't want to allow you to do "invoker.foo = 5", so if we added | 
|  | // support for accessors to be lvalues, we would also need to add some concept | 
|  | // of a constant scope. Supporting this would also add a lot of complications | 
|  | // to the operator= implementation, since some accessors might return values | 
|  | // in the const root scope that shouldn't be modified. Without a strong | 
|  | // use-case for this, it seems simpler to just disallow it. | 
|  | // | 
|  | // Additionally, the left-hand-side of the accessor must currently be an | 
|  | // identifier. So you can't do things like: | 
|  | //   function_call()[1] | 
|  | //   a = b.c.d | 
|  | // These are easier to implement if we needed them but given the very limited | 
|  | // use cases for this, it hasn't seemed worth the bother. | 
|  | class AccessorNode : public ParseNode { | 
|  | public: | 
|  | AccessorNode(); | 
|  | ~AccessorNode() override; | 
|  |  | 
|  | const AccessorNode* AsAccessor() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | // Base is the thing on the left of the [] or dot, currently always required | 
|  | // to be an identifier token. | 
|  | const Token& base() const { return base_; } | 
|  | void set_base(const Token& b) { base_ = b; } | 
|  |  | 
|  | // Index is the expression inside the []. Will be null if member is set. | 
|  | const ParseNode* index() const { return index_.get(); } | 
|  | void set_index(std::unique_ptr<ParseNode> i) { index_ = std::move(i); } | 
|  |  | 
|  | // The member is the identifier on the right hand side of the dot. Will be | 
|  | // null if the index is set. | 
|  | const IdentifierNode* member() const { return member_.get(); } | 
|  | void set_member(std::unique_ptr<IdentifierNode> i) { member_ = std::move(i); } | 
|  |  | 
|  | void SetNewLocation(int line_number); | 
|  |  | 
|  | // Evaluates the index for list accessor operations and range checks it | 
|  | // against the max length of the list. If the index is OK, sets | 
|  | // |*computed_index| and returns true. Otherwise sets the |*err| and returns | 
|  | // false. | 
|  | bool ComputeAndValidateListIndex(Scope* scope, | 
|  | size_t max_len, | 
|  | size_t* computed_index, | 
|  | Err* err) const; | 
|  |  | 
|  | private: | 
|  | Value ExecuteArrayAccess(Scope* scope, Err* err) const; | 
|  | Value ExecuteScopeAccess(Scope* scope, Err* err) const; | 
|  |  | 
|  | Token base_; | 
|  |  | 
|  | // Either index or member will be set according to what type of access this | 
|  | // is. | 
|  | std::unique_ptr<ParseNode> index_; | 
|  | std::unique_ptr<IdentifierNode> member_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(AccessorNode); | 
|  | }; | 
|  |  | 
|  | // BinaryOpNode ---------------------------------------------------------------- | 
|  |  | 
|  | class BinaryOpNode : public ParseNode { | 
|  | public: | 
|  | BinaryOpNode(); | 
|  | ~BinaryOpNode() override; | 
|  |  | 
|  | const BinaryOpNode* AsBinaryOp() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& op() const { return op_; } | 
|  | void set_op(const Token& t) { op_ = t; } | 
|  |  | 
|  | const ParseNode* left() const { return left_.get(); } | 
|  | void set_left(std::unique_ptr<ParseNode> left) { left_ = std::move(left); } | 
|  |  | 
|  | const ParseNode* right() const { return right_.get(); } | 
|  | void set_right(std::unique_ptr<ParseNode> right) { | 
|  | right_ = std::move(right); | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::unique_ptr<ParseNode> left_; | 
|  | Token op_; | 
|  | std::unique_ptr<ParseNode> right_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BinaryOpNode); | 
|  | }; | 
|  |  | 
|  | // BlockNode ------------------------------------------------------------------- | 
|  |  | 
|  | class BlockNode : public ParseNode { | 
|  | public: | 
|  | // How Execute manages the scopes and results. | 
|  | enum ResultMode { | 
|  | // Creates a new scope for the execution of this block and returns it as | 
|  | // a Value from Execute(). | 
|  | RETURNS_SCOPE, | 
|  |  | 
|  | // Executes in the context of the calling scope (variables set will go | 
|  | // into the invoking scope) and Execute will return an empty Value. | 
|  | DISCARDS_RESULT | 
|  | }; | 
|  |  | 
|  | BlockNode(ResultMode result_mode); | 
|  | ~BlockNode() override; | 
|  |  | 
|  | const BlockNode* AsBlock() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | void set_begin_token(const Token& t) { begin_token_ = t; } | 
|  | void set_end(std::unique_ptr<EndNode> e) { end_ = std::move(e); } | 
|  | const EndNode* End() const { return end_.get(); } | 
|  |  | 
|  | ResultMode result_mode() const { return result_mode_; } | 
|  |  | 
|  | const std::vector<std::unique_ptr<ParseNode>>& statements() const { | 
|  | return statements_; | 
|  | } | 
|  | void append_statement(std::unique_ptr<ParseNode> s) { | 
|  | statements_.push_back(std::move(s)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | const ResultMode result_mode_; | 
|  |  | 
|  | // Tokens corresponding to { and }, if any (may be NULL). The end is stored | 
|  | // in a custom parse node so that it can have comments hung off of it. | 
|  | Token begin_token_; | 
|  | std::unique_ptr<EndNode> end_; | 
|  |  | 
|  | std::vector<std::unique_ptr<ParseNode>> statements_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BlockNode); | 
|  | }; | 
|  |  | 
|  | // ConditionNode --------------------------------------------------------------- | 
|  |  | 
|  | class ConditionNode : public ParseNode { | 
|  | public: | 
|  | ConditionNode(); | 
|  | ~ConditionNode() override; | 
|  |  | 
|  | const ConditionNode* AsConditionNode() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | void set_if_token(const Token& token) { if_token_ = token; } | 
|  |  | 
|  | const ParseNode* condition() const { return condition_.get(); } | 
|  | void set_condition(std::unique_ptr<ParseNode> c) { | 
|  | condition_ = std::move(c); | 
|  | } | 
|  |  | 
|  | const BlockNode* if_true() const { return if_true_.get(); } | 
|  | void set_if_true(std::unique_ptr<BlockNode> t) { if_true_ = std::move(t); } | 
|  |  | 
|  | // This is either empty, a block (for the else clause), or another | 
|  | // condition. | 
|  | const ParseNode* if_false() const { return if_false_.get(); } | 
|  | void set_if_false(std::unique_ptr<ParseNode> f) { if_false_ = std::move(f); } | 
|  |  | 
|  | private: | 
|  | // Token corresponding to the "if" string. | 
|  | Token if_token_; | 
|  |  | 
|  | std::unique_ptr<ParseNode> condition_;  // Always non-null. | 
|  | std::unique_ptr<BlockNode> if_true_;    // Always non-null. | 
|  | std::unique_ptr<ParseNode> if_false_;   // May be null. | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ConditionNode); | 
|  | }; | 
|  |  | 
|  | // FunctionCallNode ------------------------------------------------------------ | 
|  |  | 
|  | class FunctionCallNode : public ParseNode { | 
|  | public: | 
|  | FunctionCallNode(); | 
|  | ~FunctionCallNode() override; | 
|  |  | 
|  | const FunctionCallNode* AsFunctionCall() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& function() const { return function_; } | 
|  | void set_function(Token t) { function_ = t; } | 
|  |  | 
|  | const ListNode* args() const { return args_.get(); } | 
|  | void set_args(std::unique_ptr<ListNode> a) { args_ = std::move(a); } | 
|  |  | 
|  | const BlockNode* block() const { return block_.get(); } | 
|  | void set_block(std::unique_ptr<BlockNode> b) { block_ = std::move(b); } | 
|  |  | 
|  | void SetNewLocation(int line_number); | 
|  |  | 
|  | private: | 
|  | Token function_; | 
|  | std::unique_ptr<ListNode> args_; | 
|  | std::unique_ptr<BlockNode> block_;  // May be null. | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(FunctionCallNode); | 
|  | }; | 
|  |  | 
|  | // IdentifierNode -------------------------------------------------------------- | 
|  |  | 
|  | class IdentifierNode : public ParseNode { | 
|  | public: | 
|  | IdentifierNode(); | 
|  | explicit IdentifierNode(const Token& token); | 
|  | ~IdentifierNode() override; | 
|  |  | 
|  | const IdentifierNode* AsIdentifier() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& value() const { return value_; } | 
|  | void set_value(const Token& t) { value_ = t; } | 
|  |  | 
|  | void SetNewLocation(int line_number); | 
|  |  | 
|  | private: | 
|  | Token value_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(IdentifierNode); | 
|  | }; | 
|  |  | 
|  | // ListNode -------------------------------------------------------------------- | 
|  |  | 
|  | class ListNode : public ParseNode { | 
|  | public: | 
|  | ListNode(); | 
|  | ~ListNode() override; | 
|  |  | 
|  | const ListNode* AsList() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | void set_begin_token(const Token& t) { begin_token_ = t; } | 
|  | const Token& Begin() const { return begin_token_; } | 
|  | void set_end(std::unique_ptr<EndNode> e) { end_ = std::move(e); } | 
|  | const EndNode* End() const { return end_.get(); } | 
|  |  | 
|  | void append_item(std::unique_ptr<ParseNode> s) { | 
|  | contents_.push_back(std::move(s)); | 
|  | } | 
|  | const std::vector<std::unique_ptr<const ParseNode>>& contents() const { | 
|  | return contents_; | 
|  | } | 
|  |  | 
|  | void SortAsStringsList(); | 
|  | void SortAsDepsList(); | 
|  |  | 
|  | // During formatting, do we want this list to always be multliline? This is | 
|  | // used to make assignments to deps, sources, etc. always be multiline lists, | 
|  | // rather than collapsed to a single line when they're one element. | 
|  | bool prefer_multiline() const { return prefer_multiline_; } | 
|  | void set_prefer_multiline(bool prefer_multiline) { | 
|  | prefer_multiline_ = prefer_multiline; | 
|  | } | 
|  |  | 
|  | struct SortRange { | 
|  | size_t begin; | 
|  | size_t end; | 
|  | SortRange(size_t begin, size_t end) : begin(begin), end(end) {} | 
|  | }; | 
|  | // Only public for testing. | 
|  | std::vector<SortRange> GetSortRanges() const; | 
|  |  | 
|  | private: | 
|  | template <typename Comparator> | 
|  | void SortList(Comparator comparator); | 
|  |  | 
|  | // Tokens corresponding to the [ and ]. The end token is stored in inside an | 
|  | // custom parse node so that it can have comments hung off of it. | 
|  | Token begin_token_; | 
|  | std::unique_ptr<EndNode> end_; | 
|  | bool prefer_multiline_; | 
|  |  | 
|  | std::vector<std::unique_ptr<const ParseNode>> contents_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ListNode); | 
|  | }; | 
|  |  | 
|  | // LiteralNode ----------------------------------------------------------------- | 
|  |  | 
|  | class LiteralNode : public ParseNode { | 
|  | public: | 
|  | LiteralNode(); | 
|  | explicit LiteralNode(const Token& token); | 
|  | ~LiteralNode() override; | 
|  |  | 
|  | const LiteralNode* AsLiteral() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& value() const { return value_; } | 
|  | void set_value(const Token& t) { value_ = t; } | 
|  |  | 
|  | void SetNewLocation(int line_number); | 
|  |  | 
|  | private: | 
|  | Token value_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(LiteralNode); | 
|  | }; | 
|  |  | 
|  | // UnaryOpNode ----------------------------------------------------------------- | 
|  |  | 
|  | class UnaryOpNode : public ParseNode { | 
|  | public: | 
|  | UnaryOpNode(); | 
|  | ~UnaryOpNode() override; | 
|  |  | 
|  | const UnaryOpNode* AsUnaryOp() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& op() const { return op_; } | 
|  | void set_op(const Token& t) { op_ = t; } | 
|  |  | 
|  | const ParseNode* operand() const { return operand_.get(); } | 
|  | void set_operand(std::unique_ptr<ParseNode> operand) { | 
|  | operand_ = std::move(operand); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Token op_; | 
|  | std::unique_ptr<ParseNode> operand_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(UnaryOpNode); | 
|  | }; | 
|  |  | 
|  | // BlockCommentNode ------------------------------------------------------------ | 
|  |  | 
|  | // This node type is only used for standalone comments (that is, those not | 
|  | // specifically attached to another syntax element. The most common of these | 
|  | // is a standard header block. This node contains only the last line of such | 
|  | // a comment block as the anchor, and other lines of the block comment are | 
|  | // hung off of it as Before comments, similar to other syntax elements. | 
|  | class BlockCommentNode : public ParseNode { | 
|  | public: | 
|  | BlockCommentNode(); | 
|  | ~BlockCommentNode() override; | 
|  |  | 
|  | const BlockCommentNode* AsBlockComment() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& comment() const { return comment_; } | 
|  | void set_comment(const Token& t) { comment_ = t; } | 
|  |  | 
|  | private: | 
|  | Token comment_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BlockCommentNode); | 
|  | }; | 
|  |  | 
|  | // EndNode --------------------------------------------------------------------- | 
|  |  | 
|  | // This node type is used as the end_ object for lists and blocks (rather than | 
|  | // just the end ']', '}', or ')' token). This is so that during formatting | 
|  | // traversal there is a node that appears at the end of the block to which | 
|  | // comments can be attached. | 
|  | class EndNode : public ParseNode { | 
|  | public: | 
|  | explicit EndNode(const Token& token); | 
|  | ~EndNode() override; | 
|  |  | 
|  | const EndNode* AsEnd() const override; | 
|  | Value Execute(Scope* scope, Err* err) const override; | 
|  | LocationRange GetRange() const override; | 
|  | Err MakeErrorDescribing( | 
|  | const std::string& msg, | 
|  | const std::string& help = std::string()) const override; | 
|  | base::Value GetJSONNode() const override; | 
|  |  | 
|  | const Token& value() const { return value_; } | 
|  | void set_value(const Token& t) { value_ = t; } | 
|  |  | 
|  | private: | 
|  | Token value_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(EndNode); | 
|  | }; | 
|  |  | 
|  | #endif  // TOOLS_GN_PARSE_TREE_H_ |