]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Interpreter / OptionValueDictionary.cpp
1 //===-- OptionValueDictionary.cpp -------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Interpreter/OptionValueDictionary.h"
11
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 #include "llvm/ADT/StringRef.h"
16 // Project includes
17 #include "lldb/Core/State.h"
18 #include "lldb/DataFormatters/FormatManager.h"
19 #include "lldb/Interpreter/OptionValueString.h"
20 #include "lldb/Utility/Args.h"
21
22 using namespace lldb;
23 using namespace lldb_private;
24
25 void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
26                                       Stream &strm, uint32_t dump_mask) {
27   const Type dict_type = ConvertTypeMaskToType(m_type_mask);
28   if (dump_mask & eDumpOptionType) {
29     if (m_type_mask != eTypeInvalid)
30       strm.Printf("(%s of %ss)", GetTypeAsCString(),
31                   GetBuiltinTypeAsCString(dict_type));
32     else
33       strm.Printf("(%s)", GetTypeAsCString());
34   }
35   if (dump_mask & eDumpOptionValue) {
36     if (dump_mask & eDumpOptionType)
37       strm.PutCString(" =");
38
39     collection::iterator pos, end = m_values.end();
40
41     strm.IndentMore();
42
43     for (pos = m_values.begin(); pos != end; ++pos) {
44       OptionValue *option_value = pos->second.get();
45       strm.EOL();
46       strm.Indent(pos->first.GetCString());
47
48       const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
49       switch (dict_type) {
50       default:
51       case eTypeArray:
52       case eTypeDictionary:
53       case eTypeProperties:
54       case eTypeFileSpecList:
55       case eTypePathMap:
56         strm.PutChar(' ');
57         option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
58         break;
59
60       case eTypeBoolean:
61       case eTypeChar:
62       case eTypeEnum:
63       case eTypeFileSpec:
64       case eTypeFormat:
65       case eTypeSInt64:
66       case eTypeString:
67       case eTypeUInt64:
68       case eTypeUUID:
69         // No need to show the type for dictionaries of simple items
70         strm.PutCString("=");
71         option_value->DumpValue(exe_ctx, strm,
72                                 (dump_mask & (~eDumpOptionType)) |
73                                     extra_dump_options);
74         break;
75       }
76     }
77     strm.IndentLess();
78   }
79 }
80
81 size_t OptionValueDictionary::GetArgs(Args &args) const {
82   args.Clear();
83   collection::const_iterator pos, end = m_values.end();
84   for (pos = m_values.begin(); pos != end; ++pos) {
85     StreamString strm;
86     strm.Printf("%s=", pos->first.GetCString());
87     pos->second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
88     args.AppendArgument(strm.GetString());
89   }
90   return args.GetArgumentCount();
91 }
92
93 Status OptionValueDictionary::SetArgs(const Args &args,
94                                       VarSetOperationType op) {
95   Status error;
96   const size_t argc = args.GetArgumentCount();
97   switch (op) {
98   case eVarSetOperationClear:
99     Clear();
100     break;
101
102   case eVarSetOperationAppend:
103   case eVarSetOperationReplace:
104   case eVarSetOperationAssign:
105     if (argc == 0) {
106       error.SetErrorString(
107           "assign operation takes one or more key=value arguments");
108       return error;
109     }
110     for (const auto &entry : args) {
111       if (entry.ref.empty()) {
112         error.SetErrorString("empty argument");
113         return error;
114       }
115       if (!entry.ref.contains('=')) {
116         error.SetErrorString(
117             "assign operation takes one or more key=value arguments");
118         return error;
119       }
120
121       llvm::StringRef key, value;
122       std::tie(key, value) = entry.ref.split('=');
123       bool key_valid = false;
124       if (key.empty()) {
125         error.SetErrorString("empty dictionary key");
126         return error;
127       }
128
129       if (key.front() == '[') {
130         // Key name starts with '[', so the key value must be in single or
131         // double quotes like: ['<key>'] ["<key>"]
132         if ((key.size() > 2) && (key.back() == ']')) {
133           // Strip leading '[' and trailing ']'
134           key = key.substr(1, key.size() - 2);
135           const char quote_char = key.front();
136           if ((quote_char == '\'') || (quote_char == '"')) {
137             if ((key.size() > 2) && (key.back() == quote_char)) {
138               // Strip the quotes
139               key = key.substr(1, key.size() - 2);
140               key_valid = true;
141             }
142           } else {
143             // square brackets, no quotes
144             key_valid = true;
145           }
146         }
147       } else {
148         // No square brackets or quotes
149         key_valid = true;
150       }
151       if (!key_valid) {
152         error.SetErrorStringWithFormat(
153             "invalid key \"%s\", the key must be a bare string or "
154             "surrounded by brackets with optional quotes: [<key>] or "
155             "['<key>'] or [\"<key>\"]",
156             key.str().c_str());
157         return error;
158       }
159
160       lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
161           value.str().c_str(), m_type_mask, error));
162       if (value_sp) {
163         if (error.Fail())
164           return error;
165         m_value_was_set = true;
166         SetValueForKey(ConstString(key), value_sp, true);
167       } else {
168         error.SetErrorString("dictionaries that can contain multiple types "
169                              "must subclass OptionValueArray");
170       }
171     }
172     break;
173
174   case eVarSetOperationRemove:
175     if (argc > 0) {
176       for (size_t i = 0; i < argc; ++i) {
177         ConstString key(args.GetArgumentAtIndex(i));
178         if (!DeleteValueForKey(key)) {
179           error.SetErrorStringWithFormat(
180               "no value found named '%s', aborting remove operation",
181               key.GetCString());
182           break;
183         }
184       }
185     } else {
186       error.SetErrorString("remove operation takes one or more key arguments");
187     }
188     break;
189
190   case eVarSetOperationInsertBefore:
191   case eVarSetOperationInsertAfter:
192   case eVarSetOperationInvalid:
193     error = OptionValue::SetValueFromString(llvm::StringRef(), op);
194     break;
195   }
196   return error;
197 }
198
199 Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
200                                                  VarSetOperationType op) {
201   Args args(value.str());
202   Status error = SetArgs(args, op);
203   if (error.Success())
204     NotifyValueChanged();
205   return error;
206 }
207
208 lldb::OptionValueSP
209 OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
210                                    llvm::StringRef name, bool will_modify,
211                                    Status &error) const {
212   lldb::OptionValueSP value_sp;
213   if (name.empty())
214     return nullptr;
215
216   llvm::StringRef left, temp;
217   std::tie(left, temp) = name.split('[');
218   if (left.size() == name.size()) {
219     error.SetErrorStringWithFormat("invalid value path '%s', %s values only "
220       "support '[<key>]' subvalues where <key> "
221       "a string value optionally delimited by "
222       "single or double quotes",
223       name.str().c_str(), GetTypeAsCString());
224     return nullptr;
225   }
226   assert(!temp.empty());
227
228   llvm::StringRef key, quote_char;
229
230   if (temp[0] == '\"' || temp[0] == '\'') {
231     quote_char = temp.take_front();
232     temp = temp.drop_front();
233   }
234
235   llvm::StringRef sub_name;
236   std::tie(key, sub_name) = temp.split(']');
237
238   if (!key.consume_back(quote_char) || key.empty()) {
239     error.SetErrorStringWithFormat("invalid value path '%s', "
240       "key names must be formatted as ['<key>'] where <key> "
241       "is a string that doesn't contain quotes and the quote"
242       " char is optional", name.str().c_str());
243     return nullptr;
244   }
245
246   value_sp = GetValueForKey(ConstString(key));
247   if (!value_sp) {
248     error.SetErrorStringWithFormat(
249       "dictionary does not contain a value for the key name '%s'",
250       key.str().c_str());
251     return nullptr;
252   }
253
254   if (sub_name.empty())
255     return value_sp;
256   return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
257 }
258
259 Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
260                                           VarSetOperationType op,
261                                           llvm::StringRef name,
262                                           llvm::StringRef value) {
263   Status error;
264   const bool will_modify = true;
265   lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
266   if (value_sp)
267     error = value_sp->SetValueFromString(value, op);
268   else {
269     if (error.AsCString() == nullptr)
270       error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
271   }
272   return error;
273 }
274
275 lldb::OptionValueSP
276 OptionValueDictionary::GetValueForKey(const ConstString &key) const {
277   lldb::OptionValueSP value_sp;
278   collection::const_iterator pos = m_values.find(key);
279   if (pos != m_values.end())
280     value_sp = pos->second;
281   return value_sp;
282 }
283
284 bool OptionValueDictionary::SetValueForKey(const ConstString &key,
285                                            const lldb::OptionValueSP &value_sp,
286                                            bool can_replace) {
287   // Make sure the value_sp object is allowed to contain values of the type
288   // passed in...
289   if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
290     if (!can_replace) {
291       collection::const_iterator pos = m_values.find(key);
292       if (pos != m_values.end())
293         return false;
294     }
295     m_values[key] = value_sp;
296     return true;
297   }
298   return false;
299 }
300
301 bool OptionValueDictionary::DeleteValueForKey(const ConstString &key) {
302   collection::iterator pos = m_values.find(key);
303   if (pos != m_values.end()) {
304     m_values.erase(pos);
305     return true;
306   }
307   return false;
308 }
309
310 lldb::OptionValueSP OptionValueDictionary::DeepCopy() const {
311   OptionValueDictionary *copied_dict =
312       new OptionValueDictionary(m_type_mask, m_raw_value_dump);
313   lldb::OptionValueSP copied_value_sp(copied_dict);
314   collection::const_iterator pos, end = m_values.end();
315   for (pos = m_values.begin(); pos != end; ++pos) {
316     StreamString strm;
317     strm.Printf("%s=", pos->first.GetCString());
318     copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true);
319   }
320   return copied_value_sp;
321 }