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