[Lldb-commits] [lldb] r252765 - Add a `PythonModule` class, and a root-level method for resolving names.
Zachary Turner via lldb-commits
lldb-commits at lists.llvm.org
Wed Nov 11 09:59:49 PST 2015
Author: zturner
Date: Wed Nov 11 11:59:49 2015
New Revision: 252765
URL: http://llvm.org/viewvc/llvm-project?rev=252765&view=rev
Log:
Add a `PythonModule` class, and a root-level method for resolving names.
Modified:
lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp?rev=252765&r1=252764&r2=252765&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp Wed Nov 11 11:59:49 2015
@@ -67,6 +67,8 @@ PythonObject::GetObjectType() const
if (!IsAllocated())
return PyObjectType::None;
+ if (PythonModule::Check(m_py_obj))
+ return PyObjectType::Module;
if (PythonList::Check(m_py_obj))
return PyObjectType::List;
if (PythonDictionary::Check(m_py_obj))
@@ -81,7 +83,7 @@ PythonObject::GetObjectType() const
}
PythonString
-PythonObject::Repr()
+PythonObject::Repr() const
{
if (!m_py_obj)
return PythonString();
@@ -92,7 +94,7 @@ PythonObject::Repr()
}
PythonString
-PythonObject::Str()
+PythonObject::Str() const
{
if (!m_py_obj)
return PythonString();
@@ -102,6 +104,43 @@ PythonObject::Str()
return PythonString(PyRefType::Owned, str);
}
+PythonObject
+PythonObject::ResolveNameGlobal(llvm::StringRef name)
+{
+ return PythonModule::MainModule().ResolveName(name);
+}
+
+PythonObject
+PythonObject::ResolveName(llvm::StringRef name) const
+{
+ // Resolve the name in the context of the specified object. If,
+ // for example, `this` refers to a PyModule, then this will look for
+ // `name` in this module. If `this` refers to a PyType, then it will
+ // resolve `name` as an attribute of that type. If `this` refers to
+ // an instance of an object, then it will resolve `name` as the value
+ // of the specified field.
+ //
+ // This function handles dotted names so that, for example, if `m_py_obj`
+ // refers to the `sys` module, and `name` == "path.append", then it
+ // will find the function `sys.path.append`.
+
+ size_t dot_pos = name.find_first_of('.');
+ 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`.
+ return GetAttributeValue(name);
+ }
+
+ // Look up the first piece of the name, and resolve the rest as a child of that.
+ PythonObject parent = ResolveName(name.substr(0, dot_pos));
+ if (!parent.IsAllocated())
+ return PythonObject();
+
+ // Tail recursion.. should be optimized by the compiler
+ return parent.ResolveName(name.substr(dot_pos + 1));
+}
+
bool
PythonObject::HasAttribute(llvm::StringRef attr) const
{
@@ -605,6 +644,62 @@ PythonDictionary::CreateStructuredDictio
return result;
}
+PythonModule::PythonModule() : PythonObject()
+{
+}
+
+PythonModule::PythonModule(PyRefType type, PyObject *py_obj)
+{
+ Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
+}
+
+PythonModule::PythonModule(const PythonModule &dict) : PythonObject(dict)
+{
+}
+
+PythonModule::~PythonModule()
+{
+}
+
+PythonModule
+PythonModule::MainModule()
+{
+ return PythonModule(PyRefType::Borrowed, PyImport_AddModule("__main__"));
+}
+
+bool
+PythonModule::Check(PyObject *py_obj)
+{
+ if (!py_obj)
+ return false;
+
+ return PyModule_Check(py_obj);
+}
+
+void
+PythonModule::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 (!PythonModule::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());
+}
+
+PythonDictionary
+PythonModule::GetDictionary() const
+{
+ return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
+}
+
PythonFile::PythonFile()
: PythonObject()
{
Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h?rev=252765&r1=252764&r2=252765&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h Wed Nov 11 11:59:49 2015
@@ -69,6 +69,7 @@ enum class PyObjectType
Dictionary,
List,
String,
+ Module,
File
};
@@ -185,15 +186,6 @@ public:
return result;
}
- PyObjectType
- GetObjectType() const;
-
- PythonString
- Repr ();
-
- PythonString
- Str ();
-
PythonObject &
operator=(const PythonObject &other)
{
@@ -201,6 +193,21 @@ public:
return *this;
}
+ PyObjectType
+ GetObjectType() const;
+
+ PythonString
+ Repr() const;
+
+ PythonString
+ Str() const;
+
+ static PythonObject
+ ResolveNameGlobal(llvm::StringRef name);
+
+ PythonObject
+ ResolveName(llvm::StringRef name) const;
+
bool
HasAttribute(llvm::StringRef attribute) const;
@@ -224,7 +231,8 @@ public:
return T(PyRefType::Borrowed, m_py_obj);
}
- StructuredData::ObjectSP CreateStructuredObject() const;
+ StructuredData::ObjectSP
+ CreateStructuredObject() const;
protected:
PyObject* m_py_obj;
@@ -338,6 +346,27 @@ public:
StructuredData::DictionarySP CreateStructuredDictionary() const;
};
+class PythonModule : public PythonObject
+{
+ public:
+ PythonModule();
+ PythonModule(PyRefType type, PyObject *o);
+ PythonModule(const PythonModule &dict);
+
+ ~PythonModule() override;
+
+ static bool Check(PyObject *py_obj);
+
+ static PythonModule MainModule();
+
+ // Bring in the no-argument base class version
+ using PythonObject::Reset;
+
+ void Reset(PyRefType type, PyObject *py_obj) override;
+
+ PythonDictionary GetDictionary() const;
+};
+
class PythonFile : public PythonObject
{
public:
Modified: lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp?rev=252765&r1=252764&r2=252765&view=diff
==============================================================================
--- lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp (original)
+++ lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp Wed Nov 11 11:59:49 2015
@@ -96,6 +96,66 @@ TEST_F(PythonDataObjectsTest, TestBorrow
EXPECT_EQ(original_refcnt + 1, borrowed_long.get()->ob_refcnt);
}
+TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot)
+{
+ PythonObject sys_module = PythonObject::ResolveNameGlobal("sys");
+ EXPECT_TRUE(sys_module.IsAllocated());
+ EXPECT_TRUE(PythonModule::Check(sys_module.get()));
+}
+
+TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot)
+{
+ PythonObject sys_module = PythonObject::ResolveNameGlobal("sys");
+ PythonObject sys_path = sys_module.ResolveName("path");
+ PythonObject sys_version_info = sys_module.ResolveName("version_info");
+ EXPECT_TRUE(sys_path.IsAllocated());
+ EXPECT_TRUE(sys_version_info.IsAllocated());
+
+ EXPECT_TRUE(PythonList::Check(sys_path.get()));
+}
+
+TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot)
+{
+ PythonObject sys_module = PythonObject::ResolveNameGlobal("sys");
+ PythonObject sys_version_info = sys_module.ResolveName("version_info");
+
+ PythonObject version_info_type(PyRefType::Owned, PyObject_Type(sys_version_info.get()));
+ EXPECT_TRUE(version_info_type.IsAllocated());
+ PythonObject major_version_field = version_info_type.ResolveName("major");
+ EXPECT_TRUE(major_version_field.IsAllocated());
+}
+
+TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot)
+{
+ PythonObject sys_module = PythonObject::ResolveNameGlobal("sys");
+ PythonObject sys_version_info = sys_module.ResolveName("version_info");
+ PythonObject major_version_field = sys_version_info.ResolveName("major");
+ PythonObject minor_version_field = sys_version_info.ResolveName("minor");
+
+ EXPECT_TRUE(major_version_field.IsAllocated());
+ EXPECT_TRUE(minor_version_field.IsAllocated());
+
+ PythonInteger major_version_value = major_version_field.AsType<PythonInteger>();
+ PythonInteger minor_version_value = minor_version_field.AsType<PythonInteger>();
+
+ EXPECT_EQ(PY_MAJOR_VERSION, major_version_value.GetInteger());
+ EXPECT_EQ(PY_MINOR_VERSION, minor_version_value.GetInteger());
+}
+
+TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot)
+{
+ PythonObject sys_path = PythonObject::ResolveNameGlobal("sys.path");
+ EXPECT_TRUE(sys_path.IsAllocated());
+ EXPECT_TRUE(PythonList::Check(sys_path.get()));
+
+ PythonInteger version_major = PythonObject::ResolveNameGlobal("sys.version_info.major").AsType<PythonInteger>();
+ PythonInteger version_minor = PythonObject::ResolveNameGlobal("sys.version_info.minor").AsType<PythonInteger>();
+ EXPECT_TRUE(version_major.IsAllocated());
+ EXPECT_TRUE(version_minor.IsAllocated());
+ EXPECT_EQ(PY_MAJOR_VERSION, version_major.GetInteger());
+ EXPECT_EQ(PY_MINOR_VERSION, version_minor.GetInteger());
+}
+
TEST_F(PythonDataObjectsTest, TestPythonInteger)
{
// Test that integers behave correctly when wrapped by a PythonInteger.
More information about the lldb-commits
mailing list