[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