aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h149
1 files changed, 105 insertions, 44 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
index 7c2fadc..ac1fe09 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -9,10 +9,14 @@
#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
-#include "lldb/Host/Config.h"
-
#if LLDB_ENABLE_PYTHON
+#include <sstream>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "lldb/Host/Config.h"
#include "lldb/Interpreter/ScriptedInterface.h"
#include "lldb/Utility/DataBufferHeap.h"
@@ -34,7 +38,7 @@ protected:
}
template <typename T = StructuredData::ObjectSP, typename... Args>
- T Dispatch(llvm::StringRef method_name, Status &error, Args... args) {
+ T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {
using namespace python;
using Locker = ScriptInterpreterPythonImpl::Locker;
@@ -56,59 +60,116 @@ protected:
return ErrorWithMessage<T>(caller_signature,
"Python implementor not allocated.", error);
- PythonObject pmeth(
- PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
+ std::tuple<Args...> original_args = std::forward_as_tuple(args...);
+ auto transformed_args = TransformArgs(original_args);
+
+ llvm::Expected<PythonObject> expected_return_object =
+ llvm::make_error<llvm::StringError>("Not initialized.",
+ llvm::inconvertibleErrorCode());
+ std::apply(
+ [&implementor, &method_name, &expected_return_object](auto &&...args) {
+ llvm::consumeError(expected_return_object.takeError());
+ expected_return_object =
+ implementor.CallMethod(method_name.data(), args...);
+ },
+ transformed_args);
+
+ if (llvm::Error e = expected_return_object.takeError()) {
+ error.SetErrorString(llvm::toString(std::move(e)).c_str());
+ return ErrorWithMessage<T>(caller_signature,
+ "Python method could not be called.", error);
+ }
- if (PyErr_Occurred())
- PyErr_Clear();
+ PythonObject py_return = std::move(expected_return_object.get());
- if (!pmeth.IsAllocated())
- return ErrorWithMessage<T>(caller_signature,
- "Python method not allocated.", error);
+ if (!py_return.IsAllocated())
+ return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
+ error);
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return ErrorWithMessage<T>(caller_signature,
- "Python method not callable.", error);
- }
+ // Now that we called the python method with the transformed arguments,
+ // we need to interate again over both the original and transformed
+ // parameter pack, and transform back the parameter that were passed in
+ // the original parameter pack as references or pointers.
+ if (sizeof...(Args) > 0)
+ if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
+ return ErrorWithMessage<T>(
+ caller_signature,
+ "Couldn't re-assign reference and pointer arguments.", error);
- if (PyErr_Occurred())
- PyErr_Clear();
+ return ExtractValueFromPythonObject<T>(py_return, error);
+ }
- // TODO: make `const char *` when removing support for Python 2.
- char *format = nullptr;
- std::string format_buffer;
+ Status GetStatusFromMethod(llvm::StringRef method_name);
- if (sizeof...(Args) > 0) {
- FormatArgs(format_buffer, args...);
- // TODO: make `const char *` when removing support for Python 2.
- format = const_cast<char *>(format_buffer.c_str());
+ template <typename T> struct transformation { using type = T; };
+ template <typename T, typename U> struct reverse_transformation {
+ static void Apply(ScriptedPythonInterface &obj, T &original_arg,
+ U transformed_arg, Status &error) {
+ // If U is not a PythonObject, don't touch it!
+ return;
+ }
+ };
+
+ template <> struct transformation<Status> {
+ using type = python::PythonObject;
+ };
+ template <typename T> struct reverse_transformation<T, python::PythonObject> {
+ static void Apply(ScriptedPythonInterface &obj, T &original_arg,
+ python::PythonObject transformed_arg, Status &error) {
+ original_arg =
+ obj.ExtractValueFromPythonObject<T>(transformed_arg, error);
}
+ };
- // TODO: make `const char *` when removing support for Python 2.
- PythonObject py_return(
- PyRefType::Owned,
- PyObject_CallMethod(implementor.get(),
- const_cast<char *>(method_name.data()), format,
- args...));
+ template <typename T> typename transformation<T>::type Transform(T object) {
+ // No Transformation for generic usage
+ return {object};
+ }
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return ErrorWithMessage<T>(caller_signature,
- "Python method could not be called.", error);
- }
+ template <> typename transformation<Status>::type Transform(Status arg) {
+ // Call SWIG Wrapper function
+ return python::ToSWIGWrapper(arg);
+ }
- if (!py_return.IsAllocated())
- return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
- error);
+ template <std::size_t... I, typename... Args>
+ auto TransformTuple(const std::tuple<Args...> &args,
+ std::index_sequence<I...>) {
+ return std::make_tuple(Transform(std::get<I>(args))...);
+ }
- return ExtractValueFromPythonObject<T>(py_return, error);
+ // This will iterate over the Dispatch parameter pack and replace in-place
+ // every `lldb_private` argument that has a SB counterpart.
+ template <typename... Args>
+ auto TransformArgs(const std::tuple<Args...> &args) {
+ return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
}
- Status GetStatusFromMethod(llvm::StringRef method_name);
+ template <typename T, typename U>
+ void TransformBack(T &original_arg, U transformed_arg, Status &error) {
+ reverse_transformation<T, U>::Apply(*this, original_arg, transformed_arg,
+ error);
+ }
+
+ template <std::size_t... I, typename... Ts, typename... Us>
+ bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
+ std::tuple<Us...> &transformed_args,
+ std::index_sequence<I...>) {
+ Status error;
+ (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
+ error),
+ ...);
+ return error.Success();
+ }
+
+ template <typename... Ts, typename... Us>
+ bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
+ std::tuple<Us...> &transformed_args) {
+ if (sizeof...(Ts) != sizeof...(Us))
+ return false;
+
+ return ReassignPtrsOrRefsArgs(original_args, transformed_args,
+ std::make_index_sequence<sizeof...(Ts)>());
+ }
template <typename T, typename... Args>
void FormatArgs(std::string &fmt, T arg, Args... args) const {
@@ -117,7 +178,7 @@ protected:
}
template <typename T> void FormatArgs(std::string &fmt, T arg) const {
- fmt += GetPythonValueFormatString(arg);
+ fmt += python::PythonFormat<T>::format;
}
void FormatArgs(std::string &fmt) const {}