12c1f46dcSZachary Turner //===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===//
22c1f46dcSZachary Turner //
32c1f46dcSZachary Turner //                     The LLVM Compiler Infrastructure
42c1f46dcSZachary Turner //
52c1f46dcSZachary Turner // This file is distributed under the University of Illinois Open Source
62c1f46dcSZachary Turner // License. See LICENSE.TXT for details.
72c1f46dcSZachary Turner //
82c1f46dcSZachary Turner //===----------------------------------------------------------------------===//
92c1f46dcSZachary Turner 
102c1f46dcSZachary Turner #ifdef LLDB_DISABLE_PYTHON
112c1f46dcSZachary Turner 
122c1f46dcSZachary Turner // Python is disabled in this build
132c1f46dcSZachary Turner 
142c1f46dcSZachary Turner #else
152c1f46dcSZachary Turner 
162c1f46dcSZachary Turner #include "lldb-python.h"
172c1f46dcSZachary Turner #include "PythonDataObjects.h"
182c1f46dcSZachary Turner #include "ScriptInterpreterPython.h"
192c1f46dcSZachary Turner 
202c1f46dcSZachary Turner #include "lldb/Core/Stream.h"
212c1f46dcSZachary Turner #include "lldb/Host/File.h"
222c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h"
232c1f46dcSZachary Turner 
242c1f46dcSZachary Turner #include <stdio.h>
252c1f46dcSZachary Turner 
262c1f46dcSZachary Turner using namespace lldb_private;
272c1f46dcSZachary Turner using namespace lldb;
282c1f46dcSZachary Turner 
292c1f46dcSZachary Turner void
302c1f46dcSZachary Turner StructuredPythonObject::Dump(Stream &s) const
312c1f46dcSZachary Turner {
322c1f46dcSZachary Turner     s << "Python Obj: 0x" << GetValue();
332c1f46dcSZachary Turner }
342c1f46dcSZachary Turner 
352c1f46dcSZachary Turner //----------------------------------------------------------------------
362c1f46dcSZachary Turner // PythonObject
372c1f46dcSZachary Turner //----------------------------------------------------------------------
382c1f46dcSZachary Turner 
392c1f46dcSZachary Turner void
402c1f46dcSZachary Turner PythonObject::Dump(Stream &strm) const
412c1f46dcSZachary Turner {
422c1f46dcSZachary Turner     if (m_py_obj)
432c1f46dcSZachary Turner     {
442c1f46dcSZachary Turner         FILE *file = ::tmpfile();
452c1f46dcSZachary Turner         if (file)
462c1f46dcSZachary Turner         {
472c1f46dcSZachary Turner             ::PyObject_Print (m_py_obj, file, 0);
482c1f46dcSZachary Turner             const long length = ftell (file);
492c1f46dcSZachary Turner             if (length)
502c1f46dcSZachary Turner             {
512c1f46dcSZachary Turner                 ::rewind(file);
522c1f46dcSZachary Turner                 std::vector<char> file_contents (length,'\0');
532c1f46dcSZachary Turner                 const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file);
542c1f46dcSZachary Turner                 if (length_read > 0)
552c1f46dcSZachary Turner                     strm.Write (file_contents.data(), length_read);
562c1f46dcSZachary Turner             }
572c1f46dcSZachary Turner             ::fclose (file);
582c1f46dcSZachary Turner         }
592c1f46dcSZachary Turner     }
602c1f46dcSZachary Turner     else
612c1f46dcSZachary Turner         strm.PutCString ("NULL");
622c1f46dcSZachary Turner }
632c1f46dcSZachary Turner 
642c1f46dcSZachary Turner PyObjectType
652c1f46dcSZachary Turner PythonObject::GetObjectType() const
662c1f46dcSZachary Turner {
67*f8b22f8fSZachary Turner     if (!IsAllocated())
682c1f46dcSZachary Turner         return PyObjectType::None;
692c1f46dcSZachary Turner 
702c1f46dcSZachary Turner     if (PyList_Check(m_py_obj))
712c1f46dcSZachary Turner         return PyObjectType::List;
722c1f46dcSZachary Turner     if (PyDict_Check(m_py_obj))
732c1f46dcSZachary Turner         return PyObjectType::Dictionary;
7422c8efcdSZachary Turner     if (PyUnicode_Check(m_py_obj))
7522c8efcdSZachary Turner         return PyObjectType::String;
7622c8efcdSZachary Turner     if (PyLong_Check(m_py_obj))
7722c8efcdSZachary Turner         return PyObjectType::Integer;
7822c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3
7922c8efcdSZachary Turner     // These functions don't exist in Python 3.x.  PyString is PyUnicode
8022c8efcdSZachary Turner     // and PyInt is PyLong.
812c1f46dcSZachary Turner     if (PyString_Check(m_py_obj))
822c1f46dcSZachary Turner         return PyObjectType::String;
8322c8efcdSZachary Turner     if (PyInt_Check(m_py_obj))
842c1f46dcSZachary Turner         return PyObjectType::Integer;
8522c8efcdSZachary Turner #endif
862c1f46dcSZachary Turner     return PyObjectType::Unknown;
872c1f46dcSZachary Turner }
882c1f46dcSZachary Turner 
892c1f46dcSZachary Turner PythonString
902c1f46dcSZachary Turner PythonObject::Repr()
912c1f46dcSZachary Turner {
922c1f46dcSZachary Turner     if (!m_py_obj)
932c1f46dcSZachary Turner         return PythonString();
942c1f46dcSZachary Turner     PyObject *repr = PyObject_Repr(m_py_obj);
952c1f46dcSZachary Turner     if (!repr)
962c1f46dcSZachary Turner         return PythonString();
97*f8b22f8fSZachary Turner     return PythonString(PyRefType::Owned, repr);
982c1f46dcSZachary Turner }
992c1f46dcSZachary Turner 
1002c1f46dcSZachary Turner PythonString
1012c1f46dcSZachary Turner PythonObject::Str()
1022c1f46dcSZachary Turner {
1032c1f46dcSZachary Turner     if (!m_py_obj)
1042c1f46dcSZachary Turner         return PythonString();
1052c1f46dcSZachary Turner     PyObject *str = PyObject_Str(m_py_obj);
1062c1f46dcSZachary Turner     if (!str)
1072c1f46dcSZachary Turner         return PythonString();
108*f8b22f8fSZachary Turner     return PythonString(PyRefType::Owned, str);
1092c1f46dcSZachary Turner }
1102c1f46dcSZachary Turner 
1112c1f46dcSZachary Turner bool
112*f8b22f8fSZachary Turner PythonObject::IsNone() const
1132c1f46dcSZachary Turner {
114*f8b22f8fSZachary Turner     return m_py_obj == Py_None;
115*f8b22f8fSZachary Turner }
116*f8b22f8fSZachary Turner 
117*f8b22f8fSZachary Turner bool
118*f8b22f8fSZachary Turner PythonObject::IsValid() const
119*f8b22f8fSZachary Turner {
120*f8b22f8fSZachary Turner     return m_py_obj != nullptr;
121*f8b22f8fSZachary Turner }
122*f8b22f8fSZachary Turner 
123*f8b22f8fSZachary Turner bool
124*f8b22f8fSZachary Turner PythonObject::IsAllocated() const
125*f8b22f8fSZachary Turner {
126*f8b22f8fSZachary Turner     return IsValid() && !IsNone();
1272c1f46dcSZachary Turner }
1282c1f46dcSZachary Turner 
1292c1f46dcSZachary Turner StructuredData::ObjectSP
1302c1f46dcSZachary Turner PythonObject::CreateStructuredObject() const
1312c1f46dcSZachary Turner {
1322c1f46dcSZachary Turner     switch (GetObjectType())
1332c1f46dcSZachary Turner     {
1342c1f46dcSZachary Turner         case PyObjectType::Dictionary:
135*f8b22f8fSZachary Turner             return PythonDictionary(PyRefType::Borrowed, m_py_obj).CreateStructuredDictionary();
1362c1f46dcSZachary Turner         case PyObjectType::Integer:
137*f8b22f8fSZachary Turner             return PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger();
1382c1f46dcSZachary Turner         case PyObjectType::List:
139*f8b22f8fSZachary Turner             return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
1402c1f46dcSZachary Turner         case PyObjectType::String:
141*f8b22f8fSZachary Turner             return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
1422c1f46dcSZachary Turner         case PyObjectType::None:
1432c1f46dcSZachary Turner             return StructuredData::ObjectSP();
1442c1f46dcSZachary Turner         default:
1452c1f46dcSZachary Turner             return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj));
1462c1f46dcSZachary Turner     }
1472c1f46dcSZachary Turner }
1482c1f46dcSZachary Turner 
1492c1f46dcSZachary Turner //----------------------------------------------------------------------
1502c1f46dcSZachary Turner // PythonString
1512c1f46dcSZachary Turner //----------------------------------------------------------------------
1522c1f46dcSZachary Turner 
153*f8b22f8fSZachary Turner PythonString::PythonString(PyRefType type, PyObject *py_obj)
154*f8b22f8fSZachary Turner     : PythonObject()
1552c1f46dcSZachary Turner {
156*f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
1572c1f46dcSZachary Turner }
1582c1f46dcSZachary Turner 
159*f8b22f8fSZachary Turner PythonString::PythonString(const PythonString &object)
160*f8b22f8fSZachary Turner     : PythonObject(object)
1612c1f46dcSZachary Turner {
1622c1f46dcSZachary Turner }
1632c1f46dcSZachary Turner 
16422c8efcdSZachary Turner PythonString::PythonString(llvm::StringRef string)
16522c8efcdSZachary Turner     : PythonObject()
1662c1f46dcSZachary Turner {
16722c8efcdSZachary Turner     SetString(string);
1682c1f46dcSZachary Turner }
1692c1f46dcSZachary Turner 
17022c8efcdSZachary Turner PythonString::PythonString(const char *string)
17122c8efcdSZachary Turner     : PythonObject()
1722c1f46dcSZachary Turner {
17322c8efcdSZachary Turner     SetString(llvm::StringRef(string));
1742c1f46dcSZachary Turner }
1752c1f46dcSZachary Turner 
176*f8b22f8fSZachary Turner PythonString::PythonString()
177*f8b22f8fSZachary Turner     : PythonObject()
1782c1f46dcSZachary Turner {
1792c1f46dcSZachary Turner }
1802c1f46dcSZachary Turner 
1812c1f46dcSZachary Turner PythonString::~PythonString ()
1822c1f46dcSZachary Turner {
1832c1f46dcSZachary Turner }
1842c1f46dcSZachary Turner 
1852c1f46dcSZachary Turner bool
18622c8efcdSZachary Turner PythonString::Check(PyObject *py_obj)
18722c8efcdSZachary Turner {
18822c8efcdSZachary Turner     if (!py_obj)
18922c8efcdSZachary Turner         return false;
19022c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
19122c8efcdSZachary Turner     // Python 3 does not have PyString objects, only PyUnicode.
19222c8efcdSZachary Turner     return PyUnicode_Check(py_obj);
19322c8efcdSZachary Turner #else
19422c8efcdSZachary Turner     return PyUnicode_Check(py_obj) || PyString_Check(py_obj);
19522c8efcdSZachary Turner #endif
19622c8efcdSZachary Turner }
19722c8efcdSZachary Turner 
198*f8b22f8fSZachary Turner void
199*f8b22f8fSZachary Turner PythonString::Reset(PyRefType type, PyObject *py_obj)
2002c1f46dcSZachary Turner {
201*f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
202*f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
203*f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
204*f8b22f8fSZachary Turner 
20522c8efcdSZachary Turner     if (!PythonString::Check(py_obj))
20622c8efcdSZachary Turner     {
207*f8b22f8fSZachary Turner         PythonObject::Reset();
208*f8b22f8fSZachary Turner         return;
20922c8efcdSZachary Turner     }
21022c8efcdSZachary Turner 
21122c8efcdSZachary Turner     // Convert this to a PyBytes object, and only store the PyBytes.  Note that in
21222c8efcdSZachary Turner     // Python 2.x, PyString and PyUnicode are interchangeable, and PyBytes is an alias
21322c8efcdSZachary Turner     // of PyString.  So on 2.x, if we get into this branch, we already have a PyBytes.
21422c8efcdSZachary Turner     if (PyUnicode_Check(py_obj))
21522c8efcdSZachary Turner     {
216*f8b22f8fSZachary Turner         // Since we're converting this to a different object, we assume ownership of the
217*f8b22f8fSZachary Turner         // new object regardless of the value of `type`.
218*f8b22f8fSZachary Turner         result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(py_obj));
21922c8efcdSZachary Turner     }
22022c8efcdSZachary Turner 
221*f8b22f8fSZachary Turner     assert(PyBytes_Check(result.get()) && "PythonString::Reset received a non-string");
222*f8b22f8fSZachary Turner 
223*f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
224*f8b22f8fSZachary Turner     // back into the virtual implementation.
225*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
2262c1f46dcSZachary Turner }
2272c1f46dcSZachary Turner 
2282c1f46dcSZachary Turner llvm::StringRef
2292c1f46dcSZachary Turner PythonString::GetString() const
2302c1f46dcSZachary Turner {
231*f8b22f8fSZachary Turner     if (IsValid())
23222c8efcdSZachary Turner     {
23322c8efcdSZachary Turner         Py_ssize_t size;
23422c8efcdSZachary Turner         char *c;
23522c8efcdSZachary Turner         PyBytes_AsStringAndSize(m_py_obj, &c, &size);
23622c8efcdSZachary Turner         return llvm::StringRef(c, size);
23722c8efcdSZachary Turner     }
2382c1f46dcSZachary Turner     return llvm::StringRef();
2392c1f46dcSZachary Turner }
2402c1f46dcSZachary Turner 
2412c1f46dcSZachary Turner size_t
2422c1f46dcSZachary Turner PythonString::GetSize() const
2432c1f46dcSZachary Turner {
244*f8b22f8fSZachary Turner     if (IsValid())
24522c8efcdSZachary Turner         return PyBytes_Size(m_py_obj);
2462c1f46dcSZachary Turner     return 0;
2472c1f46dcSZachary Turner }
2482c1f46dcSZachary Turner 
2492c1f46dcSZachary Turner void
2502c1f46dcSZachary Turner PythonString::SetString (llvm::StringRef string)
2512c1f46dcSZachary Turner {
25222c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
25322c8efcdSZachary Turner     PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
25422c8efcdSZachary Turner     PyObject *bytes = PyUnicode_AsUTF8String(unicode);
255*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Owned, bytes);
256*f8b22f8fSZachary Turner     Py_DECREF(unicode);
25722c8efcdSZachary Turner #else
258*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Owned, PyString_FromStringAndSize(string.data(), string.size()));
25922c8efcdSZachary Turner #endif
2602c1f46dcSZachary Turner }
2612c1f46dcSZachary Turner 
2622c1f46dcSZachary Turner StructuredData::StringSP
2632c1f46dcSZachary Turner PythonString::CreateStructuredString() const
2642c1f46dcSZachary Turner {
2652c1f46dcSZachary Turner     StructuredData::StringSP result(new StructuredData::String);
2662c1f46dcSZachary Turner     result->SetValue(GetString());
2672c1f46dcSZachary Turner     return result;
2682c1f46dcSZachary Turner }
2692c1f46dcSZachary Turner 
2702c1f46dcSZachary Turner //----------------------------------------------------------------------
2712c1f46dcSZachary Turner // PythonInteger
2722c1f46dcSZachary Turner //----------------------------------------------------------------------
2732c1f46dcSZachary Turner 
274*f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
275*f8b22f8fSZachary Turner     : PythonObject()
2762c1f46dcSZachary Turner {
277*f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
2782c1f46dcSZachary Turner }
2792c1f46dcSZachary Turner 
280*f8b22f8fSZachary Turner PythonInteger::PythonInteger(const PythonInteger &object)
281*f8b22f8fSZachary Turner     : PythonObject(object)
2822c1f46dcSZachary Turner {
2832c1f46dcSZachary Turner }
2842c1f46dcSZachary Turner 
285*f8b22f8fSZachary Turner PythonInteger::PythonInteger(int64_t value)
286*f8b22f8fSZachary Turner     : PythonObject()
2872c1f46dcSZachary Turner {
2882c1f46dcSZachary Turner     SetInteger(value);
2892c1f46dcSZachary Turner }
2902c1f46dcSZachary Turner 
2912c1f46dcSZachary Turner 
2922c1f46dcSZachary Turner PythonInteger::~PythonInteger ()
2932c1f46dcSZachary Turner {
2942c1f46dcSZachary Turner }
2952c1f46dcSZachary Turner 
2962c1f46dcSZachary Turner bool
29722c8efcdSZachary Turner PythonInteger::Check(PyObject *py_obj)
2982c1f46dcSZachary Turner {
29922c8efcdSZachary Turner     if (!py_obj)
30022c8efcdSZachary Turner         return false;
30122c8efcdSZachary Turner 
30222c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
30322c8efcdSZachary Turner     // Python 3 does not have PyInt_Check.  There is only one type of
30422c8efcdSZachary Turner     // integral value, long.
30522c8efcdSZachary Turner     return PyLong_Check(py_obj);
30622c8efcdSZachary Turner #else
30722c8efcdSZachary Turner     return PyLong_Check(py_obj) || PyInt_Check(py_obj);
30822c8efcdSZachary Turner #endif
3092c1f46dcSZachary Turner }
3102c1f46dcSZachary Turner 
311*f8b22f8fSZachary Turner void
312*f8b22f8fSZachary Turner PythonInteger::Reset(PyRefType type, PyObject *py_obj)
31322c8efcdSZachary Turner {
314*f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
315*f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
316*f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
317*f8b22f8fSZachary Turner 
31822c8efcdSZachary Turner     if (!PythonInteger::Check(py_obj))
31922c8efcdSZachary Turner     {
320*f8b22f8fSZachary Turner         PythonObject::Reset();
321*f8b22f8fSZachary Turner         return;
32222c8efcdSZachary Turner     }
32322c8efcdSZachary Turner 
32422c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3
32522c8efcdSZachary Turner     // Always store this as a PyLong, which makes interoperability between
32622c8efcdSZachary Turner     // Python 2.x and Python 3.x easier.  This is only necessary in 2.x,
32722c8efcdSZachary Turner     // since 3.x doesn't even have a PyInt.
32822c8efcdSZachary Turner     if (PyInt_Check(py_obj))
32922c8efcdSZachary Turner     {
330*f8b22f8fSZachary Turner         // Since we converted the original object to a different type, the new
331*f8b22f8fSZachary Turner         // object is an owned object regardless of the ownership semantics requested
332*f8b22f8fSZachary Turner         // by the user.
333*f8b22f8fSZachary Turner         result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
33422c8efcdSZachary Turner     }
33522c8efcdSZachary Turner #endif
33622c8efcdSZachary Turner 
337*f8b22f8fSZachary Turner     assert(PyLong_Check(result.get()) && "Couldn't get a PyLong from this PyObject");
33822c8efcdSZachary Turner 
339*f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
340*f8b22f8fSZachary Turner     // back into the virtual implementation.
341*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
3422c1f46dcSZachary Turner }
3432c1f46dcSZachary Turner 
3442c1f46dcSZachary Turner int64_t
3452c1f46dcSZachary Turner PythonInteger::GetInteger() const
3462c1f46dcSZachary Turner {
3472c1f46dcSZachary Turner     if (m_py_obj)
3482c1f46dcSZachary Turner     {
34922c8efcdSZachary Turner         assert(PyLong_Check(m_py_obj) && "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
35022c8efcdSZachary Turner 
3512c1f46dcSZachary Turner         return PyLong_AsLongLong(m_py_obj);
3522c1f46dcSZachary Turner     }
3532c1f46dcSZachary Turner     return UINT64_MAX;
3542c1f46dcSZachary Turner }
3552c1f46dcSZachary Turner 
3562c1f46dcSZachary Turner void
3572c1f46dcSZachary Turner PythonInteger::SetInteger(int64_t value)
3582c1f46dcSZachary Turner {
359*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
3602c1f46dcSZachary Turner }
3612c1f46dcSZachary Turner 
3622c1f46dcSZachary Turner StructuredData::IntegerSP
3632c1f46dcSZachary Turner PythonInteger::CreateStructuredInteger() const
3642c1f46dcSZachary Turner {
3652c1f46dcSZachary Turner     StructuredData::IntegerSP result(new StructuredData::Integer);
3662c1f46dcSZachary Turner     result->SetValue(GetInteger());
3672c1f46dcSZachary Turner     return result;
3682c1f46dcSZachary Turner }
3692c1f46dcSZachary Turner 
3702c1f46dcSZachary Turner //----------------------------------------------------------------------
3712c1f46dcSZachary Turner // PythonList
3722c1f46dcSZachary Turner //----------------------------------------------------------------------
3732c1f46dcSZachary Turner 
374*f8b22f8fSZachary Turner PythonList::PythonList(PyInitialValue value)
375*f8b22f8fSZachary Turner     : PythonObject()
3762c1f46dcSZachary Turner {
377*f8b22f8fSZachary Turner     if (value == PyInitialValue::Empty)
378*f8b22f8fSZachary Turner         Reset(PyRefType::Owned, PyList_New(0));
3792c1f46dcSZachary Turner }
3802c1f46dcSZachary Turner 
381*f8b22f8fSZachary Turner PythonList::PythonList(PyRefType type, PyObject *py_obj)
382*f8b22f8fSZachary Turner     : PythonObject()
3832c1f46dcSZachary Turner {
384*f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
3852c1f46dcSZachary Turner }
3862c1f46dcSZachary Turner 
387*f8b22f8fSZachary Turner PythonList::PythonList(const PythonList &list)
388*f8b22f8fSZachary Turner     : PythonObject(list)
3892c1f46dcSZachary Turner {
3902c1f46dcSZachary Turner }
3912c1f46dcSZachary Turner 
3922c1f46dcSZachary Turner PythonList::~PythonList ()
3932c1f46dcSZachary Turner {
3942c1f46dcSZachary Turner }
3952c1f46dcSZachary Turner 
3962c1f46dcSZachary Turner bool
39722c8efcdSZachary Turner PythonList::Check(PyObject *py_obj)
39822c8efcdSZachary Turner {
39922c8efcdSZachary Turner     if (!py_obj)
40022c8efcdSZachary Turner         return false;
40122c8efcdSZachary Turner     return PyList_Check(py_obj);
40222c8efcdSZachary Turner }
40322c8efcdSZachary Turner 
404*f8b22f8fSZachary Turner void
405*f8b22f8fSZachary Turner PythonList::Reset(PyRefType type, PyObject *py_obj)
4062c1f46dcSZachary Turner {
407*f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
408*f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
409*f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
410*f8b22f8fSZachary Turner 
41122c8efcdSZachary Turner     if (!PythonList::Check(py_obj))
41222c8efcdSZachary Turner     {
413*f8b22f8fSZachary Turner         PythonObject::Reset();
414*f8b22f8fSZachary Turner         return;
41522c8efcdSZachary Turner     }
41622c8efcdSZachary Turner 
417*f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
418*f8b22f8fSZachary Turner     // back into the virtual implementation.
419*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
4202c1f46dcSZachary Turner }
4212c1f46dcSZachary Turner 
4222c1f46dcSZachary Turner uint32_t
4232c1f46dcSZachary Turner PythonList::GetSize() const
4242c1f46dcSZachary Turner {
425*f8b22f8fSZachary Turner     if (IsValid())
4262c1f46dcSZachary Turner         return PyList_GET_SIZE(m_py_obj);
4272c1f46dcSZachary Turner     return 0;
4282c1f46dcSZachary Turner }
4292c1f46dcSZachary Turner 
4302c1f46dcSZachary Turner PythonObject
4312c1f46dcSZachary Turner PythonList::GetItemAtIndex(uint32_t index) const
4322c1f46dcSZachary Turner {
433*f8b22f8fSZachary Turner     if (IsValid())
434*f8b22f8fSZachary Turner         return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
4352c1f46dcSZachary Turner     return PythonObject();
4362c1f46dcSZachary Turner }
4372c1f46dcSZachary Turner 
4382c1f46dcSZachary Turner void
4392c1f46dcSZachary Turner PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object)
4402c1f46dcSZachary Turner {
441*f8b22f8fSZachary Turner     if (IsAllocated() && object.IsValid())
442*f8b22f8fSZachary Turner     {
443*f8b22f8fSZachary Turner         // PyList_SetItem is documented to "steal" a reference, so we need to
444*f8b22f8fSZachary Turner         // convert it to an owned reference by incrementing it.
445*f8b22f8fSZachary Turner         Py_INCREF(object.get());
4462c1f46dcSZachary Turner         PyList_SetItem(m_py_obj, index, object.get());
4472c1f46dcSZachary Turner     }
448*f8b22f8fSZachary Turner }
4492c1f46dcSZachary Turner 
4502c1f46dcSZachary Turner void
4512c1f46dcSZachary Turner PythonList::AppendItem(const PythonObject &object)
4522c1f46dcSZachary Turner {
453*f8b22f8fSZachary Turner     if (IsAllocated() && object.IsValid())
454*f8b22f8fSZachary Turner     {
455*f8b22f8fSZachary Turner         // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
456*f8b22f8fSZachary Turner         // here like we do with `PyList_SetItem`.
4572c1f46dcSZachary Turner         PyList_Append(m_py_obj, object.get());
4582c1f46dcSZachary Turner     }
459*f8b22f8fSZachary Turner }
4602c1f46dcSZachary Turner 
4612c1f46dcSZachary Turner StructuredData::ArraySP
4622c1f46dcSZachary Turner PythonList::CreateStructuredArray() const
4632c1f46dcSZachary Turner {
4642c1f46dcSZachary Turner     StructuredData::ArraySP result(new StructuredData::Array);
4652c1f46dcSZachary Turner     uint32_t count = GetSize();
4662c1f46dcSZachary Turner     for (uint32_t i = 0; i < count; ++i)
4672c1f46dcSZachary Turner     {
4682c1f46dcSZachary Turner         PythonObject obj = GetItemAtIndex(i);
4692c1f46dcSZachary Turner         result->AddItem(obj.CreateStructuredObject());
4702c1f46dcSZachary Turner     }
4712c1f46dcSZachary Turner     return result;
4722c1f46dcSZachary Turner }
4732c1f46dcSZachary Turner 
4742c1f46dcSZachary Turner //----------------------------------------------------------------------
4752c1f46dcSZachary Turner // PythonDictionary
4762c1f46dcSZachary Turner //----------------------------------------------------------------------
4772c1f46dcSZachary Turner 
478*f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyInitialValue value)
479*f8b22f8fSZachary Turner     : PythonObject()
4802c1f46dcSZachary Turner {
481*f8b22f8fSZachary Turner     if (value == PyInitialValue::Empty)
482*f8b22f8fSZachary Turner         Reset(PyRefType::Owned, PyDict_New());
4832c1f46dcSZachary Turner }
4842c1f46dcSZachary Turner 
485*f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
486*f8b22f8fSZachary Turner     : PythonObject()
4872c1f46dcSZachary Turner {
488*f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
4892c1f46dcSZachary Turner }
4902c1f46dcSZachary Turner 
491*f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object)
492*f8b22f8fSZachary Turner     : PythonObject(object)
4932c1f46dcSZachary Turner {
4942c1f46dcSZachary Turner }
4952c1f46dcSZachary Turner 
4962c1f46dcSZachary Turner PythonDictionary::~PythonDictionary ()
4972c1f46dcSZachary Turner {
4982c1f46dcSZachary Turner }
4992c1f46dcSZachary Turner 
5002c1f46dcSZachary Turner bool
50122c8efcdSZachary Turner PythonDictionary::Check(PyObject *py_obj)
50222c8efcdSZachary Turner {
50322c8efcdSZachary Turner     if (!py_obj)
50422c8efcdSZachary Turner         return false;
50522c8efcdSZachary Turner 
50622c8efcdSZachary Turner     return PyDict_Check(py_obj);
50722c8efcdSZachary Turner }
50822c8efcdSZachary Turner 
509*f8b22f8fSZachary Turner void
510*f8b22f8fSZachary Turner PythonDictionary::Reset(PyRefType type, PyObject *py_obj)
5112c1f46dcSZachary Turner {
512*f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
513*f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
514*f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
515*f8b22f8fSZachary Turner 
51622c8efcdSZachary Turner     if (!PythonDictionary::Check(py_obj))
51722c8efcdSZachary Turner     {
518*f8b22f8fSZachary Turner         PythonObject::Reset();
519*f8b22f8fSZachary Turner         return;
52022c8efcdSZachary Turner     }
52122c8efcdSZachary Turner 
522*f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
523*f8b22f8fSZachary Turner     // back into the virtual implementation.
524*f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
5252c1f46dcSZachary Turner }
5262c1f46dcSZachary Turner 
5272c1f46dcSZachary Turner uint32_t
5282c1f46dcSZachary Turner PythonDictionary::GetSize() const
5292c1f46dcSZachary Turner {
530*f8b22f8fSZachary Turner     if (IsValid())
5312c1f46dcSZachary Turner         return PyDict_Size(m_py_obj);
5322c1f46dcSZachary Turner     return 0;
5332c1f46dcSZachary Turner }
5342c1f46dcSZachary Turner 
5352c1f46dcSZachary Turner PythonList
5362c1f46dcSZachary Turner PythonDictionary::GetKeys() const
5372c1f46dcSZachary Turner {
538*f8b22f8fSZachary Turner     if (IsValid())
539*f8b22f8fSZachary Turner         return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
540*f8b22f8fSZachary Turner     return PythonList(PyInitialValue::Invalid);
5412c1f46dcSZachary Turner }
5422c1f46dcSZachary Turner 
5432c1f46dcSZachary Turner PythonObject
544*f8b22f8fSZachary Turner PythonDictionary::GetItemForKey(const PythonObject &key) const
5452c1f46dcSZachary Turner {
546*f8b22f8fSZachary Turner     if (IsAllocated() && key.IsValid())
547*f8b22f8fSZachary Turner         return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get()));
5482c1f46dcSZachary Turner     return PythonObject();
5492c1f46dcSZachary Turner }
5502c1f46dcSZachary Turner 
5512c1f46dcSZachary Turner void
552*f8b22f8fSZachary Turner PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value)
5532c1f46dcSZachary Turner {
554*f8b22f8fSZachary Turner     if (IsAllocated() && key.IsValid() && value.IsValid())
5552c1f46dcSZachary Turner         PyDict_SetItem(m_py_obj, key.get(), value.get());
5562c1f46dcSZachary Turner }
5572c1f46dcSZachary Turner 
5582c1f46dcSZachary Turner StructuredData::DictionarySP
5592c1f46dcSZachary Turner PythonDictionary::CreateStructuredDictionary() const
5602c1f46dcSZachary Turner {
5612c1f46dcSZachary Turner     StructuredData::DictionarySP result(new StructuredData::Dictionary);
5622c1f46dcSZachary Turner     PythonList keys(GetKeys());
5632c1f46dcSZachary Turner     uint32_t num_keys = keys.GetSize();
5642c1f46dcSZachary Turner     for (uint32_t i = 0; i < num_keys; ++i)
5652c1f46dcSZachary Turner     {
5662c1f46dcSZachary Turner         PythonObject key = keys.GetItemAtIndex(i);
5672c1f46dcSZachary Turner         PythonObject value = GetItemForKey(key);
5682c1f46dcSZachary Turner         StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
569*f8b22f8fSZachary Turner         result->AddItem(key.Str().GetString(), structured_value);
5702c1f46dcSZachary Turner     }
5712c1f46dcSZachary Turner     return result;
5722c1f46dcSZachary Turner }
5732c1f46dcSZachary Turner 
5742c1f46dcSZachary Turner #endif
575