//===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H #include "lldb/Host/Config.h" #if LLDB_ENABLE_PYTHON #include "lldb/Interpreter/ScriptedInterface.h" #include "lldb/Utility/DataBufferHeap.h" #include "PythonDataObjects.h" #include "SWIGPythonBridge.h" #include "ScriptInterpreterPythonImpl.h" namespace lldb_private { class ScriptInterpreterPythonImpl; class ScriptedPythonInterface : virtual public ScriptedInterface { public: ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); ~ScriptedPythonInterface() override = default; protected: template T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { return p.CreateStructuredObject(); } template T Dispatch(llvm::StringRef method_name, Status &error, Args... args) { using namespace python; using Locker = ScriptInterpreterPythonImpl::Locker; std::string caller_signature = llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + llvm::Twine(method_name) + llvm::Twine(")")) .str(); if (!m_object_instance_sp) return ErrorWithMessage(caller_signature, "Python object ill-formed", error); Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); PythonObject implementor(PyRefType::Borrowed, (PyObject *)m_object_instance_sp->GetValue()); if (!implementor.IsAllocated()) return ErrorWithMessage(caller_signature, "Python implementor not allocated.", error); PythonObject pmeth( PyRefType::Owned, PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); if (PyErr_Occurred()) PyErr_Clear(); if (!pmeth.IsAllocated()) return ErrorWithMessage(caller_signature, "Python method not allocated.", error); if (PyCallable_Check(pmeth.get()) == 0) { if (PyErr_Occurred()) PyErr_Clear(); return ErrorWithMessage(caller_signature, "Python method not callable.", error); } if (PyErr_Occurred()) PyErr_Clear(); // TODO: make `const char *` when removing support for Python 2. char *format = nullptr; std::string format_buffer; if (sizeof...(Args) > 0) { FormatArgs(format_buffer, args...); // TODO: make `const char *` when removing support for Python 2. format = const_cast(format_buffer.c_str()); } // TODO: make `const char *` when removing support for Python 2. PythonObject py_return( PyRefType::Owned, PyObject_CallMethod(implementor.get(), const_cast(method_name.data()), format, args...)); if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); return ErrorWithMessage(caller_signature, "Python method could not be called.", error); } if (!py_return.IsAllocated()) return ErrorWithMessage(caller_signature, "Returned object is null.", error); return ExtractValueFromPythonObject(py_return, error); } Status GetStatusFromMethod(llvm::StringRef method_name); template void FormatArgs(std::string &fmt, T arg, Args... args) const { FormatArgs(fmt, arg); FormatArgs(fmt, args...); } template void FormatArgs(std::string &fmt, T arg) const { fmt += GetPythonValueFormatString(arg); } void FormatArgs(std::string &fmt) const {} // The lifetime is managed by the ScriptInterpreter ScriptInterpreterPythonImpl &m_interpreter; }; template <> StructuredData::ArraySP ScriptedPythonInterface::ExtractValueFromPythonObject( python::PythonObject &p, Status &error); template <> StructuredData::DictionarySP ScriptedPythonInterface::ExtractValueFromPythonObject< StructuredData::DictionarySP>(python::PythonObject &p, Status &error); template <> Status ScriptedPythonInterface::ExtractValueFromPythonObject( python::PythonObject &p, Status &error); template <> lldb::DataExtractorSP ScriptedPythonInterface::ExtractValueFromPythonObject( python::PythonObject &p, Status &error); template <> llvm::Optional ScriptedPythonInterface::ExtractValueFromPythonObject< llvm::Optional>(python::PythonObject &p, Status &error); } // namespace lldb_private #endif // LLDB_ENABLE_PYTHON #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H