Commit f7e13e52 authored by scottmg's avatar scottmg Committed by Commit bot

gn format: fix comments at end of blocks

Fixes comments at the end of a block like:

  stuff() {
    sources = []
    # wee
  }

This is done by storing an EndNode (instead of just a Token) as the
end of Block and List nodes. This means there's a node in the tree
traversal for the trailing ], and gives a place to attach the comment.

Also collapses some of the expression output code to reuse Sequence.

R=brettw@chromium.org
BUG=348474

Review URL: https://codereview.chromium.org/607173002

Cr-Commit-Position: refs/heads/master@{#297226}
parent b5512bbf
...@@ -50,6 +50,7 @@ class Printer { ...@@ -50,6 +50,7 @@ class Printer {
kSequenceStyleFunctionCall, kSequenceStyleFunctionCall,
kSequenceStyleList, kSequenceStyleList,
kSequenceStyleBlock, kSequenceStyleBlock,
kSequenceStyleBracedBlock,
}; };
enum ExprStyle { enum ExprStyle {
...@@ -78,8 +79,13 @@ class Printer { ...@@ -78,8 +79,13 @@ class Printer {
// added to the output. // added to the output.
ExprStyle Expr(const ParseNode* root); ExprStyle Expr(const ParseNode* root);
// Format a list of values using the given style.
// |end| holds any trailing comments to be printed just before the closing
// bracket.
template <class PARSENODE> // Just for const covariance. template <class PARSENODE> // Just for const covariance.
void Sequence(SequenceStyle style, const std::vector<PARSENODE*>& list); void Sequence(SequenceStyle style,
const std::vector<PARSENODE*>& list,
const ParseNode* end);
std::string output_; // Output buffer. std::string output_; // Output buffer.
std::vector<Token> comments_; // Pending end-of-line comments. std::vector<Token> comments_; // Pending end-of-line comments.
...@@ -210,18 +216,14 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) { ...@@ -210,18 +216,14 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) {
Print(" "); Print(" ");
Expr(binop->right()); Expr(binop->right());
} else if (const BlockNode* block = root->AsBlock()) { } else if (const BlockNode* block = root->AsBlock()) {
Sequence(kSequenceStyleBlock, block->statements()); Sequence(kSequenceStyleBracedBlock, block->statements(), block->End());
} else if (const ConditionNode* condition = root->AsConditionNode()) { } else if (const ConditionNode* condition = root->AsConditionNode()) {
Print("if ("); Print("if (");
Expr(condition->condition()); Expr(condition->condition());
Print(") {"); Print(") ");
margin_ += kIndentSize; Sequence(kSequenceStyleBracedBlock,
Newline(); condition->if_true()->statements(),
Block(condition->if_true()); condition->if_true()->End());
margin_ -= kIndentSize;
Trim();
PrintMargin();
Print("}");
if (condition->if_false()) { if (condition->if_false()) {
Print(" else "); Print(" else ");
// If it's a block it's a bare 'else', otherwise it's an 'else if'. See // If it's a block it's a bare 'else', otherwise it's an 'else if'. See
...@@ -230,31 +232,24 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) { ...@@ -230,31 +232,24 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) {
if (is_else_if) { if (is_else_if) {
Expr(condition->if_false()); Expr(condition->if_false());
} else { } else {
Print("{"); Sequence(kSequenceStyleBracedBlock,
margin_ += kIndentSize; condition->if_false()->AsBlock()->statements(),
Newline(); condition->if_false()->AsBlock()->End());
Block(condition->if_false());
margin_ -= kIndentSize;
Trim();
PrintMargin();
Print("}");
} }
} }
} else if (const FunctionCallNode* func_call = root->AsFunctionCall()) { } else if (const FunctionCallNode* func_call = root->AsFunctionCall()) {
Print(func_call->function().value()); Print(func_call->function().value());
Sequence(kSequenceStyleFunctionCall, func_call->args()->contents()); Sequence(kSequenceStyleFunctionCall,
Print(" {"); func_call->args()->contents(),
margin_ += kIndentSize; func_call->args()->End());
Newline(); Print(" ");
Block(func_call->block()); Sequence(kSequenceStyleBracedBlock,
margin_ -= kIndentSize; func_call->block()->statements(),
Trim(); func_call->block()->End());
PrintMargin();
Print("}");
} else if (const IdentifierNode* identifier = root->AsIdentifier()) { } else if (const IdentifierNode* identifier = root->AsIdentifier()) {
Print(identifier->value().value()); Print(identifier->value().value());
} else if (const ListNode* list = root->AsList()) { } else if (const ListNode* list = root->AsList()) {
Sequence(kSequenceStyleList, list->contents()); Sequence(kSequenceStyleList, list->contents(), list->End());
} else if (const LiteralNode* literal = root->AsLiteral()) { } else if (const LiteralNode* literal = root->AsLiteral()) {
// TODO(scottmg): Quoting? // TODO(scottmg): Quoting?
Print(literal->value().value()); Print(literal->value().value());
...@@ -264,6 +259,8 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) { ...@@ -264,6 +259,8 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) {
} else if (const BlockCommentNode* block_comment = root->AsBlockComment()) { } else if (const BlockCommentNode* block_comment = root->AsBlockComment()) {
Print(block_comment->comment().value()); Print(block_comment->comment().value());
result = kExprStyleComment; result = kExprStyleComment;
} else if (const EndNode* end = root->AsEnd()) {
Print(end->value().value());
} else { } else {
CHECK(false) << "Unhandled case in Expr."; CHECK(false) << "Unhandled case in Expr.";
} }
...@@ -280,14 +277,20 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) { ...@@ -280,14 +277,20 @@ Printer::ExprStyle Printer::Expr(const ParseNode* root) {
template <class PARSENODE> template <class PARSENODE>
void Printer::Sequence(SequenceStyle style, void Printer::Sequence(SequenceStyle style,
const std::vector<PARSENODE*>& list) { const std::vector<PARSENODE*>& list,
const ParseNode* end) {
bool force_multiline = false; bool force_multiline = false;
if (style == kSequenceStyleFunctionCall) if (style == kSequenceStyleFunctionCall)
Print("("); Print("(");
else if (style == kSequenceStyleList) else if (style == kSequenceStyleList)
Print("["); Print("[");
else if (style == kSequenceStyleBracedBlock)
Print("{");
if (style == kSequenceStyleBlock || style == kSequenceStyleBracedBlock)
force_multiline = true;
if (style == kSequenceStyleBlock) if (end && end->comments() && !end->comments()->before().empty())
force_multiline = true; force_multiline = true;
// If there's before line comments, make sure we have a place to put them. // If there's before line comments, make sure we have a place to put them.
...@@ -302,7 +305,7 @@ void Printer::Sequence(SequenceStyle style, ...@@ -302,7 +305,7 @@ void Printer::Sequence(SequenceStyle style,
if (style != kSequenceStyleFunctionCall) if (style != kSequenceStyleFunctionCall)
Print(" "); Print(" ");
Expr(list[0]); Expr(list[0]);
CHECK(list[0]->comments()->after().empty()); CHECK(!list[0]->comments() || list[0]->comments()->after().empty());
if (style != kSequenceStyleFunctionCall) if (style != kSequenceStyleFunctionCall)
Print(" "); Print(" ");
} else { } else {
...@@ -311,16 +314,28 @@ void Printer::Sequence(SequenceStyle style, ...@@ -311,16 +314,28 @@ void Printer::Sequence(SequenceStyle style,
for (const auto& x : list) { for (const auto& x : list) {
Newline(); Newline();
ExprStyle expr_style = Expr(x); ExprStyle expr_style = Expr(x);
CHECK(x->comments()->after().empty()); CHECK(!x->comments() || x->comments()->after().empty());
if (i < list.size() - 1 || style == kSequenceStyleList) { if (i < list.size() - 1 || style == kSequenceStyleList) {
if (expr_style == kExprStyleRegular) if ((style == kSequenceStyleList || kSequenceStyleFunctionCall) &&
expr_style == kExprStyleRegular) {
Print(","); Print(",");
else } else {
Newline(); Newline();
}
} }
++i; ++i;
} }
// Trailing comments.
if (end->comments()) {
if (!list.empty())
Newline();
for (const auto& c : end->comments()->before()) {
Newline();
TrimAndPrintToken(c);
}
}
margin_ -= kIndentSize; margin_ -= kIndentSize;
Newline(); Newline();
} }
...@@ -329,6 +344,8 @@ void Printer::Sequence(SequenceStyle style, ...@@ -329,6 +344,8 @@ void Printer::Sequence(SequenceStyle style,
Print(")"); Print(")");
else if (style == kSequenceStyleList) else if (style == kSequenceStyleList)
Print("]"); Print("]");
else if (style == kSequenceStyleBracedBlock)
Print("}");
} }
} // namespace } // namespace
......
...@@ -24,7 +24,7 @@ bool FormatFileToString(const std::string& input_filename, ...@@ -24,7 +24,7 @@ bool FormatFileToString(const std::string& input_filename,
FILE_PATH_LITERAL(#n) \ FILE_PATH_LITERAL(#n) \
FILE_PATH_LITERAL(".golden")), \ FILE_PATH_LITERAL(".golden")), \
&expected)); \ &expected)); \
EXPECT_EQ(out, expected); \ EXPECT_EQ(expected, out); \
} }
// These are expanded out this way rather than a runtime loop so that // These are expanded out this way rather than a runtime loop so that
...@@ -43,3 +43,6 @@ FORMAT_TEST(011) ...@@ -43,3 +43,6 @@ FORMAT_TEST(011)
FORMAT_TEST(012) FORMAT_TEST(012)
FORMAT_TEST(013) FORMAT_TEST(013)
FORMAT_TEST(014) FORMAT_TEST(014)
FORMAT_TEST(015)
// TODO(scottmg): Requires precedence/parentheses FORMAT_TEST(016)
FORMAT_TEST(017)
if (is_win) {
sources = [ "a.cc" ]
# Some comment at end.
}
executable("win" # Suffix comment on arg.
# And a strangely positioned line comment for some reason
) {
defines = [ # Defines comment, suffix at end position.
]
deps = [
# Deps comment, should be forced multiline.
]
sources = [
"a.cc"
# End of single sources comment, should be forced multiline.
]
# End of block comment.
}
executable(
"win" # Suffix comment on arg.
# And a strangely positioned line comment for some reason
) {
defines = [] # Defines comment, suffix at end position.
deps = [
# Deps comment, should be forced multiline.
]
sources = [
"a.cc",
# End of single sources comment, should be forced multiline.
]
# End of block comment.
}
...@@ -40,14 +40,15 @@ ParseNode::~ParseNode() { ...@@ -40,14 +40,15 @@ ParseNode::~ParseNode() {
const AccessorNode* ParseNode::AsAccessor() const { return NULL; } const AccessorNode* ParseNode::AsAccessor() const { return NULL; }
const BinaryOpNode* ParseNode::AsBinaryOp() const { return NULL; } const BinaryOpNode* ParseNode::AsBinaryOp() const { return NULL; }
const BlockCommentNode* ParseNode::AsBlockComment() const { return NULL; }
const BlockNode* ParseNode::AsBlock() const { return NULL; } const BlockNode* ParseNode::AsBlock() const { return NULL; }
const ConditionNode* ParseNode::AsConditionNode() const { return NULL; } const ConditionNode* ParseNode::AsConditionNode() const { return NULL; }
const EndNode* ParseNode::AsEnd() const { return NULL; }
const FunctionCallNode* ParseNode::AsFunctionCall() const { return NULL; } const FunctionCallNode* ParseNode::AsFunctionCall() const { return NULL; }
const IdentifierNode* ParseNode::AsIdentifier() const { return NULL; } const IdentifierNode* ParseNode::AsIdentifier() const { return NULL; }
const ListNode* ParseNode::AsList() const { return NULL; } const ListNode* ParseNode::AsList() const { return NULL; }
const LiteralNode* ParseNode::AsLiteral() const { return NULL; } const LiteralNode* ParseNode::AsLiteral() const { return NULL; }
const UnaryOpNode* ParseNode::AsUnaryOp() const { return NULL; } const UnaryOpNode* ParseNode::AsUnaryOp() const { return NULL; }
const BlockCommentNode* ParseNode::AsBlockComment() const { return NULL; }
Comments* ParseNode::comments_mutable() { Comments* ParseNode::comments_mutable() {
if (!comments_) if (!comments_)
...@@ -263,8 +264,8 @@ Value BlockNode::Execute(Scope* containing_scope, Err* err) const { ...@@ -263,8 +264,8 @@ Value BlockNode::Execute(Scope* containing_scope, Err* err) const {
LocationRange BlockNode::GetRange() const { LocationRange BlockNode::GetRange() const {
if (begin_token_.type() != Token::INVALID && if (begin_token_.type() != Token::INVALID &&
end_token_.type() != Token::INVALID) { end_->value().type() != Token::INVALID) {
return begin_token_.range().Union(end_token_.range()); return begin_token_.range().Union(end_->value().range());
} else if (!statements_.empty()) { } else if (!statements_.empty()) {
return statements_[0]->GetRange().Union( return statements_[0]->GetRange().Union(
statements_[statements_.size() - 1]->GetRange()); statements_[statements_.size() - 1]->GetRange());
...@@ -282,6 +283,8 @@ void BlockNode::Print(std::ostream& out, int indent) const { ...@@ -282,6 +283,8 @@ void BlockNode::Print(std::ostream& out, int indent) const {
PrintComments(out, indent); PrintComments(out, indent);
for (size_t i = 0; i < statements_.size(); i++) for (size_t i = 0; i < statements_.size(); i++)
statements_[i]->Print(out, indent + 1); statements_[i]->Print(out, indent + 1);
if (end_ && end_->comments())
end_->Print(out, indent + 1);
} }
Value BlockNode::ExecuteBlockInScope(Scope* our_scope, Err* err) const { Value BlockNode::ExecuteBlockInScope(Scope* our_scope, Err* err) const {
...@@ -478,7 +481,8 @@ Value ListNode::Execute(Scope* scope, Err* err) const { ...@@ -478,7 +481,8 @@ Value ListNode::Execute(Scope* scope, Err* err) const {
} }
LocationRange ListNode::GetRange() const { LocationRange ListNode::GetRange() const {
return LocationRange(begin_token_.location(), end_token_.location()); return LocationRange(begin_token_.location(),
end_->value().location());
} }
Err ListNode::MakeErrorDescribing(const std::string& msg, Err ListNode::MakeErrorDescribing(const std::string& msg,
...@@ -491,6 +495,8 @@ void ListNode::Print(std::ostream& out, int indent) const { ...@@ -491,6 +495,8 @@ void ListNode::Print(std::ostream& out, int indent) const {
PrintComments(out, indent); PrintComments(out, indent);
for (size_t i = 0; i < contents_.size(); i++) for (size_t i = 0; i < contents_.size(); i++)
contents_[i]->Print(out, indent + 1); contents_[i]->Print(out, indent + 1);
if (end_ && end_->comments())
end_->Print(out, indent + 1);
} }
// LiteralNode ----------------------------------------------------------------- // LiteralNode -----------------------------------------------------------------
...@@ -610,3 +616,34 @@ void BlockCommentNode::Print(std::ostream& out, int indent) const { ...@@ -610,3 +616,34 @@ void BlockCommentNode::Print(std::ostream& out, int indent) const {
out << IndentFor(indent) << "BLOCK_COMMENT(" << comment_.value() << ")\n"; out << IndentFor(indent) << "BLOCK_COMMENT(" << comment_.value() << ")\n";
PrintComments(out, indent); PrintComments(out, indent);
} }
// EndNode ---------------------------------------------------------------------
EndNode::EndNode(const Token& token) : value_(token) {
}
EndNode::~EndNode() {
}
const EndNode* EndNode::AsEnd() const {
return this;
}
Value EndNode::Execute(Scope* scope, Err* err) const {
return Value();
}
LocationRange EndNode::GetRange() const {
return value_.range();
}
Err EndNode::MakeErrorDescribing(const std::string& msg,
const std::string& help) const {
return Err(value_, msg, help);
}
void EndNode::Print(std::ostream& out, int indent) const {
out << IndentFor(indent) << "END(" << value_.value() << ")\n";
PrintComments(out, indent);
}
...@@ -16,15 +16,16 @@ ...@@ -16,15 +16,16 @@
class AccessorNode; class AccessorNode;
class BinaryOpNode; class BinaryOpNode;
class BlockCommentNode;
class BlockNode; class BlockNode;
class ConditionNode; class ConditionNode;
class EndNode;
class FunctionCallNode; class FunctionCallNode;
class IdentifierNode; class IdentifierNode;
class ListNode; class ListNode;
class LiteralNode; class LiteralNode;
class Scope; class Scope;
class UnaryOpNode; class UnaryOpNode;
class BlockCommentNode;
class Comments { class Comments {
public: public:
...@@ -74,14 +75,15 @@ class ParseNode { ...@@ -74,14 +75,15 @@ class ParseNode {
virtual const AccessorNode* AsAccessor() const; virtual const AccessorNode* AsAccessor() const;
virtual const BinaryOpNode* AsBinaryOp() const; virtual const BinaryOpNode* AsBinaryOp() const;
virtual const BlockCommentNode* AsBlockComment() const;
virtual const BlockNode* AsBlock() const; virtual const BlockNode* AsBlock() const;
virtual const ConditionNode* AsConditionNode() const; virtual const ConditionNode* AsConditionNode() const;
virtual const EndNode* AsEnd() const;
virtual const FunctionCallNode* AsFunctionCall() const; virtual const FunctionCallNode* AsFunctionCall() const;
virtual const IdentifierNode* AsIdentifier() const; virtual const IdentifierNode* AsIdentifier() const;
virtual const ListNode* AsList() const; virtual const ListNode* AsList() const;
virtual const LiteralNode* AsLiteral() const; virtual const LiteralNode* AsLiteral() const;
virtual const UnaryOpNode* AsUnaryOp() const; virtual const UnaryOpNode* AsUnaryOp() const;
virtual const BlockCommentNode* AsBlockComment() const;
virtual Value Execute(Scope* scope, Err* err) const = 0; virtual Value Execute(Scope* scope, Err* err) const = 0;
...@@ -226,7 +228,8 @@ class BlockNode : public ParseNode { ...@@ -226,7 +228,8 @@ class BlockNode : public ParseNode {
virtual void Print(std::ostream& out, int indent) const OVERRIDE; virtual void Print(std::ostream& out, int indent) const OVERRIDE;
void set_begin_token(const Token& t) { begin_token_ = t; } void set_begin_token(const Token& t) { begin_token_ = t; }
void set_end_token(const Token& t) { end_token_ = t; } void set_end(scoped_ptr<EndNode> e) { end_ = e.Pass(); }
const EndNode* End() const { return end_.get(); }
const std::vector<ParseNode*>& statements() const { return statements_; } const std::vector<ParseNode*>& statements() const { return statements_; }
void append_statement(scoped_ptr<ParseNode> s) { void append_statement(scoped_ptr<ParseNode> s) {
...@@ -239,9 +242,10 @@ class BlockNode : public ParseNode { ...@@ -239,9 +242,10 @@ class BlockNode : public ParseNode {
private: private:
bool has_scope_; bool has_scope_;
// Tokens corresponding to { and }, if any (may be NULL). // 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_; Token begin_token_;
Token end_token_; scoped_ptr<EndNode> end_;
// Owning pointers, use unique_ptr when we can use C++11. // Owning pointers, use unique_ptr when we can use C++11.
std::vector<ParseNode*> statements_; std::vector<ParseNode*> statements_;
...@@ -367,7 +371,8 @@ class ListNode : public ParseNode { ...@@ -367,7 +371,8 @@ class ListNode : public ParseNode {
virtual void Print(std::ostream& out, int indent) const OVERRIDE; virtual void Print(std::ostream& out, int indent) const OVERRIDE;
void set_begin_token(const Token& t) { begin_token_ = t; } void set_begin_token(const Token& t) { begin_token_ = t; }
void set_end_token(const Token& t) { end_token_ = t; } void set_end(scoped_ptr<EndNode> e) { end_ = e.Pass(); }
const EndNode* End() const { return end_.get(); }
void append_item(scoped_ptr<ParseNode> s) { void append_item(scoped_ptr<ParseNode> s) {
contents_.push_back(s.release()); contents_.push_back(s.release());
...@@ -375,9 +380,10 @@ class ListNode : public ParseNode { ...@@ -375,9 +380,10 @@ class ListNode : public ParseNode {
const std::vector<const ParseNode*>& contents() const { return contents_; } const std::vector<const ParseNode*>& contents() const { return contents_; }
private: private:
// Tokens corresponding to the [ and ]. // 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_; Token begin_token_;
Token end_token_; scoped_ptr<EndNode> end_;
// Owning pointers, use unique_ptr when we can use C++11. // Owning pointers, use unique_ptr when we can use C++11.
std::vector<const ParseNode*> contents_; std::vector<const ParseNode*> contents_;
...@@ -469,4 +475,32 @@ class BlockCommentNode : public ParseNode { ...@@ -469,4 +475,32 @@ class BlockCommentNode : public ParseNode {
DISALLOW_COPY_AND_ASSIGN(BlockCommentNode); 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:
EndNode(const Token& token);
virtual ~EndNode();
virtual const EndNode* AsEnd() const OVERRIDE;
virtual Value Execute(Scope* scope, Err* err) const OVERRIDE;
virtual LocationRange GetRange() const OVERRIDE;
virtual Err MakeErrorDescribing(
const std::string& msg,
const std::string& help = std::string()) const OVERRIDE;
virtual void Print(std::ostream& out, int indent) 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_ #endif // TOOLS_GN_PARSE_TREE_H_
...@@ -285,7 +285,7 @@ scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left, ...@@ -285,7 +285,7 @@ scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left,
Token token) { Token token) {
scoped_ptr<ListNode> list(new ListNode); scoped_ptr<ListNode> list(new ListNode);
list->set_begin_token(token); list->set_begin_token(token);
list->set_end_token(token); list->set_end(make_scoped_ptr(new EndNode(token)));
scoped_ptr<BlockNode> block; scoped_ptr<BlockNode> block;
bool has_arg = false; bool has_arg = false;
if (LookAhead(Token::LEFT_PAREN)) { if (LookAhead(Token::LEFT_PAREN)) {
...@@ -418,7 +418,7 @@ scoped_ptr<ListNode> Parser::ParseList(Token start_token, ...@@ -418,7 +418,7 @@ scoped_ptr<ListNode> Parser::ParseList(Token start_token,
*err_ = Err(cur_token(), "Trailing comma"); *err_ = Err(cur_token(), "Trailing comma");
return scoped_ptr<ListNode>(); return scoped_ptr<ListNode>();
} }
list->set_end_token(cur_token()); list->set_end(make_scoped_ptr(new EndNode(cur_token())));
return list.Pass(); return list.Pass();
} }
...@@ -479,7 +479,7 @@ scoped_ptr<BlockNode> Parser::ParseBlock() { ...@@ -479,7 +479,7 @@ scoped_ptr<BlockNode> Parser::ParseBlock() {
for (;;) { for (;;) {
if (LookAhead(Token::RIGHT_BRACE)) { if (LookAhead(Token::RIGHT_BRACE)) {
block->set_end_token(Consume()); block->set_end(make_scoped_ptr(new EndNode(Consume())));
break; break;
} }
...@@ -526,6 +526,7 @@ void Parser::TraverseOrder(const ParseNode* root, ...@@ -526,6 +526,7 @@ void Parser::TraverseOrder(const ParseNode* root,
++i) { ++i) {
TraverseOrder(*i, pre, post); TraverseOrder(*i, pre, post);
} }
TraverseOrder(block->End(), pre, post);
} else if (const ConditionNode* condition = root->AsConditionNode()) { } else if (const ConditionNode* condition = root->AsConditionNode()) {
TraverseOrder(condition->condition(), pre, post); TraverseOrder(condition->condition(), pre, post);
TraverseOrder(condition->if_true(), pre, post); TraverseOrder(condition->if_true(), pre, post);
...@@ -542,12 +543,15 @@ void Parser::TraverseOrder(const ParseNode* root, ...@@ -542,12 +543,15 @@ void Parser::TraverseOrder(const ParseNode* root,
++i) { ++i) {
TraverseOrder(*i, pre, post); TraverseOrder(*i, pre, post);
} }
TraverseOrder(list->End(), pre, post);
} else if (root->AsLiteral()) { } else if (root->AsLiteral()) {
// Nothing. // Nothing.
} else if (const UnaryOpNode* unaryop = root->AsUnaryOp()) { } else if (const UnaryOpNode* unaryop = root->AsUnaryOp()) {
TraverseOrder(unaryop->operand(), pre, post); TraverseOrder(unaryop->operand(), pre, post);
} else if (root->AsBlockComment()) { } else if (root->AsBlockComment()) {
// Nothing. // Nothing.
} else if (root->AsEnd()) {
// Nothing.
} else { } else {
CHECK(false) << "Unhandled case in TraverseOrder."; CHECK(false) << "Unhandled case in TraverseOrder.";
} }
...@@ -592,7 +596,7 @@ void Parser::AssignComments(ParseNode* file) { ...@@ -592,7 +596,7 @@ void Parser::AssignComments(ParseNode* file) {
++i) { ++i) {
// Don't assign suffix comments to the function call or list, but instead // Don't assign suffix comments to the function call or list, but instead
// to the last thing inside. // to the last thing inside.
if ((*i)->AsFunctionCall() || (*i)->AsList()) if ((*i)->AsFunctionCall() || (*i)->AsList() || (*i)->AsEnd())
continue; continue;
const Location& start = (*i)->GetRange().begin(); const Location& start = (*i)->GetRange().begin();
...@@ -620,6 +624,7 @@ void Parser::AssignComments(ParseNode* file) { ...@@ -620,6 +624,7 @@ void Parser::AssignComments(ParseNode* file) {
// Suffix comments were assigned in reverse, so if there were multiple on // Suffix comments were assigned in reverse, so if there were multiple on
// the same node, they need to be reversed. // the same node, they need to be reversed.
const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix(); if ((*i)->comments() && !(*i)->comments()->suffix().empty())
const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix();
} }
} }
...@@ -633,6 +633,41 @@ TEST(Parser, CommentsConnectedInList) { ...@@ -633,6 +633,41 @@ TEST(Parser, CommentsConnectedInList) {
DoParserPrintTest(input, expected); DoParserPrintTest(input, expected);
} }
TEST(Parser, CommentsAtEndOfBlock) {
const char* input =
"if (is_win) {\n"
" sources = [\"a.cc\"]\n"
" # Some comment at end.\n"
"}\n";
const char* expected =
"BLOCK\n"
" CONDITION\n"
" IDENTIFIER(is_win)\n"
" BLOCK\n"
" BINARY(=)\n"
" IDENTIFIER(sources)\n"
" LIST\n"
" LITERAL(\"a.cc\")\n"
" END(})\n"
" +BEFORE_COMMENT(\"# Some comment at end.\")\n";
DoParserPrintTest(input, expected);
}
// TODO(scottmg): I could be convinced this is incorrect. It's not clear to me
// which thing this comment is intended to be attached to.
TEST(Parser, CommentsEndOfBlockSingleLine) {
const char* input =
"defines = [ # EOL defines.\n"
"]\n";
const char* expected =
"BLOCK\n"
" BINARY(=)\n"
" IDENTIFIER(defines)\n"
" +SUFFIX_COMMENT(\"# EOL defines.\")\n"
" LIST\n";
DoParserPrintTest(input, expected);
}
TEST(Parser, HangingIf) { TEST(Parser, HangingIf) {
DoParserErrorTest("if", 1, 1); DoParserErrorTest("if", 1, 1);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment