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);
283925204cSMed Ismail Bennani   virtual ~ScriptedPythonInterface() = default;
293925204cSMed Ismail Bennani 
303925204cSMed Ismail Bennani protected:
313925204cSMed Ismail Bennani   template <typename T = StructuredData::ObjectSP>
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>
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 
413925204cSMed Ismail Bennani     auto error_with_message = [&method_name, &error](llvm::StringRef message) {
423925204cSMed Ismail Bennani       error.SetErrorStringWithFormatv(
433925204cSMed Ismail Bennani           "ScriptedPythonInterface::{0} ({1}) ERROR = {2}", __FUNCTION__,
443925204cSMed Ismail Bennani           method_name, message);
453925204cSMed Ismail Bennani       return T();
463925204cSMed Ismail Bennani     };
473925204cSMed Ismail Bennani 
483925204cSMed Ismail Bennani     if (!m_object_instance_sp)
493925204cSMed Ismail Bennani       return error_with_message("Python object ill-formed");
503925204cSMed Ismail Bennani 
513925204cSMed Ismail Bennani     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
523925204cSMed Ismail Bennani                    Locker::FreeLock);
533925204cSMed Ismail Bennani 
543925204cSMed Ismail Bennani     PythonObject implementor(PyRefType::Borrowed,
553925204cSMed Ismail Bennani                              (PyObject *)m_object_instance_sp->GetValue());
563925204cSMed Ismail Bennani 
573925204cSMed Ismail Bennani     if (!implementor.IsAllocated())
583925204cSMed Ismail Bennani       return error_with_message("Python implementor not allocated.");
593925204cSMed Ismail Bennani 
603925204cSMed Ismail Bennani     PythonObject pmeth(
613925204cSMed Ismail Bennani         PyRefType::Owned,
623925204cSMed Ismail Bennani         PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
633925204cSMed Ismail Bennani 
643925204cSMed Ismail Bennani     if (PyErr_Occurred())
653925204cSMed Ismail Bennani       PyErr_Clear();
663925204cSMed Ismail Bennani 
673925204cSMed Ismail Bennani     if (!pmeth.IsAllocated())
683925204cSMed Ismail Bennani       return error_with_message("Python method not allocated.");
693925204cSMed Ismail Bennani 
703925204cSMed Ismail Bennani     if (PyCallable_Check(pmeth.get()) == 0) {
713925204cSMed Ismail Bennani       if (PyErr_Occurred())
723925204cSMed Ismail Bennani         PyErr_Clear();
733925204cSMed Ismail Bennani       return error_with_message("Python method not callable.");
743925204cSMed Ismail Bennani     }
753925204cSMed Ismail Bennani 
763925204cSMed Ismail Bennani     if (PyErr_Occurred())
773925204cSMed Ismail Bennani       PyErr_Clear();
783925204cSMed Ismail Bennani 
793925204cSMed Ismail Bennani     // TODO: make `const char *` when removing support for Python 2.
803925204cSMed Ismail Bennani     char *format = nullptr;
813925204cSMed Ismail Bennani     std::string format_buffer;
823925204cSMed Ismail Bennani 
833925204cSMed Ismail Bennani     if (sizeof...(Args) > 0) {
843925204cSMed Ismail Bennani       FormatArgs(format_buffer, args...);
853925204cSMed Ismail Bennani       // TODO: make `const char *` when removing support for Python 2.
863925204cSMed Ismail Bennani       format = const_cast<char *>(format_buffer.c_str());
873925204cSMed Ismail Bennani     }
883925204cSMed Ismail Bennani 
893925204cSMed Ismail Bennani     // TODO: make `const char *` when removing support for Python 2.
903925204cSMed Ismail Bennani     PythonObject py_return(
913925204cSMed Ismail Bennani         PyRefType::Owned,
923925204cSMed Ismail Bennani         PyObject_CallMethod(implementor.get(),
933925204cSMed Ismail Bennani                             const_cast<char *>(method_name.data()), format,
943925204cSMed Ismail Bennani                             args...));
953925204cSMed Ismail Bennani 
963925204cSMed Ismail Bennani     if (PyErr_Occurred()) {
973925204cSMed Ismail Bennani       PyErr_Print();
983925204cSMed Ismail Bennani       PyErr_Clear();
993925204cSMed Ismail Bennani       return error_with_message("Python method could not be called.");
1003925204cSMed Ismail Bennani     }
1013925204cSMed Ismail Bennani 
1023925204cSMed Ismail Bennani     if (!py_return.IsAllocated())
1033925204cSMed Ismail Bennani       return error_with_message("Returned object is null.");
1043925204cSMed Ismail Bennani 
1053925204cSMed Ismail Bennani     return ExtractValueFromPythonObject<T>(py_return, error);
1063925204cSMed Ismail Bennani   }
1073925204cSMed Ismail Bennani 
1083925204cSMed Ismail Bennani   Status GetStatusFromMethod(llvm::StringRef method_name);
1093925204cSMed Ismail Bennani 
1103925204cSMed Ismail Bennani   template <typename T, typename... Args>
1113925204cSMed Ismail Bennani   void FormatArgs(std::string &fmt, T arg, Args... args) const {
1123925204cSMed Ismail Bennani     FormatArgs(fmt, arg);
1133925204cSMed Ismail Bennani     FormatArgs(fmt, args...);
1143925204cSMed Ismail Bennani   }
1153925204cSMed Ismail Bennani 
1163925204cSMed Ismail Bennani   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
1173925204cSMed Ismail Bennani     fmt += GetPythonValueFormatString(arg);
1183925204cSMed Ismail Bennani   }
1193925204cSMed Ismail Bennani 
1203925204cSMed Ismail Bennani   void FormatArgs(std::string &fmt) const {}
1213925204cSMed Ismail Bennani 
1223925204cSMed Ismail Bennani   // The lifetime is managed by the ScriptInterpreter
1233925204cSMed Ismail Bennani   ScriptInterpreterPythonImpl &m_interpreter;
1243925204cSMed Ismail Bennani };
125*5f6f33daSMed Ismail Bennani 
126*5f6f33daSMed Ismail Bennani template <>
127*5f6f33daSMed Ismail Bennani Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
128*5f6f33daSMed Ismail Bennani     python::PythonObject &p, Status &error);
129*5f6f33daSMed Ismail Bennani 
130*5f6f33daSMed Ismail Bennani template <>
131*5f6f33daSMed Ismail Bennani lldb::DataExtractorSP
132*5f6f33daSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
133*5f6f33daSMed Ismail Bennani     python::PythonObject &p, Status &error);
134*5f6f33daSMed Ismail Bennani 
1353925204cSMed Ismail Bennani } // namespace lldb_private
1363925204cSMed Ismail Bennani 
1373925204cSMed Ismail Bennani #endif // LLDB_ENABLE_PYTHON
1383925204cSMed Ismail Bennani #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
139