xref: /llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h (revision f732157a9d067e4d300905c831a964222e0eadee)
177374d3bSMed Ismail Bennani //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===//
277374d3bSMed Ismail Bennani //
377374d3bSMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
477374d3bSMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
577374d3bSMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
677374d3bSMed Ismail Bennani //
777374d3bSMed Ismail Bennani //===----------------------------------------------------------------------===//
877374d3bSMed Ismail Bennani 
977374d3bSMed Ismail Bennani #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
1077374d3bSMed Ismail Bennani #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
1177374d3bSMed Ismail Bennani 
1277374d3bSMed Ismail Bennani #if LLDB_ENABLE_PYTHON
1377374d3bSMed Ismail Bennani 
1477374d3bSMed Ismail Bennani #include <optional>
1577374d3bSMed Ismail Bennani #include <sstream>
1677374d3bSMed Ismail Bennani #include <tuple>
1777374d3bSMed Ismail Bennani #include <type_traits>
1877374d3bSMed Ismail Bennani #include <utility>
1977374d3bSMed Ismail Bennani 
20e8504cb0SMed Ismail Bennani #include "lldb/Host/Config.h"
21e8504cb0SMed Ismail Bennani #include "lldb/Interpreter/Interfaces/ScriptedInterface.h"
22e8504cb0SMed Ismail Bennani #include "lldb/Utility/DataBufferHeap.h"
23c1d1a752SMed Ismail Bennani 
2477374d3bSMed Ismail Bennani #include "../PythonDataObjects.h"
2577374d3bSMed Ismail Bennani #include "../SWIGPythonBridge.h"
2677374d3bSMed Ismail Bennani #include "../ScriptInterpreterPythonImpl.h"
2777374d3bSMed Ismail Bennani 
2877374d3bSMed Ismail Bennani namespace lldb_private {
2977374d3bSMed Ismail Bennani class ScriptInterpreterPythonImpl;
3077374d3bSMed Ismail Bennani class ScriptedPythonInterface : virtual public ScriptedInterface {
3177374d3bSMed Ismail Bennani public:
3277374d3bSMed Ismail Bennani   ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
3377374d3bSMed Ismail Bennani   ~ScriptedPythonInterface() override = default;
3477374d3bSMed Ismail Bennani 
350a211446SMed Ismail Bennani   enum class AbstractMethodCheckerCases {
360a211446SMed Ismail Bennani     eNotImplemented,
370a211446SMed Ismail Bennani     eNotAllocated,
380a211446SMed Ismail Bennani     eNotCallable,
3921026073SMed Ismail Bennani     eUnknownArgumentCount,
4021026073SMed Ismail Bennani     eInvalidArgumentCount,
410a211446SMed Ismail Bennani     eValid
420a211446SMed Ismail Bennani   };
430a211446SMed Ismail Bennani 
4421026073SMed Ismail Bennani   struct AbstrackMethodCheckerPayload {
4521026073SMed Ismail Bennani 
4621026073SMed Ismail Bennani     struct InvalidArgumentCountPayload {
4721026073SMed Ismail Bennani       InvalidArgumentCountPayload(size_t required, size_t actual)
4821026073SMed Ismail Bennani           : required_argument_count(required), actual_argument_count(actual) {}
4921026073SMed Ismail Bennani 
5021026073SMed Ismail Bennani       size_t required_argument_count;
5121026073SMed Ismail Bennani       size_t actual_argument_count;
5221026073SMed Ismail Bennani     };
5321026073SMed Ismail Bennani 
5421026073SMed Ismail Bennani     AbstractMethodCheckerCases checker_case;
5521026073SMed Ismail Bennani     std::variant<std::monostate, InvalidArgumentCountPayload> payload;
5621026073SMed Ismail Bennani   };
5721026073SMed Ismail Bennani 
5821026073SMed Ismail Bennani   llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>>
590a211446SMed Ismail Bennani   CheckAbstractMethodImplementation(
600a211446SMed Ismail Bennani       const python::PythonDictionary &class_dict) const {
610a211446SMed Ismail Bennani 
620a211446SMed Ismail Bennani     using namespace python;
630a211446SMed Ismail Bennani 
6421026073SMed Ismail Bennani     std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload> checker;
6521026073SMed Ismail Bennani #define SET_CASE_AND_CONTINUE(method_name, case)                               \
660a211446SMed Ismail Bennani   {                                                                            \
6721026073SMed Ismail Bennani     checker[method_name] = {case, {}};                                         \
680a211446SMed Ismail Bennani     continue;                                                                  \
690a211446SMed Ismail Bennani   }
700a211446SMed Ismail Bennani 
7121026073SMed Ismail Bennani     for (const AbstractMethodRequirement &requirement :
7221026073SMed Ismail Bennani          GetAbstractMethodRequirements()) {
7321026073SMed Ismail Bennani       llvm::StringLiteral method_name = requirement.name;
740a211446SMed Ismail Bennani       if (!class_dict.HasKey(method_name))
7521026073SMed Ismail Bennani         SET_CASE_AND_CONTINUE(method_name,
760a211446SMed Ismail Bennani                               AbstractMethodCheckerCases::eNotImplemented)
770a211446SMed Ismail Bennani       auto callable_or_err = class_dict.GetItem(method_name);
7821026073SMed Ismail Bennani       if (!callable_or_err) {
7921026073SMed Ismail Bennani         llvm::consumeError(callable_or_err.takeError());
8021026073SMed Ismail Bennani         SET_CASE_AND_CONTINUE(method_name,
810a211446SMed Ismail Bennani                               AbstractMethodCheckerCases::eNotAllocated)
820a211446SMed Ismail Bennani       }
830a211446SMed Ismail Bennani 
8421026073SMed Ismail Bennani       PythonCallable callable = callable_or_err->AsType<PythonCallable>();
8521026073SMed Ismail Bennani       if (!callable)
8621026073SMed Ismail Bennani         SET_CASE_AND_CONTINUE(method_name,
8721026073SMed Ismail Bennani                               AbstractMethodCheckerCases::eNotCallable)
8821026073SMed Ismail Bennani 
8921026073SMed Ismail Bennani       if (!requirement.min_arg_count)
9021026073SMed Ismail Bennani         SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
9121026073SMed Ismail Bennani 
9221026073SMed Ismail Bennani       auto arg_info_or_err = callable.GetArgInfo();
9321026073SMed Ismail Bennani       if (!arg_info_or_err) {
9421026073SMed Ismail Bennani         llvm::consumeError(arg_info_or_err.takeError());
9521026073SMed Ismail Bennani         SET_CASE_AND_CONTINUE(method_name,
9621026073SMed Ismail Bennani                               AbstractMethodCheckerCases::eUnknownArgumentCount)
9721026073SMed Ismail Bennani       }
9821026073SMed Ismail Bennani 
9921026073SMed Ismail Bennani       PythonCallable::ArgInfo arg_info = *arg_info_or_err;
10021026073SMed Ismail Bennani       if (requirement.min_arg_count <= arg_info.max_positional_args) {
10121026073SMed Ismail Bennani         SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
10221026073SMed Ismail Bennani       } else {
10321026073SMed Ismail Bennani         checker[method_name] = {
10421026073SMed Ismail Bennani             AbstractMethodCheckerCases::eInvalidArgumentCount,
10521026073SMed Ismail Bennani             AbstrackMethodCheckerPayload::InvalidArgumentCountPayload(
10621026073SMed Ismail Bennani                 requirement.min_arg_count, arg_info.max_positional_args)};
10721026073SMed Ismail Bennani       }
10821026073SMed Ismail Bennani     }
10921026073SMed Ismail Bennani 
11021026073SMed Ismail Bennani #undef SET_CASE_AND_CONTINUE
1110a211446SMed Ismail Bennani 
1120a211446SMed Ismail Bennani     return checker;
1130a211446SMed Ismail Bennani   }
1140a211446SMed Ismail Bennani 
115f22d82ceSMed Ismail Bennani   template <typename... Args>
116f22d82ceSMed Ismail Bennani   llvm::Expected<StructuredData::GenericSP>
117f22d82ceSMed Ismail Bennani   CreatePluginObject(llvm::StringRef class_name,
118f22d82ceSMed Ismail Bennani                      StructuredData::Generic *script_obj, Args... args) {
119f22d82ceSMed Ismail Bennani     using namespace python;
120f22d82ceSMed Ismail Bennani     using Locker = ScriptInterpreterPythonImpl::Locker;
121f22d82ceSMed Ismail Bennani 
12221026073SMed Ismail Bennani     Log *log = GetLog(LLDBLog::Script);
12321026073SMed Ismail Bennani     auto create_error = [](llvm::StringLiteral format, auto &&...ts) {
12421026073SMed Ismail Bennani       return llvm::createStringError(
12521026073SMed Ismail Bennani           llvm::formatv(format.data(), std::forward<decltype(ts)>(ts)...)
12621026073SMed Ismail Bennani               .str());
1270a211446SMed Ismail Bennani     };
1280a211446SMed Ismail Bennani 
129f22d82ceSMed Ismail Bennani     bool has_class_name = !class_name.empty();
130f22d82ceSMed Ismail Bennani     bool has_interpreter_dict =
131f22d82ceSMed Ismail Bennani         !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
132a466db2bSDavid Spickett     if (!has_class_name && !has_interpreter_dict && !script_obj) {
133f22d82ceSMed Ismail Bennani       if (!has_class_name)
1340a211446SMed Ismail Bennani         return create_error("Missing script class name.");
135a466db2bSDavid Spickett       else if (!has_interpreter_dict)
1360a211446SMed Ismail Bennani         return create_error("Invalid script interpreter dictionary.");
137a466db2bSDavid Spickett       else
1380a211446SMed Ismail Bennani         return create_error("Missing scripting object.");
139a466db2bSDavid Spickett     }
140f22d82ceSMed Ismail Bennani 
141f22d82ceSMed Ismail Bennani     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
142f22d82ceSMed Ismail Bennani                    Locker::FreeLock);
143f22d82ceSMed Ismail Bennani 
144f22d82ceSMed Ismail Bennani     PythonObject result = {};
145f22d82ceSMed Ismail Bennani 
146f22d82ceSMed Ismail Bennani     if (script_obj) {
147f22d82ceSMed Ismail Bennani       result = PythonObject(PyRefType::Borrowed,
148f22d82ceSMed Ismail Bennani                             static_cast<PyObject *>(script_obj->GetValue()));
149f22d82ceSMed Ismail Bennani     } else {
150f22d82ceSMed Ismail Bennani       auto dict =
151f22d82ceSMed Ismail Bennani           PythonModule::MainModule().ResolveName<python::PythonDictionary>(
152f22d82ceSMed Ismail Bennani               m_interpreter.GetDictionaryName());
1530a211446SMed Ismail Bennani       if (!dict.IsAllocated())
15421026073SMed Ismail Bennani         return create_error("Could not find interpreter dictionary: {0}",
15521026073SMed Ismail Bennani                             m_interpreter.GetDictionaryName());
156f22d82ceSMed Ismail Bennani 
1570a211446SMed Ismail Bennani       auto init =
158f22d82ceSMed Ismail Bennani           PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
159f22d82ceSMed Ismail Bennani               class_name, dict);
1600a211446SMed Ismail Bennani       if (!init.IsAllocated())
16121026073SMed Ismail Bennani         return create_error("Could not find script class: {0}",
16221026073SMed Ismail Bennani                             class_name.data());
163f22d82ceSMed Ismail Bennani 
164f22d82ceSMed Ismail Bennani       std::tuple<Args...> original_args = std::forward_as_tuple(args...);
165f22d82ceSMed Ismail Bennani       auto transformed_args = TransformArgs(original_args);
166f22d82ceSMed Ismail Bennani 
167f22d82ceSMed Ismail Bennani       std::string error_string;
1680a211446SMed Ismail Bennani       llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
169f22d82ceSMed Ismail Bennani       if (!arg_info) {
170f22d82ceSMed Ismail Bennani         llvm::handleAllErrors(
171f22d82ceSMed Ismail Bennani             arg_info.takeError(),
172f22d82ceSMed Ismail Bennani             [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
173f22d82ceSMed Ismail Bennani             [&](const llvm::ErrorInfoBase &E) {
174f22d82ceSMed Ismail Bennani               error_string.append(E.message());
175f22d82ceSMed Ismail Bennani             });
176f22d82ceSMed Ismail Bennani         return llvm::createStringError(llvm::inconvertibleErrorCode(),
177f22d82ceSMed Ismail Bennani                                        error_string);
178f22d82ceSMed Ismail Bennani       }
179f22d82ceSMed Ismail Bennani 
180f22d82ceSMed Ismail Bennani       llvm::Expected<PythonObject> expected_return_object =
1810a211446SMed Ismail Bennani           create_error("Resulting object is not initialized.");
182f22d82ceSMed Ismail Bennani 
183*f732157aSMed Ismail Bennani       // This relax the requirement on the number of argument for
184*f732157aSMed Ismail Bennani       // initializing scripting extension if the size of the interface
185*f732157aSMed Ismail Bennani       // parameter pack contains 1 less element than the extension maximum
186*f732157aSMed Ismail Bennani       // number of positional arguments for this initializer.
187*f732157aSMed Ismail Bennani       //
188*f732157aSMed Ismail Bennani       // This addresses the cases where the embedded interpreter session
189*f732157aSMed Ismail Bennani       // dictionary is passed to the extension initializer which is not used
190*f732157aSMed Ismail Bennani       // most of the time.
191*f732157aSMed Ismail Bennani       size_t num_args = sizeof...(Args);
192*f732157aSMed Ismail Bennani       if (num_args != arg_info->max_positional_args) {
193*f732157aSMed Ismail Bennani         if (num_args != arg_info->max_positional_args - 1)
194*f732157aSMed Ismail Bennani           return create_error("Passed arguments ({0}) doesn't match the number "
195*f732157aSMed Ismail Bennani                               "of expected arguments ({1}).",
196*f732157aSMed Ismail Bennani                               num_args, arg_info->max_positional_args);
197*f732157aSMed Ismail Bennani 
198*f732157aSMed Ismail Bennani         std::apply(
199*f732157aSMed Ismail Bennani             [&init, &expected_return_object](auto &&...args) {
200*f732157aSMed Ismail Bennani               llvm::consumeError(expected_return_object.takeError());
201*f732157aSMed Ismail Bennani               expected_return_object = init(args...);
202*f732157aSMed Ismail Bennani             },
203*f732157aSMed Ismail Bennani             std::tuple_cat(transformed_args, std::make_tuple(dict)));
204*f732157aSMed Ismail Bennani       } else {
205f22d82ceSMed Ismail Bennani         std::apply(
2060a211446SMed Ismail Bennani             [&init, &expected_return_object](auto &&...args) {
207f22d82ceSMed Ismail Bennani               llvm::consumeError(expected_return_object.takeError());
2080a211446SMed Ismail Bennani               expected_return_object = init(args...);
209f22d82ceSMed Ismail Bennani             },
210f22d82ceSMed Ismail Bennani             transformed_args);
211*f732157aSMed Ismail Bennani       }
212f22d82ceSMed Ismail Bennani 
2130a211446SMed Ismail Bennani       if (!expected_return_object)
2140a211446SMed Ismail Bennani         return expected_return_object.takeError();
2150a211446SMed Ismail Bennani       result = expected_return_object.get();
216f22d82ceSMed Ismail Bennani     }
217f22d82ceSMed Ismail Bennani 
218f22d82ceSMed Ismail Bennani     if (!result.IsValid())
2190a211446SMed Ismail Bennani       return create_error("Resulting object is not a valid Python Object.");
2200a211446SMed Ismail Bennani     if (!result.HasAttribute("__class__"))
2210a211446SMed Ismail Bennani       return create_error("Resulting object doesn't have '__class__' member.");
2220a211446SMed Ismail Bennani 
2230a211446SMed Ismail Bennani     PythonObject obj_class = result.GetAttributeValue("__class__");
2240a211446SMed Ismail Bennani     if (!obj_class.IsValid())
2250a211446SMed Ismail Bennani       return create_error("Resulting class object is not a valid.");
2260a211446SMed Ismail Bennani     if (!obj_class.HasAttribute("__name__"))
2270a211446SMed Ismail Bennani       return create_error(
2280a211446SMed Ismail Bennani           "Resulting object class doesn't have '__name__' member.");
2290a211446SMed Ismail Bennani     PythonString obj_class_name =
2300a211446SMed Ismail Bennani         obj_class.GetAttributeValue("__name__").AsType<PythonString>();
2310a211446SMed Ismail Bennani 
2320a211446SMed Ismail Bennani     PythonObject object_class_mapping_proxy =
2330a211446SMed Ismail Bennani         obj_class.GetAttributeValue("__dict__");
2340a211446SMed Ismail Bennani     if (!obj_class.HasAttribute("__dict__"))
2350a211446SMed Ismail Bennani       return create_error(
2360a211446SMed Ismail Bennani           "Resulting object class doesn't have '__dict__' member.");
2370a211446SMed Ismail Bennani 
2380a211446SMed Ismail Bennani     PythonCallable dict_converter = PythonModule::BuiltinsModule()
2390a211446SMed Ismail Bennani                                         .ResolveName("dict")
2400a211446SMed Ismail Bennani                                         .AsType<PythonCallable>();
2410a211446SMed Ismail Bennani     if (!dict_converter.IsAllocated())
2420a211446SMed Ismail Bennani       return create_error(
2430a211446SMed Ismail Bennani           "Python 'builtins' module doesn't have 'dict' class.");
2440a211446SMed Ismail Bennani 
2450a211446SMed Ismail Bennani     PythonDictionary object_class_dict =
2460a211446SMed Ismail Bennani         dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();
2470a211446SMed Ismail Bennani     if (!object_class_dict.IsAllocated())
2480a211446SMed Ismail Bennani       return create_error("Coudn't create dictionary from resulting object "
2490a211446SMed Ismail Bennani                           "class mapping proxy object.");
2500a211446SMed Ismail Bennani 
2510a211446SMed Ismail Bennani     auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
2520a211446SMed Ismail Bennani     if (!checker_or_err)
2530a211446SMed Ismail Bennani       return checker_or_err.takeError();
2540a211446SMed Ismail Bennani 
25521026073SMed Ismail Bennani     llvm::Error abstract_method_errors = llvm::Error::success();
2560a211446SMed Ismail Bennani     for (const auto &method_checker : *checker_or_err)
25721026073SMed Ismail Bennani       switch (method_checker.second.checker_case) {
2580a211446SMed Ismail Bennani       case AbstractMethodCheckerCases::eNotImplemented:
25921026073SMed Ismail Bennani         abstract_method_errors = llvm::joinErrors(
26021026073SMed Ismail Bennani             std::move(abstract_method_errors),
26121026073SMed Ismail Bennani             std::move(create_error("Abstract method {0}.{1} not implemented.",
26221026073SMed Ismail Bennani                                    obj_class_name.GetString(),
26321026073SMed Ismail Bennani                                    method_checker.first)));
2640a211446SMed Ismail Bennani         break;
2650a211446SMed Ismail Bennani       case AbstractMethodCheckerCases::eNotAllocated:
26621026073SMed Ismail Bennani         abstract_method_errors = llvm::joinErrors(
26721026073SMed Ismail Bennani             std::move(abstract_method_errors),
26821026073SMed Ismail Bennani             std::move(create_error("Abstract method {0}.{1} not allocated.",
26921026073SMed Ismail Bennani                                    obj_class_name.GetString(),
27021026073SMed Ismail Bennani                                    method_checker.first)));
2710a211446SMed Ismail Bennani         break;
2720a211446SMed Ismail Bennani       case AbstractMethodCheckerCases::eNotCallable:
27321026073SMed Ismail Bennani         abstract_method_errors = llvm::joinErrors(
27421026073SMed Ismail Bennani             std::move(abstract_method_errors),
27521026073SMed Ismail Bennani             std::move(create_error("Abstract method {0}.{1} not callable.",
27621026073SMed Ismail Bennani                                    obj_class_name.GetString(),
27721026073SMed Ismail Bennani                                    method_checker.first)));
2780a211446SMed Ismail Bennani         break;
27921026073SMed Ismail Bennani       case AbstractMethodCheckerCases::eUnknownArgumentCount:
28021026073SMed Ismail Bennani         abstract_method_errors = llvm::joinErrors(
28121026073SMed Ismail Bennani             std::move(abstract_method_errors),
28221026073SMed Ismail Bennani             std::move(create_error(
28321026073SMed Ismail Bennani                 "Abstract method {0}.{1} has unknown argument count.",
28421026073SMed Ismail Bennani                 obj_class_name.GetString(), method_checker.first)));
28521026073SMed Ismail Bennani         break;
28621026073SMed Ismail Bennani       case AbstractMethodCheckerCases::eInvalidArgumentCount: {
28721026073SMed Ismail Bennani         auto &payload_variant = method_checker.second.payload;
28821026073SMed Ismail Bennani         if (!std::holds_alternative<
28921026073SMed Ismail Bennani                 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
29021026073SMed Ismail Bennani                 payload_variant)) {
29121026073SMed Ismail Bennani           abstract_method_errors = llvm::joinErrors(
29221026073SMed Ismail Bennani               std::move(abstract_method_errors),
29321026073SMed Ismail Bennani               std::move(create_error(
29421026073SMed Ismail Bennani                   "Abstract method {0}.{1} has unexpected argument count.",
29521026073SMed Ismail Bennani                   obj_class_name.GetString(), method_checker.first)));
29621026073SMed Ismail Bennani         } else {
29721026073SMed Ismail Bennani           auto payload = std::get<
29821026073SMed Ismail Bennani               AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
29921026073SMed Ismail Bennani               payload_variant);
30021026073SMed Ismail Bennani           abstract_method_errors = llvm::joinErrors(
30121026073SMed Ismail Bennani               std::move(abstract_method_errors),
30221026073SMed Ismail Bennani               std::move(
30321026073SMed Ismail Bennani                   create_error("Abstract method {0}.{1} has unexpected "
30421026073SMed Ismail Bennani                                "argument count (expected {2} but has {3}).",
30521026073SMed Ismail Bennani                                obj_class_name.GetString(), method_checker.first,
30621026073SMed Ismail Bennani                                payload.required_argument_count,
30721026073SMed Ismail Bennani                                payload.actual_argument_count)));
30821026073SMed Ismail Bennani         }
30921026073SMed Ismail Bennani       } break;
3100a211446SMed Ismail Bennani       case AbstractMethodCheckerCases::eValid:
31121026073SMed Ismail Bennani         LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.",
3120a211446SMed Ismail Bennani                  obj_class_name.GetString(), method_checker.first);
3130a211446SMed Ismail Bennani         break;
3140a211446SMed Ismail Bennani       }
3150a211446SMed Ismail Bennani 
31621026073SMed Ismail Bennani     if (abstract_method_errors) {
31721026073SMed Ismail Bennani       Status error = Status::FromError(std::move(abstract_method_errors));
31821026073SMed Ismail Bennani       LLDB_LOG(log, "Abstract method error in {0}:\n{1}", class_name,
31921026073SMed Ismail Bennani                error.AsCString());
32021026073SMed Ismail Bennani       return error.ToError();
32121026073SMed Ismail Bennani     }
322f22d82ceSMed Ismail Bennani 
323f22d82ceSMed Ismail Bennani     m_object_instance_sp = StructuredData::GenericSP(
324f22d82ceSMed Ismail Bennani         new StructuredPythonObject(std::move(result)));
325f22d82ceSMed Ismail Bennani     return m_object_instance_sp;
326f22d82ceSMed Ismail Bennani   }
327f22d82ceSMed Ismail Bennani 
32877374d3bSMed Ismail Bennani protected:
32977374d3bSMed Ismail Bennani   template <typename T = StructuredData::ObjectSP>
33077374d3bSMed Ismail Bennani   T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
33177374d3bSMed Ismail Bennani     return p.CreateStructuredObject();
33277374d3bSMed Ismail Bennani   }
33377374d3bSMed Ismail Bennani 
33477374d3bSMed Ismail Bennani   template <typename T = StructuredData::ObjectSP, typename... Args>
33577374d3bSMed Ismail Bennani   T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {
33677374d3bSMed Ismail Bennani     using namespace python;
33777374d3bSMed Ismail Bennani     using Locker = ScriptInterpreterPythonImpl::Locker;
33877374d3bSMed Ismail Bennani 
33977374d3bSMed Ismail Bennani     std::string caller_signature =
34077374d3bSMed Ismail Bennani         llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
34177374d3bSMed Ismail Bennani                     llvm::Twine(method_name) + llvm::Twine(")"))
34277374d3bSMed Ismail Bennani             .str();
34377374d3bSMed Ismail Bennani     if (!m_object_instance_sp)
34477374d3bSMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
34577374d3bSMed Ismail Bennani                                  error);
34677374d3bSMed Ismail Bennani 
34777374d3bSMed Ismail Bennani     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
34877374d3bSMed Ismail Bennani                    Locker::FreeLock);
34977374d3bSMed Ismail Bennani 
35077374d3bSMed Ismail Bennani     PythonObject implementor(PyRefType::Borrowed,
35177374d3bSMed Ismail Bennani                              (PyObject *)m_object_instance_sp->GetValue());
35277374d3bSMed Ismail Bennani 
35377374d3bSMed Ismail Bennani     if (!implementor.IsAllocated())
3549a9ec228SMed Ismail Bennani       return llvm::is_contained(GetAbstractMethods(), method_name)
3559a9ec228SMed Ismail Bennani                  ? ErrorWithMessage<T>(caller_signature,
3569a9ec228SMed Ismail Bennani                                        "Python implementor not allocated.",
3579a9ec228SMed Ismail Bennani                                        error)
3589a9ec228SMed Ismail Bennani                  : T{};
35977374d3bSMed Ismail Bennani 
36077374d3bSMed Ismail Bennani     std::tuple<Args...> original_args = std::forward_as_tuple(args...);
36177374d3bSMed Ismail Bennani     auto transformed_args = TransformArgs(original_args);
36277374d3bSMed Ismail Bennani 
36377374d3bSMed Ismail Bennani     llvm::Expected<PythonObject> expected_return_object =
36477374d3bSMed Ismail Bennani         llvm::make_error<llvm::StringError>("Not initialized.",
36577374d3bSMed Ismail Bennani                                             llvm::inconvertibleErrorCode());
36677374d3bSMed Ismail Bennani     std::apply(
36777374d3bSMed Ismail Bennani         [&implementor, &method_name, &expected_return_object](auto &&...args) {
36877374d3bSMed Ismail Bennani           llvm::consumeError(expected_return_object.takeError());
36977374d3bSMed Ismail Bennani           expected_return_object =
37077374d3bSMed Ismail Bennani               implementor.CallMethod(method_name.data(), args...);
37177374d3bSMed Ismail Bennani         },
37277374d3bSMed Ismail Bennani         transformed_args);
37377374d3bSMed Ismail Bennani 
37477374d3bSMed Ismail Bennani     if (llvm::Error e = expected_return_object.takeError()) {
375a0dd90ebSAdrian Prantl       error = Status::FromError(std::move(e));
37677374d3bSMed Ismail Bennani       return ErrorWithMessage<T>(caller_signature,
37777374d3bSMed Ismail Bennani                                  "Python method could not be called.", error);
37877374d3bSMed Ismail Bennani     }
37977374d3bSMed Ismail Bennani 
38077374d3bSMed Ismail Bennani     PythonObject py_return = std::move(expected_return_object.get());
38177374d3bSMed Ismail Bennani 
38277374d3bSMed Ismail Bennani     // Now that we called the python method with the transformed arguments,
38377374d3bSMed Ismail Bennani     // we need to interate again over both the original and transformed
38477374d3bSMed Ismail Bennani     // parameter pack, and transform back the parameter that were passed in
38577374d3bSMed Ismail Bennani     // the original parameter pack as references or pointers.
38677374d3bSMed Ismail Bennani     if (sizeof...(Args) > 0)
38777374d3bSMed Ismail Bennani       if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
38877374d3bSMed Ismail Bennani         return ErrorWithMessage<T>(
38977374d3bSMed Ismail Bennani             caller_signature,
39077374d3bSMed Ismail Bennani             "Couldn't re-assign reference and pointer arguments.", error);
39177374d3bSMed Ismail Bennani 
392f22d82ceSMed Ismail Bennani     if (!py_return.IsAllocated())
393f22d82ceSMed Ismail Bennani       return {};
39477374d3bSMed Ismail Bennani     return ExtractValueFromPythonObject<T>(py_return, error);
39577374d3bSMed Ismail Bennani   }
39677374d3bSMed Ismail Bennani 
39777374d3bSMed Ismail Bennani   template <typename... Args>
39877374d3bSMed Ismail Bennani   Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
39977374d3bSMed Ismail Bennani     Status error;
40077374d3bSMed Ismail Bennani     Dispatch<Status>(method_name, error, std::forward<Args>(args)...);
40177374d3bSMed Ismail Bennani 
40277374d3bSMed Ismail Bennani     return error;
40377374d3bSMed Ismail Bennani   }
40477374d3bSMed Ismail Bennani 
40577374d3bSMed Ismail Bennani   template <typename T> T Transform(T object) {
40677374d3bSMed Ismail Bennani     // No Transformation for generic usage
40777374d3bSMed Ismail Bennani     return {object};
40877374d3bSMed Ismail Bennani   }
40977374d3bSMed Ismail Bennani 
41077374d3bSMed Ismail Bennani   python::PythonObject Transform(bool arg) {
41177374d3bSMed Ismail Bennani     // Boolean arguments need to be turned into python objects.
41277374d3bSMed Ismail Bennani     return python::PythonBoolean(arg);
41377374d3bSMed Ismail Bennani   }
41477374d3bSMed Ismail Bennani 
415b798f4bdSAdrian Prantl   python::PythonObject Transform(const Status &arg) {
416b798f4bdSAdrian Prantl     return python::SWIGBridge::ToSWIGWrapper(arg.Clone());
417b798f4bdSAdrian Prantl   }
418b798f4bdSAdrian Prantl 
419b798f4bdSAdrian Prantl   python::PythonObject Transform(Status &&arg) {
420b798f4bdSAdrian Prantl     return python::SWIGBridge::ToSWIGWrapper(std::move(arg));
42177374d3bSMed Ismail Bennani   }
42277374d3bSMed Ismail Bennani 
423f22d82ceSMed Ismail Bennani   python::PythonObject Transform(const StructuredDataImpl &arg) {
424f22d82ceSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
425f22d82ceSMed Ismail Bennani   }
426f22d82ceSMed Ismail Bennani 
427f22d82ceSMed Ismail Bennani   python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {
428f22d82ceSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
429f22d82ceSMed Ismail Bennani   }
430f22d82ceSMed Ismail Bennani 
431*f732157aSMed Ismail Bennani   python::PythonObject Transform(lldb::TargetSP arg) {
432*f732157aSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
433*f732157aSMed Ismail Bennani   }
434*f732157aSMed Ismail Bennani 
4357a1e8783SMed Ismail Bennani   python::PythonObject Transform(lldb::ProcessSP arg) {
4367a1e8783SMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
4377a1e8783SMed Ismail Bennani   }
4387a1e8783SMed Ismail Bennani 
4399a9ec228SMed Ismail Bennani   python::PythonObject Transform(lldb::ThreadPlanSP arg) {
4409a9ec228SMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
4419a9ec228SMed Ismail Bennani   }
4429a9ec228SMed Ismail Bennani 
44377374d3bSMed Ismail Bennani   python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
44477374d3bSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
44577374d3bSMed Ismail Bennani   }
44677374d3bSMed Ismail Bennani 
44777374d3bSMed Ismail Bennani   python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) {
44877374d3bSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
44977374d3bSMed Ismail Bennani   }
45077374d3bSMed Ismail Bennani 
4519a9ec228SMed Ismail Bennani   python::PythonObject Transform(Event *arg) {
4529a9ec228SMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
4539a9ec228SMed Ismail Bennani   }
4549a9ec228SMed Ismail Bennani 
4556cb45aeaSMed Ismail Bennani   python::PythonObject Transform(lldb::StreamSP arg) {
4566cb45aeaSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg.get());
4579a9ec228SMed Ismail Bennani   }
4589a9ec228SMed Ismail Bennani 
45977374d3bSMed Ismail Bennani   python::PythonObject Transform(lldb::DataExtractorSP arg) {
46077374d3bSMed Ismail Bennani     return python::SWIGBridge::ToSWIGWrapper(arg);
46177374d3bSMed Ismail Bennani   }
46277374d3bSMed Ismail Bennani 
46377374d3bSMed Ismail Bennani   template <typename T, typename U>
46477374d3bSMed Ismail Bennani   void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
46577374d3bSMed Ismail Bennani     // If U is not a PythonObject, don't touch it!
46677374d3bSMed Ismail Bennani     return;
46777374d3bSMed Ismail Bennani   }
46877374d3bSMed Ismail Bennani 
46977374d3bSMed Ismail Bennani   template <typename T>
47077374d3bSMed Ismail Bennani   void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
47177374d3bSMed Ismail Bennani                         Status &error) {
47277374d3bSMed Ismail Bennani     original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
47377374d3bSMed Ismail Bennani   }
47477374d3bSMed Ismail Bennani 
47577374d3bSMed Ismail Bennani   void ReverseTransform(bool &original_arg,
47677374d3bSMed Ismail Bennani                         python::PythonObject transformed_arg, Status &error) {
47777374d3bSMed Ismail Bennani     python::PythonBoolean boolean_arg = python::PythonBoolean(
47877374d3bSMed Ismail Bennani         python::PyRefType::Borrowed, transformed_arg.get());
47977374d3bSMed Ismail Bennani     if (boolean_arg.IsValid())
48077374d3bSMed Ismail Bennani       original_arg = boolean_arg.GetValue();
48177374d3bSMed Ismail Bennani     else
4820642cd76SAdrian Prantl       error = Status::FromErrorStringWithFormatv(
4830642cd76SAdrian Prantl           "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION);
48477374d3bSMed Ismail Bennani   }
48577374d3bSMed Ismail Bennani 
48677374d3bSMed Ismail Bennani   template <std::size_t... I, typename... Args>
48777374d3bSMed Ismail Bennani   auto TransformTuple(const std::tuple<Args...> &args,
48877374d3bSMed Ismail Bennani                       std::index_sequence<I...>) {
48977374d3bSMed Ismail Bennani     return std::make_tuple(Transform(std::get<I>(args))...);
49077374d3bSMed Ismail Bennani   }
49177374d3bSMed Ismail Bennani 
49277374d3bSMed Ismail Bennani   // This will iterate over the Dispatch parameter pack and replace in-place
49377374d3bSMed Ismail Bennani   // every `lldb_private` argument that has a SB counterpart.
49477374d3bSMed Ismail Bennani   template <typename... Args>
49577374d3bSMed Ismail Bennani   auto TransformArgs(const std::tuple<Args...> &args) {
49677374d3bSMed Ismail Bennani     return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
49777374d3bSMed Ismail Bennani   }
49877374d3bSMed Ismail Bennani 
49977374d3bSMed Ismail Bennani   template <typename T, typename U>
50077374d3bSMed Ismail Bennani   void TransformBack(T &original_arg, U transformed_arg, Status &error) {
50177374d3bSMed Ismail Bennani     ReverseTransform(original_arg, transformed_arg, error);
50277374d3bSMed Ismail Bennani   }
50377374d3bSMed Ismail Bennani 
50477374d3bSMed Ismail Bennani   template <std::size_t... I, typename... Ts, typename... Us>
50577374d3bSMed Ismail Bennani   bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
50677374d3bSMed Ismail Bennani                               std::tuple<Us...> &transformed_args,
50777374d3bSMed Ismail Bennani                               std::index_sequence<I...>) {
50877374d3bSMed Ismail Bennani     Status error;
50977374d3bSMed Ismail Bennani     (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
51077374d3bSMed Ismail Bennani                    error),
51177374d3bSMed Ismail Bennani      ...);
51277374d3bSMed Ismail Bennani     return error.Success();
51377374d3bSMed Ismail Bennani   }
51477374d3bSMed Ismail Bennani 
51577374d3bSMed Ismail Bennani   template <typename... Ts, typename... Us>
51677374d3bSMed Ismail Bennani   bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
51777374d3bSMed Ismail Bennani                               std::tuple<Us...> &transformed_args) {
51877374d3bSMed Ismail Bennani     if (sizeof...(Ts) != sizeof...(Us))
51977374d3bSMed Ismail Bennani       return false;
52077374d3bSMed Ismail Bennani 
52177374d3bSMed Ismail Bennani     return ReassignPtrsOrRefsArgs(original_args, transformed_args,
52277374d3bSMed Ismail Bennani                                   std::make_index_sequence<sizeof...(Ts)>());
52377374d3bSMed Ismail Bennani   }
52477374d3bSMed Ismail Bennani 
52577374d3bSMed Ismail Bennani   template <typename T, typename... Args>
52677374d3bSMed Ismail Bennani   void FormatArgs(std::string &fmt, T arg, Args... args) const {
52777374d3bSMed Ismail Bennani     FormatArgs(fmt, arg);
52877374d3bSMed Ismail Bennani     FormatArgs(fmt, args...);
52977374d3bSMed Ismail Bennani   }
53077374d3bSMed Ismail Bennani 
53177374d3bSMed Ismail Bennani   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
53277374d3bSMed Ismail Bennani     fmt += python::PythonFormat<T>::format;
53377374d3bSMed Ismail Bennani   }
53477374d3bSMed Ismail Bennani 
53577374d3bSMed Ismail Bennani   void FormatArgs(std::string &fmt) const {}
53677374d3bSMed Ismail Bennani 
53777374d3bSMed Ismail Bennani   // The lifetime is managed by the ScriptInterpreter
53877374d3bSMed Ismail Bennani   ScriptInterpreterPythonImpl &m_interpreter;
53977374d3bSMed Ismail Bennani };
54077374d3bSMed Ismail Bennani 
54177374d3bSMed Ismail Bennani template <>
54277374d3bSMed Ismail Bennani StructuredData::ArraySP
54377374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
54477374d3bSMed Ismail Bennani     python::PythonObject &p, Status &error);
54577374d3bSMed Ismail Bennani 
54677374d3bSMed Ismail Bennani template <>
54777374d3bSMed Ismail Bennani StructuredData::DictionarySP
54877374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<
54977374d3bSMed Ismail Bennani     StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
55077374d3bSMed Ismail Bennani 
55177374d3bSMed Ismail Bennani template <>
55277374d3bSMed Ismail Bennani Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
55377374d3bSMed Ismail Bennani     python::PythonObject &p, Status &error);
55477374d3bSMed Ismail Bennani 
55577374d3bSMed Ismail Bennani template <>
5569a9ec228SMed Ismail Bennani Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
5579a9ec228SMed Ismail Bennani     python::PythonObject &p, Status &error);
5589a9ec228SMed Ismail Bennani 
5599a9ec228SMed Ismail Bennani template <>
5606cb45aeaSMed Ismail Bennani lldb::StreamSP
5616cb45aeaSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
5629a9ec228SMed Ismail Bennani     python::PythonObject &p, Status &error);
5639a9ec228SMed Ismail Bennani 
5649a9ec228SMed Ismail Bennani template <>
56577374d3bSMed Ismail Bennani lldb::BreakpointSP
56677374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
56777374d3bSMed Ismail Bennani     python::PythonObject &p, Status &error);
56877374d3bSMed Ismail Bennani 
56977374d3bSMed Ismail Bennani template <>
57077374d3bSMed Ismail Bennani lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
57177374d3bSMed Ismail Bennani     lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);
57277374d3bSMed Ismail Bennani 
57377374d3bSMed Ismail Bennani template <>
57477374d3bSMed Ismail Bennani lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
57577374d3bSMed Ismail Bennani     lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error);
57677374d3bSMed Ismail Bennani 
57777374d3bSMed Ismail Bennani template <>
57877374d3bSMed Ismail Bennani lldb::DataExtractorSP
57977374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
58077374d3bSMed Ismail Bennani     python::PythonObject &p, Status &error);
58177374d3bSMed Ismail Bennani 
58277374d3bSMed Ismail Bennani template <>
58377374d3bSMed Ismail Bennani std::optional<MemoryRegionInfo>
58477374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<
58577374d3bSMed Ismail Bennani     std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
58677374d3bSMed Ismail Bennani 
587*f732157aSMed Ismail Bennani template <>
588*f732157aSMed Ismail Bennani lldb::ExecutionContextRefSP
589*f732157aSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<
590*f732157aSMed Ismail Bennani     lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error);
591*f732157aSMed Ismail Bennani 
59277374d3bSMed Ismail Bennani } // namespace lldb_private
59377374d3bSMed Ismail Bennani 
59477374d3bSMed Ismail Bennani #endif // LLDB_ENABLE_PYTHON
59577374d3bSMed Ismail Bennani #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
596