diff options
| author | Med Ismail Bennani <ismail@bennani.ma> | 2023-10-25 10:05:54 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-25 10:05:54 -0700 |
| commit | f22d82cef28a882cec4d242910933e9f5d7dcdce (patch) | |
| tree | 2a75ad93c317a3b302fd0829c72fb40530114feb /lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h | |
| parent | 7ce613fc77af092dd6e9db71ce3747b75bc5616e (diff) | |
[lldb/Interpreter] Make ScriptedInterface Object creation more generic (#68052)
This patch changes the way plugin objects used with Scripted Interfaces
are created.
Instead of implementing a different SWIG method to create the object for
every scripted interface, this patch makes the creation more generic by
re-using some of the ScriptedPythonInterface templated Dispatch code.
This patch also improves error handling of the object creation by
returning an `llvm::Expected`.
Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h')
| -rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h | 106 |
1 files changed, 102 insertions, 4 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index 9163b8f6aede..190cb40dc0fc 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -32,6 +32,98 @@ public: ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); ~ScriptedPythonInterface() override = default; + template <typename... Args> + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, + StructuredData::Generic *script_obj, Args... args) { + using namespace python; + using Locker = ScriptInterpreterPythonImpl::Locker; + + bool has_class_name = !class_name.empty(); + bool has_interpreter_dict = + !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); + if (!has_class_name && !has_interpreter_dict && !script_obj) { + if (!has_class_name) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Missing script class name."); + else if (!has_interpreter_dict) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Invalid script interpreter dictionary."); + else + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Missing scripting object."); + } + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + PythonObject result = {}; + + if (script_obj) { + result = PythonObject(PyRefType::Borrowed, + static_cast<PyObject *>(script_obj->GetValue())); + } else { + auto dict = + PythonModule::MainModule().ResolveName<python::PythonDictionary>( + m_interpreter.GetDictionaryName()); + if (!dict.IsAllocated()) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Could not find interpreter dictionary: %s", + m_interpreter.GetDictionaryName()); + } + + auto method = + PythonObject::ResolveNameWithDictionary<python::PythonCallable>( + class_name, dict); + if (!method.IsAllocated()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Could not find script class: %s", + class_name.data()); + + std::tuple<Args...> original_args = std::forward_as_tuple(args...); + auto transformed_args = TransformArgs(original_args); + + std::string error_string; + llvm::Expected<PythonCallable::ArgInfo> arg_info = method.GetArgInfo(); + if (!arg_info) { + llvm::handleAllErrors( + arg_info.takeError(), + [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, + [&](const llvm::ErrorInfoBase &E) { + error_string.append(E.message()); + }); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + error_string); + } + + llvm::Expected<PythonObject> expected_return_object = + llvm::createStringError(llvm::inconvertibleErrorCode(), + "Resulting object is not initialized."); + + std::apply( + [&method, &expected_return_object](auto &&...args) { + llvm::consumeError(expected_return_object.takeError()); + expected_return_object = method(args...); + }, + transformed_args); + + if (llvm::Error e = expected_return_object.takeError()) + return e; + result = std::move(expected_return_object.get()); + } + + if (!result.IsValid()) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Resulting object is not a valid Python Object."); + + m_object_instance_sp = StructuredData::GenericSP( + new StructuredPythonObject(std::move(result))); + return m_object_instance_sp; + } + protected: template <typename T = StructuredData::ObjectSP> T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { @@ -83,10 +175,6 @@ protected: PythonObject py_return = std::move(expected_return_object.get()); - if (!py_return.IsAllocated()) - return ErrorWithMessage<T>(caller_signature, "Returned object is null.", - 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 @@ -97,6 +185,8 @@ protected: caller_signature, "Couldn't re-assign reference and pointer arguments.", error); + if (!py_return.IsAllocated()) + return {}; return ExtractValueFromPythonObject<T>(py_return, error); } @@ -122,6 +212,14 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(const StructuredDataImpl &arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + + python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } |
