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/value.h"
6
7 #include <stddef.h>
8 #include <utility>
9
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "tools/gn/scope.h"
13
14 // NOTE: Cannot use = default here due to the use of a union member.
Value()15 Value::Value() {}
16
Value(const ParseNode * origin,Type t)17 Value::Value(const ParseNode* origin, Type t) : type_(t), origin_(origin) {
18 switch (type_) {
19 case NONE:
20 break;
21 case BOOLEAN:
22 boolean_value_ = false;
23 break;
24 case INTEGER:
25 int_value_ = 0;
26 break;
27 case STRING:
28 new (&string_value_) std::string();
29 break;
30 case LIST:
31 new (&list_value_) std::vector<Value>();
32 break;
33 case SCOPE:
34 new (&scope_value_) std::unique_ptr<Scope>();
35 break;
36 }
37 }
38
Value(const ParseNode * origin,bool bool_val)39 Value::Value(const ParseNode* origin, bool bool_val)
40 : type_(BOOLEAN),
41 boolean_value_(bool_val),
42 origin_(origin) {}
43
Value(const ParseNode * origin,int64_t int_val)44 Value::Value(const ParseNode* origin, int64_t int_val)
45 : type_(INTEGER),
46 int_value_(int_val),
47 origin_(origin) {}
48
Value(const ParseNode * origin,std::string str_val)49 Value::Value(const ParseNode* origin, std::string str_val)
50 : type_(STRING),
51 string_value_(std::move(str_val)),
52 origin_(origin) {}
53
Value(const ParseNode * origin,const char * str_val)54 Value::Value(const ParseNode* origin, const char* str_val)
55 : type_(STRING),
56 string_value_(str_val),
57 origin_(origin) {}
58
Value(const ParseNode * origin,std::unique_ptr<Scope> scope)59 Value::Value(const ParseNode* origin, std::unique_ptr<Scope> scope)
60 : type_(SCOPE),
61 scope_value_(std::move(scope)),
62 origin_(origin) {}
63
Value(const Value & other)64 Value::Value(const Value& other) : type_(other.type_), origin_(other.origin_) {
65 switch (type_) {
66 case NONE:
67 break;
68 case BOOLEAN:
69 boolean_value_ = other.boolean_value_;
70 break;
71 case INTEGER:
72 int_value_ = other.int_value_;
73 break;
74 case STRING:
75 new (&string_value_) std::string(other.string_value_);
76 break;
77 case LIST:
78 new (&list_value_) std::vector<Value>(other.list_value_);
79 break;
80 case SCOPE:
81 new (&scope_value_) std::unique_ptr<Scope>(
82 other.scope_value_.get() ? other.scope_value_->MakeClosure()
83 : nullptr);
84 break;
85 }
86 }
87
Value(Value && other)88 Value::Value(Value&& other) noexcept
89 : type_(other.type_), origin_(other.origin_) {
90 switch (type_) {
91 case NONE:
92 break;
93 case BOOLEAN:
94 boolean_value_ = other.boolean_value_;
95 break;
96 case INTEGER:
97 int_value_ = other.int_value_;
98 break;
99 case STRING:
100 new (&string_value_) std::string(std::move(other.string_value_));
101 break;
102 case LIST:
103 new (&list_value_) std::vector<Value>(std::move(other.list_value_));
104 break;
105 case SCOPE:
106 new (&scope_value_) std::unique_ptr<Scope>(std::move(other.scope_value_));
107 break;
108 }
109 }
110
operator =(const Value & other)111 Value& Value::operator=(const Value& other) {
112 if (this != &other) {
113 this->~Value();
114 new (this) Value(other);
115 }
116 return *this;
117 }
118
operator =(Value && other)119 Value& Value::operator=(Value&& other) noexcept {
120 if (this != &other) {
121 this->~Value();
122 new (this) Value(std::move(other));
123 }
124 return *this;
125 }
126
~Value()127 Value::~Value() {
128 using namespace std;
129 switch (type_) {
130 case STRING:
131 string_value_.~string();
132 break;
133 case LIST:
134 list_value_.~vector<Value>();
135 break;
136 case SCOPE:
137 scope_value_.~unique_ptr<Scope>();
138 break;
139 default:;
140 }
141 }
142
143 // static
DescribeType(Type t)144 const char* Value::DescribeType(Type t) {
145 switch (t) {
146 case NONE:
147 return "none";
148 case BOOLEAN:
149 return "boolean";
150 case INTEGER:
151 return "integer";
152 case STRING:
153 return "string";
154 case LIST:
155 return "list";
156 case SCOPE:
157 return "scope";
158 default:
159 NOTREACHED();
160 return "UNKNOWN";
161 }
162 }
163
SetScopeValue(std::unique_ptr<Scope> scope)164 void Value::SetScopeValue(std::unique_ptr<Scope> scope) {
165 DCHECK(type_ == SCOPE);
166 scope_value_ = std::move(scope);
167 }
168
ToString(bool quote_string) const169 std::string Value::ToString(bool quote_string) const {
170 switch (type_) {
171 case NONE:
172 return "<void>";
173 case BOOLEAN:
174 return boolean_value_ ? "true" : "false";
175 case INTEGER:
176 return base::Int64ToString(int_value_);
177 case STRING:
178 if (quote_string) {
179 std::string result = "\"";
180 bool hanging_backslash = false;
181 for (char ch : string_value_) {
182 // If the last character was a literal backslash and the next
183 // character could form a valid escape sequence, we need to insert
184 // an extra backslash to prevent that.
185 if (hanging_backslash && (ch == '$' || ch == '"' || ch == '\\'))
186 result += '\\';
187 // If the next character is a dollar sign or double quote, it needs
188 // to be escaped; otherwise it can be printed as is.
189 if (ch == '$' || ch == '"')
190 result += '\\';
191 result += ch;
192 hanging_backslash = (ch == '\\');
193 }
194 // Again, we need to prevent the closing double quotes from becoming
195 // an escape sequence.
196 if (hanging_backslash)
197 result += '\\';
198 result += '"';
199 return result;
200 }
201 return string_value_;
202 case LIST: {
203 std::string result = "[";
204 for (size_t i = 0; i < list_value_.size(); i++) {
205 if (i > 0)
206 result += ", ";
207 result += list_value_[i].ToString(true);
208 }
209 result.push_back(']');
210 return result;
211 }
212 case SCOPE: {
213 Scope::KeyValueMap scope_values;
214 scope_value_->GetCurrentScopeValues(&scope_values);
215 if (scope_values.empty())
216 return std::string("{ }");
217
218 std::string result = "{\n";
219 for (const auto& pair : scope_values) {
220 result += " " + pair.first.as_string() + " = " +
221 pair.second.ToString(true) + "\n";
222 }
223 result += "}";
224
225 return result;
226 }
227 }
228 return std::string();
229 }
230
VerifyTypeIs(Type t,Err * err) const231 bool Value::VerifyTypeIs(Type t, Err* err) const {
232 if (type_ == t)
233 return true;
234
235 *err = Err(origin(), std::string("This is not a ") + DescribeType(t) + ".",
236 std::string("Instead I see a ") + DescribeType(type_) + " = " +
237 ToString(true));
238 return false;
239 }
240
operator ==(const Value & other) const241 bool Value::operator==(const Value& other) const {
242 if (type_ != other.type_)
243 return false;
244
245 switch (type_) {
246 case Value::BOOLEAN:
247 return boolean_value() == other.boolean_value();
248 case Value::INTEGER:
249 return int_value() == other.int_value();
250 case Value::STRING:
251 return string_value() == other.string_value();
252 case Value::LIST:
253 if (list_value().size() != other.list_value().size())
254 return false;
255 for (size_t i = 0; i < list_value().size(); i++) {
256 if (list_value()[i] != other.list_value()[i])
257 return false;
258 }
259 return true;
260 case Value::SCOPE:
261 return scope_value()->CheckCurrentScopeValuesEqual(other.scope_value());
262 case Value::NONE:
263 return false;
264 default:
265 NOTREACHED();
266 return false;
267 }
268 }
269
operator !=(const Value & other) const270 bool Value::operator!=(const Value& other) const {
271 return !operator==(other);
272 }
273