brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.2 KiB · 0efc76b Raw
360 lines · cpp
1//===-- OptionValueDictionary.cpp -----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/OptionValueDictionary.h"10 11#include "lldb/DataFormatters/FormatManager.h"12#include "lldb/Interpreter/OptionValue.h"13#include "lldb/Interpreter/OptionValueEnumeration.h"14#include "lldb/Interpreter/OptionValueString.h"15#include "lldb/Utility/Args.h"16#include "lldb/Utility/State.h"17#include "llvm/ADT/StringRef.h"18 19using namespace lldb;20using namespace lldb_private;21 22void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,23                                      Stream &strm, uint32_t dump_mask) {24  const Type dict_type = ConvertTypeMaskToType(m_type_mask);25  if (dump_mask & eDumpOptionType) {26    if (m_type_mask != eTypeInvalid)27      strm.Printf("(%s of %ss)", GetTypeAsCString(),28                  GetBuiltinTypeAsCString(dict_type));29    else30      strm.Printf("(%s)", GetTypeAsCString());31  }32  if (dump_mask & eDumpOptionValue) {33    const bool one_line = dump_mask & eDumpOptionCommand;34    if (dump_mask & (eDumpOptionType | eDumpOptionDefaultValue)) {35      strm.PutCString(" =");36      if (dump_mask & eDumpOptionDefaultValue && !m_values.empty()) {37        DefaultValueFormat label(strm);38        strm.PutCString("empty");39      }40    }41 42    if (!one_line)43      strm.IndentMore();44 45    // m_values is not guaranteed to be sorted alphabetically, so for46    // consistentcy we will sort them here before dumping47    std::map<llvm::StringRef, OptionValue *> sorted_values;48    for (const auto &value : m_values) {49      sorted_values[value.first()] = value.second.get();50    }51    for (const auto &value : sorted_values) {52      OptionValue *option_value = value.second;53 54      if (one_line)55        strm << ' ';56      else57        strm.EOL();58 59      strm.Indent(value.first);60 61      const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;62      switch (dict_type) {63      default:64      case eTypeArray:65      case eTypeDictionary:66      case eTypeProperties:67      case eTypeFileSpecList:68      case eTypePathMap:69        strm.PutChar(' ');70        option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);71        break;72 73      case eTypeBoolean:74      case eTypeChar:75      case eTypeEnum:76      case eTypeFileLineColumn:77      case eTypeFileSpec:78      case eTypeFormat:79      case eTypeSInt64:80      case eTypeString:81      case eTypeUInt64:82      case eTypeUUID:83        // No need to show the type for dictionaries of simple items84        strm.PutCString("=");85        option_value->DumpValue(exe_ctx, strm,86                                (dump_mask & (~eDumpOptionType)) |87                                    extra_dump_options);88        break;89      }90    }91    if (!one_line)92      strm.IndentLess();93  }94}95 96llvm::json::Value97OptionValueDictionary::ToJSON(const ExecutionContext *exe_ctx) const {98  llvm::json::Object dict;99  for (const auto &value : m_values) {100    dict.try_emplace(value.first(), value.second->ToJSON(exe_ctx));101  }102  return dict;103}104 105size_t OptionValueDictionary::GetArgs(Args &args) const {106  args.Clear();107  for (const auto &value : m_values) {108    StreamString strm;109    strm.Printf("%s=", value.first().data());110    value.second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);111    args.AppendArgument(strm.GetString());112  }113  return args.GetArgumentCount();114}115 116Status OptionValueDictionary::SetArgs(const Args &args,117                                      VarSetOperationType op) {118  Status error;119  const size_t argc = args.GetArgumentCount();120  switch (op) {121  case eVarSetOperationClear:122    Clear();123    break;124 125  case eVarSetOperationAppend:126  case eVarSetOperationReplace:127  case eVarSetOperationAssign:128    if (argc == 0) {129      error = Status::FromErrorString(130          "assign operation takes one or more key=value arguments");131      return error;132    }133    for (const auto &entry : args) {134      if (entry.ref().empty()) {135        error = Status::FromErrorString("empty argument");136        return error;137      }138      if (!entry.ref().contains('=')) {139        error = Status::FromErrorString(140            "assign operation takes one or more key=value arguments");141        return error;142      }143 144      llvm::StringRef key, value;145      std::tie(key, value) = entry.ref().split('=');146      bool key_valid = false;147      if (key.empty()) {148        error = Status::FromErrorString("empty dictionary key");149        return error;150      }151 152      if (key.front() == '[') {153        // Key name starts with '[', so the key value must be in single or154        // double quotes like: ['<key>'] ["<key>"]155        if ((key.size() > 2) && (key.back() == ']')) {156          // Strip leading '[' and trailing ']'157          key = key.substr(1, key.size() - 2);158          const char quote_char = key.front();159          if ((quote_char == '\'') || (quote_char == '"')) {160            if ((key.size() > 2) && (key.back() == quote_char)) {161              // Strip the quotes162              key = key.substr(1, key.size() - 2);163              key_valid = true;164            }165          } else {166            // square brackets, no quotes167            key_valid = true;168          }169        }170      } else {171        // No square brackets or quotes172        key_valid = true;173      }174      if (!key_valid) {175        error = Status::FromErrorStringWithFormat(176            "invalid key \"%s\", the key must be a bare string or "177            "surrounded by brackets with optional quotes: [<key>] or "178            "['<key>'] or [\"<key>\"]",179            key.str().c_str());180        return error;181      }182 183      if (m_type_mask == 1u << eTypeEnum) {184        auto enum_value =185            std::make_shared<OptionValueEnumeration>(m_enum_values, 0);186        error = enum_value->SetValueFromString(value);187        if (error.Fail())188          return error;189        m_value_was_set = true;190        SetValueForKey(key, enum_value, true);191      } else {192        lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(193            value.str().c_str(), m_type_mask, error));194        if (value_sp) {195          if (error.Fail())196            return error;197          m_value_was_set = true;198          SetValueForKey(key, value_sp, true);199        } else {200          error = Status::FromErrorString(201              "dictionaries that can contain multiple types "202              "must subclass OptionValueArray");203        }204      }205    }206    break;207 208  case eVarSetOperationRemove:209    if (argc > 0) {210      for (size_t i = 0; i < argc; ++i) {211        llvm::StringRef key(args.GetArgumentAtIndex(i));212        if (!DeleteValueForKey(key)) {213          error = Status::FromErrorStringWithFormat(214              "no value found named '%s', aborting remove operation",215              key.data());216          break;217        }218      }219    } else {220      error = Status::FromErrorString(221          "remove operation takes one or more key arguments");222    }223    break;224 225  case eVarSetOperationInsertBefore:226  case eVarSetOperationInsertAfter:227  case eVarSetOperationInvalid:228    error = OptionValue::SetValueFromString(llvm::StringRef(), op);229    break;230  }231  return error;232}233 234Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,235                                                 VarSetOperationType op) {236  Args args(value.str());237  Status error = SetArgs(args, op);238  if (error.Success())239    NotifyValueChanged();240  return error;241}242 243lldb::OptionValueSP244OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,245                                   llvm::StringRef name, Status &error) const {246  lldb::OptionValueSP value_sp;247  if (name.empty())248    return nullptr;249 250  llvm::StringRef left, temp;251  std::tie(left, temp) = name.split('[');252  if (left.size() == name.size()) {253    error = Status::FromErrorStringWithFormat(254        "invalid value path '%s', %s values only "255        "support '[<key>]' subvalues where <key> "256        "a string value optionally delimited by "257        "single or double quotes",258        name.str().c_str(), GetTypeAsCString());259    return nullptr;260  }261  assert(!temp.empty());262 263  llvm::StringRef key, quote_char;264 265  if (temp[0] == '\"' || temp[0] == '\'') {266    quote_char = temp.take_front();267    temp = temp.drop_front();268  }269 270  llvm::StringRef sub_name;271  std::tie(key, sub_name) = temp.split(']');272 273  if (!key.consume_back(quote_char) || key.empty()) {274    error = Status::FromErrorStringWithFormat(275        "invalid value path '%s', "276        "key names must be formatted as ['<key>'] where <key> "277        "is a string that doesn't contain quotes and the quote"278        " char is optional",279        name.str().c_str());280    return nullptr;281  }282 283  value_sp = GetValueForKey(key);284  if (!value_sp) {285    error = Status::FromErrorStringWithFormat(286        "dictionary does not contain a value for the key name '%s'",287        key.str().c_str());288    return nullptr;289  }290 291  if (sub_name.empty())292    return value_sp;293  return value_sp->GetSubValue(exe_ctx, sub_name, error);294}295 296Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,297                                          VarSetOperationType op,298                                          llvm::StringRef name,299                                          llvm::StringRef value) {300  Status error;301  lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error));302  if (value_sp)303    error = value_sp->SetValueFromString(value, op);304  else {305    if (error.AsCString() == nullptr)306      error = Status::FromErrorStringWithFormat("invalid value path '%s'",307                                                name.str().c_str());308  }309  return error;310}311 312lldb::OptionValueSP313OptionValueDictionary::GetValueForKey(llvm::StringRef key) const {314  lldb::OptionValueSP value_sp;315  auto pos = m_values.find(key);316  if (pos != m_values.end())317    value_sp = pos->second;318  return value_sp;319}320 321bool OptionValueDictionary::SetValueForKey(llvm::StringRef key,322                                           const lldb::OptionValueSP &value_sp,323                                           bool can_replace) {324  // Make sure the value_sp object is allowed to contain values of the type325  // passed in...326  if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {327    if (!can_replace) {328      auto pos = m_values.find(key);329      if (pos != m_values.end())330        return false;331    }332    m_values[key] = value_sp;333    return true;334  }335  return false;336}337 338bool OptionValueDictionary::DeleteValueForKey(llvm::StringRef key) {339  auto pos = m_values.find(key);340  if (pos != m_values.end()) {341    m_values.erase(pos);342    return true;343  }344  return false;345}346 347OptionValueSP348OptionValueDictionary::DeepCopy(const OptionValueSP &new_parent) const {349  auto copy_sp = OptionValue::DeepCopy(new_parent);350  // copy_sp->GetAsDictionary cannot be used here as it doesn't work for derived351  // types that override GetType returning a different value.352  auto *dict_value_ptr = static_cast<OptionValueDictionary *>(copy_sp.get());353  lldbassert(dict_value_ptr);354 355  for (auto &value : dict_value_ptr->m_values)356    value.second = value.second->DeepCopy(copy_sp);357 358  return copy_sp;359}360