diff options
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h')
-rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h | 149 |
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 {} |