13925204cSMed Ismail Bennani //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===//
23925204cSMed Ismail Bennani //
33925204cSMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43925204cSMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
53925204cSMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63925204cSMed Ismail Bennani //
73925204cSMed Ismail Bennani //===----------------------------------------------------------------------===//
83925204cSMed Ismail Bennani 
93925204cSMed Ismail Bennani #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
103925204cSMed Ismail Bennani #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
113925204cSMed Ismail Bennani 
123925204cSMed Ismail Bennani #include "lldb/Host/Config.h"
133925204cSMed Ismail Bennani 
143925204cSMed Ismail Bennani #if LLDB_ENABLE_PYTHON
153925204cSMed Ismail Bennani 
163925204cSMed Ismail Bennani #include "lldb/Interpreter/ScriptedInterface.h"
173925204cSMed Ismail Bennani #include "lldb/Utility/DataBufferHeap.h"
183925204cSMed Ismail Bennani 
193925204cSMed Ismail Bennani #include "PythonDataObjects.h"
203925204cSMed Ismail Bennani #include "SWIGPythonBridge.h"
213925204cSMed Ismail Bennani #include "ScriptInterpreterPythonImpl.h"
223925204cSMed Ismail Bennani 
233925204cSMed Ismail Bennani namespace lldb_private {
243925204cSMed Ismail Bennani class ScriptInterpreterPythonImpl;
253925204cSMed Ismail Bennani class ScriptedPythonInterface : virtual public ScriptedInterface {
263925204cSMed Ismail Bennani public:
273925204cSMed Ismail Bennani   ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
28*99166339SJonas Devlieghere   ~ScriptedPythonInterface() override = default;
293925204cSMed Ismail Bennani 
303925204cSMed Ismail Bennani protected:
313925204cSMed Ismail Bennani   template <typename T = StructuredData::ObjectSP>
ExtractValueFromPythonObject(python::PythonObject & p,Status & error)323925204cSMed Ismail Bennani   T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
333925204cSMed Ismail Bennani     return p.CreateStructuredObject();
343925204cSMed Ismail Bennani   }
353925204cSMed Ismail Bennani 
363925204cSMed Ismail Bennani   template <typename T = StructuredData::ObjectSP, typename... Args>
Dispatch(llvm::StringRef method_name,Status & error,Args...args)373925204cSMed Ismail Bennani   T Dispatch(llvm::StringRef method_name, Status &error, Args... args) {
383925204cSMed Ismail Bennani     using namespace python;
393925204cSMed Ismail Bennani     using Locker = ScriptInterpreterPythonImpl::Locker;
403925204cSMed Ismail Bennani 
4159d8dd79SMed Ismail Bennani     std::string caller_signature =
4288a941baSMed Ismail Bennani         llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
4359d8dd79SMed Ismail Bennani                     llvm::Twine(method_name) + llvm::Twine(")"))
4459d8dd79SMed Ismail Bennani             .str();
453925204cSMed Ismail Bennani     if (!m_object_instance_sp)
4659d8dd79SMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
4759d8dd79SMed Ismail Bennani                                  error);
483925204cSMed Ismail Bennani 
493925204cSMed Ismail Bennani     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
503925204cSMed Ismail Bennani                    Locker::FreeLock);
513925204cSMed Ismail Bennani 
523925204cSMed Ismail Bennani     PythonObject implementor(PyRefType::Borrowed,
533925204cSMed Ismail Bennani                              (PyObject *)m_object_instance_sp->GetValue());
543925204cSMed Ismail Bennani 
553925204cSMed Ismail Bennani     if (!implementor.IsAllocated())
5659d8dd79SMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature,
5759d8dd79SMed Ismail Bennani                                  "Python implementor not allocated.", error);
583925204cSMed Ismail Bennani 
593925204cSMed Ismail Bennani     PythonObject pmeth(
603925204cSMed Ismail Bennani         PyRefType::Owned,
613925204cSMed Ismail Bennani         PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
623925204cSMed Ismail Bennani 
633925204cSMed Ismail Bennani     if (PyErr_Occurred())
643925204cSMed Ismail Bennani       PyErr_Clear();
653925204cSMed Ismail Bennani 
663925204cSMed Ismail Bennani     if (!pmeth.IsAllocated())
6759d8dd79SMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature,
6859d8dd79SMed Ismail Bennani                                  "Python method not allocated.", error);
693925204cSMed Ismail Bennani 
703925204cSMed Ismail Bennani     if (PyCallable_Check(pmeth.get()) == 0) {
713925204cSMed Ismail Bennani       if (PyErr_Occurred())
723925204cSMed Ismail Bennani         PyErr_Clear();
7359d8dd79SMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature,
7459d8dd79SMed Ismail Bennani                                  "Python method not callable.", error);
753925204cSMed Ismail Bennani     }
763925204cSMed Ismail Bennani 
773925204cSMed Ismail Bennani     if (PyErr_Occurred())
783925204cSMed Ismail Bennani       PyErr_Clear();
793925204cSMed Ismail Bennani 
803925204cSMed Ismail Bennani     // TODO: make `const char *` when removing support for Python 2.
813925204cSMed Ismail Bennani     char *format = nullptr;
823925204cSMed Ismail Bennani     std::string format_buffer;
833925204cSMed Ismail Bennani 
843925204cSMed Ismail Bennani     if (sizeof...(Args) > 0) {
853925204cSMed Ismail Bennani       FormatArgs(format_buffer, args...);
863925204cSMed Ismail Bennani       // TODO: make `const char *` when removing support for Python 2.
873925204cSMed Ismail Bennani       format = const_cast<char *>(format_buffer.c_str());
883925204cSMed Ismail Bennani     }
893925204cSMed Ismail Bennani 
903925204cSMed Ismail Bennani     // TODO: make `const char *` when removing support for Python 2.
913925204cSMed Ismail Bennani     PythonObject py_return(
923925204cSMed Ismail Bennani         PyRefType::Owned,
933925204cSMed Ismail Bennani         PyObject_CallMethod(implementor.get(),
943925204cSMed Ismail Bennani                             const_cast<char *>(method_name.data()), format,
953925204cSMed Ismail Bennani                             args...));
963925204cSMed Ismail Bennani 
973925204cSMed Ismail Bennani     if (PyErr_Occurred()) {
983925204cSMed Ismail Bennani       PyErr_Print();
993925204cSMed Ismail Bennani       PyErr_Clear();
10059d8dd79SMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature,
10159d8dd79SMed Ismail Bennani                                  "Python method could not be called.", error);
1023925204cSMed Ismail Bennani     }
1033925204cSMed Ismail Bennani 
1043925204cSMed Ismail Bennani     if (!py_return.IsAllocated())
10559d8dd79SMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
10659d8dd79SMed Ismail Bennani                                  error);
1073925204cSMed Ismail Bennani 
1083925204cSMed Ismail Bennani     return ExtractValueFromPythonObject<T>(py_return, error);
1093925204cSMed Ismail Bennani   }
1103925204cSMed Ismail Bennani 
1113925204cSMed Ismail Bennani   Status GetStatusFromMethod(llvm::StringRef method_name);
1123925204cSMed Ismail Bennani 
1133925204cSMed Ismail Bennani   template <typename T, typename... Args>
FormatArgs(std::string & fmt,T arg,Args...args)1143925204cSMed Ismail Bennani   void FormatArgs(std::string &fmt, T arg, Args... args) const {
1153925204cSMed Ismail Bennani     FormatArgs(fmt, arg);
1163925204cSMed Ismail Bennani     FormatArgs(fmt, args...);
1173925204cSMed Ismail Bennani   }
1183925204cSMed Ismail Bennani 
FormatArgs(std::string & fmt,T arg)1193925204cSMed Ismail Bennani   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
1203925204cSMed Ismail Bennani     fmt += GetPythonValueFormatString(arg);
1213925204cSMed Ismail Bennani   }
1223925204cSMed Ismail Bennani 
FormatArgs(std::string & fmt)1233925204cSMed Ismail Bennani   void FormatArgs(std::string &fmt) const {}
1243925204cSMed Ismail Bennani 
1253925204cSMed Ismail Bennani   // The lifetime is managed by the ScriptInterpreter
1263925204cSMed Ismail Bennani   ScriptInterpreterPythonImpl &m_interpreter;
1273925204cSMed Ismail Bennani };
1285f6f33daSMed Ismail Bennani 
1295f6f33daSMed Ismail Bennani template <>
13070665844SMed Ismail Bennani StructuredData::ArraySP
13170665844SMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
13270665844SMed Ismail Bennani     python::PythonObject &p, Status &error);
13370665844SMed Ismail Bennani 
13470665844SMed Ismail Bennani template <>
13559d8dd79SMed Ismail Bennani StructuredData::DictionarySP
13659d8dd79SMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<
13759d8dd79SMed Ismail Bennani     StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
13859d8dd79SMed Ismail Bennani 
13959d8dd79SMed Ismail Bennani template <>
1405f6f33daSMed Ismail Bennani Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
1415f6f33daSMed Ismail Bennani     python::PythonObject &p, Status &error);
1425f6f33daSMed Ismail Bennani 
1435f6f33daSMed Ismail Bennani template <>
1445f6f33daSMed Ismail Bennani lldb::DataExtractorSP
1455f6f33daSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
1465f6f33daSMed Ismail Bennani     python::PythonObject &p, Status &error);
1475f6f33daSMed Ismail Bennani 
148a758c9f7SMed Ismail Bennani template <>
149a758c9f7SMed Ismail Bennani llvm::Optional<MemoryRegionInfo>
150a758c9f7SMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<
151a758c9f7SMed Ismail Bennani     llvm::Optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
152a758c9f7SMed Ismail Bennani 
1533925204cSMed Ismail Bennani } // namespace lldb_private
1543925204cSMed Ismail Bennani 
1553925204cSMed Ismail Bennani #endif // LLDB_ENABLE_PYTHON
1563925204cSMed Ismail Bennani #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
157