OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "tools/gn/parser.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "tools/gn/functions.h" | |
9 #include "tools/gn/operators.h" | |
10 #include "tools/gn/token.h" | |
11 | |
12 namespace { | |
13 | |
14 // Returns true if the two tokens are on the same line. We assume they're in | |
15 // the same file. | |
16 bool IsSameLine(const Token& a, const Token& b) { | |
17 DCHECK(a.location().file() == b.location().file()); | |
18 return a.location().line_number() == b.location().line_number(); | |
19 } | |
20 | |
21 } // namespace | |
22 | |
23 Parser::Parser(const std::vector<Token>& tokens, Err* err) | |
24 : tokens_(tokens), | |
25 err_(err), | |
26 cur_(0) { | |
27 } | |
28 | |
29 Parser::~Parser() { | |
30 } | |
31 | |
32 // static | |
33 scoped_ptr<ParseNode> Parser::Parse(const std::vector<Token>& tokens, | |
34 Err* err) { | |
35 Parser p(tokens, err); | |
36 return p.ParseBlock(false).PassAs<ParseNode>(); | |
37 } | |
38 | |
39 // static | |
40 scoped_ptr<ParseNode> Parser::ParseExpression(const std::vector<Token>& tokens, | |
41 Err* err) { | |
42 Parser p(tokens, err); | |
43 return p.ParseExpression().Pass(); | |
44 } | |
45 | |
46 bool Parser::IsToken(Token::Type type, char* str) const { | |
47 if (at_end()) | |
48 return false; | |
49 return cur_token().type() == type || cur_token().value() == str; | |
50 } | |
51 | |
52 scoped_ptr<AccessorNode> Parser::ParseAccessor() { | |
53 scoped_ptr<AccessorNode> accessor(new AccessorNode); | |
54 | |
55 DCHECK(cur_token().type() == Token::IDENTIFIER); | |
56 accessor->set_base(cur_token()); | |
57 cur_++; // Skip identifier. | |
58 cur_++; // Skip "[" (we know this exists because the existance of this | |
59 // token is how the caller knows it's an accessor. | |
60 | |
61 if (at_end()) { | |
62 *err_ = MakeEOFError("Got EOF when looking for list index."); | |
63 return scoped_ptr<AccessorNode>(); | |
64 } | |
65 | |
66 // Get the expression. | |
67 scoped_ptr<ParseNode> expr = ParseExpression().Pass(); | |
68 if (has_error()) | |
69 return scoped_ptr<AccessorNode>(); | |
70 if (at_end()) { | |
71 *err_ = MakeEOFError("Got EOF when looking for list accessor ]"); | |
72 return scoped_ptr<AccessorNode>(); | |
73 } | |
74 accessor->set_index(expr.Pass()); | |
75 | |
76 // Skip over "]" | |
77 if (!cur_token().IsScoperEqualTo("]")) { | |
78 *err_ = Err(cur_token(), "Expecting ]", | |
79 "You started a list access but didn't terminate it, and instead " | |
80 "I fould this\nstupid thing."); | |
81 return scoped_ptr<AccessorNode>(); | |
82 } | |
83 cur_++; | |
84 | |
85 return accessor.Pass(); | |
86 } | |
87 | |
88 // Blocks at the file scope don't need {} so we have the option to ignore | |
89 // them. When need_braces is set, we'll expect a begin an end brace. | |
90 // | |
91 // block := "{" block_contents "}" | |
92 // block_contents := (expression | conditional | block)* | |
93 scoped_ptr<BlockNode> Parser::ParseBlock(bool need_braces) { | |
94 scoped_ptr<BlockNode> block(new BlockNode(true)); | |
95 | |
96 // Eat initial { if necessary. | |
97 const Token* opening_curly_brace; | |
98 if (need_braces) { | |
99 if (at_end()) { | |
100 *err_ = MakeEOFError("Got EOF when looking for { for block.", | |
101 "It should have been after here."); | |
102 return scoped_ptr<BlockNode>(); | |
103 } else if(!IsScopeBeginScoper(cur_token())) { | |
104 *err_ = Err(cur_token(), "Expecting { instead of this thing.", | |
105 "THOU SHALT USE CURLY BRACES FOR ALL BLOCKS."); | |
106 return scoped_ptr<BlockNode>(); | |
107 } | |
108 opening_curly_brace = &cur_token(); | |
109 block->set_begin_token(opening_curly_brace); | |
110 cur_++; | |
111 } | |
112 | |
113 // Loop until EOF or end brace found. | |
114 while (!at_end() && !IsScopeEndScoper(cur_token())) { | |
115 if (cur_token().IsIdentifierEqualTo("if")) { | |
116 // Conditional. | |
117 block->append_statement(ParseCondition().PassAs<ParseNode>()); | |
118 } else if (IsScopeBeginScoper(cur_token())) { | |
119 // Nested block. | |
120 block->append_statement(ParseBlock(true).PassAs<ParseNode>()); | |
121 } else { | |
122 // Everything else is an expression. | |
123 block->append_statement(ParseExpression().PassAs<ParseNode>()); | |
124 } | |
125 if (has_error()) | |
126 return scoped_ptr<BlockNode>(); | |
127 } | |
128 | |
129 // Eat the ending "}" if necessary. | |
130 if (need_braces) { | |
131 if (at_end() || !IsScopeEndScoper(cur_token())) { | |
132 *err_ = Err(*opening_curly_brace, "Expecting }", | |
133 "I ran headlong into the end of the file looking for the " | |
134 "closing brace\ncorresponding to this one."); | |
135 return scoped_ptr<BlockNode>(); | |
136 } | |
137 block->set_end_token(&cur_token()); | |
138 cur_++; // Skip past "}". | |
139 } | |
140 | |
141 return block.Pass(); | |
142 } | |
143 | |
144 // conditional := "if (" expression ")" block [else_conditional] | |
145 // else_conditional := ("else" block) | ("else" conditional) | |
146 scoped_ptr<ConditionNode> Parser::ParseCondition() { | |
147 scoped_ptr<ConditionNode> cond(new ConditionNode); | |
148 | |
149 // Skip past "if". | |
150 const Token& if_token = cur_token(); | |
151 cond->set_if_token(if_token); | |
152 DCHECK(if_token.IsIdentifierEqualTo("if")); | |
153 cur_++; | |
154 | |
155 if (at_end() || !IsFunctionCallArgBeginScoper(cur_token())) { | |
156 *err_ = Err(if_token, "Expecting \"(\" after \"if\"", | |
157 "Did you think this was Python or something?"); | |
158 return scoped_ptr<ConditionNode>(); | |
159 } | |
160 | |
161 // Skip over (. | |
162 const Token& open_paren_token = cur_token(); | |
163 cur_++; | |
164 if (at_end()) { | |
165 *err_ = Err(if_token, "Unexpected EOF inside if condition"); | |
166 return scoped_ptr<ConditionNode>(); | |
167 } | |
168 | |
169 // Condition inside (). | |
170 cond->set_condition(ParseExpression().Pass()); | |
171 if (has_error()) | |
172 return scoped_ptr<ConditionNode>(); | |
173 | |
174 if (at_end() || !IsFunctionCallArgEndScoper(cur_token())) { | |
175 *err_ = Err(open_paren_token, "Expecting \")\" for \"if\" condition", | |
176 "You didn't finish the thought you started here."); | |
177 return scoped_ptr<ConditionNode>(); | |
178 } | |
179 cur_++; // Skip over ) | |
180 | |
181 // Contents of {}. | |
182 cond->set_if_true(ParseBlock(true).Pass()); | |
183 if (has_error()) | |
184 return scoped_ptr<ConditionNode>(); | |
185 | |
186 // Optional "else" at the end. | |
187 if (!at_end() && cur_token().IsIdentifierEqualTo("else")) { | |
188 cur_++; | |
189 | |
190 // The else may be followed by an if or a block. | |
191 if (at_end()) { | |
192 *err_ = MakeEOFError("Ran into end of file after \"else\".", | |
193 "else, WHAT?!?!?"); | |
194 return scoped_ptr<ConditionNode>(); | |
195 } | |
196 if (cur_token().IsIdentifierEqualTo("if")) { | |
197 // "else if() {" | |
198 cond->set_if_false(ParseCondition().PassAs<ParseNode>()); | |
199 } else if (IsScopeBeginScoper(cur_token())) { | |
200 // "else {" | |
201 cond->set_if_false(ParseBlock(true).PassAs<ParseNode>()); | |
202 } else { | |
203 // else <anything else> | |
204 *err_ = Err(cur_token(), "Expected \"if\" or \"{\" after \"else\".", | |
205 "This is neither of those things."); | |
206 return scoped_ptr<ConditionNode>(); | |
207 } | |
208 } | |
209 | |
210 if (has_error()) | |
211 return scoped_ptr<ConditionNode>(); | |
212 return cond.Pass(); | |
213 } | |
214 | |
215 // expression := paren_expression | accessor | identifier | literal | | |
216 // funccall | unary_expression | binary_expression | |
217 // | |
218 // accessor := identifier <non-newline-whitespace>* "[" expression "]" | |
219 // | |
220 // The "non-newline-whitespace is used to differentiate between this case: | |
221 // a[1] | |
222 // and this one: | |
223 // a | |
224 // [1] | |
225 // The second one is kind of stupid (since it does nothing with the values) | |
226 // but is still legal. | |
227 scoped_ptr<ParseNode> Parser::ParseExpression() { | |
228 scoped_ptr<ParseNode> expr = ParseExpressionExceptBinaryOperators(); | |
229 if (has_error()) | |
230 return scoped_ptr<ParseNode>(); | |
231 | |
232 // That may have hit EOF, in which case we can't have any binary operators. | |
233 if (at_end()) | |
234 return expr.Pass(); | |
235 | |
236 // TODO(brettw) handle operator precidence! | |
237 // Gobble up all subsequent expressions as long as there are binary | |
238 // operators. | |
239 | |
240 if (IsBinaryOperator(cur_token())) { | |
241 scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode); | |
242 binary_op->set_left(expr.Pass()); | |
243 const Token& operator_token = cur_token(); | |
244 binary_op->set_op(operator_token); | |
245 cur_++; | |
246 if (at_end()) { | |
247 *err_ = Err(operator_token, "Unexpected EOF in expression.", | |
248 "I was looking for the right-hand-side of this operator."); | |
249 return scoped_ptr<ParseNode>(); | |
250 } | |
251 binary_op->set_right(ParseExpression().Pass()); | |
252 if (has_error()) | |
253 return scoped_ptr<ParseNode>(); | |
254 return binary_op.PassAs<ParseNode>(); | |
255 } | |
256 | |
257 return expr.Pass(); | |
258 } | |
259 | |
260 | |
261 // This internal one does not handle binary operators, since it requires | |
262 // looking at the "next" thing. The regular ParseExpression above handles it. | |
263 scoped_ptr<ParseNode> Parser::ParseExpressionExceptBinaryOperators() { | |
264 if (at_end()) | |
265 return scoped_ptr<ParseNode>(); | |
266 | |
267 const Token& token = cur_token(); | |
268 | |
269 // Unary expression. | |
270 if (IsUnaryOperator(token)) | |
271 return ParseUnaryOp().PassAs<ParseNode>(); | |
272 | |
273 // Parenthesized expressions. | |
274 if (token.IsScoperEqualTo("(")) | |
275 return ParseParenExpression(); | |
276 | |
277 // Function calls. | |
278 if (token.type() == Token::IDENTIFIER) { | |
279 if (has_next_token() && IsFunctionCallArgBeginScoper(next_token())) | |
280 return ParseFunctionCall().PassAs<ParseNode>(); | |
281 } | |
282 | |
283 // Lists. | |
284 if (token.IsScoperEqualTo("[")) { | |
285 return ParseList(Token(Location(), Token::SCOPER, "["), | |
286 Token(Location(), Token::SCOPER, "]")).PassAs<ParseNode>(); | |
287 } | |
288 | |
289 // Literals. | |
290 if (token.type() == Token::STRING || token.type() == Token::INTEGER) { | |
291 cur_++; | |
292 return scoped_ptr<ParseNode>(new LiteralNode(token)); | |
293 } | |
294 | |
295 // Accessors. | |
296 if (token.type() == Token::IDENTIFIER && | |
297 has_next_token() && next_token().IsScoperEqualTo("[") && | |
298 IsSameLine(token, next_token())) { | |
299 return ParseAccessor().PassAs<ParseNode>(); | |
300 } | |
301 | |
302 // Identifiers. | |
303 if (token.type() == Token::IDENTIFIER) { | |
304 cur_++; | |
305 return scoped_ptr<ParseNode>(new IdentifierNode(token)); | |
306 } | |
307 | |
308 // Handle errors. | |
309 if (token.type() == Token::SEPARATOR) { | |
310 *err_ = Err(token, "Unexpected comma.", | |
311 "You can't put a comma here, it must be in list separating " | |
312 "complete\nthoughts."); | |
313 } else if (IsScopeBeginScoper(token)) { | |
314 *err_ = Err(token, "Unexpected token.", | |
315 "You can't put a \"{\" scope here, it must be in a block."); | |
316 } else { | |
317 *err_ = Err(token, "Unexpected token.", | |
318 "I was really hoping for something else here and you let me down
."); | |
319 } | |
320 return scoped_ptr<ParseNode>(); | |
321 } | |
322 | |
323 // function_call := identifier "(" list_contents ")" | |
324 // [<non-newline-whitespace>* block] | |
325 scoped_ptr<FunctionCallNode> Parser::ParseFunctionCall() { | |
326 scoped_ptr<FunctionCallNode> func(new FunctionCallNode); | |
327 | |
328 const Token& function_token = cur_token(); | |
329 func->set_function(function_token); | |
330 | |
331 // This function should only get called when we know we have a function, | |
332 // which only happens when there is a paren following the name. Skip past it. | |
333 DCHECK(has_next_token()); | |
334 cur_++; // Skip past function name to (. | |
335 const Token& open_paren_token = cur_token(); | |
336 DCHECK(IsFunctionCallArgBeginScoper(open_paren_token)); | |
337 | |
338 if (at_end()) { | |
339 *err_ = Err(open_paren_token, "Unexpected EOF for function call.", | |
340 "You didn't finish the thought you started here."); | |
341 return scoped_ptr<FunctionCallNode>(); | |
342 } | |
343 | |
344 // Arguments. | |
345 func->set_args(ParseList(Token(Location(), Token::SCOPER, "("), | |
346 Token(Location(), Token::SCOPER, ")"))); | |
347 if (has_error()) | |
348 return scoped_ptr<FunctionCallNode>(); | |
349 | |
350 // Optional {} after function call for certain functions. The "{" must be on | |
351 // the same line as the ")" to disambiguate the case of a function followed | |
352 // by a random block just used for scoping purposes. | |
353 if (!at_end() && IsScopeBeginScoper(cur_token())) { | |
354 const Token& args_end_token = tokens_[cur_ - 1]; | |
355 DCHECK(args_end_token.IsScoperEqualTo(")")); | |
356 if (IsSameLine(args_end_token, cur_token())) | |
357 func->set_block(ParseBlock(true).Pass()); | |
358 } | |
359 | |
360 if (has_error()) | |
361 return scoped_ptr<FunctionCallNode>(); | |
362 return func.Pass(); | |
363 } | |
364 | |
365 // list := "[" expression* "]" | |
366 // list_contents := [(expression ",")* expression [","]] | |
367 // | |
368 // The list_contents is also used in function calls surrounded by parens, so | |
369 // this function takes the tokens that are expected to surround the list. | |
370 scoped_ptr<ListNode> Parser::ParseList(const Token& expected_begin, | |
371 const Token& expected_end) { | |
372 scoped_ptr<ListNode> list(new ListNode); | |
373 | |
374 const Token& open_bracket_token = cur_token(); | |
375 list->set_begin_token(open_bracket_token); | |
376 cur_++; // Skip "[" or "(". | |
377 | |
378 bool need_separator = false; | |
379 while(true) { | |
380 if (at_end()) { | |
381 *err_ = Err(open_bracket_token, "EOF found when parsing list.", | |
382 "I expected a \"" + expected_end.value().as_string() + | |
383 "\" corresponding to this one."); | |
384 return scoped_ptr<ListNode>(); | |
385 } | |
386 if (cur_token().type() == expected_end.type() && | |
387 cur_token().value() == expected_end.value()) { | |
388 list->set_end_token(cur_token()); | |
389 cur_++; | |
390 break; | |
391 } | |
392 | |
393 if (need_separator) { | |
394 DCHECK(!list->contents().empty()); | |
395 LocationRange prev_item_range = | |
396 list->contents().at(list->contents().size() - 1)->GetRange(); | |
397 *err_ = Err(prev_item_range.end(), | |
398 "Need comma separating items in list.", | |
399 "You probably need a comma after this thingy."); | |
400 err_->AppendRange(prev_item_range); | |
401 return scoped_ptr<ListNode>(); | |
402 } | |
403 scoped_ptr<ParseNode> expr = ParseExpression().Pass(); | |
404 if (has_error()) | |
405 return scoped_ptr<ListNode>(); | |
406 list->append_item(expr.Pass()); | |
407 | |
408 need_separator = true; | |
409 if (!at_end()) { | |
410 // Skip over the separator, marking that we found it. | |
411 if (cur_token().type() == Token::SEPARATOR) { | |
412 cur_++; | |
413 need_separator = false; | |
414 } | |
415 } | |
416 } | |
417 return list.Pass(); | |
418 } | |
419 | |
420 // paren_expression := "(" expression ")" | |
421 scoped_ptr<ParseNode> Parser::ParseParenExpression() { | |
422 const Token& open_paren_token = cur_token(); | |
423 cur_++; // Skip over ( | |
424 | |
425 scoped_ptr<ParseNode> ret = ParseExpression(); | |
426 if (has_error()) | |
427 return scoped_ptr<ParseNode>(); | |
428 | |
429 if (at_end()) { | |
430 *err_ = Err(open_paren_token, "EOF found when parsing expression.", | |
431 "I was looking for a \")\" corresponding to this one."); | |
432 return scoped_ptr<ParseNode>(); | |
433 } | |
434 if (!cur_token().IsScoperEqualTo(")")) { | |
435 *err_ = Err(open_paren_token, "Expected \")\" for expression", | |
436 "I was looking for a \")\" corresponding to this one."); | |
437 return scoped_ptr<ParseNode>(); | |
438 } | |
439 cur_++; // Skip over ) | |
440 return ret.Pass(); | |
441 } | |
442 | |
443 // unary_expression := "!" expression | |
444 scoped_ptr<UnaryOpNode> Parser::ParseUnaryOp() { | |
445 scoped_ptr<UnaryOpNode> unary(new UnaryOpNode); | |
446 | |
447 DCHECK(!at_end() && IsUnaryOperator(cur_token())); | |
448 const Token& op_token = cur_token(); | |
449 unary->set_op(op_token); | |
450 cur_++; | |
451 | |
452 if (at_end()) { | |
453 *err_ = Err(op_token, "Expected expression.", | |
454 "This operator needs something to operate on."); | |
455 return scoped_ptr<UnaryOpNode>(); | |
456 } | |
457 unary->set_operand(ParseExpression().Pass()); | |
458 if (has_error()) | |
459 return scoped_ptr<UnaryOpNode>(); | |
460 return unary.Pass(); | |
461 } | |
462 | |
463 Err Parser::MakeEOFError(const std::string& message, | |
464 const std::string& help) const { | |
465 if (tokens_.empty()) | |
466 return Err(Location(NULL, 1, 1), message, help); | |
467 | |
468 const Token& last = tokens_[tokens_.size() - 1]; | |
469 return Err(last, message, help); | |
470 } | |
OLD | NEW |