Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: tools/gn/parser.cc

Issue 2187523003: Allow creation and modification of scopes in GN. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/parser.h ('k') | tools/gn/parser_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/gn/parser.h" 5 #include "tools/gn/parser.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "tools/gn/functions.h" 11 #include "tools/gn/functions.h"
12 #include "tools/gn/operators.h" 12 #include "tools/gn/operators.h"
13 #include "tools/gn/token.h" 13 #include "tools/gn/token.h"
14 14
15 const char kGrammar_Help[] = 15 const char kGrammar_Help[] =
16 "GN build language grammar\n" 16 "Language and grammar for GN build files\n"
17 "\n" 17 "\n"
18 "Tokens\n" 18 "Tokens\n"
19 "\n" 19 "\n"
20 " GN build files are read as sequences of tokens. While splitting the\n" 20 " GN build files are read as sequences of tokens. While splitting the\n"
21 " file into tokens, the next token is the longest sequence of characters\n" 21 " file into tokens, the next token is the longest sequence of characters\n"
22 " that form a valid token.\n" 22 " that form a valid token.\n"
23 "\n" 23 "\n"
24 "White space and comments\n" 24 "White space and comments\n"
25 "\n" 25 "\n"
26 " White space is comprised of spaces (U+0020), horizontal tabs (U+0009),\n" 26 " White space is comprised of spaces (U+0020), horizontal tabs (U+0009),\n"
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 "\n" 72 "\n"
73 " \\\" U+0022 quotation mark\n" 73 " \\\" U+0022 quotation mark\n"
74 " \\$ U+0024 dollar sign\n" 74 " \\$ U+0024 dollar sign\n"
75 " \\\\ U+005C backslash\n" 75 " \\\\ U+005C backslash\n"
76 "\n" 76 "\n"
77 " All other backslashes represent themselves.\n" 77 " All other backslashes represent themselves.\n"
78 "\n" 78 "\n"
79 " To insert an arbitrary byte value, use $0xFF. For example, to\n" 79 " To insert an arbitrary byte value, use $0xFF. For example, to\n"
80 " insert a newline character: \"Line one$0x0ALine two\".\n" 80 " insert a newline character: \"Line one$0x0ALine two\".\n"
81 "\n" 81 "\n"
82 " An expansion will evaluate the variable following the '$' and insert\n"
83 " a stringified version of it into the result. For example, to concat\n"
84 " two path components with a slash separating them:\n"
85 " \"$var_one/$var_two\"\n"
86 " Use the \"${var_one}\" format to be explicitly deliniate the variable\n"
87 " for otherwise-ambiguous cases.\n"
88 "\n"
82 "Punctuation\n" 89 "Punctuation\n"
83 "\n" 90 "\n"
84 " The following character sequences represent punctuation:\n" 91 " The following character sequences represent punctuation:\n"
85 "\n" 92 "\n"
86 " + += == != ( )\n" 93 " + += == != ( )\n"
87 " - -= < <= [ ]\n" 94 " - -= < <= [ ]\n"
88 " ! = > >= { }\n" 95 " ! = > >= { }\n"
89 " && || . ,\n" 96 " && || . ,\n"
90 "\n" 97 "\n"
91 "Grammar\n" 98 "Grammar\n"
92 "\n" 99 "\n"
93 " The input tokens form a syntax tree following a context-free grammar:\n" 100 " The input tokens form a syntax tree following a context-free grammar:\n"
94 "\n" 101 "\n"
95 " File = StatementList .\n" 102 " File = StatementList .\n"
96 "\n" 103 "\n"
97 " Statement = Assignment | Call | Condition .\n" 104 " Statement = Assignment | Call | Condition .\n"
98 " Assignment = identifier AssignOp Expr .\n" 105 " LValue = identifier | ArrayAccess | ScopeAccess .\n"
106 " Assignment = LValue AssignOp Expr .\n"
99 " Call = identifier \"(\" [ ExprList ] \")\" [ Block ] .\n" 107 " Call = identifier \"(\" [ ExprList ] \")\" [ Block ] .\n"
100 " Condition = \"if\" \"(\" Expr \")\" Block\n" 108 " Condition = \"if\" \"(\" Expr \")\" Block\n"
101 " [ \"else\" ( Condition | Block ) ] .\n" 109 " [ \"else\" ( Condition | Block ) ] .\n"
102 " Block = \"{\" StatementList \"}\" .\n" 110 " Block = \"{\" StatementList \"}\" .\n"
103 " StatementList = { Statement } .\n" 111 " StatementList = { Statement } .\n"
104 "\n" 112 "\n"
105 " ArrayAccess = identifier \"[\" { identifier | integer } \"]\" .\n" 113 " ArrayAccess = identifier \"[\" Expr \"]\" .\n"
106 " ScopeAccess = identifier \".\" identifier .\n" 114 " ScopeAccess = identifier \".\" identifier .\n"
107 " Expr = UnaryExpr | Expr BinaryOp Expr .\n" 115 " Expr = UnaryExpr | Expr BinaryOp Expr .\n"
108 " UnaryExpr = PrimaryExpr | UnaryOp UnaryExpr .\n" 116 " UnaryExpr = PrimaryExpr | UnaryOp UnaryExpr .\n"
109 " PrimaryExpr = identifier | integer | string | Call\n" 117 " PrimaryExpr = identifier | integer | string | Call\n"
110 " | ArrayAccess | ScopeAccess\n" 118 " | ArrayAccess | ScopeAccess | Block\n"
111 " | \"(\" Expr \")\"\n" 119 " | \"(\" Expr \")\"\n"
112 " | \"[\" [ ExprList [ \",\" ] ] \"]\" .\n" 120 " | \"[\" [ ExprList [ \",\" ] ] \"]\" .\n"
113 " ExprList = Expr { \",\" Expr } .\n" 121 " ExprList = Expr { \",\" Expr } .\n"
114 "\n" 122 "\n"
115 " AssignOp = \"=\" | \"+=\" | \"-=\" .\n" 123 " AssignOp = \"=\" | \"+=\" | \"-=\" .\n"
116 " UnaryOp = \"!\" .\n" 124 " UnaryOp = \"!\" .\n"
117 " BinaryOp = \"+\" | \"-\" // highest priority\n" 125 " BinaryOp = \"+\" | \"-\" // highest priority\n"
118 " | \"<\" | \"<=\" | \">\" | \">=\"\n" 126 " | \"<\" | \"<=\" | \">\" | \">=\"\n"
119 " | \"==\" | \"!=\"\n" 127 " | \"==\" | \"!=\"\n"
120 " | \"&&\"\n" 128 " | \"&&\"\n"
121 " | \"||\" . // lowest priority\n" 129 " | \"||\" . // lowest priority\n"
122 "\n" 130 "\n"
123 " All binary operators are left-associative.\n"; 131 " All binary operators are left-associative.\n"
132 "\n"
133 "Types\n"
134 "\n"
135 " The GN language is dynamically typed. The following types are used:\n"
136 "\n"
137 " - Boolean: Uses the keywords \"true\" and \"false\". There is no\n"
138 " implicit conversion between booleans and integers.\n"
139 "\n"
140 " - Integers: All numbers in GN are signed 64-bit integers.\n"
141 "\n"
142 " - Strings: Strings are 8-bit with no enforced encoding. When a string\n"
143 " is used to interact with other systems with particular encodings\n"
144 " (like the Windows and Mac filesystems) it is assumed to be UTF-8.\n"
145 " See \"String literals\" above for more.\n"
146 "\n"
147 " - Lists: Lists are arbitrary-length ordered lists of values. See\n"
148 " \"Lists\" below for more.\n"
149 "\n"
150 " - Scopes: Scopes are like dictionaries that use variable names for\n"
151 " keys. See \"Scopes\" below for more.\n"
152 "\n"
153 "Lists\n"
154 "\n"
155 " Lists are created with [] and using commas to separate items:\n"
156 "\n"
157 " mylist = [ 0, 1, 2, \"some string\" ]\n"
158 "\n"
159 " A comma after the last item is optional. Lists are dereferenced using\n"
160 " 0-based indexing:\n"
161 "\n"
162 " mylist[0] += 1\n"
163 " var = mylist[2]\n"
164 "\n"
165 " Lists can be concatenated using the '+' and '+=' operators. Bare\n"
166 " values can not be concatenated with lists, to add a single item,\n"
167 " it must be put into a list of length one.\n"
168 "\n"
169 " Items can be removed from lists using the '-' and '-=' operators.\n"
170 " This will remove all occurrences of every item in the right-hand list\n"
171 " from the left-hand list. It is an error to remove an item not in the\n"
172 " list. This is to prevent common typos and to detect dead code that\n"
173 " is removing things that no longer apply.\n"
174 "\n"
175 " It is an error to use '=' to replace a nonempty list with another\n"
176 " nonempty list. This is to prevent accidentally overwriting data\n"
177 " when in most cases '+=' was intended. To overwrite a list on purpose,\n"
178 " first assign it to the empty list:\n"
179 "\n"
180 " mylist = []\n"
181 " mylist = otherlist\n"
182 "\n"
183 " When assigning to a list named 'sources' using '=' or '+=', list\n"
184 " items may be automatically filtered out.\n"
185 " See \"gn help set_sources_assignment_filter\" for more.\n"
186 "\n"
187 "Scopes\n"
188 "\n"
189 " All execution happens in the context of a scope which holds the\n"
190 " current state (like variables). With the exception of loops and\n"
191 " conditions, '{' introduces a new scope that has a parent reference to\n"
192 " the old scope.\n"
193 "\n"
194 " Variable reads recursively search all nested scopes until the\n"
195 " variable is found or there are no more scopes. Variable writes always\n"
196 " go into the current scope. This means that after the closing '}'\n"
197 " (again excepting loops and conditions), all local variables will be\n"
198 " restored to the previous values. This also means that \"foo = foo\"\n"
199 " can do useful work by copying a variable into the current scope that\n"
200 " was defined in a containing scope.\n"
201 "\n"
202 " Scopes can also be assigned to variables. Such scopes can be created\n"
203 " by functions like exec_script, when invoking a template (the template\n"
204 " code refers to the variables set by the invoking code by the\n"
205 " implicitly-created \"invoker\" scope), or explicitly like:\n"
206 "\n"
207 " empty_scope = {}\n"
208 " myvalues = {\n"
209 " foo = 21\n"
210 " bar = \"something\"\n"
211 " }\n"
212 "\n"
213 " Inside such a scope definition can be any GN code including\n"
214 " conditionals and function calls. After the close of the scope, it will\n"
215 " contain all variables explicitly set by the code contained inside it.\n"
216 " After this, the values can be read, modified, or added to:\n"
217 "\n"
218 " myvalues.foo += 2\n"
219 " empty_scope.new_thing = [ 1, 2, 3 ]\n";
124 220
125 enum Precedence { 221 enum Precedence {
126 PRECEDENCE_ASSIGNMENT = 1, // Lowest precedence. 222 PRECEDENCE_ASSIGNMENT = 1, // Lowest precedence.
127 PRECEDENCE_OR = 2, 223 PRECEDENCE_OR = 2,
128 PRECEDENCE_AND = 3, 224 PRECEDENCE_AND = 3,
129 PRECEDENCE_EQUALITY = 4, 225 PRECEDENCE_EQUALITY = 4,
130 PRECEDENCE_RELATION = 5, 226 PRECEDENCE_RELATION = 5,
131 PRECEDENCE_SUM = 6, 227 PRECEDENCE_SUM = 6,
132 PRECEDENCE_PREFIX = 7, 228 PRECEDENCE_PREFIX = 7,
133 PRECEDENCE_CALL = 8, 229 PRECEDENCE_CALL = 8,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 {nullptr, &Parser::BinaryOperator, PRECEDENCE_RELATION}, // LESS_THAN 261 {nullptr, &Parser::BinaryOperator, PRECEDENCE_RELATION}, // LESS_THAN
166 {nullptr, &Parser::BinaryOperator, PRECEDENCE_RELATION}, // GREATER_THAN 262 {nullptr, &Parser::BinaryOperator, PRECEDENCE_RELATION}, // GREATER_THAN
167 {nullptr, &Parser::BinaryOperator, PRECEDENCE_AND}, // BOOLEAN_AND 263 {nullptr, &Parser::BinaryOperator, PRECEDENCE_AND}, // BOOLEAN_AND
168 {nullptr, &Parser::BinaryOperator, PRECEDENCE_OR}, // BOOLEAN_OR 264 {nullptr, &Parser::BinaryOperator, PRECEDENCE_OR}, // BOOLEAN_OR
169 {&Parser::Not, nullptr, -1}, // BANG 265 {&Parser::Not, nullptr, -1}, // BANG
170 {nullptr, &Parser::DotOperator, PRECEDENCE_DOT}, // DOT 266 {nullptr, &Parser::DotOperator, PRECEDENCE_DOT}, // DOT
171 {&Parser::Group, nullptr, -1}, // LEFT_PAREN 267 {&Parser::Group, nullptr, -1}, // LEFT_PAREN
172 {nullptr, nullptr, -1}, // RIGHT_PAREN 268 {nullptr, nullptr, -1}, // RIGHT_PAREN
173 {&Parser::List, &Parser::Subscript, PRECEDENCE_CALL}, // LEFT_BRACKET 269 {&Parser::List, &Parser::Subscript, PRECEDENCE_CALL}, // LEFT_BRACKET
174 {nullptr, nullptr, -1}, // RIGHT_BRACKET 270 {nullptr, nullptr, -1}, // RIGHT_BRACKET
175 {nullptr, nullptr, -1}, // LEFT_BRACE 271 {&Parser::Block, nullptr, -1}, // LEFT_BRACE
176 {nullptr, nullptr, -1}, // RIGHT_BRACE 272 {nullptr, nullptr, -1}, // RIGHT_BRACE
177 {nullptr, nullptr, -1}, // IF 273 {nullptr, nullptr, -1}, // IF
178 {nullptr, nullptr, -1}, // ELSE 274 {nullptr, nullptr, -1}, // ELSE
179 {&Parser::Name, &Parser::IdentifierOrCall, PRECEDENCE_CALL}, // IDENTIFIER 275 {&Parser::Name, &Parser::IdentifierOrCall, PRECEDENCE_CALL}, // IDENTIFIER
180 {nullptr, nullptr, -1}, // COMMA 276 {nullptr, nullptr, -1}, // COMMA
181 {nullptr, nullptr, -1}, // UNCLASSIFIED_COMMENT 277 {nullptr, nullptr, -1}, // UNCLASSIFIED_COMMENT
182 {nullptr, nullptr, -1}, // LINE_COMMENT 278 {nullptr, nullptr, -1}, // LINE_COMMENT
183 {nullptr, nullptr, -1}, // SUFFIX_COMMENT 279 {nullptr, nullptr, -1}, // SUFFIX_COMMENT
184 {&Parser::BlockComment, nullptr, -1}, // BLOCK_COMMENT 280 {&Parser::BlockComment, nullptr, -1}, // BLOCK_COMMENT
185 }; 281 };
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 return std::unique_ptr<ParseNode>(); 445 return std::unique_ptr<ParseNode>();
350 } 446 }
351 left = (this->*infix)(std::move(left), token); 447 left = (this->*infix)(std::move(left), token);
352 if (has_error()) 448 if (has_error())
353 return std::unique_ptr<ParseNode>(); 449 return std::unique_ptr<ParseNode>();
354 } 450 }
355 451
356 return left; 452 return left;
357 } 453 }
358 454
455 std::unique_ptr<ParseNode> Parser::Block(Token token) {
456 // This entrypoing into ParseBlock means its part of an expression and we
457 // always want the result.
458 return ParseBlock(token, BlockNode::RETURNS_SCOPE);
459 }
460
359 std::unique_ptr<ParseNode> Parser::Literal(Token token) { 461 std::unique_ptr<ParseNode> Parser::Literal(Token token) {
360 return base::WrapUnique(new LiteralNode(token)); 462 return base::WrapUnique(new LiteralNode(token));
361 } 463 }
362 464
363 std::unique_ptr<ParseNode> Parser::Name(Token token) { 465 std::unique_ptr<ParseNode> Parser::Name(Token token) {
364 return IdentifierOrCall(std::unique_ptr<ParseNode>(), token); 466 return IdentifierOrCall(std::unique_ptr<ParseNode>(), token);
365 } 467 }
366 468
367 std::unique_ptr<ParseNode> Parser::BlockComment(Token token) { 469 std::unique_ptr<ParseNode> Parser::BlockComment(Token token) {
368 std::unique_ptr<BlockCommentNode> comment(new BlockCommentNode()); 470 std::unique_ptr<BlockCommentNode> comment(new BlockCommentNode());
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 if (Match(Token::RIGHT_PAREN)) { 536 if (Match(Token::RIGHT_PAREN)) {
435 // Nothing, just an empty call. 537 // Nothing, just an empty call.
436 } else { 538 } else {
437 list = ParseList(start_token, Token::RIGHT_PAREN, false); 539 list = ParseList(start_token, Token::RIGHT_PAREN, false);
438 if (has_error()) 540 if (has_error())
439 return std::unique_ptr<ParseNode>(); 541 return std::unique_ptr<ParseNode>();
440 Consume(Token::RIGHT_PAREN, "Expected ')' after call"); 542 Consume(Token::RIGHT_PAREN, "Expected ')' after call");
441 } 543 }
442 // Optionally with a scope. 544 // Optionally with a scope.
443 if (LookAhead(Token::LEFT_BRACE)) { 545 if (LookAhead(Token::LEFT_BRACE)) {
444 block = ParseBlock(); 546 block = ParseBlock(Consume(), BlockNode::DISCARDS_RESULT);
445 if (has_error()) 547 if (has_error())
446 return std::unique_ptr<ParseNode>(); 548 return std::unique_ptr<ParseNode>();
447 } 549 }
448 } 550 }
449 551
450 if (!left && !has_arg) { 552 if (!left && !has_arg) {
451 // Not a function call, just a standalone identifier. 553 // Not a function call, just a standalone identifier.
452 return std::unique_ptr<ParseNode>(new IdentifierNode(token)); 554 return std::unique_ptr<ParseNode>(new IdentifierNode(token));
453 } 555 }
454 std::unique_ptr<FunctionCallNode> func_call(new FunctionCallNode); 556 std::unique_ptr<FunctionCallNode> func_call(new FunctionCallNode);
455 func_call->set_function(token); 557 func_call->set_function(token);
456 func_call->set_args(std::move(list)); 558 func_call->set_args(std::move(list));
457 if (block) 559 if (block)
458 func_call->set_block(std::move(block)); 560 func_call->set_block(std::move(block));
459 return std::move(func_call); 561 return std::move(func_call);
460 } 562 }
461 563
462 std::unique_ptr<ParseNode> Parser::Assignment(std::unique_ptr<ParseNode> left, 564 std::unique_ptr<ParseNode> Parser::Assignment(std::unique_ptr<ParseNode> left,
463 Token token) { 565 Token token) {
464 if (left->AsIdentifier() == nullptr) { 566 if (left->AsIdentifier() == nullptr && left->AsAccessor() == nullptr) {
465 *err_ = Err(left.get(), "Left-hand side of assignment must be identifier."); 567 *err_ = Err(left.get(),
568 "The left-hand side of an assignment must be an identifier, "
569 "scope access, or array access.");
466 return std::unique_ptr<ParseNode>(); 570 return std::unique_ptr<ParseNode>();
467 } 571 }
468 std::unique_ptr<ParseNode> value = ParseExpression(PRECEDENCE_ASSIGNMENT); 572 std::unique_ptr<ParseNode> value = ParseExpression(PRECEDENCE_ASSIGNMENT);
469 if (!value) { 573 if (!value) {
470 if (!has_error()) 574 if (!has_error())
471 *err_ = Err(token, "Expected right-hand side for assignment."); 575 *err_ = Err(token, "Expected right-hand side for assignment.");
472 return std::unique_ptr<ParseNode>(); 576 return std::unique_ptr<ParseNode>();
473 } 577 }
474 std::unique_ptr<BinaryOpNode> assign(new BinaryOpNode); 578 std::unique_ptr<BinaryOpNode> assign(new BinaryOpNode);
475 assign->set_op(token); 579 assign->set_op(token);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 } 664 }
561 if (just_got_comma && !allow_trailing_comma) { 665 if (just_got_comma && !allow_trailing_comma) {
562 *err_ = Err(cur_token(), "Trailing comma"); 666 *err_ = Err(cur_token(), "Trailing comma");
563 return std::unique_ptr<ListNode>(); 667 return std::unique_ptr<ListNode>();
564 } 668 }
565 list->set_end(base::WrapUnique(new EndNode(cur_token()))); 669 list->set_end(base::WrapUnique(new EndNode(cur_token())));
566 return list; 670 return list;
567 } 671 }
568 672
569 std::unique_ptr<ParseNode> Parser::ParseFile() { 673 std::unique_ptr<ParseNode> Parser::ParseFile() {
570 std::unique_ptr<BlockNode> file(new BlockNode); 674 std::unique_ptr<BlockNode> file(new BlockNode(BlockNode::DISCARDS_RESULT));
571 for (;;) { 675 for (;;) {
572 if (at_end()) 676 if (at_end())
573 break; 677 break;
574 std::unique_ptr<ParseNode> statement = ParseStatement(); 678 std::unique_ptr<ParseNode> statement = ParseStatement();
575 if (!statement) 679 if (!statement)
576 break; 680 break;
577 file->append_statement(std::move(statement)); 681 file->append_statement(std::move(statement));
578 } 682 }
579 if (!at_end() && !has_error()) 683 if (!at_end() && !has_error())
580 *err_ = Err(cur_token(), "Unexpected here, should be newline."); 684 *err_ = Err(cur_token(), "Unexpected here, should be newline.");
(...skipping 23 matching lines...) Expand all
604 return stmt; 708 return stmt;
605 } 709 }
606 if (!has_error()) { 710 if (!has_error()) {
607 Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token(); 711 Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token();
608 *err_ = Err(token, "Expecting assignment or function call."); 712 *err_ = Err(token, "Expecting assignment or function call.");
609 } 713 }
610 return std::unique_ptr<ParseNode>(); 714 return std::unique_ptr<ParseNode>();
611 } 715 }
612 } 716 }
613 717
614 std::unique_ptr<BlockNode> Parser::ParseBlock() { 718 std::unique_ptr<BlockNode> Parser::ParseBlock(
615 Token begin_token = 719 Token begin_brace,
616 Consume(Token::LEFT_BRACE, "Expected '{' to start a block."); 720 BlockNode::ResultMode result_mode) {
617 if (has_error()) 721 if (has_error())
618 return std::unique_ptr<BlockNode>(); 722 return std::unique_ptr<BlockNode>();
619 std::unique_ptr<BlockNode> block(new BlockNode); 723 std::unique_ptr<BlockNode> block(new BlockNode(result_mode));
620 block->set_begin_token(begin_token); 724 block->set_begin_token(begin_brace);
621 725
622 for (;;) { 726 for (;;) {
623 if (LookAhead(Token::RIGHT_BRACE)) { 727 if (LookAhead(Token::RIGHT_BRACE)) {
624 block->set_end(base::WrapUnique(new EndNode(Consume()))); 728 block->set_end(base::WrapUnique(new EndNode(Consume())));
625 break; 729 break;
626 } 730 }
627 731
628 std::unique_ptr<ParseNode> statement = ParseStatement(); 732 std::unique_ptr<ParseNode> statement = ParseStatement();
629 if (!statement) 733 if (!statement)
630 return std::unique_ptr<BlockNode>(); 734 return std::unique_ptr<BlockNode>();
631 block->append_statement(std::move(statement)); 735 block->append_statement(std::move(statement));
632 } 736 }
633 return block; 737 return block;
634 } 738 }
635 739
636 std::unique_ptr<ParseNode> Parser::ParseCondition() { 740 std::unique_ptr<ParseNode> Parser::ParseCondition() {
637 std::unique_ptr<ConditionNode> condition(new ConditionNode); 741 std::unique_ptr<ConditionNode> condition(new ConditionNode);
638 condition->set_if_token(Consume(Token::IF, "Expected 'if'")); 742 condition->set_if_token(Consume(Token::IF, "Expected 'if'"));
639 Consume(Token::LEFT_PAREN, "Expected '(' after 'if'."); 743 Consume(Token::LEFT_PAREN, "Expected '(' after 'if'.");
640 condition->set_condition(ParseExpression()); 744 condition->set_condition(ParseExpression());
641 if (IsAssignment(condition->condition())) 745 if (IsAssignment(condition->condition()))
642 *err_ = Err(condition->condition(), "Assignment not allowed in 'if'."); 746 *err_ = Err(condition->condition(), "Assignment not allowed in 'if'.");
643 Consume(Token::RIGHT_PAREN, "Expected ')' after condition of 'if'."); 747 Consume(Token::RIGHT_PAREN, "Expected ')' after condition of 'if'.");
644 condition->set_if_true(ParseBlock()); 748 condition->set_if_true(ParseBlock(
749 Consume(Token::LEFT_BRACE, "Expected '{' to start 'if' block."),
750 BlockNode::DISCARDS_RESULT));
645 if (Match(Token::ELSE)) { 751 if (Match(Token::ELSE)) {
646 if (LookAhead(Token::LEFT_BRACE)) { 752 if (LookAhead(Token::LEFT_BRACE)) {
647 condition->set_if_false(ParseBlock()); 753 condition->set_if_false(ParseBlock(Consume(),
754 BlockNode::DISCARDS_RESULT));
648 } else if (LookAhead(Token::IF)) { 755 } else if (LookAhead(Token::IF)) {
649 condition->set_if_false(ParseStatement()); 756 condition->set_if_false(ParseStatement());
650 } else { 757 } else {
651 *err_ = Err(cur_token(), "Expected '{' or 'if' after 'else'."); 758 *err_ = Err(cur_token(), "Expected '{' or 'if' after 'else'.");
652 return std::unique_ptr<ParseNode>(); 759 return std::unique_ptr<ParseNode>();
653 } 760 }
654 } 761 }
655 if (has_error()) 762 if (has_error())
656 return std::unique_ptr<ParseNode>(); 763 return std::unique_ptr<ParseNode>();
657 return std::move(condition); 764 return std::move(condition);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 break; 868 break;
762 } 869 }
763 } 870 }
764 871
765 // Suffix comments were assigned in reverse, so if there were multiple on 872 // Suffix comments were assigned in reverse, so if there were multiple on
766 // the same node, they need to be reversed. 873 // the same node, they need to be reversed.
767 if ((*i)->comments() && !(*i)->comments()->suffix().empty()) 874 if ((*i)->comments() && !(*i)->comments()->suffix().empty())
768 const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix(); 875 const_cast<ParseNode*>(*i)->comments_mutable()->ReverseSuffix();
769 } 876 }
770 } 877 }
OLDNEW
« no previous file with comments | « tools/gn/parser.h ('k') | tools/gn/parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698