9
9
#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
10
10
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
11
11
12
- #include " lldb/Host/Config.h"
13
-
14
12
#if LLDB_ENABLE_PYTHON
15
13
14
+ #include < sstream>
15
+ #include < tuple>
16
+ #include < type_traits>
17
+ #include < utility>
18
+
19
+ #include " lldb/Host/Config.h"
16
20
#include " lldb/Interpreter/ScriptedInterface.h"
17
21
#include " lldb/Utility/DataBufferHeap.h"
18
22
@@ -34,7 +38,7 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
34
38
}
35
39
36
40
template <typename T = StructuredData::ObjectSP, typename ... Args>
37
- T Dispatch (llvm::StringRef method_name, Status &error, Args... args) {
41
+ T Dispatch (llvm::StringRef method_name, Status &error, Args && ...args) {
38
42
using namespace python ;
39
43
using Locker = ScriptInterpreterPythonImpl::Locker;
40
44
@@ -56,59 +60,116 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
56
60
return ErrorWithMessage<T>(caller_signature,
57
61
" Python implementor not allocated." , error);
58
62
59
- PythonObject pmeth (
60
- PyRefType::Owned,
61
- PyObject_GetAttrString (implementor.get (), method_name.str ().c_str ()));
63
+ std::tuple<Args...> original_args = std::forward_as_tuple (args...);
64
+ auto transformed_args = TransformArgs (original_args);
65
+
66
+ llvm::Expected<PythonObject> expected_return_object =
67
+ llvm::make_error<llvm::StringError>(" Not initialized." ,
68
+ llvm::inconvertibleErrorCode ());
69
+ std::apply (
70
+ [&implementor, &method_name, &expected_return_object](auto &&...args ) {
71
+ llvm::consumeError (expected_return_object.takeError ());
72
+ expected_return_object =
73
+ implementor.CallMethod (method_name.data (), args...);
74
+ },
75
+ transformed_args);
76
+
77
+ if (llvm::Error e = expected_return_object.takeError ()) {
78
+ error.SetErrorString (llvm::toString (std::move (e)).c_str ());
79
+ return ErrorWithMessage<T>(caller_signature,
80
+ " Python method could not be called." , error);
81
+ }
62
82
63
- if (PyErr_Occurred ())
64
- PyErr_Clear ();
83
+ PythonObject py_return = std::move (expected_return_object.get ());
65
84
66
- if (!pmeth .IsAllocated ())
67
- return ErrorWithMessage<T>(caller_signature,
68
- " Python method not allocated. " , error);
85
+ if (!py_return .IsAllocated ())
86
+ return ErrorWithMessage<T>(caller_signature, " Returned object is null. " ,
87
+ error);
69
88
70
- if (PyCallable_Check (pmeth.get ()) == 0 ) {
71
- if (PyErr_Occurred ())
72
- PyErr_Clear ();
73
- return ErrorWithMessage<T>(caller_signature,
74
- " Python method not callable." , error);
75
- }
89
+ // Now that we called the python method with the transformed arguments,
90
+ // we need to interate again over both the original and transformed
91
+ // parameter pack, and transform back the parameter that were passed in
92
+ // the original parameter pack as references or pointers.
93
+ if (sizeof ...(Args) > 0 )
94
+ if (!ReassignPtrsOrRefsArgs (original_args, transformed_args))
95
+ return ErrorWithMessage<T>(
96
+ caller_signature,
97
+ " Couldn't re-assign reference and pointer arguments." , error);
76
98
77
- if ( PyErr_Occurred ())
78
- PyErr_Clear ();
99
+ return ExtractValueFromPythonObject<T>(py_return, error);
100
+ }
79
101
80
- // TODO: make `const char *` when removing support for Python 2.
81
- char *format = nullptr ;
82
- std::string format_buffer;
102
+ Status GetStatusFromMethod (llvm::StringRef method_name);
83
103
84
- if (sizeof ...(Args) > 0 ) {
85
- FormatArgs (format_buffer, args...);
86
- // TODO: make `const char *` when removing support for Python 2.
87
- format = const_cast <char *>(format_buffer.c_str ());
104
+ template <typename T> struct transformation { using type = T; };
105
+ template <typename T, typename U> struct reverse_transformation {
106
+ static void Apply (ScriptedPythonInterface &obj, T &original_arg,
107
+ U transformed_arg, Status &error) {
108
+ // If U is not a PythonObject, don't touch it!
109
+ return ;
110
+ }
111
+ };
112
+
113
+ template <> struct transformation <Status> {
114
+ using type = python::PythonObject;
115
+ };
116
+ template <typename T> struct reverse_transformation <T, python::PythonObject> {
117
+ static void Apply (ScriptedPythonInterface &obj, T &original_arg,
118
+ python::PythonObject transformed_arg, Status &error) {
119
+ original_arg =
120
+ obj.ExtractValueFromPythonObject <T>(transformed_arg, error);
88
121
}
122
+ };
89
123
90
- // TODO: make `const char *` when removing support for Python 2.
91
- PythonObject py_return (
92
- PyRefType::Owned,
93
- PyObject_CallMethod (implementor.get (),
94
- const_cast <char *>(method_name.data ()), format,
95
- args...));
124
+ template <typename T> typename transformation<T>::type Transform (T object) {
125
+ // No Transformation for generic usage
126
+ return {object};
127
+ }
96
128
97
- if (PyErr_Occurred ()) {
98
- PyErr_Print ();
99
- PyErr_Clear ();
100
- return ErrorWithMessage<T>(caller_signature,
101
- " Python method could not be called." , error);
102
- }
129
+ template <> typename transformation<Status>::type Transform (Status arg) {
130
+ // Call SWIG Wrapper function
131
+ return python::ToSWIGWrapper (arg);
132
+ }
103
133
104
- if (!py_return.IsAllocated ())
105
- return ErrorWithMessage<T>(caller_signature, " Returned object is null." ,
106
- error);
134
+ template <std::size_t ... I, typename ... Args>
135
+ auto TransformTuple (const std::tuple<Args...> &args,
136
+ std::index_sequence<I...>) {
137
+ return std::make_tuple (Transform (std::get<I>(args))...);
138
+ }
107
139
108
- return ExtractValueFromPythonObject<T>(py_return, error);
140
+ // This will iterate over the Dispatch parameter pack and replace in-place
141
+ // every `lldb_private` argument that has a SB counterpart.
142
+ template <typename ... Args>
143
+ auto TransformArgs (const std::tuple<Args...> &args) {
144
+ return TransformTuple (args, std::make_index_sequence<sizeof ...(Args)>());
109
145
}
110
146
111
- Status GetStatusFromMethod (llvm::StringRef method_name);
147
+ template <typename T, typename U>
148
+ void TransformBack (T &original_arg, U transformed_arg, Status &error) {
149
+ reverse_transformation<T, U>::Apply (*this , original_arg, transformed_arg,
150
+ error);
151
+ }
152
+
153
+ template <std::size_t ... I, typename ... Ts, typename ... Us>
154
+ bool ReassignPtrsOrRefsArgs (std::tuple<Ts...> &original_args,
155
+ std::tuple<Us...> &transformed_args,
156
+ std::index_sequence<I...>) {
157
+ Status error;
158
+ (TransformBack (std::get<I>(original_args), std::get<I>(transformed_args),
159
+ error),
160
+ ...);
161
+ return error.Success ();
162
+ }
163
+
164
+ template <typename ... Ts, typename ... Us>
165
+ bool ReassignPtrsOrRefsArgs (std::tuple<Ts...> &original_args,
166
+ std::tuple<Us...> &transformed_args) {
167
+ if (sizeof ...(Ts) != sizeof ...(Us))
168
+ return false ;
169
+
170
+ return ReassignPtrsOrRefsArgs (original_args, transformed_args,
171
+ std::make_index_sequence<sizeof ...(Ts)>());
172
+ }
112
173
113
174
template <typename T, typename ... Args>
114
175
void FormatArgs (std::string &fmt, T arg, Args... args) const {
@@ -117,7 +178,7 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
117
178
}
118
179
119
180
template <typename T> void FormatArgs (std::string &fmt, T arg) const {
120
- fmt += GetPythonValueFormatString (arg) ;
181
+ fmt += python::PythonFormat<T>::format ;
121
182
}
122
183
123
184
void FormatArgs (std::string &fmt) const {}
0 commit comments