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