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
11Value::Value()
12    : type_(NONE),
13      boolean_value_(false),
14      int_value_(0),
15      origin_(NULL) {
16}
17
18Value::Value(const ParseNode* origin, Type t)
19    : type_(t),
20      boolean_value_(false),
21      int_value_(0),
22      origin_(origin) {
23}
24
25Value::Value(const ParseNode* origin, bool bool_val)
26    : type_(BOOLEAN),
27      boolean_value_(bool_val),
28      int_value_(0),
29      origin_(origin) {
30}
31
32Value::Value(const ParseNode* origin, int64 int_val)
33    : type_(INTEGER),
34      boolean_value_(false),
35      int_value_(int_val),
36      origin_(origin) {
37}
38
39Value::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
48Value::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
56Value::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
65Value::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
76Value::~Value() {
77}
78
79Value& 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
92const 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
112void Value::SetScopeValue(scoped_ptr<Scope> scope) {
113  DCHECK(type_ == SCOPE);
114  scope_value_ = scope.Pass();
115}
116
117std::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
168bool 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
179bool 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
208bool Value::operator!=(const Value& other) const {
209  return !operator==(other);
210}
211