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/parse_tree.h"
6
7 #include <string>
8
9 #include "base/stl_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "tools/gn/functions.h"
12 #include "tools/gn/operators.h"
13 #include "tools/gn/scope.h"
14 #include "tools/gn/string_utils.h"
15
16 namespace {
17
IndentFor(int value)18 std::string IndentFor(int value) {
19 return std::string(value, ' ');
20 }
21
22 } // namespace
23
Comments()24 Comments::Comments() {
25 }
26
~Comments()27 Comments::~Comments() {
28 }
29
ReverseSuffix()30 void Comments::ReverseSuffix() {
31 for (int i = 0, j = static_cast<int>(suffix_.size() - 1); i < j; ++i, --j)
32 std::swap(suffix_[i], suffix_[j]);
33 }
34
ParseNode()35 ParseNode::ParseNode() {
36 }
37
~ParseNode()38 ParseNode::~ParseNode() {
39 }
40
AsAccessor() const41 const AccessorNode* ParseNode::AsAccessor() const { return NULL; }
AsBinaryOp() const42 const BinaryOpNode* ParseNode::AsBinaryOp() const { return NULL; }
AsBlock() const43 const BlockNode* ParseNode::AsBlock() const { return NULL; }
AsConditionNode() const44 const ConditionNode* ParseNode::AsConditionNode() const { return NULL; }
AsFunctionCall() const45 const FunctionCallNode* ParseNode::AsFunctionCall() const { return NULL; }
AsIdentifier() const46 const IdentifierNode* ParseNode::AsIdentifier() const { return NULL; }
AsList() const47 const ListNode* ParseNode::AsList() const { return NULL; }
AsLiteral() const48 const LiteralNode* ParseNode::AsLiteral() const { return NULL; }
AsUnaryOp() const49 const UnaryOpNode* ParseNode::AsUnaryOp() const { return NULL; }
AsBlockComment() const50 const BlockCommentNode* ParseNode::AsBlockComment() const { return NULL; }
51
comments_mutable()52 Comments* ParseNode::comments_mutable() {
53 if (!comments_)
54 comments_.reset(new Comments);
55 return comments_.get();
56 }
57
PrintComments(std::ostream & out,int indent) const58 void ParseNode::PrintComments(std::ostream& out, int indent) const {
59 if (comments_) {
60 std::string ind = IndentFor(indent + 1);
61 for (std::vector<Token>::const_iterator i(comments_->before().begin());
62 i != comments_->before().end();
63 ++i) {
64 out << ind << "+BEFORE_COMMENT(\"" << i->value() << "\")\n";
65 }
66 for (std::vector<Token>::const_iterator i(comments_->suffix().begin());
67 i != comments_->suffix().end();
68 ++i) {
69 out << ind << "+SUFFIX_COMMENT(\"" << i->value() << "\")\n";
70 }
71 for (std::vector<Token>::const_iterator i(comments_->after().begin());
72 i != comments_->after().end();
73 ++i) {
74 out << ind << "+AFTER_COMMENT(\"" << i->value() << "\")\n";
75 }
76 }
77 }
78
79 // AccessorNode ---------------------------------------------------------------
80
AccessorNode()81 AccessorNode::AccessorNode() {
82 }
83
~AccessorNode()84 AccessorNode::~AccessorNode() {
85 }
86
AsAccessor() const87 const AccessorNode* AccessorNode::AsAccessor() const {
88 return this;
89 }
90
Execute(Scope * scope,Err * err) const91 Value AccessorNode::Execute(Scope* scope, Err* err) const {
92 if (index_)
93 return ExecuteArrayAccess(scope, err);
94 else if (member_)
95 return ExecuteScopeAccess(scope, err);
96 NOTREACHED();
97 return Value();
98 }
99
GetRange() const100 LocationRange AccessorNode::GetRange() const {
101 if (index_)
102 return LocationRange(base_.location(), index_->GetRange().end());
103 else if (member_)
104 return LocationRange(base_.location(), member_->GetRange().end());
105 NOTREACHED();
106 return LocationRange();
107 }
108
MakeErrorDescribing(const std::string & msg,const std::string & help) const109 Err AccessorNode::MakeErrorDescribing(const std::string& msg,
110 const std::string& help) const {
111 return Err(GetRange(), msg, help);
112 }
113
Print(std::ostream & out,int indent) const114 void AccessorNode::Print(std::ostream& out, int indent) const {
115 out << IndentFor(indent) << "ACCESSOR\n";
116 PrintComments(out, indent);
117 out << IndentFor(indent + 1) << base_.value() << "\n";
118 if (index_)
119 index_->Print(out, indent + 1);
120 else if (member_)
121 member_->Print(out, indent + 1);
122 }
123
ExecuteArrayAccess(Scope * scope,Err * err) const124 Value AccessorNode::ExecuteArrayAccess(Scope* scope, Err* err) const {
125 Value index_value = index_->Execute(scope, err);
126 if (err->has_error())
127 return Value();
128 if (!index_value.VerifyTypeIs(Value::INTEGER, err))
129 return Value();
130
131 const Value* base_value = scope->GetValue(base_.value(), true);
132 if (!base_value) {
133 *err = MakeErrorDescribing("Undefined identifier.");
134 return Value();
135 }
136 if (!base_value->VerifyTypeIs(Value::LIST, err))
137 return Value();
138
139 int64 index_int = index_value.int_value();
140 if (index_int < 0) {
141 *err = Err(index_->GetRange(), "Negative array subscript.",
142 "You gave me " + base::Int64ToString(index_int) + ".");
143 return Value();
144 }
145 size_t index_sizet = static_cast<size_t>(index_int);
146 if (index_sizet >= base_value->list_value().size()) {
147 *err = Err(index_->GetRange(), "Array subscript out of range.",
148 "You gave me " + base::Int64ToString(index_int) +
149 " but I was expecting something from 0 to " +
150 base::Int64ToString(
151 static_cast<int64>(base_value->list_value().size()) - 1) +
152 ", inclusive.");
153 return Value();
154 }
155
156 // Doing this assumes that there's no way in the language to do anything
157 // between the time the reference is created and the time that the reference
158 // is used. If there is, this will crash! Currently, this is just used for
159 // array accesses where this "shouldn't" happen.
160 return base_value->list_value()[index_sizet];
161 }
162
ExecuteScopeAccess(Scope * scope,Err * err) const163 Value AccessorNode::ExecuteScopeAccess(Scope* scope, Err* err) const {
164 // We jump through some hoops here since ideally a.b will count "b" as
165 // accessed in the given scope. The value "a" might be in some normal nested
166 // scope and we can modify it, but it might also be inherited from the
167 // readonly root scope and we can't do used variable tracking on it. (It's
168 // not legal to const cast it away since the root scope will be in readonly
169 // mode and being accessed from multiple threads without locking.) So this
170 // code handles both cases.
171 const Value* result = NULL;
172
173 // Look up the value in the scope named by "base_".
174 Value* mutable_base_value = scope->GetMutableValue(base_.value(), true);
175 if (mutable_base_value) {
176 // Common case: base value is mutable so we can track variable accesses
177 // for unused value warnings.
178 if (!mutable_base_value->VerifyTypeIs(Value::SCOPE, err))
179 return Value();
180 result = mutable_base_value->scope_value()->GetValue(
181 member_->value().value(), true);
182 } else {
183 // Fall back to see if the value is on a read-only scope.
184 const Value* const_base_value = scope->GetValue(base_.value(), true);
185 if (const_base_value) {
186 // Read only value, don't try to mark the value access as a "used" one.
187 if (!const_base_value->VerifyTypeIs(Value::SCOPE, err))
188 return Value();
189 result =
190 const_base_value->scope_value()->GetValue(member_->value().value());
191 } else {
192 *err = Err(base_, "Undefined identifier.");
193 return Value();
194 }
195 }
196
197 if (!result) {
198 *err = Err(member_.get(), "No value named \"" +
199 member_->value().value() + "\" in scope \"" + base_.value() + "\"");
200 return Value();
201 }
202 return *result;
203 }
204
205 // BinaryOpNode ---------------------------------------------------------------
206
BinaryOpNode()207 BinaryOpNode::BinaryOpNode() {
208 }
209
~BinaryOpNode()210 BinaryOpNode::~BinaryOpNode() {
211 }
212
AsBinaryOp() const213 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const {
214 return this;
215 }
216
Execute(Scope * scope,Err * err) const217 Value BinaryOpNode::Execute(Scope* scope, Err* err) const {
218 return ExecuteBinaryOperator(scope, this, left_.get(), right_.get(), err);
219 }
220
GetRange() const221 LocationRange BinaryOpNode::GetRange() const {
222 return left_->GetRange().Union(right_->GetRange());
223 }
224
MakeErrorDescribing(const std::string & msg,const std::string & help) const225 Err BinaryOpNode::MakeErrorDescribing(const std::string& msg,
226 const std::string& help) const {
227 return Err(op_, msg, help);
228 }
229
Print(std::ostream & out,int indent) const230 void BinaryOpNode::Print(std::ostream& out, int indent) const {
231 out << IndentFor(indent) << "BINARY(" << op_.value() << ")\n";
232 PrintComments(out, indent);
233 left_->Print(out, indent + 1);
234 right_->Print(out, indent + 1);
235 }
236
237 // BlockNode ------------------------------------------------------------------
238
BlockNode(bool has_scope)239 BlockNode::BlockNode(bool has_scope) : has_scope_(has_scope) {
240 }
241
~BlockNode()242 BlockNode::~BlockNode() {
243 STLDeleteContainerPointers(statements_.begin(), statements_.end());
244 }
245
AsBlock() const246 const BlockNode* BlockNode::AsBlock() const {
247 return this;
248 }
249
Execute(Scope * containing_scope,Err * err) const250 Value BlockNode::Execute(Scope* containing_scope, Err* err) const {
251 if (has_scope_) {
252 Scope our_scope(containing_scope);
253 Value ret = ExecuteBlockInScope(&our_scope, err);
254 if (err->has_error())
255 return Value();
256
257 // Check for unused vars in the scope.
258 our_scope.CheckForUnusedVars(err);
259 return ret;
260 }
261 return ExecuteBlockInScope(containing_scope, err);
262 }
263
GetRange() const264 LocationRange BlockNode::GetRange() const {
265 if (begin_token_.type() != Token::INVALID &&
266 end_token_.type() != Token::INVALID) {
267 return begin_token_.range().Union(end_token_.range());
268 } else if (!statements_.empty()) {
269 return statements_[0]->GetRange().Union(
270 statements_[statements_.size() - 1]->GetRange());
271 }
272 return LocationRange();
273 }
274
MakeErrorDescribing(const std::string & msg,const std::string & help) const275 Err BlockNode::MakeErrorDescribing(const std::string& msg,
276 const std::string& help) const {
277 return Err(GetRange(), msg, help);
278 }
279
Print(std::ostream & out,int indent) const280 void BlockNode::Print(std::ostream& out, int indent) const {
281 out << IndentFor(indent) << "BLOCK\n";
282 PrintComments(out, indent);
283 for (size_t i = 0; i < statements_.size(); i++)
284 statements_[i]->Print(out, indent + 1);
285 }
286
ExecuteBlockInScope(Scope * our_scope,Err * err) const287 Value BlockNode::ExecuteBlockInScope(Scope* our_scope, Err* err) const {
288 for (size_t i = 0; i < statements_.size() && !err->has_error(); i++) {
289 // Check for trying to execute things with no side effects in a block.
290 const ParseNode* cur = statements_[i];
291 if (cur->AsList() || cur->AsLiteral() || cur->AsUnaryOp() ||
292 cur->AsIdentifier()) {
293 *err = cur->MakeErrorDescribing(
294 "This statement has no effect.",
295 "Either delete it or do something with the result.");
296 return Value();
297 }
298 cur->Execute(our_scope, err);
299 }
300 return Value();
301 }
302
303 // ConditionNode --------------------------------------------------------------
304
ConditionNode()305 ConditionNode::ConditionNode() {
306 }
307
~ConditionNode()308 ConditionNode::~ConditionNode() {
309 }
310
AsConditionNode() const311 const ConditionNode* ConditionNode::AsConditionNode() const {
312 return this;
313 }
314
Execute(Scope * scope,Err * err) const315 Value ConditionNode::Execute(Scope* scope, Err* err) const {
316 Value condition_result = condition_->Execute(scope, err);
317 if (err->has_error())
318 return Value();
319 if (condition_result.type() != Value::BOOLEAN) {
320 *err = condition_->MakeErrorDescribing(
321 "Condition does not evaluate to a boolean value.",
322 std::string("This is a value of type \"") +
323 Value::DescribeType(condition_result.type()) +
324 "\" instead.");
325 err->AppendRange(if_token_.range());
326 return Value();
327 }
328
329 if (condition_result.boolean_value()) {
330 if_true_->ExecuteBlockInScope(scope, err);
331 } else if (if_false_) {
332 // The else block is optional. It's either another condition (for an
333 // "else if" and we can just Execute it and the condition will handle
334 // the scoping) or it's a block indicating an "else" in which ase we
335 // need to be sure it inherits our scope.
336 const BlockNode* if_false_block = if_false_->AsBlock();
337 if (if_false_block)
338 if_false_block->ExecuteBlockInScope(scope, err);
339 else
340 if_false_->Execute(scope, err);
341 }
342
343 return Value();
344 }
345
GetRange() const346 LocationRange ConditionNode::GetRange() const {
347 if (if_false_)
348 return if_token_.range().Union(if_false_->GetRange());
349 return if_token_.range().Union(if_true_->GetRange());
350 }
351
MakeErrorDescribing(const std::string & msg,const std::string & help) const352 Err ConditionNode::MakeErrorDescribing(const std::string& msg,
353 const std::string& help) const {
354 return Err(if_token_, msg, help);
355 }
356
Print(std::ostream & out,int indent) const357 void ConditionNode::Print(std::ostream& out, int indent) const {
358 out << IndentFor(indent) << "CONDITION\n";
359 PrintComments(out, indent);
360 condition_->Print(out, indent + 1);
361 if_true_->Print(out, indent + 1);
362 if (if_false_)
363 if_false_->Print(out, indent + 1);
364 }
365
366 // FunctionCallNode -----------------------------------------------------------
367
FunctionCallNode()368 FunctionCallNode::FunctionCallNode() {
369 }
370
~FunctionCallNode()371 FunctionCallNode::~FunctionCallNode() {
372 }
373
AsFunctionCall() const374 const FunctionCallNode* FunctionCallNode::AsFunctionCall() const {
375 return this;
376 }
377
Execute(Scope * scope,Err * err) const378 Value FunctionCallNode::Execute(Scope* scope, Err* err) const {
379 return functions::RunFunction(scope, this, args_.get(), block_.get(), err);
380 }
381
GetRange() const382 LocationRange FunctionCallNode::GetRange() const {
383 if (function_.type() == Token::INVALID)
384 return LocationRange(); // This will be null in some tests.
385 if (block_)
386 return function_.range().Union(block_->GetRange());
387 return function_.range().Union(args_->GetRange());
388 }
389
MakeErrorDescribing(const std::string & msg,const std::string & help) const390 Err FunctionCallNode::MakeErrorDescribing(const std::string& msg,
391 const std::string& help) const {
392 return Err(function_, msg, help);
393 }
394
Print(std::ostream & out,int indent) const395 void FunctionCallNode::Print(std::ostream& out, int indent) const {
396 out << IndentFor(indent) << "FUNCTION(" << function_.value() << ")\n";
397 PrintComments(out, indent);
398 args_->Print(out, indent + 1);
399 if (block_)
400 block_->Print(out, indent + 1);
401 }
402
403 // IdentifierNode --------------------------------------------------------------
404
IdentifierNode()405 IdentifierNode::IdentifierNode() {
406 }
407
IdentifierNode(const Token & token)408 IdentifierNode::IdentifierNode(const Token& token) : value_(token) {
409 }
410
~IdentifierNode()411 IdentifierNode::~IdentifierNode() {
412 }
413
AsIdentifier() const414 const IdentifierNode* IdentifierNode::AsIdentifier() const {
415 return this;
416 }
417
Execute(Scope * scope,Err * err) const418 Value IdentifierNode::Execute(Scope* scope, Err* err) const {
419 const Value* value = scope->GetValue(value_.value(), true);
420 Value result;
421 if (!value) {
422 *err = MakeErrorDescribing("Undefined identifier");
423 return result;
424 }
425
426 result = *value;
427 result.set_origin(this);
428 return result;
429 }
430
GetRange() const431 LocationRange IdentifierNode::GetRange() const {
432 return value_.range();
433 }
434
MakeErrorDescribing(const std::string & msg,const std::string & help) const435 Err IdentifierNode::MakeErrorDescribing(const std::string& msg,
436 const std::string& help) const {
437 return Err(value_, msg, help);
438 }
439
Print(std::ostream & out,int indent) const440 void IdentifierNode::Print(std::ostream& out, int indent) const {
441 out << IndentFor(indent) << "IDENTIFIER(" << value_.value() << ")\n";
442 PrintComments(out, indent);
443 }
444
445 // ListNode -------------------------------------------------------------------
446
ListNode()447 ListNode::ListNode() {
448 }
449
~ListNode()450 ListNode::~ListNode() {
451 STLDeleteContainerPointers(contents_.begin(), contents_.end());
452 }
453
AsList() const454 const ListNode* ListNode::AsList() const {
455 return this;
456 }
457
Execute(Scope * scope,Err * err) const458 Value ListNode::Execute(Scope* scope, Err* err) const {
459 Value result_value(this, Value::LIST);
460 std::vector<Value>& results = result_value.list_value();
461 results.reserve(contents_.size());
462
463 for (size_t i = 0; i < contents_.size(); i++) {
464 const ParseNode* cur = contents_[i];
465 if (cur->AsBlockComment())
466 continue;
467 results.push_back(cur->Execute(scope, err));
468 if (err->has_error())
469 return Value();
470 if (results.back().type() == Value::NONE) {
471 *err = cur->MakeErrorDescribing(
472 "This does not evaluate to a value.",
473 "I can't do something with nothing.");
474 return Value();
475 }
476 }
477 return result_value;
478 }
479
GetRange() const480 LocationRange ListNode::GetRange() const {
481 return LocationRange(begin_token_.location(), end_token_.location());
482 }
483
MakeErrorDescribing(const std::string & msg,const std::string & help) const484 Err ListNode::MakeErrorDescribing(const std::string& msg,
485 const std::string& help) const {
486 return Err(begin_token_, msg, help);
487 }
488
Print(std::ostream & out,int indent) const489 void ListNode::Print(std::ostream& out, int indent) const {
490 out << IndentFor(indent) << "LIST\n";
491 PrintComments(out, indent);
492 for (size_t i = 0; i < contents_.size(); i++)
493 contents_[i]->Print(out, indent + 1);
494 }
495
496 // LiteralNode -----------------------------------------------------------------
497
LiteralNode()498 LiteralNode::LiteralNode() {
499 }
500
LiteralNode(const Token & token)501 LiteralNode::LiteralNode(const Token& token) : value_(token) {
502 }
503
~LiteralNode()504 LiteralNode::~LiteralNode() {
505 }
506
AsLiteral() const507 const LiteralNode* LiteralNode::AsLiteral() const {
508 return this;
509 }
510
Execute(Scope * scope,Err * err) const511 Value LiteralNode::Execute(Scope* scope, Err* err) const {
512 switch (value_.type()) {
513 case Token::TRUE_TOKEN:
514 return Value(this, true);
515 case Token::FALSE_TOKEN:
516 return Value(this, false);
517 case Token::INTEGER: {
518 int64 result_int;
519 if (!base::StringToInt64(value_.value(), &result_int)) {
520 *err = MakeErrorDescribing("This does not look like an integer");
521 return Value();
522 }
523 return Value(this, result_int);
524 }
525 case Token::STRING: {
526 Value v(this, Value::STRING);
527 ExpandStringLiteral(scope, value_, &v, err);
528 return v;
529 }
530 default:
531 NOTREACHED();
532 return Value();
533 }
534 }
535
GetRange() const536 LocationRange LiteralNode::GetRange() const {
537 return value_.range();
538 }
539
MakeErrorDescribing(const std::string & msg,const std::string & help) const540 Err LiteralNode::MakeErrorDescribing(const std::string& msg,
541 const std::string& help) const {
542 return Err(value_, msg, help);
543 }
544
Print(std::ostream & out,int indent) const545 void LiteralNode::Print(std::ostream& out, int indent) const {
546 out << IndentFor(indent) << "LITERAL(" << value_.value() << ")\n";
547 PrintComments(out, indent);
548 }
549
550 // UnaryOpNode ----------------------------------------------------------------
551
UnaryOpNode()552 UnaryOpNode::UnaryOpNode() {
553 }
554
~UnaryOpNode()555 UnaryOpNode::~UnaryOpNode() {
556 }
557
AsUnaryOp() const558 const UnaryOpNode* UnaryOpNode::AsUnaryOp() const {
559 return this;
560 }
561
Execute(Scope * scope,Err * err) const562 Value UnaryOpNode::Execute(Scope* scope, Err* err) const {
563 Value operand_value = operand_->Execute(scope, err);
564 if (err->has_error())
565 return Value();
566 return ExecuteUnaryOperator(scope, this, operand_value, err);
567 }
568
GetRange() const569 LocationRange UnaryOpNode::GetRange() const {
570 return op_.range().Union(operand_->GetRange());
571 }
572
MakeErrorDescribing(const std::string & msg,const std::string & help) const573 Err UnaryOpNode::MakeErrorDescribing(const std::string& msg,
574 const std::string& help) const {
575 return Err(op_, msg, help);
576 }
577
Print(std::ostream & out,int indent) const578 void UnaryOpNode::Print(std::ostream& out, int indent) const {
579 out << IndentFor(indent) << "UNARY(" << op_.value() << ")\n";
580 PrintComments(out, indent);
581 operand_->Print(out, indent + 1);
582 }
583
584 // BlockCommentNode ------------------------------------------------------------
585
BlockCommentNode()586 BlockCommentNode::BlockCommentNode() {
587 }
588
~BlockCommentNode()589 BlockCommentNode::~BlockCommentNode() {
590 }
591
AsBlockComment() const592 const BlockCommentNode* BlockCommentNode::AsBlockComment() const {
593 return this;
594 }
595
Execute(Scope * scope,Err * err) const596 Value BlockCommentNode::Execute(Scope* scope, Err* err) const {
597 return Value();
598 }
599
GetRange() const600 LocationRange BlockCommentNode::GetRange() const {
601 return comment_.range();
602 }
603
MakeErrorDescribing(const std::string & msg,const std::string & help) const604 Err BlockCommentNode::MakeErrorDescribing(const std::string& msg,
605 const std::string& help) const {
606 return Err(comment_, msg, help);
607 }
608
Print(std::ostream & out,int indent) const609 void BlockCommentNode::Print(std::ostream& out, int indent) const {
610 out << IndentFor(indent) << "BLOCK_COMMENT(" << comment_.value() << ")\n";
611 PrintComments(out, indent);
612 }
613