1*c9157d92SDimitry Andric //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// 2*c9157d92SDimitry Andric // 3*c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*c9157d92SDimitry Andric // 7*c9157d92SDimitry Andric //===----------------------------------------------------------------------===// 8*c9157d92SDimitry Andric 9*c9157d92SDimitry Andric #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 10*c9157d92SDimitry Andric #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 11*c9157d92SDimitry Andric 12*c9157d92SDimitry Andric #if LLDB_ENABLE_PYTHON 13*c9157d92SDimitry Andric 14*c9157d92SDimitry Andric #include <optional> 15*c9157d92SDimitry Andric #include <sstream> 16*c9157d92SDimitry Andric #include <tuple> 17*c9157d92SDimitry Andric #include <type_traits> 18*c9157d92SDimitry Andric #include <utility> 19*c9157d92SDimitry Andric 20*c9157d92SDimitry Andric #include "lldb/Host/Config.h" 21*c9157d92SDimitry Andric #include "lldb/Interpreter/Interfaces/ScriptedInterface.h" 22*c9157d92SDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 23*c9157d92SDimitry Andric 24*c9157d92SDimitry Andric #include "../PythonDataObjects.h" 25*c9157d92SDimitry Andric #include "../SWIGPythonBridge.h" 26*c9157d92SDimitry Andric #include "../ScriptInterpreterPythonImpl.h" 27*c9157d92SDimitry Andric 28*c9157d92SDimitry Andric namespace lldb_private { 29*c9157d92SDimitry Andric class ScriptInterpreterPythonImpl; 30*c9157d92SDimitry Andric class ScriptedPythonInterface : virtual public ScriptedInterface { 31*c9157d92SDimitry Andric public: 32*c9157d92SDimitry Andric ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 33*c9157d92SDimitry Andric ~ScriptedPythonInterface() override = default; 34*c9157d92SDimitry Andric 35*c9157d92SDimitry Andric enum class AbstractMethodCheckerCases { 36*c9157d92SDimitry Andric eNotImplemented, 37*c9157d92SDimitry Andric eNotAllocated, 38*c9157d92SDimitry Andric eNotCallable, 39*c9157d92SDimitry Andric eValid 40*c9157d92SDimitry Andric }; 41*c9157d92SDimitry Andric 42*c9157d92SDimitry Andric llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>> CheckAbstractMethodImplementation(const python::PythonDictionary & class_dict)43*c9157d92SDimitry Andric CheckAbstractMethodImplementation( 44*c9157d92SDimitry Andric const python::PythonDictionary &class_dict) const { 45*c9157d92SDimitry Andric 46*c9157d92SDimitry Andric using namespace python; 47*c9157d92SDimitry Andric 48*c9157d92SDimitry Andric std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker; 49*c9157d92SDimitry Andric #define SET_ERROR_AND_CONTINUE(method_name, error) \ 50*c9157d92SDimitry Andric { \ 51*c9157d92SDimitry Andric checker[method_name] = error; \ 52*c9157d92SDimitry Andric continue; \ 53*c9157d92SDimitry Andric } 54*c9157d92SDimitry Andric 55*c9157d92SDimitry Andric for (const llvm::StringLiteral &method_name : GetAbstractMethods()) { 56*c9157d92SDimitry Andric if (!class_dict.HasKey(method_name)) 57*c9157d92SDimitry Andric SET_ERROR_AND_CONTINUE(method_name, 58*c9157d92SDimitry Andric AbstractMethodCheckerCases::eNotImplemented) 59*c9157d92SDimitry Andric auto callable_or_err = class_dict.GetItem(method_name); 60*c9157d92SDimitry Andric if (!callable_or_err) 61*c9157d92SDimitry Andric SET_ERROR_AND_CONTINUE(method_name, 62*c9157d92SDimitry Andric AbstractMethodCheckerCases::eNotAllocated) 63*c9157d92SDimitry Andric if (!PythonCallable::Check(callable_or_err.get().get())) 64*c9157d92SDimitry Andric SET_ERROR_AND_CONTINUE(method_name, 65*c9157d92SDimitry Andric AbstractMethodCheckerCases::eNotCallable) 66*c9157d92SDimitry Andric checker[method_name] = AbstractMethodCheckerCases::eValid; 67*c9157d92SDimitry Andric } 68*c9157d92SDimitry Andric 69*c9157d92SDimitry Andric #undef HANDLE_ERROR 70*c9157d92SDimitry Andric 71*c9157d92SDimitry Andric return checker; 72*c9157d92SDimitry Andric } 73*c9157d92SDimitry Andric 74*c9157d92SDimitry Andric template <typename... Args> 75*c9157d92SDimitry Andric llvm::Expected<StructuredData::GenericSP> CreatePluginObject(llvm::StringRef class_name,StructuredData::Generic * script_obj,Args...args)76*c9157d92SDimitry Andric CreatePluginObject(llvm::StringRef class_name, 77*c9157d92SDimitry Andric StructuredData::Generic *script_obj, Args... args) { 78*c9157d92SDimitry Andric using namespace python; 79*c9157d92SDimitry Andric using Locker = ScriptInterpreterPythonImpl::Locker; 80*c9157d92SDimitry Andric 81*c9157d92SDimitry Andric auto create_error = [](std::string message) { 82*c9157d92SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), message); 83*c9157d92SDimitry Andric }; 84*c9157d92SDimitry Andric 85*c9157d92SDimitry Andric bool has_class_name = !class_name.empty(); 86*c9157d92SDimitry Andric bool has_interpreter_dict = 87*c9157d92SDimitry Andric !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 88*c9157d92SDimitry Andric if (!has_class_name && !has_interpreter_dict && !script_obj) { 89*c9157d92SDimitry Andric if (!has_class_name) 90*c9157d92SDimitry Andric return create_error("Missing script class name."); 91*c9157d92SDimitry Andric else if (!has_interpreter_dict) 92*c9157d92SDimitry Andric return create_error("Invalid script interpreter dictionary."); 93*c9157d92SDimitry Andric else 94*c9157d92SDimitry Andric return create_error("Missing scripting object."); 95*c9157d92SDimitry Andric } 96*c9157d92SDimitry Andric 97*c9157d92SDimitry Andric Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 98*c9157d92SDimitry Andric Locker::FreeLock); 99*c9157d92SDimitry Andric 100*c9157d92SDimitry Andric PythonObject result = {}; 101*c9157d92SDimitry Andric 102*c9157d92SDimitry Andric if (script_obj) { 103*c9157d92SDimitry Andric result = PythonObject(PyRefType::Borrowed, 104*c9157d92SDimitry Andric static_cast<PyObject *>(script_obj->GetValue())); 105*c9157d92SDimitry Andric } else { 106*c9157d92SDimitry Andric auto dict = 107*c9157d92SDimitry Andric PythonModule::MainModule().ResolveName<python::PythonDictionary>( 108*c9157d92SDimitry Andric m_interpreter.GetDictionaryName()); 109*c9157d92SDimitry Andric if (!dict.IsAllocated()) 110*c9157d92SDimitry Andric return create_error( 111*c9157d92SDimitry Andric llvm::formatv("Could not find interpreter dictionary: %s", 112*c9157d92SDimitry Andric m_interpreter.GetDictionaryName())); 113*c9157d92SDimitry Andric 114*c9157d92SDimitry Andric auto init = 115*c9157d92SDimitry Andric PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 116*c9157d92SDimitry Andric class_name, dict); 117*c9157d92SDimitry Andric if (!init.IsAllocated()) 118*c9157d92SDimitry Andric return create_error(llvm::formatv("Could not find script class: %s", 119*c9157d92SDimitry Andric class_name.data())); 120*c9157d92SDimitry Andric 121*c9157d92SDimitry Andric std::tuple<Args...> original_args = std::forward_as_tuple(args...); 122*c9157d92SDimitry Andric auto transformed_args = TransformArgs(original_args); 123*c9157d92SDimitry Andric 124*c9157d92SDimitry Andric std::string error_string; 125*c9157d92SDimitry Andric llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo(); 126*c9157d92SDimitry Andric if (!arg_info) { 127*c9157d92SDimitry Andric llvm::handleAllErrors( 128*c9157d92SDimitry Andric arg_info.takeError(), 129*c9157d92SDimitry Andric [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 130*c9157d92SDimitry Andric [&](const llvm::ErrorInfoBase &E) { 131*c9157d92SDimitry Andric error_string.append(E.message()); 132*c9157d92SDimitry Andric }); 133*c9157d92SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 134*c9157d92SDimitry Andric error_string); 135*c9157d92SDimitry Andric } 136*c9157d92SDimitry Andric 137*c9157d92SDimitry Andric llvm::Expected<PythonObject> expected_return_object = 138*c9157d92SDimitry Andric create_error("Resulting object is not initialized."); 139*c9157d92SDimitry Andric 140*c9157d92SDimitry Andric std::apply( 141*c9157d92SDimitry Andric [&init, &expected_return_object](auto &&...args) { 142*c9157d92SDimitry Andric llvm::consumeError(expected_return_object.takeError()); 143*c9157d92SDimitry Andric expected_return_object = init(args...); 144*c9157d92SDimitry Andric }, 145*c9157d92SDimitry Andric transformed_args); 146*c9157d92SDimitry Andric 147*c9157d92SDimitry Andric if (!expected_return_object) 148*c9157d92SDimitry Andric return expected_return_object.takeError(); 149*c9157d92SDimitry Andric result = expected_return_object.get(); 150*c9157d92SDimitry Andric } 151*c9157d92SDimitry Andric 152*c9157d92SDimitry Andric if (!result.IsValid()) 153*c9157d92SDimitry Andric return create_error("Resulting object is not a valid Python Object."); 154*c9157d92SDimitry Andric if (!result.HasAttribute("__class__")) 155*c9157d92SDimitry Andric return create_error("Resulting object doesn't have '__class__' member."); 156*c9157d92SDimitry Andric 157*c9157d92SDimitry Andric PythonObject obj_class = result.GetAttributeValue("__class__"); 158*c9157d92SDimitry Andric if (!obj_class.IsValid()) 159*c9157d92SDimitry Andric return create_error("Resulting class object is not a valid."); 160*c9157d92SDimitry Andric if (!obj_class.HasAttribute("__name__")) 161*c9157d92SDimitry Andric return create_error( 162*c9157d92SDimitry Andric "Resulting object class doesn't have '__name__' member."); 163*c9157d92SDimitry Andric PythonString obj_class_name = 164*c9157d92SDimitry Andric obj_class.GetAttributeValue("__name__").AsType<PythonString>(); 165*c9157d92SDimitry Andric 166*c9157d92SDimitry Andric PythonObject object_class_mapping_proxy = 167*c9157d92SDimitry Andric obj_class.GetAttributeValue("__dict__"); 168*c9157d92SDimitry Andric if (!obj_class.HasAttribute("__dict__")) 169*c9157d92SDimitry Andric return create_error( 170*c9157d92SDimitry Andric "Resulting object class doesn't have '__dict__' member."); 171*c9157d92SDimitry Andric 172*c9157d92SDimitry Andric PythonCallable dict_converter = PythonModule::BuiltinsModule() 173*c9157d92SDimitry Andric .ResolveName("dict") 174*c9157d92SDimitry Andric .AsType<PythonCallable>(); 175*c9157d92SDimitry Andric if (!dict_converter.IsAllocated()) 176*c9157d92SDimitry Andric return create_error( 177*c9157d92SDimitry Andric "Python 'builtins' module doesn't have 'dict' class."); 178*c9157d92SDimitry Andric 179*c9157d92SDimitry Andric PythonDictionary object_class_dict = 180*c9157d92SDimitry Andric dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>(); 181*c9157d92SDimitry Andric if (!object_class_dict.IsAllocated()) 182*c9157d92SDimitry Andric return create_error("Coudn't create dictionary from resulting object " 183*c9157d92SDimitry Andric "class mapping proxy object."); 184*c9157d92SDimitry Andric 185*c9157d92SDimitry Andric auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict); 186*c9157d92SDimitry Andric if (!checker_or_err) 187*c9157d92SDimitry Andric return checker_or_err.takeError(); 188*c9157d92SDimitry Andric 189*c9157d92SDimitry Andric for (const auto &method_checker : *checker_or_err) 190*c9157d92SDimitry Andric switch (method_checker.second) { 191*c9157d92SDimitry Andric case AbstractMethodCheckerCases::eNotImplemented: 192*c9157d92SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Script), 193*c9157d92SDimitry Andric "Abstract method {0}.{1} not implemented.", 194*c9157d92SDimitry Andric obj_class_name.GetString(), method_checker.first); 195*c9157d92SDimitry Andric break; 196*c9157d92SDimitry Andric case AbstractMethodCheckerCases::eNotAllocated: 197*c9157d92SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Script), 198*c9157d92SDimitry Andric "Abstract method {0}.{1} not allocated.", 199*c9157d92SDimitry Andric obj_class_name.GetString(), method_checker.first); 200*c9157d92SDimitry Andric break; 201*c9157d92SDimitry Andric case AbstractMethodCheckerCases::eNotCallable: 202*c9157d92SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Script), 203*c9157d92SDimitry Andric "Abstract method {0}.{1} not callable.", 204*c9157d92SDimitry Andric obj_class_name.GetString(), method_checker.first); 205*c9157d92SDimitry Andric break; 206*c9157d92SDimitry Andric case AbstractMethodCheckerCases::eValid: 207*c9157d92SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Script), 208*c9157d92SDimitry Andric "Abstract method {0}.{1} implemented & valid.", 209*c9157d92SDimitry Andric obj_class_name.GetString(), method_checker.first); 210*c9157d92SDimitry Andric break; 211*c9157d92SDimitry Andric } 212*c9157d92SDimitry Andric 213*c9157d92SDimitry Andric for (const auto &method_checker : *checker_or_err) 214*c9157d92SDimitry Andric if (method_checker.second != AbstractMethodCheckerCases::eValid) 215*c9157d92SDimitry Andric return create_error( 216*c9157d92SDimitry Andric llvm::formatv("Abstract method {0}.{1} missing. Enable lldb " 217*c9157d92SDimitry Andric "script log for more details.", 218*c9157d92SDimitry Andric obj_class_name.GetString(), method_checker.first)); 219*c9157d92SDimitry Andric 220*c9157d92SDimitry Andric m_object_instance_sp = StructuredData::GenericSP( 221*c9157d92SDimitry Andric new StructuredPythonObject(std::move(result))); 222*c9157d92SDimitry Andric return m_object_instance_sp; 223*c9157d92SDimitry Andric } 224*c9157d92SDimitry Andric 225*c9157d92SDimitry Andric protected: 226*c9157d92SDimitry Andric template <typename T = StructuredData::ObjectSP> ExtractValueFromPythonObject(python::PythonObject & p,Status & error)227*c9157d92SDimitry Andric T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 228*c9157d92SDimitry Andric return p.CreateStructuredObject(); 229*c9157d92SDimitry Andric } 230*c9157d92SDimitry Andric 231*c9157d92SDimitry Andric template <typename T = StructuredData::ObjectSP, typename... Args> Dispatch(llvm::StringRef method_name,Status & error,Args &&...args)232*c9157d92SDimitry Andric T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 233*c9157d92SDimitry Andric using namespace python; 234*c9157d92SDimitry Andric using Locker = ScriptInterpreterPythonImpl::Locker; 235*c9157d92SDimitry Andric 236*c9157d92SDimitry Andric std::string caller_signature = 237*c9157d92SDimitry Andric llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 238*c9157d92SDimitry Andric llvm::Twine(method_name) + llvm::Twine(")")) 239*c9157d92SDimitry Andric .str(); 240*c9157d92SDimitry Andric if (!m_object_instance_sp) 241*c9157d92SDimitry Andric return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 242*c9157d92SDimitry Andric error); 243*c9157d92SDimitry Andric 244*c9157d92SDimitry Andric Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 245*c9157d92SDimitry Andric Locker::FreeLock); 246*c9157d92SDimitry Andric 247*c9157d92SDimitry Andric PythonObject implementor(PyRefType::Borrowed, 248*c9157d92SDimitry Andric (PyObject *)m_object_instance_sp->GetValue()); 249*c9157d92SDimitry Andric 250*c9157d92SDimitry Andric if (!implementor.IsAllocated()) 251*c9157d92SDimitry Andric return ErrorWithMessage<T>(caller_signature, 252*c9157d92SDimitry Andric "Python implementor not allocated.", error); 253*c9157d92SDimitry Andric 254*c9157d92SDimitry Andric std::tuple<Args...> original_args = std::forward_as_tuple(args...); 255*c9157d92SDimitry Andric auto transformed_args = TransformArgs(original_args); 256*c9157d92SDimitry Andric 257*c9157d92SDimitry Andric llvm::Expected<PythonObject> expected_return_object = 258*c9157d92SDimitry Andric llvm::make_error<llvm::StringError>("Not initialized.", 259*c9157d92SDimitry Andric llvm::inconvertibleErrorCode()); 260*c9157d92SDimitry Andric std::apply( 261*c9157d92SDimitry Andric [&implementor, &method_name, &expected_return_object](auto &&...args) { 262*c9157d92SDimitry Andric llvm::consumeError(expected_return_object.takeError()); 263*c9157d92SDimitry Andric expected_return_object = 264*c9157d92SDimitry Andric implementor.CallMethod(method_name.data(), args...); 265*c9157d92SDimitry Andric }, 266*c9157d92SDimitry Andric transformed_args); 267*c9157d92SDimitry Andric 268*c9157d92SDimitry Andric if (llvm::Error e = expected_return_object.takeError()) { 269*c9157d92SDimitry Andric error.SetErrorString(llvm::toString(std::move(e)).c_str()); 270*c9157d92SDimitry Andric return ErrorWithMessage<T>(caller_signature, 271*c9157d92SDimitry Andric "Python method could not be called.", error); 272*c9157d92SDimitry Andric } 273*c9157d92SDimitry Andric 274*c9157d92SDimitry Andric PythonObject py_return = std::move(expected_return_object.get()); 275*c9157d92SDimitry Andric 276*c9157d92SDimitry Andric // Now that we called the python method with the transformed arguments, 277*c9157d92SDimitry Andric // we need to interate again over both the original and transformed 278*c9157d92SDimitry Andric // parameter pack, and transform back the parameter that were passed in 279*c9157d92SDimitry Andric // the original parameter pack as references or pointers. 280*c9157d92SDimitry Andric if (sizeof...(Args) > 0) 281*c9157d92SDimitry Andric if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 282*c9157d92SDimitry Andric return ErrorWithMessage<T>( 283*c9157d92SDimitry Andric caller_signature, 284*c9157d92SDimitry Andric "Couldn't re-assign reference and pointer arguments.", error); 285*c9157d92SDimitry Andric 286*c9157d92SDimitry Andric if (!py_return.IsAllocated()) 287*c9157d92SDimitry Andric return {}; 288*c9157d92SDimitry Andric return ExtractValueFromPythonObject<T>(py_return, error); 289*c9157d92SDimitry Andric } 290*c9157d92SDimitry Andric 291*c9157d92SDimitry Andric template <typename... Args> GetStatusFromMethod(llvm::StringRef method_name,Args &&...args)292*c9157d92SDimitry Andric Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 293*c9157d92SDimitry Andric Status error; 294*c9157d92SDimitry Andric Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 295*c9157d92SDimitry Andric 296*c9157d92SDimitry Andric return error; 297*c9157d92SDimitry Andric } 298*c9157d92SDimitry Andric Transform(T object)299*c9157d92SDimitry Andric template <typename T> T Transform(T object) { 300*c9157d92SDimitry Andric // No Transformation for generic usage 301*c9157d92SDimitry Andric return {object}; 302*c9157d92SDimitry Andric } 303*c9157d92SDimitry Andric Transform(bool arg)304*c9157d92SDimitry Andric python::PythonObject Transform(bool arg) { 305*c9157d92SDimitry Andric // Boolean arguments need to be turned into python objects. 306*c9157d92SDimitry Andric return python::PythonBoolean(arg); 307*c9157d92SDimitry Andric } 308*c9157d92SDimitry Andric Transform(Status arg)309*c9157d92SDimitry Andric python::PythonObject Transform(Status arg) { 310*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 311*c9157d92SDimitry Andric } 312*c9157d92SDimitry Andric Transform(const StructuredDataImpl & arg)313*c9157d92SDimitry Andric python::PythonObject Transform(const StructuredDataImpl &arg) { 314*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 315*c9157d92SDimitry Andric } 316*c9157d92SDimitry Andric Transform(lldb::ExecutionContextRefSP arg)317*c9157d92SDimitry Andric python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 318*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 319*c9157d92SDimitry Andric } 320*c9157d92SDimitry Andric Transform(lldb::ProcessSP arg)321*c9157d92SDimitry Andric python::PythonObject Transform(lldb::ProcessSP arg) { 322*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 323*c9157d92SDimitry Andric } 324*c9157d92SDimitry Andric Transform(lldb::ProcessAttachInfoSP arg)325*c9157d92SDimitry Andric python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 326*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 327*c9157d92SDimitry Andric } 328*c9157d92SDimitry Andric Transform(lldb::ProcessLaunchInfoSP arg)329*c9157d92SDimitry Andric python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 330*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 331*c9157d92SDimitry Andric } 332*c9157d92SDimitry Andric Transform(lldb::DataExtractorSP arg)333*c9157d92SDimitry Andric python::PythonObject Transform(lldb::DataExtractorSP arg) { 334*c9157d92SDimitry Andric return python::SWIGBridge::ToSWIGWrapper(arg); 335*c9157d92SDimitry Andric } 336*c9157d92SDimitry Andric 337*c9157d92SDimitry Andric template <typename T, typename U> ReverseTransform(T & original_arg,U transformed_arg,Status & error)338*c9157d92SDimitry Andric void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 339*c9157d92SDimitry Andric // If U is not a PythonObject, don't touch it! 340*c9157d92SDimitry Andric return; 341*c9157d92SDimitry Andric } 342*c9157d92SDimitry Andric 343*c9157d92SDimitry Andric template <typename T> ReverseTransform(T & original_arg,python::PythonObject transformed_arg,Status & error)344*c9157d92SDimitry Andric void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 345*c9157d92SDimitry Andric Status &error) { 346*c9157d92SDimitry Andric original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 347*c9157d92SDimitry Andric } 348*c9157d92SDimitry Andric ReverseTransform(bool & original_arg,python::PythonObject transformed_arg,Status & error)349*c9157d92SDimitry Andric void ReverseTransform(bool &original_arg, 350*c9157d92SDimitry Andric python::PythonObject transformed_arg, Status &error) { 351*c9157d92SDimitry Andric python::PythonBoolean boolean_arg = python::PythonBoolean( 352*c9157d92SDimitry Andric python::PyRefType::Borrowed, transformed_arg.get()); 353*c9157d92SDimitry Andric if (boolean_arg.IsValid()) 354*c9157d92SDimitry Andric original_arg = boolean_arg.GetValue(); 355*c9157d92SDimitry Andric else 356*c9157d92SDimitry Andric error.SetErrorString( 357*c9157d92SDimitry Andric llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION) 358*c9157d92SDimitry Andric .str()); 359*c9157d92SDimitry Andric } 360*c9157d92SDimitry Andric 361*c9157d92SDimitry Andric template <std::size_t... I, typename... Args> TransformTuple(const std::tuple<Args...> & args,std::index_sequence<I...>)362*c9157d92SDimitry Andric auto TransformTuple(const std::tuple<Args...> &args, 363*c9157d92SDimitry Andric std::index_sequence<I...>) { 364*c9157d92SDimitry Andric return std::make_tuple(Transform(std::get<I>(args))...); 365*c9157d92SDimitry Andric } 366*c9157d92SDimitry Andric 367*c9157d92SDimitry Andric // This will iterate over the Dispatch parameter pack and replace in-place 368*c9157d92SDimitry Andric // every `lldb_private` argument that has a SB counterpart. 369*c9157d92SDimitry Andric template <typename... Args> TransformArgs(const std::tuple<Args...> & args)370*c9157d92SDimitry Andric auto TransformArgs(const std::tuple<Args...> &args) { 371*c9157d92SDimitry Andric return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 372*c9157d92SDimitry Andric } 373*c9157d92SDimitry Andric 374*c9157d92SDimitry Andric template <typename T, typename U> TransformBack(T & original_arg,U transformed_arg,Status & error)375*c9157d92SDimitry Andric void TransformBack(T &original_arg, U transformed_arg, Status &error) { 376*c9157d92SDimitry Andric ReverseTransform(original_arg, transformed_arg, error); 377*c9157d92SDimitry Andric } 378*c9157d92SDimitry Andric 379*c9157d92SDimitry Andric template <std::size_t... I, typename... Ts, typename... Us> ReassignPtrsOrRefsArgs(std::tuple<Ts...> & original_args,std::tuple<Us...> & transformed_args,std::index_sequence<I...>)380*c9157d92SDimitry Andric bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 381*c9157d92SDimitry Andric std::tuple<Us...> &transformed_args, 382*c9157d92SDimitry Andric std::index_sequence<I...>) { 383*c9157d92SDimitry Andric Status error; 384*c9157d92SDimitry Andric (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 385*c9157d92SDimitry Andric error), 386*c9157d92SDimitry Andric ...); 387*c9157d92SDimitry Andric return error.Success(); 388*c9157d92SDimitry Andric } 389*c9157d92SDimitry Andric 390*c9157d92SDimitry Andric template <typename... Ts, typename... Us> ReassignPtrsOrRefsArgs(std::tuple<Ts...> & original_args,std::tuple<Us...> & transformed_args)391*c9157d92SDimitry Andric bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 392*c9157d92SDimitry Andric std::tuple<Us...> &transformed_args) { 393*c9157d92SDimitry Andric if (sizeof...(Ts) != sizeof...(Us)) 394*c9157d92SDimitry Andric return false; 395*c9157d92SDimitry Andric 396*c9157d92SDimitry Andric return ReassignPtrsOrRefsArgs(original_args, transformed_args, 397*c9157d92SDimitry Andric std::make_index_sequence<sizeof...(Ts)>()); 398*c9157d92SDimitry Andric } 399*c9157d92SDimitry Andric 400*c9157d92SDimitry Andric template <typename T, typename... Args> FormatArgs(std::string & fmt,T arg,Args...args)401*c9157d92SDimitry Andric void FormatArgs(std::string &fmt, T arg, Args... args) const { 402*c9157d92SDimitry Andric FormatArgs(fmt, arg); 403*c9157d92SDimitry Andric FormatArgs(fmt, args...); 404*c9157d92SDimitry Andric } 405*c9157d92SDimitry Andric FormatArgs(std::string & fmt,T arg)406*c9157d92SDimitry Andric template <typename T> void FormatArgs(std::string &fmt, T arg) const { 407*c9157d92SDimitry Andric fmt += python::PythonFormat<T>::format; 408*c9157d92SDimitry Andric } 409*c9157d92SDimitry Andric FormatArgs(std::string & fmt)410*c9157d92SDimitry Andric void FormatArgs(std::string &fmt) const {} 411*c9157d92SDimitry Andric 412*c9157d92SDimitry Andric // The lifetime is managed by the ScriptInterpreter 413*c9157d92SDimitry Andric ScriptInterpreterPythonImpl &m_interpreter; 414*c9157d92SDimitry Andric }; 415*c9157d92SDimitry Andric 416*c9157d92SDimitry Andric template <> 417*c9157d92SDimitry Andric StructuredData::ArraySP 418*c9157d92SDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 419*c9157d92SDimitry Andric python::PythonObject &p, Status &error); 420*c9157d92SDimitry Andric 421*c9157d92SDimitry Andric template <> 422*c9157d92SDimitry Andric StructuredData::DictionarySP 423*c9157d92SDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject< 424*c9157d92SDimitry Andric StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 425*c9157d92SDimitry Andric 426*c9157d92SDimitry Andric template <> 427*c9157d92SDimitry Andric Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 428*c9157d92SDimitry Andric python::PythonObject &p, Status &error); 429*c9157d92SDimitry Andric 430*c9157d92SDimitry Andric template <> 431*c9157d92SDimitry Andric lldb::BreakpointSP 432*c9157d92SDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 433*c9157d92SDimitry Andric python::PythonObject &p, Status &error); 434*c9157d92SDimitry Andric 435*c9157d92SDimitry Andric template <> 436*c9157d92SDimitry Andric lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 437*c9157d92SDimitry Andric lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 438*c9157d92SDimitry Andric 439*c9157d92SDimitry Andric template <> 440*c9157d92SDimitry Andric lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 441*c9157d92SDimitry Andric lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 442*c9157d92SDimitry Andric 443*c9157d92SDimitry Andric template <> 444*c9157d92SDimitry Andric lldb::DataExtractorSP 445*c9157d92SDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 446*c9157d92SDimitry Andric python::PythonObject &p, Status &error); 447*c9157d92SDimitry Andric 448*c9157d92SDimitry Andric template <> 449*c9157d92SDimitry Andric std::optional<MemoryRegionInfo> 450*c9157d92SDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject< 451*c9157d92SDimitry Andric std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 452*c9157d92SDimitry Andric 453*c9157d92SDimitry Andric } // namespace lldb_private 454*c9157d92SDimitry Andric 455*c9157d92SDimitry Andric #endif // LLDB_ENABLE_PYTHON 456*c9157d92SDimitry Andric #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 457