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