• 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 "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