diff options
author | Zachary Turner <zturner@google.com> | 2015-11-11 19:42:27 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2015-11-11 19:42:27 +0000 |
commit | a140514733e0ab0310688c727b70ba3e2a4a8ddc (patch) | |
tree | 00c8c54435082bda6ae8c33cb9eac146fe31865a /lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp | |
parent | 51c402838ca37b51701f7e03738f6e503c7d1c7e (diff) | |
download | bcm5719-llvm-a140514733e0ab0310688c727b70ba3e2a4a8ddc.tar.gz bcm5719-llvm-a140514733e0ab0310688c727b70ba3e2a4a8ddc.zip |
Create `PythonTuple` and `PythonCallable` wrapper classes.
This adds PythonTuple and PythonCallable classes to PythonDataObjects.
Additionally, unit tests are provided that exercise this functionality,
including invoking manipulating and checking for validity of tuples,
and invoking and checking for validity of callables using a variety
of different syntaxes.
The goal here is to eventually replace the code in python-wrapper.swig
that directly uses the Python C API to deal with callables and name
resolution with this code that can be more easily tested and debugged.
llvm-svn: 252787
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp')
-rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp | 255 |
1 files changed, 251 insertions, 4 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index a621c05338d..0c5ba7d343a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -71,6 +71,8 @@ PythonObject::GetObjectType() const return PyObjectType::Module; if (PythonList::Check(m_py_obj)) return PyObjectType::List; + if (PythonTuple::Check(m_py_obj)) + return PyObjectType::Tuple; if (PythonDictionary::Check(m_py_obj)) return PyObjectType::Dictionary; if (PythonString::Check(m_py_obj)) @@ -79,6 +81,8 @@ PythonObject::GetObjectType() const return PyObjectType::Integer; if (PythonFile::Check(m_py_obj)) return PyObjectType::File; + if (PythonCallable::Check(m_py_obj)) + return PyObjectType::Callable; return PyObjectType::Unknown; } @@ -105,9 +109,20 @@ PythonObject::Str() const } PythonObject -PythonObject::ResolveNameGlobal(llvm::StringRef name) +PythonObject::ResolveNameWithDictionary(llvm::StringRef name, PythonDictionary dict) { - return PythonModule::MainModule().ResolveName(name); + size_t dot_pos = name.find_first_of('.'); + llvm::StringRef piece = name.substr(0, dot_pos); + PythonObject result = dict.GetItemForKey(PythonString(piece)); + if (dot_pos == llvm::StringRef::npos) + { + // There was no dot, we're done. + return result; + } + + // There was a dot. The remaining portion of the name should be looked up in + // the context of the object that was found in the dictionary. + return result.ResolveName(name.substr(dot_pos + 1)); } PythonObject @@ -128,7 +143,7 @@ PythonObject::ResolveName(llvm::StringRef name) const if (dot_pos == llvm::StringRef::npos) { // No dots in the name, we should be able to find the value immediately - // as an attribute of `use_object`. + // as an attribute of `m_py_obj`. return GetAttributeValue(name); } @@ -545,6 +560,132 @@ PythonList::CreateStructuredArray() const } //---------------------------------------------------------------------- +// PythonTuple +//---------------------------------------------------------------------- + +PythonTuple::PythonTuple(PyInitialValue value) + : PythonObject() +{ + if (value == PyInitialValue::Empty) + Reset(PyRefType::Owned, PyTuple_New(0)); +} + +PythonTuple::PythonTuple(int tuple_size) + : PythonObject() +{ + Reset(PyRefType::Owned, PyTuple_New(tuple_size)); +} + +PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj) + : PythonObject() +{ + Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple +} + +PythonTuple::PythonTuple(const PythonTuple &tuple) + : PythonObject(tuple) +{ +} + +PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) +{ + m_py_obj = PyTuple_New(objects.size()); + + uint32_t idx = 0; + for (auto object : objects) + { + if (object.IsValid()) + SetItemAtIndex(idx, object); + idx++; + } +} + +PythonTuple::PythonTuple(std::initializer_list<PyObject*> objects) +{ + m_py_obj = PyTuple_New(objects.size()); + + uint32_t idx = 0; + for (auto py_object : objects) + { + PythonObject object(PyRefType::Borrowed, py_object); + if (object.IsValid()) + SetItemAtIndex(idx, object); + idx++; + } +} + +PythonTuple::~PythonTuple() +{ +} + +bool +PythonTuple::Check(PyObject *py_obj) +{ + if (!py_obj) + return false; + return PyTuple_Check(py_obj); +} + +void +PythonTuple::Reset(PyRefType type, PyObject *py_obj) +{ + // Grab the desired reference type so that if we end up rejecting + // `py_obj` it still gets decremented if necessary. + PythonObject result(type, py_obj); + + if (!PythonTuple::Check(py_obj)) + { + PythonObject::Reset(); + return; + } + + // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls + // back into the virtual implementation. + PythonObject::Reset(PyRefType::Borrowed, result.get()); +} + +uint32_t +PythonTuple::GetSize() const +{ + if (IsValid()) + return PyTuple_GET_SIZE(m_py_obj); + return 0; +} + +PythonObject +PythonTuple::GetItemAtIndex(uint32_t index) const +{ + if (IsValid()) + return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index)); + return PythonObject(); +} + +void +PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) +{ + if (IsAllocated() && object.IsValid()) + { + // PyTuple_SetItem is documented to "steal" a reference, so we need to + // convert it to an owned reference by incrementing it. + Py_INCREF(object.get()); + PyTuple_SetItem(m_py_obj, index, object.get()); + } +} + +StructuredData::ArraySP +PythonTuple::CreateStructuredArray() const +{ + StructuredData::ArraySP result(new StructuredData::Array); + uint32_t count = GetSize(); + for (uint32_t i = 0; i < count; ++i) + { + PythonObject obj = GetItemAtIndex(i); + result->AddItem(obj.CreateStructuredObject()); + } + return result; +} + +//---------------------------------------------------------------------- // PythonDictionary //---------------------------------------------------------------------- @@ -662,9 +803,26 @@ PythonModule::~PythonModule() } PythonModule +PythonModule::BuiltinsModule() +{ +#if PY_MAJOR_VERSION >= 3 + return AddModule("builtins"); +#else + return AddModule("__builtin__"); +#endif +} + +PythonModule PythonModule::MainModule() { - return PythonModule(PyRefType::Borrowed, PyImport_AddModule("__main__")); + return AddModule("__main__"); +} + +PythonModule +PythonModule::AddModule(llvm::StringRef module) +{ + std::string str = module.str(); + return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str())); } bool @@ -700,6 +858,95 @@ PythonModule::GetDictionary() const return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj)); } +PythonCallable::PythonCallable() : PythonObject() +{ +} + +PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj) +{ + Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable +} + +PythonCallable::PythonCallable(const PythonCallable &callable) + : PythonObject(callable) +{ +} + +PythonCallable::~PythonCallable() +{ +} + +bool +PythonCallable::Check(PyObject *py_obj) +{ + if (!py_obj) + return false; + + return PyCallable_Check(py_obj); +} + +void +PythonCallable::Reset(PyRefType type, PyObject *py_obj) +{ + // Grab the desired reference type so that if we end up rejecting + // `py_obj` it still gets decremented if necessary. + PythonObject result(type, py_obj); + + if (!PythonCallable::Check(py_obj)) + { + PythonObject::Reset(); + return; + } + + // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls + // back into the virtual implementation. + PythonObject::Reset(PyRefType::Borrowed, result.get()); +} + + +void +PythonCallable::GetNumArguments(size_t &num_args, bool &has_varargs, bool &has_kwargs) const +{ + num_args = 0; + has_varargs = false; + has_kwargs = false; + if (!IsValid()) + return; + + PyObject *py_func_obj = m_py_obj; + if (PyMethod_Check(py_func_obj)) + py_func_obj = PyMethod_GET_FUNCTION(py_func_obj); + + if (!py_func_obj) + return; + + PyCodeObject* code = (PyCodeObject*)PyFunction_GET_CODE(py_func_obj); + if (!code) + return; + + num_args = code->co_argcount; + if (code->co_flags & CO_VARARGS) + has_varargs = true; + if (code->co_flags & CO_VARKEYWORDS) + has_kwargs = true; +} + +PythonObject +PythonCallable::operator ()(std::initializer_list<PyObject*> args) +{ + PythonTuple arg_tuple(args); + return PythonObject(PyRefType::Owned, + PyObject_CallObject(m_py_obj, arg_tuple.get())); +} + +PythonObject +PythonCallable::operator ()(std::initializer_list<PythonObject> args) +{ + PythonTuple arg_tuple(args); + return PythonObject(PyRefType::Owned, + PyObject_CallObject(m_py_obj, arg_tuple.get())); +} + PythonFile::PythonFile() : PythonObject() { |