OLD | NEW |
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/parse_tree.h" | 5 #include "tools/gn/parse_tree.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 } | 46 } |
47 | 47 |
48 AccessorNode::~AccessorNode() { | 48 AccessorNode::~AccessorNode() { |
49 } | 49 } |
50 | 50 |
51 const AccessorNode* AccessorNode::AsAccessor() const { | 51 const AccessorNode* AccessorNode::AsAccessor() const { |
52 return this; | 52 return this; |
53 } | 53 } |
54 | 54 |
55 Value AccessorNode::Execute(Scope* scope, Err* err) const { | 55 Value AccessorNode::Execute(Scope* scope, Err* err) const { |
| 56 if (index_) |
| 57 return ExecuteArrayAccess(scope, err); |
| 58 else if (member_) |
| 59 return ExecuteScopeAccess(scope, err); |
| 60 NOTREACHED(); |
| 61 return Value(); |
| 62 } |
| 63 |
| 64 LocationRange AccessorNode::GetRange() const { |
| 65 if (index_) |
| 66 return LocationRange(base_.location(), index_->GetRange().end()); |
| 67 else if (member_) |
| 68 return LocationRange(base_.location(), member_->GetRange().end()); |
| 69 NOTREACHED(); |
| 70 return LocationRange(); |
| 71 } |
| 72 |
| 73 Err AccessorNode::MakeErrorDescribing(const std::string& msg, |
| 74 const std::string& help) const { |
| 75 return Err(GetRange(), msg, help); |
| 76 } |
| 77 |
| 78 void AccessorNode::Print(std::ostream& out, int indent) const { |
| 79 out << IndentFor(indent) << "ACCESSOR\n"; |
| 80 out << IndentFor(indent + 1) << base_.value() << "\n"; |
| 81 if (index_) |
| 82 index_->Print(out, indent + 1); |
| 83 else if (member_) |
| 84 member_->Print(out, indent + 1); |
| 85 } |
| 86 |
| 87 Value AccessorNode::ExecuteArrayAccess(Scope* scope, Err* err) const { |
56 Value index_value = index_->Execute(scope, err); | 88 Value index_value = index_->Execute(scope, err); |
57 if (err->has_error()) | 89 if (err->has_error()) |
58 return Value(); | 90 return Value(); |
59 if (!index_value.VerifyTypeIs(Value::INTEGER, err)) | 91 if (!index_value.VerifyTypeIs(Value::INTEGER, err)) |
60 return Value(); | 92 return Value(); |
61 | 93 |
62 const Value* base_value = scope->GetValue(base_.value(), true); | 94 const Value* base_value = scope->GetValue(base_.value(), true); |
63 if (!base_value) { | 95 if (!base_value) { |
64 *err = MakeErrorDescribing("Undefined identifier."); | 96 *err = MakeErrorDescribing("Undefined identifier."); |
65 return Value(); | 97 return Value(); |
(...skipping 18 matching lines...) Expand all Loading... |
84 return Value(); | 116 return Value(); |
85 } | 117 } |
86 | 118 |
87 // Doing this assumes that there's no way in the language to do anything | 119 // Doing this assumes that there's no way in the language to do anything |
88 // between the time the reference is created and the time that the reference | 120 // between the time the reference is created and the time that the reference |
89 // is used. If there is, this will crash! Currently, this is just used for | 121 // is used. If there is, this will crash! Currently, this is just used for |
90 // array accesses where this "shouldn't" happen. | 122 // array accesses where this "shouldn't" happen. |
91 return base_value->list_value()[index_sizet]; | 123 return base_value->list_value()[index_sizet]; |
92 } | 124 } |
93 | 125 |
94 LocationRange AccessorNode::GetRange() const { | 126 Value AccessorNode::ExecuteScopeAccess(Scope* scope, Err* err) const { |
95 return LocationRange(base_.location(), index_->GetRange().end()); | 127 // We jump through some hoops here since ideally a.b will count "b" as |
96 } | 128 // accessed in the given scope. The value "a" might be in some normal nested |
| 129 // scope and we can modify it, but it might also be inherited from the |
| 130 // readonly root scope and we can't do used variable tracking on it. (It's |
| 131 // not legal to const cast it away since the root scope will be in readonly |
| 132 // mode and being accessed from multiple threads without locking.) So this |
| 133 // code handles both cases. |
| 134 const Value* result = NULL; |
97 | 135 |
98 Err AccessorNode::MakeErrorDescribing(const std::string& msg, | 136 // Look up the value in the scope named by "base_". |
99 const std::string& help) const { | 137 Value* mutable_base_value = scope->GetMutableValue(base_.value(), true); |
100 return Err(GetRange(), msg, help); | 138 if (mutable_base_value) { |
101 } | 139 // Common case: base value is mutable so we can track variable accesses |
| 140 // for unused value warnings. |
| 141 if (!mutable_base_value->VerifyTypeIs(Value::SCOPE, err)) |
| 142 return Value(); |
| 143 result = mutable_base_value->scope_value()->GetValue( |
| 144 member_->value().value(), true); |
| 145 } else { |
| 146 // Fall back to see if the value is on a read-only scope. |
| 147 const Value* const_base_value = scope->GetValue(base_.value(), true); |
| 148 if (const_base_value) { |
| 149 // Read only value, don't try to mark the value access as a "used" one. |
| 150 if (!const_base_value->VerifyTypeIs(Value::SCOPE, err)) |
| 151 return Value(); |
| 152 result = |
| 153 const_base_value->scope_value()->GetValue(member_->value().value()); |
| 154 } else { |
| 155 *err = Err(base_, "Undefined identifier."); |
| 156 return Value(); |
| 157 } |
| 158 } |
102 | 159 |
103 void AccessorNode::Print(std::ostream& out, int indent) const { | 160 if (!result) { |
104 out << IndentFor(indent) << "ACCESSOR\n"; | 161 *err = Err(member_.get(), "No value named \"" + |
105 out << IndentFor(indent + 1) << base_.value() << "\n"; | 162 member_->value().value() + "\" in scope \"" + base_.value() + "\""); |
106 index_->Print(out, indent + 1); | 163 return Value(); |
| 164 } |
| 165 return *result; |
107 } | 166 } |
108 | 167 |
109 // BinaryOpNode --------------------------------------------------------------- | 168 // BinaryOpNode --------------------------------------------------------------- |
110 | 169 |
111 BinaryOpNode::BinaryOpNode() { | 170 BinaryOpNode::BinaryOpNode() { |
112 } | 171 } |
113 | 172 |
114 BinaryOpNode::~BinaryOpNode() { | 173 BinaryOpNode::~BinaryOpNode() { |
115 } | 174 } |
116 | 175 |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 | 520 |
462 Err UnaryOpNode::MakeErrorDescribing(const std::string& msg, | 521 Err UnaryOpNode::MakeErrorDescribing(const std::string& msg, |
463 const std::string& help) const { | 522 const std::string& help) const { |
464 return Err(op_, msg, help); | 523 return Err(op_, msg, help); |
465 } | 524 } |
466 | 525 |
467 void UnaryOpNode::Print(std::ostream& out, int indent) const { | 526 void UnaryOpNode::Print(std::ostream& out, int indent) const { |
468 out << IndentFor(indent) << "UNARY(" << op_.value() << ")\n"; | 527 out << IndentFor(indent) << "UNARY(" << op_.value() << ")\n"; |
469 operand_->Print(out, indent + 1); | 528 operand_->Print(out, indent + 1); |
470 } | 529 } |
OLD | NEW |