• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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