15f757f3fSDimitry Andric //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
105f757f3fSDimitry Andric #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
115f757f3fSDimitry Andric 
125f757f3fSDimitry Andric #if LLDB_ENABLE_PYTHON
135f757f3fSDimitry Andric 
145f757f3fSDimitry Andric #include <optional>
155f757f3fSDimitry Andric #include <sstream>
165f757f3fSDimitry Andric #include <tuple>
175f757f3fSDimitry Andric #include <type_traits>
185f757f3fSDimitry Andric #include <utility>
195f757f3fSDimitry Andric 
205f757f3fSDimitry Andric #include "lldb/Host/Config.h"
215f757f3fSDimitry Andric #include "lldb/Interpreter/Interfaces/ScriptedInterface.h"
225f757f3fSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
235f757f3fSDimitry Andric 
245f757f3fSDimitry Andric #include "../PythonDataObjects.h"
255f757f3fSDimitry Andric #include "../SWIGPythonBridge.h"
265f757f3fSDimitry Andric #include "../ScriptInterpreterPythonImpl.h"
275f757f3fSDimitry Andric 
285f757f3fSDimitry Andric namespace lldb_private {
295f757f3fSDimitry Andric class ScriptInterpreterPythonImpl;
305f757f3fSDimitry Andric class ScriptedPythonInterface : virtual public ScriptedInterface {
315f757f3fSDimitry Andric public:
325f757f3fSDimitry Andric   ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
335f757f3fSDimitry Andric   ~ScriptedPythonInterface() override = default;
345f757f3fSDimitry Andric 
355f757f3fSDimitry Andric   enum class AbstractMethodCheckerCases {
365f757f3fSDimitry Andric     eNotImplemented,
375f757f3fSDimitry Andric     eNotAllocated,
385f757f3fSDimitry Andric     eNotCallable,
395f757f3fSDimitry Andric     eValid
405f757f3fSDimitry Andric   };
415f757f3fSDimitry Andric 
425f757f3fSDimitry Andric   llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>>
435f757f3fSDimitry Andric   CheckAbstractMethodImplementation(
445f757f3fSDimitry Andric       const python::PythonDictionary &class_dict) const {
455f757f3fSDimitry Andric 
465f757f3fSDimitry Andric     using namespace python;
475f757f3fSDimitry Andric 
485f757f3fSDimitry Andric     std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker;
495f757f3fSDimitry Andric #define SET_ERROR_AND_CONTINUE(method_name, error)                             \
505f757f3fSDimitry Andric   {                                                                            \
515f757f3fSDimitry Andric     checker[method_name] = error;                                              \
525f757f3fSDimitry Andric     continue;                                                                  \
535f757f3fSDimitry Andric   }
545f757f3fSDimitry Andric 
555f757f3fSDimitry Andric     for (const llvm::StringLiteral &method_name : GetAbstractMethods()) {
565f757f3fSDimitry Andric       if (!class_dict.HasKey(method_name))
575f757f3fSDimitry Andric         SET_ERROR_AND_CONTINUE(method_name,
585f757f3fSDimitry Andric                                AbstractMethodCheckerCases::eNotImplemented)
595f757f3fSDimitry Andric       auto callable_or_err = class_dict.GetItem(method_name);
605f757f3fSDimitry Andric       if (!callable_or_err)
615f757f3fSDimitry Andric         SET_ERROR_AND_CONTINUE(method_name,
625f757f3fSDimitry Andric                                AbstractMethodCheckerCases::eNotAllocated)
635f757f3fSDimitry Andric       if (!PythonCallable::Check(callable_or_err.get().get()))
645f757f3fSDimitry Andric         SET_ERROR_AND_CONTINUE(method_name,
655f757f3fSDimitry Andric                                AbstractMethodCheckerCases::eNotCallable)
665f757f3fSDimitry Andric       checker[method_name] = AbstractMethodCheckerCases::eValid;
675f757f3fSDimitry Andric     }
685f757f3fSDimitry Andric 
695f757f3fSDimitry Andric #undef HANDLE_ERROR
705f757f3fSDimitry Andric 
715f757f3fSDimitry Andric     return checker;
725f757f3fSDimitry Andric   }
735f757f3fSDimitry Andric 
745f757f3fSDimitry Andric   template <typename... Args>
755f757f3fSDimitry Andric   llvm::Expected<StructuredData::GenericSP>
765f757f3fSDimitry Andric   CreatePluginObject(llvm::StringRef class_name,
775f757f3fSDimitry Andric                      StructuredData::Generic *script_obj, Args... args) {
785f757f3fSDimitry Andric     using namespace python;
795f757f3fSDimitry Andric     using Locker = ScriptInterpreterPythonImpl::Locker;
805f757f3fSDimitry Andric 
815f757f3fSDimitry Andric     auto create_error = [](std::string message) {
825f757f3fSDimitry Andric       return llvm::createStringError(llvm::inconvertibleErrorCode(), message);
835f757f3fSDimitry Andric     };
845f757f3fSDimitry Andric 
855f757f3fSDimitry Andric     bool has_class_name = !class_name.empty();
865f757f3fSDimitry Andric     bool has_interpreter_dict =
875f757f3fSDimitry Andric         !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
885f757f3fSDimitry Andric     if (!has_class_name && !has_interpreter_dict && !script_obj) {
895f757f3fSDimitry Andric       if (!has_class_name)
905f757f3fSDimitry Andric         return create_error("Missing script class name.");
915f757f3fSDimitry Andric       else if (!has_interpreter_dict)
925f757f3fSDimitry Andric         return create_error("Invalid script interpreter dictionary.");
935f757f3fSDimitry Andric       else
945f757f3fSDimitry Andric         return create_error("Missing scripting object.");
955f757f3fSDimitry Andric     }
965f757f3fSDimitry Andric 
975f757f3fSDimitry Andric     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
985f757f3fSDimitry Andric                    Locker::FreeLock);
995f757f3fSDimitry Andric 
1005f757f3fSDimitry Andric     PythonObject result = {};
1015f757f3fSDimitry Andric 
1025f757f3fSDimitry Andric     if (script_obj) {
1035f757f3fSDimitry Andric       result = PythonObject(PyRefType::Borrowed,
1045f757f3fSDimitry Andric                             static_cast<PyObject *>(script_obj->GetValue()));
1055f757f3fSDimitry Andric     } else {
1065f757f3fSDimitry Andric       auto dict =
1075f757f3fSDimitry Andric           PythonModule::MainModule().ResolveName<python::PythonDictionary>(
1085f757f3fSDimitry Andric               m_interpreter.GetDictionaryName());
1095f757f3fSDimitry Andric       if (!dict.IsAllocated())
1105f757f3fSDimitry Andric         return create_error(
1115f757f3fSDimitry Andric             llvm::formatv("Could not find interpreter dictionary: %s",
1125f757f3fSDimitry Andric                           m_interpreter.GetDictionaryName()));
1135f757f3fSDimitry Andric 
1145f757f3fSDimitry Andric       auto init =
1155f757f3fSDimitry Andric           PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
1165f757f3fSDimitry Andric               class_name, dict);
1175f757f3fSDimitry Andric       if (!init.IsAllocated())
118*0fca6ea1SDimitry Andric         return create_error(llvm::formatv("Could not find script class: {0}",
1195f757f3fSDimitry Andric                                           class_name.data()));
1205f757f3fSDimitry Andric 
1215f757f3fSDimitry Andric       std::tuple<Args...> original_args = std::forward_as_tuple(args...);
1225f757f3fSDimitry Andric       auto transformed_args = TransformArgs(original_args);
1235f757f3fSDimitry Andric 
1245f757f3fSDimitry Andric       std::string error_string;
1255f757f3fSDimitry Andric       llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
1265f757f3fSDimitry Andric       if (!arg_info) {
1275f757f3fSDimitry Andric         llvm::handleAllErrors(
1285f757f3fSDimitry Andric             arg_info.takeError(),
1295f757f3fSDimitry Andric             [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
1305f757f3fSDimitry Andric             [&](const llvm::ErrorInfoBase &E) {
1315f757f3fSDimitry Andric               error_string.append(E.message());
1325f757f3fSDimitry Andric             });
1335f757f3fSDimitry Andric         return llvm::createStringError(llvm::inconvertibleErrorCode(),
1345f757f3fSDimitry Andric                                        error_string);
1355f757f3fSDimitry Andric       }
1365f757f3fSDimitry Andric 
1375f757f3fSDimitry Andric       llvm::Expected<PythonObject> expected_return_object =
1385f757f3fSDimitry Andric           create_error("Resulting object is not initialized.");
1395f757f3fSDimitry Andric 
1405f757f3fSDimitry Andric       std::apply(
1415f757f3fSDimitry Andric           [&init, &expected_return_object](auto &&...args) {
1425f757f3fSDimitry Andric             llvm::consumeError(expected_return_object.takeError());
1435f757f3fSDimitry Andric             expected_return_object = init(args...);
1445f757f3fSDimitry Andric           },
1455f757f3fSDimitry Andric           transformed_args);
1465f757f3fSDimitry Andric 
1475f757f3fSDimitry Andric       if (!expected_return_object)
1485f757f3fSDimitry Andric         return expected_return_object.takeError();
1495f757f3fSDimitry Andric       result = expected_return_object.get();
1505f757f3fSDimitry Andric     }
1515f757f3fSDimitry Andric 
1525f757f3fSDimitry Andric     if (!result.IsValid())
1535f757f3fSDimitry Andric       return create_error("Resulting object is not a valid Python Object.");
1545f757f3fSDimitry Andric     if (!result.HasAttribute("__class__"))
1555f757f3fSDimitry Andric       return create_error("Resulting object doesn't have '__class__' member.");
1565f757f3fSDimitry Andric 
1575f757f3fSDimitry Andric     PythonObject obj_class = result.GetAttributeValue("__class__");
1585f757f3fSDimitry Andric     if (!obj_class.IsValid())
1595f757f3fSDimitry Andric       return create_error("Resulting class object is not a valid.");
1605f757f3fSDimitry Andric     if (!obj_class.HasAttribute("__name__"))
1615f757f3fSDimitry Andric       return create_error(
1625f757f3fSDimitry Andric           "Resulting object class doesn't have '__name__' member.");
1635f757f3fSDimitry Andric     PythonString obj_class_name =
1645f757f3fSDimitry Andric         obj_class.GetAttributeValue("__name__").AsType<PythonString>();
1655f757f3fSDimitry Andric 
1665f757f3fSDimitry Andric     PythonObject object_class_mapping_proxy =
1675f757f3fSDimitry Andric         obj_class.GetAttributeValue("__dict__");
1685f757f3fSDimitry Andric     if (!obj_class.HasAttribute("__dict__"))
1695f757f3fSDimitry Andric       return create_error(
1705f757f3fSDimitry Andric           "Resulting object class doesn't have '__dict__' member.");
1715f757f3fSDimitry Andric 
1725f757f3fSDimitry Andric     PythonCallable dict_converter = PythonModule::BuiltinsModule()
1735f757f3fSDimitry Andric                                         .ResolveName("dict")
1745f757f3fSDimitry Andric                                         .AsType<PythonCallable>();
1755f757f3fSDimitry Andric     if (!dict_converter.IsAllocated())
1765f757f3fSDimitry Andric       return create_error(
1775f757f3fSDimitry Andric           "Python 'builtins' module doesn't have 'dict' class.");
1785f757f3fSDimitry Andric 
1795f757f3fSDimitry Andric     PythonDictionary object_class_dict =
1805f757f3fSDimitry Andric         dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();
1815f757f3fSDimitry Andric     if (!object_class_dict.IsAllocated())
1825f757f3fSDimitry Andric       return create_error("Coudn't create dictionary from resulting object "
1835f757f3fSDimitry Andric                           "class mapping proxy object.");
1845f757f3fSDimitry Andric 
1855f757f3fSDimitry Andric     auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
1865f757f3fSDimitry Andric     if (!checker_or_err)
1875f757f3fSDimitry Andric       return checker_or_err.takeError();
1885f757f3fSDimitry Andric 
1895f757f3fSDimitry Andric     for (const auto &method_checker : *checker_or_err)
1905f757f3fSDimitry Andric       switch (method_checker.second) {
1915f757f3fSDimitry Andric       case AbstractMethodCheckerCases::eNotImplemented:
1925f757f3fSDimitry Andric         LLDB_LOG(GetLog(LLDBLog::Script),
1935f757f3fSDimitry Andric                  "Abstract method {0}.{1} not implemented.",
1945f757f3fSDimitry Andric                  obj_class_name.GetString(), method_checker.first);
1955f757f3fSDimitry Andric         break;
1965f757f3fSDimitry Andric       case AbstractMethodCheckerCases::eNotAllocated:
1975f757f3fSDimitry Andric         LLDB_LOG(GetLog(LLDBLog::Script),
1985f757f3fSDimitry Andric                  "Abstract method {0}.{1} not allocated.",
1995f757f3fSDimitry Andric                  obj_class_name.GetString(), method_checker.first);
2005f757f3fSDimitry Andric         break;
2015f757f3fSDimitry Andric       case AbstractMethodCheckerCases::eNotCallable:
2025f757f3fSDimitry Andric         LLDB_LOG(GetLog(LLDBLog::Script),
2035f757f3fSDimitry Andric                  "Abstract method {0}.{1} not callable.",
2045f757f3fSDimitry Andric                  obj_class_name.GetString(), method_checker.first);
2055f757f3fSDimitry Andric         break;
2065f757f3fSDimitry Andric       case AbstractMethodCheckerCases::eValid:
2075f757f3fSDimitry Andric         LLDB_LOG(GetLog(LLDBLog::Script),
2085f757f3fSDimitry Andric                  "Abstract method {0}.{1} implemented & valid.",
2095f757f3fSDimitry Andric                  obj_class_name.GetString(), method_checker.first);
2105f757f3fSDimitry Andric         break;
2115f757f3fSDimitry Andric       }
2125f757f3fSDimitry Andric 
2135f757f3fSDimitry Andric     for (const auto &method_checker : *checker_or_err)
2145f757f3fSDimitry Andric       if (method_checker.second != AbstractMethodCheckerCases::eValid)
2155f757f3fSDimitry Andric         return create_error(
2165f757f3fSDimitry Andric             llvm::formatv("Abstract method {0}.{1} missing. Enable lldb "
2175f757f3fSDimitry Andric                           "script log for more details.",
2185f757f3fSDimitry Andric                           obj_class_name.GetString(), method_checker.first));
2195f757f3fSDimitry Andric 
2205f757f3fSDimitry Andric     m_object_instance_sp = StructuredData::GenericSP(
2215f757f3fSDimitry Andric         new StructuredPythonObject(std::move(result)));
2225f757f3fSDimitry Andric     return m_object_instance_sp;
2235f757f3fSDimitry Andric   }
2245f757f3fSDimitry Andric 
2255f757f3fSDimitry Andric protected:
2265f757f3fSDimitry Andric   template <typename T = StructuredData::ObjectSP>
2275f757f3fSDimitry Andric   T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
2285f757f3fSDimitry Andric     return p.CreateStructuredObject();
2295f757f3fSDimitry Andric   }
2305f757f3fSDimitry Andric 
2315f757f3fSDimitry Andric   template <typename T = StructuredData::ObjectSP, typename... Args>
2325f757f3fSDimitry Andric   T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {
2335f757f3fSDimitry Andric     using namespace python;
2345f757f3fSDimitry Andric     using Locker = ScriptInterpreterPythonImpl::Locker;
2355f757f3fSDimitry Andric 
2365f757f3fSDimitry Andric     std::string caller_signature =
2375f757f3fSDimitry Andric         llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
2385f757f3fSDimitry Andric                     llvm::Twine(method_name) + llvm::Twine(")"))
2395f757f3fSDimitry Andric             .str();
2405f757f3fSDimitry Andric     if (!m_object_instance_sp)
2415f757f3fSDimitry Andric       return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
2425f757f3fSDimitry Andric                                  error);
2435f757f3fSDimitry Andric 
2445f757f3fSDimitry Andric     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
2455f757f3fSDimitry Andric                    Locker::FreeLock);
2465f757f3fSDimitry Andric 
2475f757f3fSDimitry Andric     PythonObject implementor(PyRefType::Borrowed,
2485f757f3fSDimitry Andric                              (PyObject *)m_object_instance_sp->GetValue());
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric     if (!implementor.IsAllocated())
251*0fca6ea1SDimitry Andric       return llvm::is_contained(GetAbstractMethods(), method_name)
252*0fca6ea1SDimitry Andric                  ? ErrorWithMessage<T>(caller_signature,
253*0fca6ea1SDimitry Andric                                        "Python implementor not allocated.",
254*0fca6ea1SDimitry Andric                                        error)
255*0fca6ea1SDimitry Andric                  : T{};
2565f757f3fSDimitry Andric 
2575f757f3fSDimitry Andric     std::tuple<Args...> original_args = std::forward_as_tuple(args...);
2585f757f3fSDimitry Andric     auto transformed_args = TransformArgs(original_args);
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric     llvm::Expected<PythonObject> expected_return_object =
2615f757f3fSDimitry Andric         llvm::make_error<llvm::StringError>("Not initialized.",
2625f757f3fSDimitry Andric                                             llvm::inconvertibleErrorCode());
2635f757f3fSDimitry Andric     std::apply(
2645f757f3fSDimitry Andric         [&implementor, &method_name, &expected_return_object](auto &&...args) {
2655f757f3fSDimitry Andric           llvm::consumeError(expected_return_object.takeError());
2665f757f3fSDimitry Andric           expected_return_object =
2675f757f3fSDimitry Andric               implementor.CallMethod(method_name.data(), args...);
2685f757f3fSDimitry Andric         },
2695f757f3fSDimitry Andric         transformed_args);
2705f757f3fSDimitry Andric 
2715f757f3fSDimitry Andric     if (llvm::Error e = expected_return_object.takeError()) {
2725f757f3fSDimitry Andric       error.SetErrorString(llvm::toString(std::move(e)).c_str());
2735f757f3fSDimitry Andric       return ErrorWithMessage<T>(caller_signature,
2745f757f3fSDimitry Andric                                  "Python method could not be called.", error);
2755f757f3fSDimitry Andric     }
2765f757f3fSDimitry Andric 
2775f757f3fSDimitry Andric     PythonObject py_return = std::move(expected_return_object.get());
2785f757f3fSDimitry Andric 
2795f757f3fSDimitry Andric     // Now that we called the python method with the transformed arguments,
2805f757f3fSDimitry Andric     // we need to interate again over both the original and transformed
2815f757f3fSDimitry Andric     // parameter pack, and transform back the parameter that were passed in
2825f757f3fSDimitry Andric     // the original parameter pack as references or pointers.
2835f757f3fSDimitry Andric     if (sizeof...(Args) > 0)
2845f757f3fSDimitry Andric       if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
2855f757f3fSDimitry Andric         return ErrorWithMessage<T>(
2865f757f3fSDimitry Andric             caller_signature,
2875f757f3fSDimitry Andric             "Couldn't re-assign reference and pointer arguments.", error);
2885f757f3fSDimitry Andric 
2895f757f3fSDimitry Andric     if (!py_return.IsAllocated())
2905f757f3fSDimitry Andric       return {};
2915f757f3fSDimitry Andric     return ExtractValueFromPythonObject<T>(py_return, error);
2925f757f3fSDimitry Andric   }
2935f757f3fSDimitry Andric 
2945f757f3fSDimitry Andric   template <typename... Args>
2955f757f3fSDimitry Andric   Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
2965f757f3fSDimitry Andric     Status error;
2975f757f3fSDimitry Andric     Dispatch<Status>(method_name, error, std::forward<Args>(args)...);
2985f757f3fSDimitry Andric 
2995f757f3fSDimitry Andric     return error;
3005f757f3fSDimitry Andric   }
3015f757f3fSDimitry Andric 
3025f757f3fSDimitry Andric   template <typename T> T Transform(T object) {
3035f757f3fSDimitry Andric     // No Transformation for generic usage
3045f757f3fSDimitry Andric     return {object};
3055f757f3fSDimitry Andric   }
3065f757f3fSDimitry Andric 
3075f757f3fSDimitry Andric   python::PythonObject Transform(bool arg) {
3085f757f3fSDimitry Andric     // Boolean arguments need to be turned into python objects.
3095f757f3fSDimitry Andric     return python::PythonBoolean(arg);
3105f757f3fSDimitry Andric   }
3115f757f3fSDimitry Andric 
3125f757f3fSDimitry Andric   python::PythonObject Transform(Status arg) {
3135f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3145f757f3fSDimitry Andric   }
3155f757f3fSDimitry Andric 
3165f757f3fSDimitry Andric   python::PythonObject Transform(const StructuredDataImpl &arg) {
3175f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3185f757f3fSDimitry Andric   }
3195f757f3fSDimitry Andric 
3205f757f3fSDimitry Andric   python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {
3215f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3225f757f3fSDimitry Andric   }
3235f757f3fSDimitry Andric 
3245f757f3fSDimitry Andric   python::PythonObject Transform(lldb::ProcessSP arg) {
3255f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3265f757f3fSDimitry Andric   }
3275f757f3fSDimitry Andric 
328*0fca6ea1SDimitry Andric   python::PythonObject Transform(lldb::ThreadPlanSP arg) {
329*0fca6ea1SDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
330*0fca6ea1SDimitry Andric   }
331*0fca6ea1SDimitry Andric 
3325f757f3fSDimitry Andric   python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
3335f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3345f757f3fSDimitry Andric   }
3355f757f3fSDimitry Andric 
3365f757f3fSDimitry Andric   python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) {
3375f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3385f757f3fSDimitry Andric   }
3395f757f3fSDimitry Andric 
340*0fca6ea1SDimitry Andric   python::PythonObject Transform(Event *arg) {
341*0fca6ea1SDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
342*0fca6ea1SDimitry Andric   }
343*0fca6ea1SDimitry Andric 
344*0fca6ea1SDimitry Andric   python::PythonObject Transform(lldb::StreamSP arg) {
345*0fca6ea1SDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg.get());
346*0fca6ea1SDimitry Andric   }
347*0fca6ea1SDimitry Andric 
3485f757f3fSDimitry Andric   python::PythonObject Transform(lldb::DataExtractorSP arg) {
3495f757f3fSDimitry Andric     return python::SWIGBridge::ToSWIGWrapper(arg);
3505f757f3fSDimitry Andric   }
3515f757f3fSDimitry Andric 
3525f757f3fSDimitry Andric   template <typename T, typename U>
3535f757f3fSDimitry Andric   void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
3545f757f3fSDimitry Andric     // If U is not a PythonObject, don't touch it!
3555f757f3fSDimitry Andric     return;
3565f757f3fSDimitry Andric   }
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric   template <typename T>
3595f757f3fSDimitry Andric   void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
3605f757f3fSDimitry Andric                         Status &error) {
3615f757f3fSDimitry Andric     original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
3625f757f3fSDimitry Andric   }
3635f757f3fSDimitry Andric 
3645f757f3fSDimitry Andric   void ReverseTransform(bool &original_arg,
3655f757f3fSDimitry Andric                         python::PythonObject transformed_arg, Status &error) {
3665f757f3fSDimitry Andric     python::PythonBoolean boolean_arg = python::PythonBoolean(
3675f757f3fSDimitry Andric         python::PyRefType::Borrowed, transformed_arg.get());
3685f757f3fSDimitry Andric     if (boolean_arg.IsValid())
3695f757f3fSDimitry Andric       original_arg = boolean_arg.GetValue();
3705f757f3fSDimitry Andric     else
3715f757f3fSDimitry Andric       error.SetErrorString(
3725f757f3fSDimitry Andric           llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION)
3735f757f3fSDimitry Andric               .str());
3745f757f3fSDimitry Andric   }
3755f757f3fSDimitry Andric 
3765f757f3fSDimitry Andric   template <std::size_t... I, typename... Args>
3775f757f3fSDimitry Andric   auto TransformTuple(const std::tuple<Args...> &args,
3785f757f3fSDimitry Andric                       std::index_sequence<I...>) {
3795f757f3fSDimitry Andric     return std::make_tuple(Transform(std::get<I>(args))...);
3805f757f3fSDimitry Andric   }
3815f757f3fSDimitry Andric 
3825f757f3fSDimitry Andric   // This will iterate over the Dispatch parameter pack and replace in-place
3835f757f3fSDimitry Andric   // every `lldb_private` argument that has a SB counterpart.
3845f757f3fSDimitry Andric   template <typename... Args>
3855f757f3fSDimitry Andric   auto TransformArgs(const std::tuple<Args...> &args) {
3865f757f3fSDimitry Andric     return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
3875f757f3fSDimitry Andric   }
3885f757f3fSDimitry Andric 
3895f757f3fSDimitry Andric   template <typename T, typename U>
3905f757f3fSDimitry Andric   void TransformBack(T &original_arg, U transformed_arg, Status &error) {
3915f757f3fSDimitry Andric     ReverseTransform(original_arg, transformed_arg, error);
3925f757f3fSDimitry Andric   }
3935f757f3fSDimitry Andric 
3945f757f3fSDimitry Andric   template <std::size_t... I, typename... Ts, typename... Us>
3955f757f3fSDimitry Andric   bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
3965f757f3fSDimitry Andric                               std::tuple<Us...> &transformed_args,
3975f757f3fSDimitry Andric                               std::index_sequence<I...>) {
3985f757f3fSDimitry Andric     Status error;
3995f757f3fSDimitry Andric     (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
4005f757f3fSDimitry Andric                    error),
4015f757f3fSDimitry Andric      ...);
4025f757f3fSDimitry Andric     return error.Success();
4035f757f3fSDimitry Andric   }
4045f757f3fSDimitry Andric 
4055f757f3fSDimitry Andric   template <typename... Ts, typename... Us>
4065f757f3fSDimitry Andric   bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
4075f757f3fSDimitry Andric                               std::tuple<Us...> &transformed_args) {
4085f757f3fSDimitry Andric     if (sizeof...(Ts) != sizeof...(Us))
4095f757f3fSDimitry Andric       return false;
4105f757f3fSDimitry Andric 
4115f757f3fSDimitry Andric     return ReassignPtrsOrRefsArgs(original_args, transformed_args,
4125f757f3fSDimitry Andric                                   std::make_index_sequence<sizeof...(Ts)>());
4135f757f3fSDimitry Andric   }
4145f757f3fSDimitry Andric 
4155f757f3fSDimitry Andric   template <typename T, typename... Args>
4165f757f3fSDimitry Andric   void FormatArgs(std::string &fmt, T arg, Args... args) const {
4175f757f3fSDimitry Andric     FormatArgs(fmt, arg);
4185f757f3fSDimitry Andric     FormatArgs(fmt, args...);
4195f757f3fSDimitry Andric   }
4205f757f3fSDimitry Andric 
4215f757f3fSDimitry Andric   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
4225f757f3fSDimitry Andric     fmt += python::PythonFormat<T>::format;
4235f757f3fSDimitry Andric   }
4245f757f3fSDimitry Andric 
4255f757f3fSDimitry Andric   void FormatArgs(std::string &fmt) const {}
4265f757f3fSDimitry Andric 
4275f757f3fSDimitry Andric   // The lifetime is managed by the ScriptInterpreter
4285f757f3fSDimitry Andric   ScriptInterpreterPythonImpl &m_interpreter;
4295f757f3fSDimitry Andric };
4305f757f3fSDimitry Andric 
4315f757f3fSDimitry Andric template <>
4325f757f3fSDimitry Andric StructuredData::ArraySP
4335f757f3fSDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
4345f757f3fSDimitry Andric     python::PythonObject &p, Status &error);
4355f757f3fSDimitry Andric 
4365f757f3fSDimitry Andric template <>
4375f757f3fSDimitry Andric StructuredData::DictionarySP
4385f757f3fSDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<
4395f757f3fSDimitry Andric     StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
4405f757f3fSDimitry Andric 
4415f757f3fSDimitry Andric template <>
4425f757f3fSDimitry Andric Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
4435f757f3fSDimitry Andric     python::PythonObject &p, Status &error);
4445f757f3fSDimitry Andric 
4455f757f3fSDimitry Andric template <>
446*0fca6ea1SDimitry Andric Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
447*0fca6ea1SDimitry Andric     python::PythonObject &p, Status &error);
448*0fca6ea1SDimitry Andric 
449*0fca6ea1SDimitry Andric template <>
450*0fca6ea1SDimitry Andric lldb::StreamSP
451*0fca6ea1SDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
452*0fca6ea1SDimitry Andric     python::PythonObject &p, Status &error);
453*0fca6ea1SDimitry Andric 
454*0fca6ea1SDimitry Andric template <>
4555f757f3fSDimitry Andric lldb::BreakpointSP
4565f757f3fSDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
4575f757f3fSDimitry Andric     python::PythonObject &p, Status &error);
4585f757f3fSDimitry Andric 
4595f757f3fSDimitry Andric template <>
4605f757f3fSDimitry Andric lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
4615f757f3fSDimitry Andric     lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);
4625f757f3fSDimitry Andric 
4635f757f3fSDimitry Andric template <>
4645f757f3fSDimitry Andric lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
4655f757f3fSDimitry Andric     lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error);
4665f757f3fSDimitry Andric 
4675f757f3fSDimitry Andric template <>
4685f757f3fSDimitry Andric lldb::DataExtractorSP
4695f757f3fSDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
4705f757f3fSDimitry Andric     python::PythonObject &p, Status &error);
4715f757f3fSDimitry Andric 
4725f757f3fSDimitry Andric template <>
4735f757f3fSDimitry Andric std::optional<MemoryRegionInfo>
4745f757f3fSDimitry Andric ScriptedPythonInterface::ExtractValueFromPythonObject<
4755f757f3fSDimitry Andric     std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
4765f757f3fSDimitry Andric 
4775f757f3fSDimitry Andric } // namespace lldb_private
4785f757f3fSDimitry Andric 
4795f757f3fSDimitry Andric #endif // LLDB_ENABLE_PYTHON
4805f757f3fSDimitry Andric #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
481