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 "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h"
9 #include "tools/gn/scope.h"
10
Value()11 Value::Value()
12 : type_(NONE),
13 boolean_value_(false),
14 int_value_(0),
15 origin_(NULL) {
16 }
17
Value(const ParseNode * origin,Type t)18 Value::Value(const ParseNode* origin, Type t)
19 : type_(t),
20 boolean_value_(false),
21 int_value_(0),
22 origin_(origin) {
23 }
24
Value(const ParseNode * origin,bool bool_val)25 Value::Value(const ParseNode* origin, bool bool_val)
26 : type_(BOOLEAN),
27 boolean_value_(bool_val),
28 int_value_(0),
29 origin_(origin) {
30 }
31
Value(const ParseNode * origin,int64 int_val)32 Value::Value(const ParseNode* origin, int64 int_val)
33 : type_(INTEGER),
34 boolean_value_(false),
35 int_value_(int_val),
36 origin_(origin) {
37 }
38
Value(const ParseNode * origin,std::string str_val)39 Value::Value(const ParseNode* origin, std::string str_val)
40 : type_(STRING),
41 string_value_(),
42 boolean_value_(false),
43 int_value_(0),
44 origin_(origin) {
45 string_value_.swap(str_val);
46 }
47
Value(const ParseNode * origin,const char * str_val)48 Value::Value(const ParseNode* origin, const char* str_val)
49 : type_(STRING),
50 string_value_(str_val),
51 boolean_value_(false),
52 int_value_(0),
53 origin_(origin) {
54 }
55
Value(const ParseNode * origin,scoped_ptr<Scope> scope)56 Value::Value(const ParseNode* origin, scoped_ptr<Scope> scope)
57 : type_(SCOPE),
58 string_value_(),
59 boolean_value_(false),
60 int_value_(0),
61 scope_value_(scope.Pass()),
62 origin_(origin) {
63 }
64
Value(const Value & other)65 Value::Value(const Value& other)
66 : type_(other.type_),
67 string_value_(other.string_value_),
68 boolean_value_(other.boolean_value_),
69 int_value_(other.int_value_),
70 list_value_(other.list_value_),
71 origin_(other.origin_) {
72 if (type() == SCOPE && other.scope_value_.get())
73 scope_value_ = other.scope_value_->MakeClosure();
74 }
75
~Value()76 Value::~Value() {
77 }
78
operator =(const Value & other)79 Value& Value::operator=(const Value& other) {
80 type_ = other.type_;
81 string_value_ = other.string_value_;
82 boolean_value_ = other.boolean_value_;
83 int_value_ = other.int_value_;
84 list_value_ = other.list_value_;
85 if (type() == SCOPE && other.scope_value_.get())
86 scope_value_ = other.scope_value_->MakeClosure();
87 origin_ = other.origin_;
88 return *this;
89 }
90
91 // static
DescribeType(Type t)92 const char* Value::DescribeType(Type t) {
93 switch (t) {
94 case NONE:
95 return "none";
96 case BOOLEAN:
97 return "boolean";
98 case INTEGER:
99 return "integer";
100 case STRING:
101 return "string";
102 case LIST:
103 return "list";
104 case SCOPE:
105 return "scope";
106 default:
107 NOTREACHED();
108 return "UNKNOWN";
109 }
110 }
111
SetScopeValue(scoped_ptr<Scope> scope)112 void Value::SetScopeValue(scoped_ptr<Scope> scope) {
113 DCHECK(type_ == SCOPE);
114 scope_value_ = scope.Pass();
115 }
116
ToString(bool quote_string) const117 std::string Value::ToString(bool quote_string) const {
118 switch (type_) {
119 case NONE:
120 return "<void>";
121 case BOOLEAN:
122 return boolean_value_ ? "true" : "false";
123 case INTEGER:
124 return base::Int64ToString(int_value_);
125 case STRING:
126 if (quote_string) {
127 std::string escaped = string_value_;
128 // First escape all special uses of a backslash.
129 ReplaceSubstringsAfterOffset(&escaped, 0, "\\$", "\\\\$");
130 ReplaceSubstringsAfterOffset(&escaped, 0, "\\\"", "\\\\\"");
131
132 // Now escape special chars.
133 ReplaceSubstringsAfterOffset(&escaped, 0, "$", "\\$");
134 ReplaceSubstringsAfterOffset(&escaped, 0, "\"", "\\\"");
135 return "\"" + escaped + "\"";
136 }
137 return string_value_;
138 case LIST: {
139 std::string result = "[";
140 for (size_t i = 0; i < list_value_.size(); i++) {
141 if (i > 0)
142 result += ", ";
143 result += list_value_[i].ToString(true);
144 }
145 result.push_back(']');
146 return result;
147 }
148 case SCOPE: {
149 Scope::KeyValueMap scope_values;
150 scope_value_->GetCurrentScopeValues(&scope_values);
151 if (scope_values.empty())
152 return std::string("{ }");
153
154 std::string result = "{\n";
155 for (Scope::KeyValueMap::const_iterator i = scope_values.begin();
156 i != scope_values.end(); ++i) {
157 result += " " + i->first.as_string() + " = " +
158 i->second.ToString(true) + "\n";
159 }
160 result += "}";
161
162 return result;
163 }
164 }
165 return std::string();
166 }
167
VerifyTypeIs(Type t,Err * err) const168 bool Value::VerifyTypeIs(Type t, Err* err) const {
169 if (type_ == t)
170 return true;
171
172 *err = Err(origin(),
173 std::string("This is not a ") + DescribeType(t) + ".",
174 std::string("Instead I see a ") + DescribeType(type_) + " = " +
175 ToString(true));
176 return false;
177 }
178
operator ==(const Value & other) const179 bool Value::operator==(const Value& other) const {
180 if (type_ != other.type_)
181 return false;
182
183 switch (type_) {
184 case Value::BOOLEAN:
185 return boolean_value() == other.boolean_value();
186 case Value::INTEGER:
187 return int_value() == other.int_value();
188 case Value::STRING:
189 return string_value() == other.string_value();
190 case Value::LIST:
191 if (list_value().size() != other.list_value().size())
192 return false;
193 for (size_t i = 0; i < list_value().size(); i++) {
194 if (list_value()[i] != other.list_value()[i])
195 return false;
196 }
197 return true;
198 case Value::SCOPE:
199 // Scopes are always considered not equal because there's currently
200 // no use case for comparing them, and it requires a bunch of complex
201 // iteration code.
202 return false;
203 default:
204 return false;
205 }
206 }
207
operator !=(const Value & other) const208 bool Value::operator!=(const Value& other) const {
209 return !operator==(other);
210 }
211