const Property *OptionValueProperties::GetPropertyAtPath(
    const ExecutionContext *exe_ctx, bool will_modify, llvm::StringRef name) const {
  const Property *property = nullptr;
  if (name.empty())
    return nullptr;
  llvm::StringRef sub_name;
  ConstString key;
  size_t key_len = name.find_first_of(".[{");

  if (key_len != llvm::StringRef::npos) {
    key.SetString(name.take_front(key_len));
    sub_name = name.drop_front(key_len);
  } else
    key.SetString(name);

  property = GetProperty(exe_ctx, will_modify, key);
  if (sub_name.empty() || !property)
    return property;

  if (sub_name[0] == '.') {
    OptionValueProperties *sub_properties =
        property->GetValue()->GetAsProperties();
    if (sub_properties)
      return sub_properties->GetPropertyAtPath(exe_ctx, will_modify,
                                                sub_name.drop_front());
  }
  return nullptr;
}
static bool FindFunctionInModule(ConstString &mangled_name,
                                 llvm::Module *module, const char *orig_name) {
  for (const auto &func : module->getFunctionList()) {
    const StringRef &name = func.getName();
    if (name.find(orig_name) != StringRef::npos) {
      mangled_name.SetString(name);
      return true;
    }
  }

  return false;
}
lldb::OptionValueSP
OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,
  llvm::StringRef name, bool will_modify,
                                   Error &error) const {
  lldb::OptionValueSP value_sp;
  if (name.empty())
    return OptionValueSP();

  llvm::StringRef sub_name;
  ConstString key;
  size_t key_len = name.find_first_of(".[{");
  if (key_len != llvm::StringRef::npos) {
    key.SetString(name.take_front(key_len));
    sub_name = name.drop_front(key_len);
  } else
    key.SetString(name);

  value_sp = GetValueForKey(exe_ctx, key, will_modify);
  if (sub_name.empty() || !value_sp)
    return value_sp;

  switch (sub_name[0]) {
  case '.': {
    lldb::OptionValueSP return_val_sp;
    return_val_sp =
        value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), will_modify, error);
    if (!return_val_sp) {
      if (Properties::IsSettingExperimental(sub_name.drop_front())) {
        size_t experimental_len =
            strlen(Properties::GetExperimentalSettingsName());
        if (sub_name[experimental_len + 1] == '.')
          return_val_sp = value_sp->GetSubValue(
              exe_ctx, sub_name.drop_front(experimental_len + 2), will_modify, error);
        // It isn't an error if an experimental setting is not present.
        if (!return_val_sp)
          error.Clear();
      }
    }
    return return_val_sp;
  }
  case '{':
    // Predicate matching for predicates like
    // "<setting-name>{<predicate>}"
    // strings are parsed by the current OptionValueProperties subclass
    // to mean whatever they want to. For instance a subclass of
    // OptionValueProperties for a lldb_private::Target might implement:
    // "target.run-args{arch==i386}"   -- only set run args if the arch is
    // i386
    // "target.run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the
    // path matches
    // "target.run-args{basename==test&&arch==x86_64}" -- only set run args
    // if executable basename is "test" and arch is "x86_64"
    if (sub_name[1]) {
      llvm::StringRef predicate_start = sub_name.drop_front();
      size_t pos = predicate_start.find_first_of('}');
      if (pos != llvm::StringRef::npos) {
        auto predicate = predicate_start.take_front(pos);
        auto rest = predicate_start.drop_front(pos);
        if (PredicateMatches(exe_ctx, predicate)) {
          if (!rest.empty()) {
            // Still more subvalue string to evaluate
            return value_sp->GetSubValue(exe_ctx, rest,
                                          will_modify, error);
          } else {
            // We have a match!
            break;
          }
        }
      }
    }
    // Predicate didn't match or wasn't correctly formed
    value_sp.reset();
    break;

  case '[':
    // Array or dictionary access for subvalues like:
    // "[12]"       -- access 12th array element
    // "['hello']"  -- dictionary access of key named hello
    return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);

  default:
    value_sp.reset();
    break;
  }
  return value_sp;
}