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"
22190fadcdSZachary Turner #include "lldb/Host/FileSystem.h"
232c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h"
242c1f46dcSZachary Turner 
25190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h"
26190fadcdSZachary Turner 
272c1f46dcSZachary Turner #include <stdio.h>
282c1f46dcSZachary Turner 
29744959b9SEnrico Granata #include "llvm/ADT/StringSwitch.h"
30744959b9SEnrico Granata 
312c1f46dcSZachary Turner using namespace lldb_private;
322c1f46dcSZachary Turner using namespace lldb;
332c1f46dcSZachary Turner 
342c1f46dcSZachary Turner void
35d9c9da53SJason Molenda StructuredPythonObject::Dump(Stream &s, bool pretty_print) const
362c1f46dcSZachary Turner {
372c1f46dcSZachary Turner     s << "Python Obj: 0x" << GetValue();
382c1f46dcSZachary Turner }
392c1f46dcSZachary Turner 
402c1f46dcSZachary Turner //----------------------------------------------------------------------
412c1f46dcSZachary Turner // PythonObject
422c1f46dcSZachary Turner //----------------------------------------------------------------------
432c1f46dcSZachary Turner 
442c1f46dcSZachary Turner void
452c1f46dcSZachary Turner PythonObject::Dump(Stream &strm) const
462c1f46dcSZachary Turner {
472c1f46dcSZachary Turner     if (m_py_obj)
482c1f46dcSZachary Turner     {
492c1f46dcSZachary Turner         FILE *file = ::tmpfile();
502c1f46dcSZachary Turner         if (file)
512c1f46dcSZachary Turner         {
522c1f46dcSZachary Turner             ::PyObject_Print (m_py_obj, file, 0);
532c1f46dcSZachary Turner             const long length = ftell (file);
542c1f46dcSZachary Turner             if (length)
552c1f46dcSZachary Turner             {
562c1f46dcSZachary Turner                 ::rewind(file);
572c1f46dcSZachary Turner                 std::vector<char> file_contents (length,'\0');
582c1f46dcSZachary Turner                 const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file);
592c1f46dcSZachary Turner                 if (length_read > 0)
602c1f46dcSZachary Turner                     strm.Write (file_contents.data(), length_read);
612c1f46dcSZachary Turner             }
622c1f46dcSZachary Turner             ::fclose (file);
632c1f46dcSZachary Turner         }
642c1f46dcSZachary Turner     }
652c1f46dcSZachary Turner     else
662c1f46dcSZachary Turner         strm.PutCString ("NULL");
672c1f46dcSZachary Turner }
682c1f46dcSZachary Turner 
692c1f46dcSZachary Turner PyObjectType
702c1f46dcSZachary Turner PythonObject::GetObjectType() const
712c1f46dcSZachary Turner {
72f8b22f8fSZachary Turner     if (!IsAllocated())
732c1f46dcSZachary Turner         return PyObjectType::None;
742c1f46dcSZachary Turner 
757841efbbSZachary Turner     if (PythonModule::Check(m_py_obj))
767841efbbSZachary Turner         return PyObjectType::Module;
7718426935SZachary Turner     if (PythonList::Check(m_py_obj))
782c1f46dcSZachary Turner         return PyObjectType::List;
79a1405147SZachary Turner     if (PythonTuple::Check(m_py_obj))
80a1405147SZachary Turner         return PyObjectType::Tuple;
8118426935SZachary Turner     if (PythonDictionary::Check(m_py_obj))
822c1f46dcSZachary Turner         return PyObjectType::Dictionary;
8318426935SZachary Turner     if (PythonString::Check(m_py_obj))
8422c8efcdSZachary Turner         return PyObjectType::String;
855a72c02bSZachary Turner #if PY_MAJOR_VERSION >= 3
865a72c02bSZachary Turner     if (PythonBytes::Check(m_py_obj))
875a72c02bSZachary Turner         return PyObjectType::Bytes;
885a72c02bSZachary Turner #endif
89f9d6d204SZachary Turner     if (PythonByteArray::Check(m_py_obj))
90f9d6d204SZachary Turner         return PyObjectType::ByteArray;
9118426935SZachary Turner     if (PythonInteger::Check(m_py_obj))
9222c8efcdSZachary Turner         return PyObjectType::Integer;
939c40264fSZachary Turner     if (PythonFile::Check(m_py_obj))
949c40264fSZachary Turner         return PyObjectType::File;
95a1405147SZachary Turner     if (PythonCallable::Check(m_py_obj))
96a1405147SZachary Turner         return PyObjectType::Callable;
972c1f46dcSZachary Turner     return PyObjectType::Unknown;
982c1f46dcSZachary Turner }
992c1f46dcSZachary Turner 
1002c1f46dcSZachary Turner PythonString
1017841efbbSZachary Turner PythonObject::Repr() const
1022c1f46dcSZachary Turner {
1032c1f46dcSZachary Turner     if (!m_py_obj)
1042c1f46dcSZachary Turner         return PythonString();
1052c1f46dcSZachary Turner     PyObject *repr = PyObject_Repr(m_py_obj);
1062c1f46dcSZachary Turner     if (!repr)
1072c1f46dcSZachary Turner         return PythonString();
108f8b22f8fSZachary Turner     return PythonString(PyRefType::Owned, repr);
1092c1f46dcSZachary Turner }
1102c1f46dcSZachary Turner 
1112c1f46dcSZachary Turner PythonString
1127841efbbSZachary Turner PythonObject::Str() const
1132c1f46dcSZachary Turner {
1142c1f46dcSZachary Turner     if (!m_py_obj)
1152c1f46dcSZachary Turner         return PythonString();
1162c1f46dcSZachary Turner     PyObject *str = PyObject_Str(m_py_obj);
1172c1f46dcSZachary Turner     if (!str)
1182c1f46dcSZachary Turner         return PythonString();
119f8b22f8fSZachary Turner     return PythonString(PyRefType::Owned, str);
1202c1f46dcSZachary Turner }
1212c1f46dcSZachary Turner 
1227841efbbSZachary Turner PythonObject
12302bf92d2SZachary Turner PythonObject::ResolveNameWithDictionary(llvm::StringRef name, const PythonDictionary &dict)
1247841efbbSZachary Turner {
125a1405147SZachary Turner     size_t dot_pos = name.find_first_of('.');
126a1405147SZachary Turner     llvm::StringRef piece = name.substr(0, dot_pos);
127a1405147SZachary Turner     PythonObject result = dict.GetItemForKey(PythonString(piece));
128a1405147SZachary Turner     if (dot_pos == llvm::StringRef::npos)
129a1405147SZachary Turner     {
130a1405147SZachary Turner         // There was no dot, we're done.
131a1405147SZachary Turner         return result;
132a1405147SZachary Turner     }
133a1405147SZachary Turner 
134a1405147SZachary Turner     // There was a dot.  The remaining portion of the name should be looked up in
135a1405147SZachary Turner     // the context of the object that was found in the dictionary.
136a1405147SZachary Turner     return result.ResolveName(name.substr(dot_pos + 1));
1377841efbbSZachary Turner }
1387841efbbSZachary Turner 
1397841efbbSZachary Turner PythonObject
1407841efbbSZachary Turner PythonObject::ResolveName(llvm::StringRef name) const
1417841efbbSZachary Turner {
1427841efbbSZachary Turner     // Resolve the name in the context of the specified object.  If,
1437841efbbSZachary Turner     // for example, `this` refers to a PyModule, then this will look for
1447841efbbSZachary Turner     // `name` in this module.  If `this` refers to a PyType, then it will
1457841efbbSZachary Turner     // resolve `name` as an attribute of that type.  If `this` refers to
1467841efbbSZachary Turner     // an instance of an object, then it will resolve `name` as the value
1477841efbbSZachary Turner     // of the specified field.
1487841efbbSZachary Turner     //
1497841efbbSZachary Turner     // This function handles dotted names so that, for example, if `m_py_obj`
1507841efbbSZachary Turner     // refers to the `sys` module, and `name` == "path.append", then it
1517841efbbSZachary Turner     // will find the function `sys.path.append`.
1527841efbbSZachary Turner 
1537841efbbSZachary Turner     size_t dot_pos = name.find_first_of('.');
1547841efbbSZachary Turner     if (dot_pos == llvm::StringRef::npos)
1557841efbbSZachary Turner     {
1567841efbbSZachary Turner         // No dots in the name, we should be able to find the value immediately
157a1405147SZachary Turner         // as an attribute of `m_py_obj`.
1587841efbbSZachary Turner         return GetAttributeValue(name);
1597841efbbSZachary Turner     }
1607841efbbSZachary Turner 
1617841efbbSZachary Turner     // Look up the first piece of the name, and resolve the rest as a child of that.
1627841efbbSZachary Turner     PythonObject parent = ResolveName(name.substr(0, dot_pos));
1637841efbbSZachary Turner     if (!parent.IsAllocated())
1647841efbbSZachary Turner         return PythonObject();
1657841efbbSZachary Turner 
1667841efbbSZachary Turner     // Tail recursion.. should be optimized by the compiler
1677841efbbSZachary Turner     return parent.ResolveName(name.substr(dot_pos + 1));
1687841efbbSZachary Turner }
1697841efbbSZachary Turner 
1702c1f46dcSZachary Turner bool
1719c40264fSZachary Turner PythonObject::HasAttribute(llvm::StringRef attr) const
1729c40264fSZachary Turner {
1739c40264fSZachary Turner     if (!IsValid())
1749c40264fSZachary Turner         return false;
1759c40264fSZachary Turner     PythonString py_attr(attr);
1769c40264fSZachary Turner     return !!PyObject_HasAttr(m_py_obj, py_attr.get());
1779c40264fSZachary Turner }
1789c40264fSZachary Turner 
1797d6d218eSZachary Turner PythonObject
1807d6d218eSZachary Turner PythonObject::GetAttributeValue(llvm::StringRef attr) const
1817d6d218eSZachary Turner {
1827d6d218eSZachary Turner     if (!IsValid())
1837d6d218eSZachary Turner         return PythonObject();
1847d6d218eSZachary Turner 
1857d6d218eSZachary Turner     PythonString py_attr(attr);
1867d6d218eSZachary Turner     if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
1877d6d218eSZachary Turner         return PythonObject();
1887d6d218eSZachary Turner 
1897d6d218eSZachary Turner     return PythonObject(PyRefType::Owned,
1907d6d218eSZachary Turner         PyObject_GetAttr(m_py_obj, py_attr.get()));
1917d6d218eSZachary Turner }
1927d6d218eSZachary Turner 
1939c40264fSZachary Turner bool
194f8b22f8fSZachary Turner PythonObject::IsNone() const
1952c1f46dcSZachary Turner {
196f8b22f8fSZachary Turner     return m_py_obj == Py_None;
197f8b22f8fSZachary Turner }
198f8b22f8fSZachary Turner 
199f8b22f8fSZachary Turner bool
200f8b22f8fSZachary Turner PythonObject::IsValid() const
201f8b22f8fSZachary Turner {
202f8b22f8fSZachary Turner     return m_py_obj != nullptr;
203f8b22f8fSZachary Turner }
204f8b22f8fSZachary Turner 
205f8b22f8fSZachary Turner bool
206f8b22f8fSZachary Turner PythonObject::IsAllocated() const
207f8b22f8fSZachary Turner {
208f8b22f8fSZachary Turner     return IsValid() && !IsNone();
2092c1f46dcSZachary Turner }
2102c1f46dcSZachary Turner 
2112c1f46dcSZachary Turner StructuredData::ObjectSP
2122c1f46dcSZachary Turner PythonObject::CreateStructuredObject() const
2132c1f46dcSZachary Turner {
2142c1f46dcSZachary Turner     switch (GetObjectType())
2152c1f46dcSZachary Turner     {
2162c1f46dcSZachary Turner         case PyObjectType::Dictionary:
217f8b22f8fSZachary Turner             return PythonDictionary(PyRefType::Borrowed, m_py_obj).CreateStructuredDictionary();
2182c1f46dcSZachary Turner         case PyObjectType::Integer:
219f8b22f8fSZachary Turner             return PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger();
2202c1f46dcSZachary Turner         case PyObjectType::List:
221f8b22f8fSZachary Turner             return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
2222c1f46dcSZachary Turner         case PyObjectType::String:
223f8b22f8fSZachary Turner             return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
2245a72c02bSZachary Turner         case PyObjectType::Bytes:
2255a72c02bSZachary Turner             return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
226f9d6d204SZachary Turner         case PyObjectType::ByteArray:
227f9d6d204SZachary Turner             return PythonByteArray(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
2282c1f46dcSZachary Turner         case PyObjectType::None:
2292c1f46dcSZachary Turner             return StructuredData::ObjectSP();
2302c1f46dcSZachary Turner         default:
2312c1f46dcSZachary Turner             return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj));
2322c1f46dcSZachary Turner     }
2332c1f46dcSZachary Turner }
2342c1f46dcSZachary Turner 
2352c1f46dcSZachary Turner //----------------------------------------------------------------------
2362c1f46dcSZachary Turner // PythonString
2372c1f46dcSZachary Turner //----------------------------------------------------------------------
2385a72c02bSZachary Turner PythonBytes::PythonBytes() : PythonObject()
2395a72c02bSZachary Turner {
2405a72c02bSZachary Turner }
2415a72c02bSZachary Turner 
2425a72c02bSZachary Turner PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject()
2435a72c02bSZachary Turner {
2445a72c02bSZachary Turner     SetBytes(bytes);
2455a72c02bSZachary Turner }
2465a72c02bSZachary Turner 
2475a72c02bSZachary Turner PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject()
2485a72c02bSZachary Turner {
2495a72c02bSZachary Turner     SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
2505a72c02bSZachary Turner }
2515a72c02bSZachary Turner 
2525a72c02bSZachary Turner PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject()
2535a72c02bSZachary Turner {
2545a72c02bSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
2555a72c02bSZachary Turner }
2565a72c02bSZachary Turner 
2575a72c02bSZachary Turner PythonBytes::PythonBytes(const PythonBytes &object) : PythonObject(object)
2585a72c02bSZachary Turner {
2595a72c02bSZachary Turner }
2605a72c02bSZachary Turner 
2615a72c02bSZachary Turner PythonBytes::~PythonBytes()
2625a72c02bSZachary Turner {
2635a72c02bSZachary Turner }
2645a72c02bSZachary Turner 
2655a72c02bSZachary Turner bool
2665a72c02bSZachary Turner PythonBytes::Check(PyObject *py_obj)
2675a72c02bSZachary Turner {
2685a72c02bSZachary Turner     if (!py_obj)
2695a72c02bSZachary Turner         return false;
2705a72c02bSZachary Turner     if (PyBytes_Check(py_obj))
2715a72c02bSZachary Turner         return true;
2725a72c02bSZachary Turner     return false;
2735a72c02bSZachary Turner }
2745a72c02bSZachary Turner 
2755a72c02bSZachary Turner void
2765a72c02bSZachary Turner PythonBytes::Reset(PyRefType type, PyObject *py_obj)
2775a72c02bSZachary Turner {
2785a72c02bSZachary Turner     // Grab the desired reference type so that if we end up rejecting
2795a72c02bSZachary Turner     // `py_obj` it still gets decremented if necessary.
2805a72c02bSZachary Turner     PythonObject result(type, py_obj);
2815a72c02bSZachary Turner 
2825a72c02bSZachary Turner     if (!PythonBytes::Check(py_obj))
2835a72c02bSZachary Turner     {
2845a72c02bSZachary Turner         PythonObject::Reset();
2855a72c02bSZachary Turner         return;
2865a72c02bSZachary Turner     }
2875a72c02bSZachary Turner 
2885a72c02bSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
2895a72c02bSZachary Turner     // back into the virtual implementation.
2905a72c02bSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
2915a72c02bSZachary Turner }
2925a72c02bSZachary Turner 
2935a72c02bSZachary Turner llvm::ArrayRef<uint8_t>
2945a72c02bSZachary Turner PythonBytes::GetBytes() const
2955a72c02bSZachary Turner {
2965a72c02bSZachary Turner     if (!IsValid())
2975a72c02bSZachary Turner         return llvm::ArrayRef<uint8_t>();
2985a72c02bSZachary Turner 
2995a72c02bSZachary Turner     Py_ssize_t size;
3005a72c02bSZachary Turner     char *c;
3015a72c02bSZachary Turner 
3025a72c02bSZachary Turner     PyBytes_AsStringAndSize(m_py_obj, &c, &size);
3035a72c02bSZachary Turner     return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
3045a72c02bSZachary Turner }
3055a72c02bSZachary Turner 
3065a72c02bSZachary Turner size_t
3075a72c02bSZachary Turner PythonBytes::GetSize() const
3085a72c02bSZachary Turner {
3095a72c02bSZachary Turner     if (!IsValid())
3105a72c02bSZachary Turner         return 0;
3115a72c02bSZachary Turner     return PyBytes_Size(m_py_obj);
3125a72c02bSZachary Turner }
3135a72c02bSZachary Turner 
3145a72c02bSZachary Turner void
3155a72c02bSZachary Turner PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes)
3165a72c02bSZachary Turner {
3175a72c02bSZachary Turner     const char *data = reinterpret_cast<const char *>(bytes.data());
3185a72c02bSZachary Turner     PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size());
3195a72c02bSZachary Turner     PythonObject::Reset(PyRefType::Owned, py_bytes);
3205a72c02bSZachary Turner }
3215a72c02bSZachary Turner 
3225a72c02bSZachary Turner StructuredData::StringSP
3235a72c02bSZachary Turner PythonBytes::CreateStructuredString() const
3245a72c02bSZachary Turner {
3255a72c02bSZachary Turner     StructuredData::StringSP result(new StructuredData::String);
3265a72c02bSZachary Turner     Py_ssize_t size;
3275a72c02bSZachary Turner     char *c;
3285a72c02bSZachary Turner     PyBytes_AsStringAndSize(m_py_obj, &c, &size);
3295a72c02bSZachary Turner     result->SetValue(std::string(c, size));
3305a72c02bSZachary Turner     return result;
3315a72c02bSZachary Turner }
3325a72c02bSZachary Turner 
333f9d6d204SZachary Turner PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes) : PythonByteArray(bytes.data(), bytes.size())
334f9d6d204SZachary Turner {
335f9d6d204SZachary Turner }
336f9d6d204SZachary Turner 
337f9d6d204SZachary Turner PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length)
338f9d6d204SZachary Turner {
339f9d6d204SZachary Turner     const char *str = reinterpret_cast<const char *>(bytes);
340f9d6d204SZachary Turner     Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length));
341f9d6d204SZachary Turner }
342f9d6d204SZachary Turner 
343f9d6d204SZachary Turner PythonByteArray::PythonByteArray(PyRefType type, PyObject *o)
344f9d6d204SZachary Turner {
345f9d6d204SZachary Turner     Reset(type, o);
346f9d6d204SZachary Turner }
347f9d6d204SZachary Turner 
348f9d6d204SZachary Turner PythonByteArray::PythonByteArray(const PythonBytes &object) : PythonObject(object)
349f9d6d204SZachary Turner {
350f9d6d204SZachary Turner }
351f9d6d204SZachary Turner 
352f9d6d204SZachary Turner PythonByteArray::~PythonByteArray()
353f9d6d204SZachary Turner {
354f9d6d204SZachary Turner }
355f9d6d204SZachary Turner 
356f9d6d204SZachary Turner bool
357f9d6d204SZachary Turner PythonByteArray::Check(PyObject *py_obj)
358f9d6d204SZachary Turner {
359f9d6d204SZachary Turner     if (!py_obj)
360f9d6d204SZachary Turner         return false;
361f9d6d204SZachary Turner     if (PyByteArray_Check(py_obj))
362f9d6d204SZachary Turner         return true;
363f9d6d204SZachary Turner     return false;
364f9d6d204SZachary Turner }
365f9d6d204SZachary Turner 
366f9d6d204SZachary Turner void
367f9d6d204SZachary Turner PythonByteArray::Reset(PyRefType type, PyObject *py_obj)
368f9d6d204SZachary Turner {
369f9d6d204SZachary Turner     // Grab the desired reference type so that if we end up rejecting
370f9d6d204SZachary Turner     // `py_obj` it still gets decremented if necessary.
371f9d6d204SZachary Turner     PythonObject result(type, py_obj);
372f9d6d204SZachary Turner 
373f9d6d204SZachary Turner     if (!PythonByteArray::Check(py_obj))
374f9d6d204SZachary Turner     {
375f9d6d204SZachary Turner         PythonObject::Reset();
376f9d6d204SZachary Turner         return;
377f9d6d204SZachary Turner     }
378f9d6d204SZachary Turner 
379f9d6d204SZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
380f9d6d204SZachary Turner     // back into the virtual implementation.
381f9d6d204SZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
382f9d6d204SZachary Turner }
383f9d6d204SZachary Turner 
384f9d6d204SZachary Turner llvm::ArrayRef<uint8_t>
385f9d6d204SZachary Turner PythonByteArray::GetBytes() const
386f9d6d204SZachary Turner {
387f9d6d204SZachary Turner     if (!IsValid())
388f9d6d204SZachary Turner         return llvm::ArrayRef<uint8_t>();
389f9d6d204SZachary Turner 
390f9d6d204SZachary Turner     char *c = PyByteArray_AsString(m_py_obj);
391f9d6d204SZachary Turner     size_t size = GetSize();
392f9d6d204SZachary Turner     return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
393f9d6d204SZachary Turner }
394f9d6d204SZachary Turner 
395f9d6d204SZachary Turner size_t
396f9d6d204SZachary Turner PythonByteArray::GetSize() const
397f9d6d204SZachary Turner {
398f9d6d204SZachary Turner     if (!IsValid())
399f9d6d204SZachary Turner         return 0;
400f9d6d204SZachary Turner 
401f9d6d204SZachary Turner     return PyByteArray_Size(m_py_obj);
402f9d6d204SZachary Turner }
403f9d6d204SZachary Turner 
404f9d6d204SZachary Turner StructuredData::StringSP
405f9d6d204SZachary Turner PythonByteArray::CreateStructuredString() const
406f9d6d204SZachary Turner {
407f9d6d204SZachary Turner     StructuredData::StringSP result(new StructuredData::String);
408f9d6d204SZachary Turner     llvm::ArrayRef<uint8_t> bytes = GetBytes();
409f9d6d204SZachary Turner     const char *str = reinterpret_cast<const char *>(bytes.data());
410f9d6d204SZachary Turner     result->SetValue(std::string(str, bytes.size()));
411f9d6d204SZachary Turner     return result;
412f9d6d204SZachary Turner }
413f9d6d204SZachary Turner 
4145a72c02bSZachary Turner //----------------------------------------------------------------------
4155a72c02bSZachary Turner // PythonString
4165a72c02bSZachary Turner //----------------------------------------------------------------------
4172c1f46dcSZachary Turner 
418f8b22f8fSZachary Turner PythonString::PythonString(PyRefType type, PyObject *py_obj)
419f8b22f8fSZachary Turner     : PythonObject()
4202c1f46dcSZachary Turner {
421f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
4222c1f46dcSZachary Turner }
4232c1f46dcSZachary Turner 
424f8b22f8fSZachary Turner PythonString::PythonString(const PythonString &object)
425f8b22f8fSZachary Turner     : PythonObject(object)
4262c1f46dcSZachary Turner {
4272c1f46dcSZachary Turner }
4282c1f46dcSZachary Turner 
42922c8efcdSZachary Turner PythonString::PythonString(llvm::StringRef string)
43022c8efcdSZachary Turner     : PythonObject()
4312c1f46dcSZachary Turner {
43222c8efcdSZachary Turner     SetString(string);
4332c1f46dcSZachary Turner }
4342c1f46dcSZachary Turner 
43522c8efcdSZachary Turner PythonString::PythonString(const char *string)
43622c8efcdSZachary Turner     : PythonObject()
4372c1f46dcSZachary Turner {
43822c8efcdSZachary Turner     SetString(llvm::StringRef(string));
4392c1f46dcSZachary Turner }
4402c1f46dcSZachary Turner 
441f8b22f8fSZachary Turner PythonString::PythonString()
442f8b22f8fSZachary Turner     : PythonObject()
4432c1f46dcSZachary Turner {
4442c1f46dcSZachary Turner }
4452c1f46dcSZachary Turner 
4462c1f46dcSZachary Turner PythonString::~PythonString ()
4472c1f46dcSZachary Turner {
4482c1f46dcSZachary Turner }
4492c1f46dcSZachary Turner 
4502c1f46dcSZachary Turner bool
45122c8efcdSZachary Turner PythonString::Check(PyObject *py_obj)
45222c8efcdSZachary Turner {
45322c8efcdSZachary Turner     if (!py_obj)
45422c8efcdSZachary Turner         return false;
45518426935SZachary Turner 
4567d6d218eSZachary Turner     if (PyUnicode_Check(py_obj))
4577d6d218eSZachary Turner         return true;
4587d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
4597d6d218eSZachary Turner     if (PyString_Check(py_obj))
4607d6d218eSZachary Turner         return true;
46122c8efcdSZachary Turner #endif
4627d6d218eSZachary Turner     return false;
46322c8efcdSZachary Turner }
46422c8efcdSZachary Turner 
465f8b22f8fSZachary Turner void
466f8b22f8fSZachary Turner PythonString::Reset(PyRefType type, PyObject *py_obj)
4672c1f46dcSZachary Turner {
468f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
469f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
470f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
471f8b22f8fSZachary Turner 
47222c8efcdSZachary Turner     if (!PythonString::Check(py_obj))
47322c8efcdSZachary Turner     {
474f8b22f8fSZachary Turner         PythonObject::Reset();
475f8b22f8fSZachary Turner         return;
47622c8efcdSZachary Turner     }
4777d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
4787d6d218eSZachary Turner     // In Python 2, Don't store PyUnicode objects directly, because we need
4797d6d218eSZachary Turner     // access to their underlying character buffers which Python 2 doesn't
4807d6d218eSZachary Turner     // provide.
4817d6d218eSZachary Turner     if (PyUnicode_Check(py_obj))
4827d6d218eSZachary Turner         result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(result.get()));
4837d6d218eSZachary Turner #endif
484f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
485f8b22f8fSZachary Turner     // back into the virtual implementation.
486f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
4872c1f46dcSZachary Turner }
4882c1f46dcSZachary Turner 
4892c1f46dcSZachary Turner llvm::StringRef
4902c1f46dcSZachary Turner PythonString::GetString() const
4912c1f46dcSZachary Turner {
49218426935SZachary Turner     if (!IsValid())
49318426935SZachary Turner         return llvm::StringRef();
49418426935SZachary Turner 
49522c8efcdSZachary Turner     Py_ssize_t size;
49622c8efcdSZachary Turner     char *c;
49718426935SZachary Turner 
49818426935SZachary Turner #if PY_MAJOR_VERSION >= 3
49918426935SZachary Turner     c = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
50018426935SZachary Turner #else
50118426935SZachary Turner     PyString_AsStringAndSize(m_py_obj, &c, &size);
50218426935SZachary Turner #endif
50322c8efcdSZachary Turner     return llvm::StringRef(c, size);
50422c8efcdSZachary Turner }
5052c1f46dcSZachary Turner 
5062c1f46dcSZachary Turner size_t
5072c1f46dcSZachary Turner PythonString::GetSize() const
5082c1f46dcSZachary Turner {
509f8b22f8fSZachary Turner     if (IsValid())
51018426935SZachary Turner     {
51118426935SZachary Turner #if PY_MAJOR_VERSION >= 3
51218426935SZachary Turner         return PyUnicode_GetSize(m_py_obj);
51318426935SZachary Turner #else
51418426935SZachary Turner         return PyString_Size(m_py_obj);
51518426935SZachary Turner #endif
51618426935SZachary Turner     }
5172c1f46dcSZachary Turner     return 0;
5182c1f46dcSZachary Turner }
5192c1f46dcSZachary Turner 
5202c1f46dcSZachary Turner void
5212c1f46dcSZachary Turner PythonString::SetString (llvm::StringRef string)
5222c1f46dcSZachary Turner {
52322c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
52422c8efcdSZachary Turner     PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
52518426935SZachary Turner     PythonObject::Reset(PyRefType::Owned, unicode);
52622c8efcdSZachary Turner #else
52718426935SZachary Turner     PyObject *str = PyString_FromStringAndSize(string.data(), string.size());
52818426935SZachary Turner     PythonObject::Reset(PyRefType::Owned, str);
52922c8efcdSZachary Turner #endif
5302c1f46dcSZachary Turner }
5312c1f46dcSZachary Turner 
5322c1f46dcSZachary Turner StructuredData::StringSP
5332c1f46dcSZachary Turner PythonString::CreateStructuredString() const
5342c1f46dcSZachary Turner {
5352c1f46dcSZachary Turner     StructuredData::StringSP result(new StructuredData::String);
5362c1f46dcSZachary Turner     result->SetValue(GetString());
5372c1f46dcSZachary Turner     return result;
5382c1f46dcSZachary Turner }
5392c1f46dcSZachary Turner 
5402c1f46dcSZachary Turner //----------------------------------------------------------------------
5412c1f46dcSZachary Turner // PythonInteger
5422c1f46dcSZachary Turner //----------------------------------------------------------------------
5432c1f46dcSZachary Turner 
5447d6d218eSZachary Turner PythonInteger::PythonInteger()
5457d6d218eSZachary Turner     : PythonObject()
5467d6d218eSZachary Turner {
5477d6d218eSZachary Turner 
5487d6d218eSZachary Turner }
5497d6d218eSZachary Turner 
550f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
551f8b22f8fSZachary Turner     : PythonObject()
5522c1f46dcSZachary Turner {
553f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
5542c1f46dcSZachary Turner }
5552c1f46dcSZachary Turner 
556f8b22f8fSZachary Turner PythonInteger::PythonInteger(const PythonInteger &object)
557f8b22f8fSZachary Turner     : PythonObject(object)
5582c1f46dcSZachary Turner {
5592c1f46dcSZachary Turner }
5602c1f46dcSZachary Turner 
561f8b22f8fSZachary Turner PythonInteger::PythonInteger(int64_t value)
562f8b22f8fSZachary Turner     : PythonObject()
5632c1f46dcSZachary Turner {
5642c1f46dcSZachary Turner     SetInteger(value);
5652c1f46dcSZachary Turner }
5662c1f46dcSZachary Turner 
5672c1f46dcSZachary Turner 
5682c1f46dcSZachary Turner PythonInteger::~PythonInteger ()
5692c1f46dcSZachary Turner {
5702c1f46dcSZachary Turner }
5712c1f46dcSZachary Turner 
5722c1f46dcSZachary Turner bool
57322c8efcdSZachary Turner PythonInteger::Check(PyObject *py_obj)
5742c1f46dcSZachary Turner {
57522c8efcdSZachary Turner     if (!py_obj)
57622c8efcdSZachary Turner         return false;
57722c8efcdSZachary Turner 
57822c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
57922c8efcdSZachary Turner     // Python 3 does not have PyInt_Check.  There is only one type of
58022c8efcdSZachary Turner     // integral value, long.
58122c8efcdSZachary Turner     return PyLong_Check(py_obj);
58222c8efcdSZachary Turner #else
58322c8efcdSZachary Turner     return PyLong_Check(py_obj) || PyInt_Check(py_obj);
58422c8efcdSZachary Turner #endif
5852c1f46dcSZachary Turner }
5862c1f46dcSZachary Turner 
587f8b22f8fSZachary Turner void
588f8b22f8fSZachary Turner PythonInteger::Reset(PyRefType type, PyObject *py_obj)
58922c8efcdSZachary Turner {
590f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
591f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
592f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
593f8b22f8fSZachary Turner 
59422c8efcdSZachary Turner     if (!PythonInteger::Check(py_obj))
59522c8efcdSZachary Turner     {
596f8b22f8fSZachary Turner         PythonObject::Reset();
597f8b22f8fSZachary Turner         return;
59822c8efcdSZachary Turner     }
59922c8efcdSZachary Turner 
60022c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3
60122c8efcdSZachary Turner     // Always store this as a PyLong, which makes interoperability between
60222c8efcdSZachary Turner     // Python 2.x and Python 3.x easier.  This is only necessary in 2.x,
60322c8efcdSZachary Turner     // since 3.x doesn't even have a PyInt.
60422c8efcdSZachary Turner     if (PyInt_Check(py_obj))
60522c8efcdSZachary Turner     {
606f8b22f8fSZachary Turner         // Since we converted the original object to a different type, the new
607f8b22f8fSZachary Turner         // object is an owned object regardless of the ownership semantics requested
608f8b22f8fSZachary Turner         // by the user.
609f8b22f8fSZachary Turner         result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
61022c8efcdSZachary Turner     }
61122c8efcdSZachary Turner #endif
61222c8efcdSZachary Turner 
613f8b22f8fSZachary Turner     assert(PyLong_Check(result.get()) && "Couldn't get a PyLong from this PyObject");
61422c8efcdSZachary Turner 
615f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
616f8b22f8fSZachary Turner     // back into the virtual implementation.
617f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
6182c1f46dcSZachary Turner }
6192c1f46dcSZachary Turner 
6202c1f46dcSZachary Turner int64_t
6212c1f46dcSZachary Turner PythonInteger::GetInteger() const
6222c1f46dcSZachary Turner {
6232c1f46dcSZachary Turner     if (m_py_obj)
6242c1f46dcSZachary Turner     {
62522c8efcdSZachary Turner         assert(PyLong_Check(m_py_obj) && "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
62622c8efcdSZachary Turner 
627*008ec446SGreg Clayton         int overflow = 0;
628*008ec446SGreg Clayton         int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
629*008ec446SGreg Clayton         if (overflow != 0)
630*008ec446SGreg Clayton         {
631*008ec446SGreg Clayton             // We got an integer that overflows, like 18446744072853913392L
632*008ec446SGreg Clayton             // we can't use PyLong_AsLongLong() as it will return
633*008ec446SGreg Clayton             // 0xffffffffffffffff. If we use the unsigned long long
634*008ec446SGreg Clayton             // it will work as expected.
635*008ec446SGreg Clayton             const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
636*008ec446SGreg Clayton             result = *((int64_t *)&uval);
637*008ec446SGreg Clayton         }
638*008ec446SGreg Clayton         return result;
6392c1f46dcSZachary Turner     }
6402c1f46dcSZachary Turner     return UINT64_MAX;
6412c1f46dcSZachary Turner }
6422c1f46dcSZachary Turner 
6432c1f46dcSZachary Turner void
6442c1f46dcSZachary Turner PythonInteger::SetInteger(int64_t value)
6452c1f46dcSZachary Turner {
646f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
6472c1f46dcSZachary Turner }
6482c1f46dcSZachary Turner 
6492c1f46dcSZachary Turner StructuredData::IntegerSP
6502c1f46dcSZachary Turner PythonInteger::CreateStructuredInteger() const
6512c1f46dcSZachary Turner {
6522c1f46dcSZachary Turner     StructuredData::IntegerSP result(new StructuredData::Integer);
6532c1f46dcSZachary Turner     result->SetValue(GetInteger());
6542c1f46dcSZachary Turner     return result;
6552c1f46dcSZachary Turner }
6562c1f46dcSZachary Turner 
6572c1f46dcSZachary Turner //----------------------------------------------------------------------
6582c1f46dcSZachary Turner // PythonList
6592c1f46dcSZachary Turner //----------------------------------------------------------------------
6602c1f46dcSZachary Turner 
661f8b22f8fSZachary Turner PythonList::PythonList(PyInitialValue value)
662f8b22f8fSZachary Turner     : PythonObject()
6632c1f46dcSZachary Turner {
664f8b22f8fSZachary Turner     if (value == PyInitialValue::Empty)
665f8b22f8fSZachary Turner         Reset(PyRefType::Owned, PyList_New(0));
6662c1f46dcSZachary Turner }
6672c1f46dcSZachary Turner 
66887f47729SZachary Turner PythonList::PythonList(int list_size)
66987f47729SZachary Turner     : PythonObject()
67087f47729SZachary Turner {
67187f47729SZachary Turner     Reset(PyRefType::Owned, PyList_New(list_size));
67287f47729SZachary Turner }
67387f47729SZachary Turner 
674f8b22f8fSZachary Turner PythonList::PythonList(PyRefType type, PyObject *py_obj)
675f8b22f8fSZachary Turner     : PythonObject()
6762c1f46dcSZachary Turner {
677f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
6782c1f46dcSZachary Turner }
6792c1f46dcSZachary Turner 
680f8b22f8fSZachary Turner PythonList::PythonList(const PythonList &list)
681f8b22f8fSZachary Turner     : PythonObject(list)
6822c1f46dcSZachary Turner {
6832c1f46dcSZachary Turner }
6842c1f46dcSZachary Turner 
6852c1f46dcSZachary Turner PythonList::~PythonList ()
6862c1f46dcSZachary Turner {
6872c1f46dcSZachary Turner }
6882c1f46dcSZachary Turner 
6892c1f46dcSZachary Turner bool
69022c8efcdSZachary Turner PythonList::Check(PyObject *py_obj)
69122c8efcdSZachary Turner {
69222c8efcdSZachary Turner     if (!py_obj)
69322c8efcdSZachary Turner         return false;
69422c8efcdSZachary Turner     return PyList_Check(py_obj);
69522c8efcdSZachary Turner }
69622c8efcdSZachary Turner 
697f8b22f8fSZachary Turner void
698f8b22f8fSZachary Turner PythonList::Reset(PyRefType type, PyObject *py_obj)
6992c1f46dcSZachary Turner {
700f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
701f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
702f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
703f8b22f8fSZachary Turner 
70422c8efcdSZachary Turner     if (!PythonList::Check(py_obj))
70522c8efcdSZachary Turner     {
706f8b22f8fSZachary Turner         PythonObject::Reset();
707f8b22f8fSZachary Turner         return;
70822c8efcdSZachary Turner     }
70922c8efcdSZachary Turner 
710f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
711f8b22f8fSZachary Turner     // back into the virtual implementation.
712f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
7132c1f46dcSZachary Turner }
7142c1f46dcSZachary Turner 
7152c1f46dcSZachary Turner uint32_t
7162c1f46dcSZachary Turner PythonList::GetSize() const
7172c1f46dcSZachary Turner {
718f8b22f8fSZachary Turner     if (IsValid())
7192c1f46dcSZachary Turner         return PyList_GET_SIZE(m_py_obj);
7202c1f46dcSZachary Turner     return 0;
7212c1f46dcSZachary Turner }
7222c1f46dcSZachary Turner 
7232c1f46dcSZachary Turner PythonObject
7242c1f46dcSZachary Turner PythonList::GetItemAtIndex(uint32_t index) const
7252c1f46dcSZachary Turner {
726f8b22f8fSZachary Turner     if (IsValid())
727f8b22f8fSZachary Turner         return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
7282c1f46dcSZachary Turner     return PythonObject();
7292c1f46dcSZachary Turner }
7302c1f46dcSZachary Turner 
7312c1f46dcSZachary Turner void
7322c1f46dcSZachary Turner PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object)
7332c1f46dcSZachary Turner {
734f8b22f8fSZachary Turner     if (IsAllocated() && object.IsValid())
735f8b22f8fSZachary Turner     {
736f8b22f8fSZachary Turner         // PyList_SetItem is documented to "steal" a reference, so we need to
737f8b22f8fSZachary Turner         // convert it to an owned reference by incrementing it.
738f8b22f8fSZachary Turner         Py_INCREF(object.get());
7392c1f46dcSZachary Turner         PyList_SetItem(m_py_obj, index, object.get());
7402c1f46dcSZachary Turner     }
741f8b22f8fSZachary Turner }
7422c1f46dcSZachary Turner 
7432c1f46dcSZachary Turner void
7442c1f46dcSZachary Turner PythonList::AppendItem(const PythonObject &object)
7452c1f46dcSZachary Turner {
746f8b22f8fSZachary Turner     if (IsAllocated() && object.IsValid())
747f8b22f8fSZachary Turner     {
748f8b22f8fSZachary Turner         // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
749f8b22f8fSZachary Turner         // here like we do with `PyList_SetItem`.
7502c1f46dcSZachary Turner         PyList_Append(m_py_obj, object.get());
7512c1f46dcSZachary Turner     }
752f8b22f8fSZachary Turner }
7532c1f46dcSZachary Turner 
7542c1f46dcSZachary Turner StructuredData::ArraySP
7552c1f46dcSZachary Turner PythonList::CreateStructuredArray() const
7562c1f46dcSZachary Turner {
7572c1f46dcSZachary Turner     StructuredData::ArraySP result(new StructuredData::Array);
7582c1f46dcSZachary Turner     uint32_t count = GetSize();
7592c1f46dcSZachary Turner     for (uint32_t i = 0; i < count; ++i)
7602c1f46dcSZachary Turner     {
7612c1f46dcSZachary Turner         PythonObject obj = GetItemAtIndex(i);
7622c1f46dcSZachary Turner         result->AddItem(obj.CreateStructuredObject());
7632c1f46dcSZachary Turner     }
7642c1f46dcSZachary Turner     return result;
7652c1f46dcSZachary Turner }
7662c1f46dcSZachary Turner 
7672c1f46dcSZachary Turner //----------------------------------------------------------------------
768a1405147SZachary Turner // PythonTuple
769a1405147SZachary Turner //----------------------------------------------------------------------
770a1405147SZachary Turner 
771a1405147SZachary Turner PythonTuple::PythonTuple(PyInitialValue value)
772a1405147SZachary Turner     : PythonObject()
773a1405147SZachary Turner {
774a1405147SZachary Turner     if (value == PyInitialValue::Empty)
775a1405147SZachary Turner         Reset(PyRefType::Owned, PyTuple_New(0));
776a1405147SZachary Turner }
777a1405147SZachary Turner 
778a1405147SZachary Turner PythonTuple::PythonTuple(int tuple_size)
779a1405147SZachary Turner     : PythonObject()
780a1405147SZachary Turner {
781a1405147SZachary Turner     Reset(PyRefType::Owned, PyTuple_New(tuple_size));
782a1405147SZachary Turner }
783a1405147SZachary Turner 
784a1405147SZachary Turner PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj)
785a1405147SZachary Turner     : PythonObject()
786a1405147SZachary Turner {
787a1405147SZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple
788a1405147SZachary Turner }
789a1405147SZachary Turner 
790a1405147SZachary Turner PythonTuple::PythonTuple(const PythonTuple &tuple)
791a1405147SZachary Turner     : PythonObject(tuple)
792a1405147SZachary Turner {
793a1405147SZachary Turner }
794a1405147SZachary Turner 
795a1405147SZachary Turner PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects)
796a1405147SZachary Turner {
797a1405147SZachary Turner     m_py_obj = PyTuple_New(objects.size());
798a1405147SZachary Turner 
799a1405147SZachary Turner     uint32_t idx = 0;
800a1405147SZachary Turner     for (auto object : objects)
801a1405147SZachary Turner     {
802a1405147SZachary Turner         if (object.IsValid())
803a1405147SZachary Turner             SetItemAtIndex(idx, object);
804a1405147SZachary Turner         idx++;
805a1405147SZachary Turner     }
806a1405147SZachary Turner }
807a1405147SZachary Turner 
808a1405147SZachary Turner PythonTuple::PythonTuple(std::initializer_list<PyObject*> objects)
809a1405147SZachary Turner {
810a1405147SZachary Turner     m_py_obj = PyTuple_New(objects.size());
811a1405147SZachary Turner 
812a1405147SZachary Turner     uint32_t idx = 0;
813a1405147SZachary Turner     for (auto py_object : objects)
814a1405147SZachary Turner     {
815a1405147SZachary Turner         PythonObject object(PyRefType::Borrowed, py_object);
816a1405147SZachary Turner         if (object.IsValid())
817a1405147SZachary Turner             SetItemAtIndex(idx, object);
818a1405147SZachary Turner         idx++;
819a1405147SZachary Turner     }
820a1405147SZachary Turner }
821a1405147SZachary Turner 
822a1405147SZachary Turner PythonTuple::~PythonTuple()
823a1405147SZachary Turner {
824a1405147SZachary Turner }
825a1405147SZachary Turner 
826a1405147SZachary Turner bool
827a1405147SZachary Turner PythonTuple::Check(PyObject *py_obj)
828a1405147SZachary Turner {
829a1405147SZachary Turner     if (!py_obj)
830a1405147SZachary Turner         return false;
831a1405147SZachary Turner     return PyTuple_Check(py_obj);
832a1405147SZachary Turner }
833a1405147SZachary Turner 
834a1405147SZachary Turner void
835a1405147SZachary Turner PythonTuple::Reset(PyRefType type, PyObject *py_obj)
836a1405147SZachary Turner {
837a1405147SZachary Turner     // Grab the desired reference type so that if we end up rejecting
838a1405147SZachary Turner     // `py_obj` it still gets decremented if necessary.
839a1405147SZachary Turner     PythonObject result(type, py_obj);
840a1405147SZachary Turner 
841a1405147SZachary Turner     if (!PythonTuple::Check(py_obj))
842a1405147SZachary Turner     {
843a1405147SZachary Turner         PythonObject::Reset();
844a1405147SZachary Turner         return;
845a1405147SZachary Turner     }
846a1405147SZachary Turner 
847a1405147SZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
848a1405147SZachary Turner     // back into the virtual implementation.
849a1405147SZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
850a1405147SZachary Turner }
851a1405147SZachary Turner 
852a1405147SZachary Turner uint32_t
853a1405147SZachary Turner PythonTuple::GetSize() const
854a1405147SZachary Turner {
855a1405147SZachary Turner     if (IsValid())
856a1405147SZachary Turner         return PyTuple_GET_SIZE(m_py_obj);
857a1405147SZachary Turner     return 0;
858a1405147SZachary Turner }
859a1405147SZachary Turner 
860a1405147SZachary Turner PythonObject
861a1405147SZachary Turner PythonTuple::GetItemAtIndex(uint32_t index) const
862a1405147SZachary Turner {
863a1405147SZachary Turner     if (IsValid())
864a1405147SZachary Turner         return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
865a1405147SZachary Turner     return PythonObject();
866a1405147SZachary Turner }
867a1405147SZachary Turner 
868a1405147SZachary Turner void
869a1405147SZachary Turner PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object)
870a1405147SZachary Turner {
871a1405147SZachary Turner     if (IsAllocated() && object.IsValid())
872a1405147SZachary Turner     {
873a1405147SZachary Turner         // PyTuple_SetItem is documented to "steal" a reference, so we need to
874a1405147SZachary Turner         // convert it to an owned reference by incrementing it.
875a1405147SZachary Turner         Py_INCREF(object.get());
876a1405147SZachary Turner         PyTuple_SetItem(m_py_obj, index, object.get());
877a1405147SZachary Turner     }
878a1405147SZachary Turner }
879a1405147SZachary Turner 
880a1405147SZachary Turner StructuredData::ArraySP
881a1405147SZachary Turner PythonTuple::CreateStructuredArray() const
882a1405147SZachary Turner {
883a1405147SZachary Turner     StructuredData::ArraySP result(new StructuredData::Array);
884a1405147SZachary Turner     uint32_t count = GetSize();
885a1405147SZachary Turner     for (uint32_t i = 0; i < count; ++i)
886a1405147SZachary Turner     {
887a1405147SZachary Turner         PythonObject obj = GetItemAtIndex(i);
888a1405147SZachary Turner         result->AddItem(obj.CreateStructuredObject());
889a1405147SZachary Turner     }
890a1405147SZachary Turner     return result;
891a1405147SZachary Turner }
892a1405147SZachary Turner 
893a1405147SZachary Turner //----------------------------------------------------------------------
8942c1f46dcSZachary Turner // PythonDictionary
8952c1f46dcSZachary Turner //----------------------------------------------------------------------
8962c1f46dcSZachary Turner 
897f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyInitialValue value)
898f8b22f8fSZachary Turner     : PythonObject()
8992c1f46dcSZachary Turner {
900f8b22f8fSZachary Turner     if (value == PyInitialValue::Empty)
901f8b22f8fSZachary Turner         Reset(PyRefType::Owned, PyDict_New());
9022c1f46dcSZachary Turner }
9032c1f46dcSZachary Turner 
904f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
905f8b22f8fSZachary Turner     : PythonObject()
9062c1f46dcSZachary Turner {
907f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
9082c1f46dcSZachary Turner }
9092c1f46dcSZachary Turner 
910f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object)
911f8b22f8fSZachary Turner     : PythonObject(object)
9122c1f46dcSZachary Turner {
9132c1f46dcSZachary Turner }
9142c1f46dcSZachary Turner 
9152c1f46dcSZachary Turner PythonDictionary::~PythonDictionary ()
9162c1f46dcSZachary Turner {
9172c1f46dcSZachary Turner }
9182c1f46dcSZachary Turner 
9192c1f46dcSZachary Turner bool
92022c8efcdSZachary Turner PythonDictionary::Check(PyObject *py_obj)
92122c8efcdSZachary Turner {
92222c8efcdSZachary Turner     if (!py_obj)
92322c8efcdSZachary Turner         return false;
92422c8efcdSZachary Turner 
92522c8efcdSZachary Turner     return PyDict_Check(py_obj);
92622c8efcdSZachary Turner }
92722c8efcdSZachary Turner 
928f8b22f8fSZachary Turner void
929f8b22f8fSZachary Turner PythonDictionary::Reset(PyRefType type, PyObject *py_obj)
9302c1f46dcSZachary Turner {
931f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
932f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
933f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
934f8b22f8fSZachary Turner 
93522c8efcdSZachary Turner     if (!PythonDictionary::Check(py_obj))
93622c8efcdSZachary Turner     {
937f8b22f8fSZachary Turner         PythonObject::Reset();
938f8b22f8fSZachary Turner         return;
93922c8efcdSZachary Turner     }
94022c8efcdSZachary Turner 
941f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
942f8b22f8fSZachary Turner     // back into the virtual implementation.
943f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
9442c1f46dcSZachary Turner }
9452c1f46dcSZachary Turner 
9462c1f46dcSZachary Turner uint32_t
9472c1f46dcSZachary Turner PythonDictionary::GetSize() const
9482c1f46dcSZachary Turner {
949f8b22f8fSZachary Turner     if (IsValid())
9502c1f46dcSZachary Turner         return PyDict_Size(m_py_obj);
9512c1f46dcSZachary Turner     return 0;
9522c1f46dcSZachary Turner }
9532c1f46dcSZachary Turner 
9542c1f46dcSZachary Turner PythonList
9552c1f46dcSZachary Turner PythonDictionary::GetKeys() const
9562c1f46dcSZachary Turner {
957f8b22f8fSZachary Turner     if (IsValid())
958f8b22f8fSZachary Turner         return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
959f8b22f8fSZachary Turner     return PythonList(PyInitialValue::Invalid);
9602c1f46dcSZachary Turner }
9612c1f46dcSZachary Turner 
9622c1f46dcSZachary Turner PythonObject
963f8b22f8fSZachary Turner PythonDictionary::GetItemForKey(const PythonObject &key) const
9642c1f46dcSZachary Turner {
965f8b22f8fSZachary Turner     if (IsAllocated() && key.IsValid())
966f8b22f8fSZachary Turner         return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get()));
9672c1f46dcSZachary Turner     return PythonObject();
9682c1f46dcSZachary Turner }
9692c1f46dcSZachary Turner 
9702c1f46dcSZachary Turner void
971f8b22f8fSZachary Turner PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value)
9722c1f46dcSZachary Turner {
973f8b22f8fSZachary Turner     if (IsAllocated() && key.IsValid() && value.IsValid())
9742c1f46dcSZachary Turner         PyDict_SetItem(m_py_obj, key.get(), value.get());
9752c1f46dcSZachary Turner }
9762c1f46dcSZachary Turner 
9772c1f46dcSZachary Turner StructuredData::DictionarySP
9782c1f46dcSZachary Turner PythonDictionary::CreateStructuredDictionary() const
9792c1f46dcSZachary Turner {
9802c1f46dcSZachary Turner     StructuredData::DictionarySP result(new StructuredData::Dictionary);
9812c1f46dcSZachary Turner     PythonList keys(GetKeys());
9822c1f46dcSZachary Turner     uint32_t num_keys = keys.GetSize();
9832c1f46dcSZachary Turner     for (uint32_t i = 0; i < num_keys; ++i)
9842c1f46dcSZachary Turner     {
9852c1f46dcSZachary Turner         PythonObject key = keys.GetItemAtIndex(i);
9862c1f46dcSZachary Turner         PythonObject value = GetItemForKey(key);
9872c1f46dcSZachary Turner         StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
988f8b22f8fSZachary Turner         result->AddItem(key.Str().GetString(), structured_value);
9892c1f46dcSZachary Turner     }
9902c1f46dcSZachary Turner     return result;
9912c1f46dcSZachary Turner }
9922c1f46dcSZachary Turner 
9937841efbbSZachary Turner PythonModule::PythonModule() : PythonObject()
9947841efbbSZachary Turner {
9957841efbbSZachary Turner }
9967841efbbSZachary Turner 
9977841efbbSZachary Turner PythonModule::PythonModule(PyRefType type, PyObject *py_obj)
9987841efbbSZachary Turner {
9997841efbbSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
10007841efbbSZachary Turner }
10017841efbbSZachary Turner 
10027841efbbSZachary Turner PythonModule::PythonModule(const PythonModule &dict) : PythonObject(dict)
10037841efbbSZachary Turner {
10047841efbbSZachary Turner }
10057841efbbSZachary Turner 
10067841efbbSZachary Turner PythonModule::~PythonModule()
10077841efbbSZachary Turner {
10087841efbbSZachary Turner }
10097841efbbSZachary Turner 
10107841efbbSZachary Turner PythonModule
1011a1405147SZachary Turner PythonModule::BuiltinsModule()
1012a1405147SZachary Turner {
1013a1405147SZachary Turner #if PY_MAJOR_VERSION >= 3
1014a1405147SZachary Turner     return AddModule("builtins");
1015a1405147SZachary Turner #else
1016a1405147SZachary Turner     return AddModule("__builtin__");
1017a1405147SZachary Turner #endif
1018a1405147SZachary Turner }
1019a1405147SZachary Turner 
1020a1405147SZachary Turner PythonModule
10217841efbbSZachary Turner PythonModule::MainModule()
10227841efbbSZachary Turner {
1023a1405147SZachary Turner     return AddModule("__main__");
1024a1405147SZachary Turner }
1025a1405147SZachary Turner 
1026a1405147SZachary Turner PythonModule
1027a1405147SZachary Turner PythonModule::AddModule(llvm::StringRef module)
1028a1405147SZachary Turner {
1029a1405147SZachary Turner     std::string str = module.str();
1030a1405147SZachary Turner     return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
10317841efbbSZachary Turner }
10327841efbbSZachary Turner 
10332419f1d5SZachary Turner 
10342419f1d5SZachary Turner PythonModule
10352419f1d5SZachary Turner PythonModule::ImportModule(llvm::StringRef module)
10362419f1d5SZachary Turner {
10372419f1d5SZachary Turner     std::string str = module.str();
10382419f1d5SZachary Turner     return PythonModule(PyRefType::Owned, PyImport_ImportModule(str.c_str()));
10392419f1d5SZachary Turner }
10402419f1d5SZachary Turner 
10417841efbbSZachary Turner bool
10427841efbbSZachary Turner PythonModule::Check(PyObject *py_obj)
10437841efbbSZachary Turner {
10447841efbbSZachary Turner     if (!py_obj)
10457841efbbSZachary Turner         return false;
10467841efbbSZachary Turner 
10477841efbbSZachary Turner     return PyModule_Check(py_obj);
10487841efbbSZachary Turner }
10497841efbbSZachary Turner 
10507841efbbSZachary Turner void
10517841efbbSZachary Turner PythonModule::Reset(PyRefType type, PyObject *py_obj)
10527841efbbSZachary Turner {
10537841efbbSZachary Turner     // Grab the desired reference type so that if we end up rejecting
10547841efbbSZachary Turner     // `py_obj` it still gets decremented if necessary.
10557841efbbSZachary Turner     PythonObject result(type, py_obj);
10567841efbbSZachary Turner 
10577841efbbSZachary Turner     if (!PythonModule::Check(py_obj))
10587841efbbSZachary Turner     {
10597841efbbSZachary Turner         PythonObject::Reset();
10607841efbbSZachary Turner         return;
10617841efbbSZachary Turner     }
10627841efbbSZachary Turner 
10637841efbbSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
10647841efbbSZachary Turner     // back into the virtual implementation.
10657841efbbSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
10667841efbbSZachary Turner }
10677841efbbSZachary Turner 
10687841efbbSZachary Turner PythonDictionary
10697841efbbSZachary Turner PythonModule::GetDictionary() const
10707841efbbSZachary Turner {
10717841efbbSZachary Turner     return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
10727841efbbSZachary Turner }
10737841efbbSZachary Turner 
1074a1405147SZachary Turner PythonCallable::PythonCallable() : PythonObject()
1075a1405147SZachary Turner {
1076a1405147SZachary Turner }
1077a1405147SZachary Turner 
1078a1405147SZachary Turner PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj)
1079a1405147SZachary Turner {
1080a1405147SZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable
1081a1405147SZachary Turner }
1082a1405147SZachary Turner 
1083a1405147SZachary Turner PythonCallable::PythonCallable(const PythonCallable &callable)
1084a1405147SZachary Turner     : PythonObject(callable)
1085a1405147SZachary Turner {
1086a1405147SZachary Turner }
1087a1405147SZachary Turner 
1088a1405147SZachary Turner PythonCallable::~PythonCallable()
1089a1405147SZachary Turner {
1090a1405147SZachary Turner }
1091a1405147SZachary Turner 
1092a1405147SZachary Turner bool
1093a1405147SZachary Turner PythonCallable::Check(PyObject *py_obj)
1094a1405147SZachary Turner {
1095a1405147SZachary Turner     if (!py_obj)
1096a1405147SZachary Turner         return false;
1097a1405147SZachary Turner 
1098a1405147SZachary Turner     return PyCallable_Check(py_obj);
1099a1405147SZachary Turner }
1100a1405147SZachary Turner 
1101a1405147SZachary Turner void
1102a1405147SZachary Turner PythonCallable::Reset(PyRefType type, PyObject *py_obj)
1103a1405147SZachary Turner {
1104a1405147SZachary Turner     // Grab the desired reference type so that if we end up rejecting
1105a1405147SZachary Turner     // `py_obj` it still gets decremented if necessary.
1106a1405147SZachary Turner     PythonObject result(type, py_obj);
1107a1405147SZachary Turner 
1108a1405147SZachary Turner     if (!PythonCallable::Check(py_obj))
1109a1405147SZachary Turner     {
1110a1405147SZachary Turner         PythonObject::Reset();
1111a1405147SZachary Turner         return;
1112a1405147SZachary Turner     }
1113a1405147SZachary Turner 
1114a1405147SZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
1115a1405147SZachary Turner     // back into the virtual implementation.
1116a1405147SZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
1117a1405147SZachary Turner }
1118a1405147SZachary Turner 
1119a1405147SZachary Turner 
1120b58fb2f4SZachary Turner PythonCallable::ArgInfo
1121b58fb2f4SZachary Turner PythonCallable::GetNumArguments() const
1122a1405147SZachary Turner {
1123a5d6765cSEnrico Granata     ArgInfo result = { 0, false, false, false };
1124a1405147SZachary Turner     if (!IsValid())
1125b58fb2f4SZachary Turner         return result;
1126a1405147SZachary Turner 
1127a1405147SZachary Turner     PyObject *py_func_obj = m_py_obj;
1128a1405147SZachary Turner     if (PyMethod_Check(py_func_obj))
1129a5d6765cSEnrico Granata     {
1130a1405147SZachary Turner         py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
1131a5d6765cSEnrico Granata         PythonObject im_self = GetAttributeValue("im_self");
1132a5d6765cSEnrico Granata         if (im_self.IsValid() && !im_self.IsNone())
1133a5d6765cSEnrico Granata             result.is_bound_method = true;
1134a5d6765cSEnrico Granata     }
1135a5d6765cSEnrico Granata     else
1136a5d6765cSEnrico Granata     {
1137a5d6765cSEnrico Granata         // see if this is a callable object with an __call__ method
1138a5d6765cSEnrico Granata         if (!PyFunction_Check(py_func_obj))
1139a5d6765cSEnrico Granata         {
1140a5d6765cSEnrico Granata             PythonObject __call__ = GetAttributeValue("__call__");
1141a5d6765cSEnrico Granata             if (__call__.IsValid())
1142a5d6765cSEnrico Granata             {
1143a5d6765cSEnrico Granata                 auto __callable__ = __call__.AsType<PythonCallable>();
1144a5d6765cSEnrico Granata                 if (__callable__.IsValid())
1145a5d6765cSEnrico Granata                 {
1146a5d6765cSEnrico Granata                     py_func_obj = PyMethod_GET_FUNCTION(__callable__.get());
1147a5d6765cSEnrico Granata                     PythonObject im_self = GetAttributeValue("im_self");
1148a5d6765cSEnrico Granata                     if (im_self.IsValid() && !im_self.IsNone())
1149a5d6765cSEnrico Granata                         result.is_bound_method = true;
1150a5d6765cSEnrico Granata                 }
1151a5d6765cSEnrico Granata             }
1152a5d6765cSEnrico Granata         }
1153a5d6765cSEnrico Granata     }
1154a1405147SZachary Turner 
1155a1405147SZachary Turner     if (!py_func_obj)
1156b58fb2f4SZachary Turner         return result;
1157a1405147SZachary Turner 
1158a1405147SZachary Turner     PyCodeObject* code = (PyCodeObject*)PyFunction_GET_CODE(py_func_obj);
1159a1405147SZachary Turner     if (!code)
1160b58fb2f4SZachary Turner         return result;
1161a1405147SZachary Turner 
1162b58fb2f4SZachary Turner     result.count = code->co_argcount;
1163b58fb2f4SZachary Turner     result.has_varargs = !!(code->co_flags & CO_VARARGS);
1164b58fb2f4SZachary Turner     result.has_kwargs = !!(code->co_flags & CO_VARKEYWORDS);
1165b58fb2f4SZachary Turner     return result;
1166b58fb2f4SZachary Turner }
1167b58fb2f4SZachary Turner 
1168b58fb2f4SZachary Turner PythonObject
1169b58fb2f4SZachary Turner PythonCallable::operator ()()
1170b58fb2f4SZachary Turner {
1171b58fb2f4SZachary Turner     return PythonObject(PyRefType::Owned,
1172b58fb2f4SZachary Turner         PyObject_CallObject(m_py_obj, nullptr));
1173a1405147SZachary Turner }
1174a1405147SZachary Turner 
1175a1405147SZachary Turner PythonObject
1176a1405147SZachary Turner PythonCallable::operator ()(std::initializer_list<PyObject*> args)
1177a1405147SZachary Turner {
1178a1405147SZachary Turner     PythonTuple arg_tuple(args);
1179a1405147SZachary Turner     return PythonObject(PyRefType::Owned,
1180a1405147SZachary Turner         PyObject_CallObject(m_py_obj, arg_tuple.get()));
1181a1405147SZachary Turner }
1182a1405147SZachary Turner 
1183a1405147SZachary Turner PythonObject
1184a1405147SZachary Turner PythonCallable::operator ()(std::initializer_list<PythonObject> args)
1185a1405147SZachary Turner {
1186a1405147SZachary Turner     PythonTuple arg_tuple(args);
1187a1405147SZachary Turner     return PythonObject(PyRefType::Owned,
1188a1405147SZachary Turner         PyObject_CallObject(m_py_obj, arg_tuple.get()));
1189a1405147SZachary Turner }
1190a1405147SZachary Turner 
119132064024SZachary Turner PythonFile::PythonFile()
119232064024SZachary Turner     : PythonObject()
119332064024SZachary Turner {
119432064024SZachary Turner }
119532064024SZachary Turner 
11969c40264fSZachary Turner PythonFile::PythonFile(File &file, const char *mode)
11979c40264fSZachary Turner {
11989c40264fSZachary Turner     Reset(file, mode);
11999c40264fSZachary Turner }
12009c40264fSZachary Turner 
1201eda01c31SZachary Turner PythonFile::PythonFile(const char *path, const char *mode)
1202eda01c31SZachary Turner {
1203190fadcdSZachary Turner     lldb_private::File file(path, GetOptionsFromMode(mode));
1204eda01c31SZachary Turner     Reset(file, mode);
1205eda01c31SZachary Turner }
1206eda01c31SZachary Turner 
12079c40264fSZachary Turner PythonFile::PythonFile(PyRefType type, PyObject *o)
12089c40264fSZachary Turner {
12099c40264fSZachary Turner     Reset(type, o);
12109c40264fSZachary Turner }
12119c40264fSZachary Turner 
12129c40264fSZachary Turner PythonFile::~PythonFile()
12139c40264fSZachary Turner {
12149c40264fSZachary Turner }
12159c40264fSZachary Turner 
12169c40264fSZachary Turner bool
12179c40264fSZachary Turner PythonFile::Check(PyObject *py_obj)
12189c40264fSZachary Turner {
12199c40264fSZachary Turner #if PY_MAJOR_VERSION < 3
12209c40264fSZachary Turner     return PyFile_Check(py_obj);
12219c40264fSZachary Turner #else
12229c40264fSZachary Turner     // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
12239c40264fSZachary Turner     // first-class object type anymore.  `PyFile_FromFd` is just a thin wrapper
12249c40264fSZachary Turner     // over `io.open()`, which returns some object derived from `io.IOBase`.
12259c40264fSZachary Turner     // As a result, the only way to detect a file in Python 3 is to check whether
12269c40264fSZachary Turner     // it inherits from `io.IOBase`.  Since it is possible for non-files to also
12279c40264fSZachary Turner     // inherit from `io.IOBase`, we additionally verify that it has the `fileno`
12289c40264fSZachary Turner     // attribute, which should guarantee that it is backed by the file system.
12299c40264fSZachary Turner     PythonObject io_module(PyRefType::Owned, PyImport_ImportModule("io"));
12309c40264fSZachary Turner     PythonDictionary io_dict(PyRefType::Borrowed, PyModule_GetDict(io_module.get()));
12319c40264fSZachary Turner     PythonObject io_base_class = io_dict.GetItemForKey(PythonString("IOBase"));
12329c40264fSZachary Turner 
12339c40264fSZachary Turner     PythonObject object_type(PyRefType::Owned, PyObject_Type(py_obj));
12349c40264fSZachary Turner 
12359c40264fSZachary Turner     if (1 != PyObject_IsSubclass(object_type.get(), io_base_class.get()))
12369c40264fSZachary Turner         return false;
12379c40264fSZachary Turner     if (!object_type.HasAttribute("fileno"))
12389c40264fSZachary Turner         return false;
12399c40264fSZachary Turner 
12409c40264fSZachary Turner     return true;
12419c40264fSZachary Turner #endif
12429c40264fSZachary Turner }
12439c40264fSZachary Turner 
12449c40264fSZachary Turner void
12459c40264fSZachary Turner PythonFile::Reset(PyRefType type, PyObject *py_obj)
12469c40264fSZachary Turner {
12479c40264fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
12489c40264fSZachary Turner     // `py_obj` it still gets decremented if necessary.
12499c40264fSZachary Turner     PythonObject result(type, py_obj);
12509c40264fSZachary Turner 
12519c40264fSZachary Turner     if (!PythonFile::Check(py_obj))
12529c40264fSZachary Turner     {
12539c40264fSZachary Turner         PythonObject::Reset();
12549c40264fSZachary Turner         return;
12559c40264fSZachary Turner     }
12569c40264fSZachary Turner 
12579c40264fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack
12589c40264fSZachary Turner     // overflow since it calls back into the virtual implementation.
12599c40264fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
12609c40264fSZachary Turner }
12619c40264fSZachary Turner 
12629c40264fSZachary Turner void
12639c40264fSZachary Turner PythonFile::Reset(File &file, const char *mode)
12649c40264fSZachary Turner {
126532ac147bSZachary Turner     if (!file.IsValid())
126632ac147bSZachary Turner     {
126732ac147bSZachary Turner         Reset();
126832ac147bSZachary Turner         return;
126932ac147bSZachary Turner     }
127032ac147bSZachary Turner 
12719c40264fSZachary Turner     char *cmode = const_cast<char *>(mode);
12729c40264fSZachary Turner #if PY_MAJOR_VERSION >= 3
12739c40264fSZachary Turner     Reset(PyRefType::Owned,
12749c40264fSZachary Turner         PyFile_FromFd(file.GetDescriptor(), nullptr, cmode, -1, nullptr, "ignore", nullptr, 0));
12759c40264fSZachary Turner #else
12769c40264fSZachary Turner     // Read through the Python source, doesn't seem to modify these strings
12779c40264fSZachary Turner     Reset(PyRefType::Owned,
12789c40264fSZachary Turner         PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, nullptr));
12799c40264fSZachary Turner #endif
12809c40264fSZachary Turner }
12819c40264fSZachary Turner 
1282744959b9SEnrico Granata uint32_t
1283744959b9SEnrico Granata PythonFile::GetOptionsFromMode(llvm::StringRef mode)
1284744959b9SEnrico Granata {
1285744959b9SEnrico Granata     if (mode.empty())
1286744959b9SEnrico Granata         return 0;
1287744959b9SEnrico Granata 
1288744959b9SEnrico Granata     return llvm::StringSwitch<uint32_t>(mode.str().c_str())
1289744959b9SEnrico Granata     .Case("r",   File::eOpenOptionRead)
1290744959b9SEnrico Granata     .Case("w",   File::eOpenOptionWrite)
1291c5273d92SStephane Sezer     .Case("a",   File::eOpenOptionWrite|File::eOpenOptionAppend|File::eOpenOptionCanCreate)
1292744959b9SEnrico Granata     .Case("r+",  File::eOpenOptionRead|File::eOpenOptionWrite)
1293744959b9SEnrico Granata     .Case("w+",  File::eOpenOptionRead|File::eOpenOptionWrite|File::eOpenOptionCanCreate|File::eOpenOptionTruncate)
1294c5273d92SStephane Sezer     .Case("a+",  File::eOpenOptionRead|File::eOpenOptionWrite|File::eOpenOptionAppend|File::eOpenOptionCanCreate)
1295744959b9SEnrico Granata     .Default(0);
1296744959b9SEnrico Granata }
1297744959b9SEnrico Granata 
1298eda01c31SZachary Turner bool
1299eda01c31SZachary Turner PythonFile::GetUnderlyingFile(File &file) const
1300eda01c31SZachary Turner {
1301eda01c31SZachary Turner     if (!IsValid())
1302eda01c31SZachary Turner         return false;
1303eda01c31SZachary Turner 
1304eda01c31SZachary Turner     file.Close();
1305eda01c31SZachary Turner     // We don't own the file descriptor returned by this function, make sure the
1306eda01c31SZachary Turner     // File object knows about that.
1307eda01c31SZachary Turner     file.SetDescriptor(PyObject_AsFileDescriptor(m_py_obj), false);
1308744959b9SEnrico Granata     PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>();
1309744959b9SEnrico Granata     file.SetOptions(PythonFile::GetOptionsFromMode(py_mode.GetString()));
1310eda01c31SZachary Turner     return file.IsValid();
1311eda01c31SZachary Turner }
1312eda01c31SZachary Turner 
1313eda01c31SZachary Turner 
13142c1f46dcSZachary Turner #endif
1315