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"
22*190fadcdSZachary Turner #include "lldb/Host/FileSystem.h"
232c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h"
242c1f46dcSZachary Turner 
25*190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h"
26*190fadcdSZachary 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
352c1f46dcSZachary Turner StructuredPythonObject::Dump(Stream &s) 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 
6272c1f46dcSZachary Turner         return PyLong_AsLongLong(m_py_obj);
6282c1f46dcSZachary Turner     }
6292c1f46dcSZachary Turner     return UINT64_MAX;
6302c1f46dcSZachary Turner }
6312c1f46dcSZachary Turner 
6322c1f46dcSZachary Turner void
6332c1f46dcSZachary Turner PythonInteger::SetInteger(int64_t value)
6342c1f46dcSZachary Turner {
635f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
6362c1f46dcSZachary Turner }
6372c1f46dcSZachary Turner 
6382c1f46dcSZachary Turner StructuredData::IntegerSP
6392c1f46dcSZachary Turner PythonInteger::CreateStructuredInteger() const
6402c1f46dcSZachary Turner {
6412c1f46dcSZachary Turner     StructuredData::IntegerSP result(new StructuredData::Integer);
6422c1f46dcSZachary Turner     result->SetValue(GetInteger());
6432c1f46dcSZachary Turner     return result;
6442c1f46dcSZachary Turner }
6452c1f46dcSZachary Turner 
6462c1f46dcSZachary Turner //----------------------------------------------------------------------
6472c1f46dcSZachary Turner // PythonList
6482c1f46dcSZachary Turner //----------------------------------------------------------------------
6492c1f46dcSZachary Turner 
650f8b22f8fSZachary Turner PythonList::PythonList(PyInitialValue value)
651f8b22f8fSZachary Turner     : PythonObject()
6522c1f46dcSZachary Turner {
653f8b22f8fSZachary Turner     if (value == PyInitialValue::Empty)
654f8b22f8fSZachary Turner         Reset(PyRefType::Owned, PyList_New(0));
6552c1f46dcSZachary Turner }
6562c1f46dcSZachary Turner 
65787f47729SZachary Turner PythonList::PythonList(int list_size)
65887f47729SZachary Turner     : PythonObject()
65987f47729SZachary Turner {
66087f47729SZachary Turner     Reset(PyRefType::Owned, PyList_New(list_size));
66187f47729SZachary Turner }
66287f47729SZachary Turner 
663f8b22f8fSZachary Turner PythonList::PythonList(PyRefType type, PyObject *py_obj)
664f8b22f8fSZachary Turner     : PythonObject()
6652c1f46dcSZachary Turner {
666f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
6672c1f46dcSZachary Turner }
6682c1f46dcSZachary Turner 
669f8b22f8fSZachary Turner PythonList::PythonList(const PythonList &list)
670f8b22f8fSZachary Turner     : PythonObject(list)
6712c1f46dcSZachary Turner {
6722c1f46dcSZachary Turner }
6732c1f46dcSZachary Turner 
6742c1f46dcSZachary Turner PythonList::~PythonList ()
6752c1f46dcSZachary Turner {
6762c1f46dcSZachary Turner }
6772c1f46dcSZachary Turner 
6782c1f46dcSZachary Turner bool
67922c8efcdSZachary Turner PythonList::Check(PyObject *py_obj)
68022c8efcdSZachary Turner {
68122c8efcdSZachary Turner     if (!py_obj)
68222c8efcdSZachary Turner         return false;
68322c8efcdSZachary Turner     return PyList_Check(py_obj);
68422c8efcdSZachary Turner }
68522c8efcdSZachary Turner 
686f8b22f8fSZachary Turner void
687f8b22f8fSZachary Turner PythonList::Reset(PyRefType type, PyObject *py_obj)
6882c1f46dcSZachary Turner {
689f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
690f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
691f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
692f8b22f8fSZachary Turner 
69322c8efcdSZachary Turner     if (!PythonList::Check(py_obj))
69422c8efcdSZachary Turner     {
695f8b22f8fSZachary Turner         PythonObject::Reset();
696f8b22f8fSZachary Turner         return;
69722c8efcdSZachary Turner     }
69822c8efcdSZachary Turner 
699f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
700f8b22f8fSZachary Turner     // back into the virtual implementation.
701f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
7022c1f46dcSZachary Turner }
7032c1f46dcSZachary Turner 
7042c1f46dcSZachary Turner uint32_t
7052c1f46dcSZachary Turner PythonList::GetSize() const
7062c1f46dcSZachary Turner {
707f8b22f8fSZachary Turner     if (IsValid())
7082c1f46dcSZachary Turner         return PyList_GET_SIZE(m_py_obj);
7092c1f46dcSZachary Turner     return 0;
7102c1f46dcSZachary Turner }
7112c1f46dcSZachary Turner 
7122c1f46dcSZachary Turner PythonObject
7132c1f46dcSZachary Turner PythonList::GetItemAtIndex(uint32_t index) const
7142c1f46dcSZachary Turner {
715f8b22f8fSZachary Turner     if (IsValid())
716f8b22f8fSZachary Turner         return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
7172c1f46dcSZachary Turner     return PythonObject();
7182c1f46dcSZachary Turner }
7192c1f46dcSZachary Turner 
7202c1f46dcSZachary Turner void
7212c1f46dcSZachary Turner PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object)
7222c1f46dcSZachary Turner {
723f8b22f8fSZachary Turner     if (IsAllocated() && object.IsValid())
724f8b22f8fSZachary Turner     {
725f8b22f8fSZachary Turner         // PyList_SetItem is documented to "steal" a reference, so we need to
726f8b22f8fSZachary Turner         // convert it to an owned reference by incrementing it.
727f8b22f8fSZachary Turner         Py_INCREF(object.get());
7282c1f46dcSZachary Turner         PyList_SetItem(m_py_obj, index, object.get());
7292c1f46dcSZachary Turner     }
730f8b22f8fSZachary Turner }
7312c1f46dcSZachary Turner 
7322c1f46dcSZachary Turner void
7332c1f46dcSZachary Turner PythonList::AppendItem(const PythonObject &object)
7342c1f46dcSZachary Turner {
735f8b22f8fSZachary Turner     if (IsAllocated() && object.IsValid())
736f8b22f8fSZachary Turner     {
737f8b22f8fSZachary Turner         // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
738f8b22f8fSZachary Turner         // here like we do with `PyList_SetItem`.
7392c1f46dcSZachary Turner         PyList_Append(m_py_obj, object.get());
7402c1f46dcSZachary Turner     }
741f8b22f8fSZachary Turner }
7422c1f46dcSZachary Turner 
7432c1f46dcSZachary Turner StructuredData::ArraySP
7442c1f46dcSZachary Turner PythonList::CreateStructuredArray() const
7452c1f46dcSZachary Turner {
7462c1f46dcSZachary Turner     StructuredData::ArraySP result(new StructuredData::Array);
7472c1f46dcSZachary Turner     uint32_t count = GetSize();
7482c1f46dcSZachary Turner     for (uint32_t i = 0; i < count; ++i)
7492c1f46dcSZachary Turner     {
7502c1f46dcSZachary Turner         PythonObject obj = GetItemAtIndex(i);
7512c1f46dcSZachary Turner         result->AddItem(obj.CreateStructuredObject());
7522c1f46dcSZachary Turner     }
7532c1f46dcSZachary Turner     return result;
7542c1f46dcSZachary Turner }
7552c1f46dcSZachary Turner 
7562c1f46dcSZachary Turner //----------------------------------------------------------------------
757a1405147SZachary Turner // PythonTuple
758a1405147SZachary Turner //----------------------------------------------------------------------
759a1405147SZachary Turner 
760a1405147SZachary Turner PythonTuple::PythonTuple(PyInitialValue value)
761a1405147SZachary Turner     : PythonObject()
762a1405147SZachary Turner {
763a1405147SZachary Turner     if (value == PyInitialValue::Empty)
764a1405147SZachary Turner         Reset(PyRefType::Owned, PyTuple_New(0));
765a1405147SZachary Turner }
766a1405147SZachary Turner 
767a1405147SZachary Turner PythonTuple::PythonTuple(int tuple_size)
768a1405147SZachary Turner     : PythonObject()
769a1405147SZachary Turner {
770a1405147SZachary Turner     Reset(PyRefType::Owned, PyTuple_New(tuple_size));
771a1405147SZachary Turner }
772a1405147SZachary Turner 
773a1405147SZachary Turner PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj)
774a1405147SZachary Turner     : PythonObject()
775a1405147SZachary Turner {
776a1405147SZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple
777a1405147SZachary Turner }
778a1405147SZachary Turner 
779a1405147SZachary Turner PythonTuple::PythonTuple(const PythonTuple &tuple)
780a1405147SZachary Turner     : PythonObject(tuple)
781a1405147SZachary Turner {
782a1405147SZachary Turner }
783a1405147SZachary Turner 
784a1405147SZachary Turner PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects)
785a1405147SZachary Turner {
786a1405147SZachary Turner     m_py_obj = PyTuple_New(objects.size());
787a1405147SZachary Turner 
788a1405147SZachary Turner     uint32_t idx = 0;
789a1405147SZachary Turner     for (auto object : objects)
790a1405147SZachary Turner     {
791a1405147SZachary Turner         if (object.IsValid())
792a1405147SZachary Turner             SetItemAtIndex(idx, object);
793a1405147SZachary Turner         idx++;
794a1405147SZachary Turner     }
795a1405147SZachary Turner }
796a1405147SZachary Turner 
797a1405147SZachary Turner PythonTuple::PythonTuple(std::initializer_list<PyObject*> objects)
798a1405147SZachary Turner {
799a1405147SZachary Turner     m_py_obj = PyTuple_New(objects.size());
800a1405147SZachary Turner 
801a1405147SZachary Turner     uint32_t idx = 0;
802a1405147SZachary Turner     for (auto py_object : objects)
803a1405147SZachary Turner     {
804a1405147SZachary Turner         PythonObject object(PyRefType::Borrowed, py_object);
805a1405147SZachary Turner         if (object.IsValid())
806a1405147SZachary Turner             SetItemAtIndex(idx, object);
807a1405147SZachary Turner         idx++;
808a1405147SZachary Turner     }
809a1405147SZachary Turner }
810a1405147SZachary Turner 
811a1405147SZachary Turner PythonTuple::~PythonTuple()
812a1405147SZachary Turner {
813a1405147SZachary Turner }
814a1405147SZachary Turner 
815a1405147SZachary Turner bool
816a1405147SZachary Turner PythonTuple::Check(PyObject *py_obj)
817a1405147SZachary Turner {
818a1405147SZachary Turner     if (!py_obj)
819a1405147SZachary Turner         return false;
820a1405147SZachary Turner     return PyTuple_Check(py_obj);
821a1405147SZachary Turner }
822a1405147SZachary Turner 
823a1405147SZachary Turner void
824a1405147SZachary Turner PythonTuple::Reset(PyRefType type, PyObject *py_obj)
825a1405147SZachary Turner {
826a1405147SZachary Turner     // Grab the desired reference type so that if we end up rejecting
827a1405147SZachary Turner     // `py_obj` it still gets decremented if necessary.
828a1405147SZachary Turner     PythonObject result(type, py_obj);
829a1405147SZachary Turner 
830a1405147SZachary Turner     if (!PythonTuple::Check(py_obj))
831a1405147SZachary Turner     {
832a1405147SZachary Turner         PythonObject::Reset();
833a1405147SZachary Turner         return;
834a1405147SZachary Turner     }
835a1405147SZachary Turner 
836a1405147SZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
837a1405147SZachary Turner     // back into the virtual implementation.
838a1405147SZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
839a1405147SZachary Turner }
840a1405147SZachary Turner 
841a1405147SZachary Turner uint32_t
842a1405147SZachary Turner PythonTuple::GetSize() const
843a1405147SZachary Turner {
844a1405147SZachary Turner     if (IsValid())
845a1405147SZachary Turner         return PyTuple_GET_SIZE(m_py_obj);
846a1405147SZachary Turner     return 0;
847a1405147SZachary Turner }
848a1405147SZachary Turner 
849a1405147SZachary Turner PythonObject
850a1405147SZachary Turner PythonTuple::GetItemAtIndex(uint32_t index) const
851a1405147SZachary Turner {
852a1405147SZachary Turner     if (IsValid())
853a1405147SZachary Turner         return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
854a1405147SZachary Turner     return PythonObject();
855a1405147SZachary Turner }
856a1405147SZachary Turner 
857a1405147SZachary Turner void
858a1405147SZachary Turner PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object)
859a1405147SZachary Turner {
860a1405147SZachary Turner     if (IsAllocated() && object.IsValid())
861a1405147SZachary Turner     {
862a1405147SZachary Turner         // PyTuple_SetItem is documented to "steal" a reference, so we need to
863a1405147SZachary Turner         // convert it to an owned reference by incrementing it.
864a1405147SZachary Turner         Py_INCREF(object.get());
865a1405147SZachary Turner         PyTuple_SetItem(m_py_obj, index, object.get());
866a1405147SZachary Turner     }
867a1405147SZachary Turner }
868a1405147SZachary Turner 
869a1405147SZachary Turner StructuredData::ArraySP
870a1405147SZachary Turner PythonTuple::CreateStructuredArray() const
871a1405147SZachary Turner {
872a1405147SZachary Turner     StructuredData::ArraySP result(new StructuredData::Array);
873a1405147SZachary Turner     uint32_t count = GetSize();
874a1405147SZachary Turner     for (uint32_t i = 0; i < count; ++i)
875a1405147SZachary Turner     {
876a1405147SZachary Turner         PythonObject obj = GetItemAtIndex(i);
877a1405147SZachary Turner         result->AddItem(obj.CreateStructuredObject());
878a1405147SZachary Turner     }
879a1405147SZachary Turner     return result;
880a1405147SZachary Turner }
881a1405147SZachary Turner 
882a1405147SZachary Turner //----------------------------------------------------------------------
8832c1f46dcSZachary Turner // PythonDictionary
8842c1f46dcSZachary Turner //----------------------------------------------------------------------
8852c1f46dcSZachary Turner 
886f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyInitialValue value)
887f8b22f8fSZachary Turner     : PythonObject()
8882c1f46dcSZachary Turner {
889f8b22f8fSZachary Turner     if (value == PyInitialValue::Empty)
890f8b22f8fSZachary Turner         Reset(PyRefType::Owned, PyDict_New());
8912c1f46dcSZachary Turner }
8922c1f46dcSZachary Turner 
893f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
894f8b22f8fSZachary Turner     : PythonObject()
8952c1f46dcSZachary Turner {
896f8b22f8fSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
8972c1f46dcSZachary Turner }
8982c1f46dcSZachary Turner 
899f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object)
900f8b22f8fSZachary Turner     : PythonObject(object)
9012c1f46dcSZachary Turner {
9022c1f46dcSZachary Turner }
9032c1f46dcSZachary Turner 
9042c1f46dcSZachary Turner PythonDictionary::~PythonDictionary ()
9052c1f46dcSZachary Turner {
9062c1f46dcSZachary Turner }
9072c1f46dcSZachary Turner 
9082c1f46dcSZachary Turner bool
90922c8efcdSZachary Turner PythonDictionary::Check(PyObject *py_obj)
91022c8efcdSZachary Turner {
91122c8efcdSZachary Turner     if (!py_obj)
91222c8efcdSZachary Turner         return false;
91322c8efcdSZachary Turner 
91422c8efcdSZachary Turner     return PyDict_Check(py_obj);
91522c8efcdSZachary Turner }
91622c8efcdSZachary Turner 
917f8b22f8fSZachary Turner void
918f8b22f8fSZachary Turner PythonDictionary::Reset(PyRefType type, PyObject *py_obj)
9192c1f46dcSZachary Turner {
920f8b22f8fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
921f8b22f8fSZachary Turner     // `py_obj` it still gets decremented if necessary.
922f8b22f8fSZachary Turner     PythonObject result(type, py_obj);
923f8b22f8fSZachary Turner 
92422c8efcdSZachary Turner     if (!PythonDictionary::Check(py_obj))
92522c8efcdSZachary Turner     {
926f8b22f8fSZachary Turner         PythonObject::Reset();
927f8b22f8fSZachary Turner         return;
92822c8efcdSZachary Turner     }
92922c8efcdSZachary Turner 
930f8b22f8fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
931f8b22f8fSZachary Turner     // back into the virtual implementation.
932f8b22f8fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
9332c1f46dcSZachary Turner }
9342c1f46dcSZachary Turner 
9352c1f46dcSZachary Turner uint32_t
9362c1f46dcSZachary Turner PythonDictionary::GetSize() const
9372c1f46dcSZachary Turner {
938f8b22f8fSZachary Turner     if (IsValid())
9392c1f46dcSZachary Turner         return PyDict_Size(m_py_obj);
9402c1f46dcSZachary Turner     return 0;
9412c1f46dcSZachary Turner }
9422c1f46dcSZachary Turner 
9432c1f46dcSZachary Turner PythonList
9442c1f46dcSZachary Turner PythonDictionary::GetKeys() const
9452c1f46dcSZachary Turner {
946f8b22f8fSZachary Turner     if (IsValid())
947f8b22f8fSZachary Turner         return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
948f8b22f8fSZachary Turner     return PythonList(PyInitialValue::Invalid);
9492c1f46dcSZachary Turner }
9502c1f46dcSZachary Turner 
9512c1f46dcSZachary Turner PythonObject
952f8b22f8fSZachary Turner PythonDictionary::GetItemForKey(const PythonObject &key) const
9532c1f46dcSZachary Turner {
954f8b22f8fSZachary Turner     if (IsAllocated() && key.IsValid())
955f8b22f8fSZachary Turner         return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get()));
9562c1f46dcSZachary Turner     return PythonObject();
9572c1f46dcSZachary Turner }
9582c1f46dcSZachary Turner 
9592c1f46dcSZachary Turner void
960f8b22f8fSZachary Turner PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value)
9612c1f46dcSZachary Turner {
962f8b22f8fSZachary Turner     if (IsAllocated() && key.IsValid() && value.IsValid())
9632c1f46dcSZachary Turner         PyDict_SetItem(m_py_obj, key.get(), value.get());
9642c1f46dcSZachary Turner }
9652c1f46dcSZachary Turner 
9662c1f46dcSZachary Turner StructuredData::DictionarySP
9672c1f46dcSZachary Turner PythonDictionary::CreateStructuredDictionary() const
9682c1f46dcSZachary Turner {
9692c1f46dcSZachary Turner     StructuredData::DictionarySP result(new StructuredData::Dictionary);
9702c1f46dcSZachary Turner     PythonList keys(GetKeys());
9712c1f46dcSZachary Turner     uint32_t num_keys = keys.GetSize();
9722c1f46dcSZachary Turner     for (uint32_t i = 0; i < num_keys; ++i)
9732c1f46dcSZachary Turner     {
9742c1f46dcSZachary Turner         PythonObject key = keys.GetItemAtIndex(i);
9752c1f46dcSZachary Turner         PythonObject value = GetItemForKey(key);
9762c1f46dcSZachary Turner         StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
977f8b22f8fSZachary Turner         result->AddItem(key.Str().GetString(), structured_value);
9782c1f46dcSZachary Turner     }
9792c1f46dcSZachary Turner     return result;
9802c1f46dcSZachary Turner }
9812c1f46dcSZachary Turner 
9827841efbbSZachary Turner PythonModule::PythonModule() : PythonObject()
9837841efbbSZachary Turner {
9847841efbbSZachary Turner }
9857841efbbSZachary Turner 
9867841efbbSZachary Turner PythonModule::PythonModule(PyRefType type, PyObject *py_obj)
9877841efbbSZachary Turner {
9887841efbbSZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
9897841efbbSZachary Turner }
9907841efbbSZachary Turner 
9917841efbbSZachary Turner PythonModule::PythonModule(const PythonModule &dict) : PythonObject(dict)
9927841efbbSZachary Turner {
9937841efbbSZachary Turner }
9947841efbbSZachary Turner 
9957841efbbSZachary Turner PythonModule::~PythonModule()
9967841efbbSZachary Turner {
9977841efbbSZachary Turner }
9987841efbbSZachary Turner 
9997841efbbSZachary Turner PythonModule
1000a1405147SZachary Turner PythonModule::BuiltinsModule()
1001a1405147SZachary Turner {
1002a1405147SZachary Turner #if PY_MAJOR_VERSION >= 3
1003a1405147SZachary Turner     return AddModule("builtins");
1004a1405147SZachary Turner #else
1005a1405147SZachary Turner     return AddModule("__builtin__");
1006a1405147SZachary Turner #endif
1007a1405147SZachary Turner }
1008a1405147SZachary Turner 
1009a1405147SZachary Turner PythonModule
10107841efbbSZachary Turner PythonModule::MainModule()
10117841efbbSZachary Turner {
1012a1405147SZachary Turner     return AddModule("__main__");
1013a1405147SZachary Turner }
1014a1405147SZachary Turner 
1015a1405147SZachary Turner PythonModule
1016a1405147SZachary Turner PythonModule::AddModule(llvm::StringRef module)
1017a1405147SZachary Turner {
1018a1405147SZachary Turner     std::string str = module.str();
1019a1405147SZachary Turner     return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
10207841efbbSZachary Turner }
10217841efbbSZachary Turner 
10222419f1d5SZachary Turner 
10232419f1d5SZachary Turner PythonModule
10242419f1d5SZachary Turner PythonModule::ImportModule(llvm::StringRef module)
10252419f1d5SZachary Turner {
10262419f1d5SZachary Turner     std::string str = module.str();
10272419f1d5SZachary Turner     return PythonModule(PyRefType::Owned, PyImport_ImportModule(str.c_str()));
10282419f1d5SZachary Turner }
10292419f1d5SZachary Turner 
10307841efbbSZachary Turner bool
10317841efbbSZachary Turner PythonModule::Check(PyObject *py_obj)
10327841efbbSZachary Turner {
10337841efbbSZachary Turner     if (!py_obj)
10347841efbbSZachary Turner         return false;
10357841efbbSZachary Turner 
10367841efbbSZachary Turner     return PyModule_Check(py_obj);
10377841efbbSZachary Turner }
10387841efbbSZachary Turner 
10397841efbbSZachary Turner void
10407841efbbSZachary Turner PythonModule::Reset(PyRefType type, PyObject *py_obj)
10417841efbbSZachary Turner {
10427841efbbSZachary Turner     // Grab the desired reference type so that if we end up rejecting
10437841efbbSZachary Turner     // `py_obj` it still gets decremented if necessary.
10447841efbbSZachary Turner     PythonObject result(type, py_obj);
10457841efbbSZachary Turner 
10467841efbbSZachary Turner     if (!PythonModule::Check(py_obj))
10477841efbbSZachary Turner     {
10487841efbbSZachary Turner         PythonObject::Reset();
10497841efbbSZachary Turner         return;
10507841efbbSZachary Turner     }
10517841efbbSZachary Turner 
10527841efbbSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
10537841efbbSZachary Turner     // back into the virtual implementation.
10547841efbbSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
10557841efbbSZachary Turner }
10567841efbbSZachary Turner 
10577841efbbSZachary Turner PythonDictionary
10587841efbbSZachary Turner PythonModule::GetDictionary() const
10597841efbbSZachary Turner {
10607841efbbSZachary Turner     return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
10617841efbbSZachary Turner }
10627841efbbSZachary Turner 
1063a1405147SZachary Turner PythonCallable::PythonCallable() : PythonObject()
1064a1405147SZachary Turner {
1065a1405147SZachary Turner }
1066a1405147SZachary Turner 
1067a1405147SZachary Turner PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj)
1068a1405147SZachary Turner {
1069a1405147SZachary Turner     Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable
1070a1405147SZachary Turner }
1071a1405147SZachary Turner 
1072a1405147SZachary Turner PythonCallable::PythonCallable(const PythonCallable &callable)
1073a1405147SZachary Turner     : PythonObject(callable)
1074a1405147SZachary Turner {
1075a1405147SZachary Turner }
1076a1405147SZachary Turner 
1077a1405147SZachary Turner PythonCallable::~PythonCallable()
1078a1405147SZachary Turner {
1079a1405147SZachary Turner }
1080a1405147SZachary Turner 
1081a1405147SZachary Turner bool
1082a1405147SZachary Turner PythonCallable::Check(PyObject *py_obj)
1083a1405147SZachary Turner {
1084a1405147SZachary Turner     if (!py_obj)
1085a1405147SZachary Turner         return false;
1086a1405147SZachary Turner 
1087a1405147SZachary Turner     return PyCallable_Check(py_obj);
1088a1405147SZachary Turner }
1089a1405147SZachary Turner 
1090a1405147SZachary Turner void
1091a1405147SZachary Turner PythonCallable::Reset(PyRefType type, PyObject *py_obj)
1092a1405147SZachary Turner {
1093a1405147SZachary Turner     // Grab the desired reference type so that if we end up rejecting
1094a1405147SZachary Turner     // `py_obj` it still gets decremented if necessary.
1095a1405147SZachary Turner     PythonObject result(type, py_obj);
1096a1405147SZachary Turner 
1097a1405147SZachary Turner     if (!PythonCallable::Check(py_obj))
1098a1405147SZachary Turner     {
1099a1405147SZachary Turner         PythonObject::Reset();
1100a1405147SZachary Turner         return;
1101a1405147SZachary Turner     }
1102a1405147SZachary Turner 
1103a1405147SZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
1104a1405147SZachary Turner     // back into the virtual implementation.
1105a1405147SZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
1106a1405147SZachary Turner }
1107a1405147SZachary Turner 
1108a1405147SZachary Turner 
1109b58fb2f4SZachary Turner PythonCallable::ArgInfo
1110b58fb2f4SZachary Turner PythonCallable::GetNumArguments() const
1111a1405147SZachary Turner {
1112b58fb2f4SZachary Turner     ArgInfo result = { 0, false, false };
1113a1405147SZachary Turner     if (!IsValid())
1114b58fb2f4SZachary Turner         return result;
1115a1405147SZachary Turner 
1116a1405147SZachary Turner     PyObject *py_func_obj = m_py_obj;
1117a1405147SZachary Turner     if (PyMethod_Check(py_func_obj))
1118a1405147SZachary Turner         py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
1119a1405147SZachary Turner 
1120a1405147SZachary Turner     if (!py_func_obj)
1121b58fb2f4SZachary Turner         return result;
1122a1405147SZachary Turner 
1123a1405147SZachary Turner     PyCodeObject* code = (PyCodeObject*)PyFunction_GET_CODE(py_func_obj);
1124a1405147SZachary Turner     if (!code)
1125b58fb2f4SZachary Turner         return result;
1126a1405147SZachary Turner 
1127b58fb2f4SZachary Turner     result.count = code->co_argcount;
1128b58fb2f4SZachary Turner     result.has_varargs = !!(code->co_flags & CO_VARARGS);
1129b58fb2f4SZachary Turner     result.has_kwargs = !!(code->co_flags & CO_VARKEYWORDS);
1130b58fb2f4SZachary Turner     return result;
1131b58fb2f4SZachary Turner }
1132b58fb2f4SZachary Turner 
1133b58fb2f4SZachary Turner PythonObject
1134b58fb2f4SZachary Turner PythonCallable::operator ()()
1135b58fb2f4SZachary Turner {
1136b58fb2f4SZachary Turner     return PythonObject(PyRefType::Owned,
1137b58fb2f4SZachary Turner         PyObject_CallObject(m_py_obj, nullptr));
1138a1405147SZachary Turner }
1139a1405147SZachary Turner 
1140a1405147SZachary Turner PythonObject
1141a1405147SZachary Turner PythonCallable::operator ()(std::initializer_list<PyObject*> args)
1142a1405147SZachary Turner {
1143a1405147SZachary Turner     PythonTuple arg_tuple(args);
1144a1405147SZachary Turner     return PythonObject(PyRefType::Owned,
1145a1405147SZachary Turner         PyObject_CallObject(m_py_obj, arg_tuple.get()));
1146a1405147SZachary Turner }
1147a1405147SZachary Turner 
1148a1405147SZachary Turner PythonObject
1149a1405147SZachary Turner PythonCallable::operator ()(std::initializer_list<PythonObject> args)
1150a1405147SZachary Turner {
1151a1405147SZachary Turner     PythonTuple arg_tuple(args);
1152a1405147SZachary Turner     return PythonObject(PyRefType::Owned,
1153a1405147SZachary Turner         PyObject_CallObject(m_py_obj, arg_tuple.get()));
1154a1405147SZachary Turner }
1155a1405147SZachary Turner 
115632064024SZachary Turner PythonFile::PythonFile()
115732064024SZachary Turner     : PythonObject()
115832064024SZachary Turner {
115932064024SZachary Turner }
116032064024SZachary Turner 
11619c40264fSZachary Turner PythonFile::PythonFile(File &file, const char *mode)
11629c40264fSZachary Turner {
11639c40264fSZachary Turner     Reset(file, mode);
11649c40264fSZachary Turner }
11659c40264fSZachary Turner 
1166eda01c31SZachary Turner PythonFile::PythonFile(const char *path, const char *mode)
1167eda01c31SZachary Turner {
1168*190fadcdSZachary Turner     lldb_private::File file(path, GetOptionsFromMode(mode));
1169eda01c31SZachary Turner     Reset(file, mode);
1170eda01c31SZachary Turner }
1171eda01c31SZachary Turner 
11729c40264fSZachary Turner PythonFile::PythonFile(PyRefType type, PyObject *o)
11739c40264fSZachary Turner {
11749c40264fSZachary Turner     Reset(type, o);
11759c40264fSZachary Turner }
11769c40264fSZachary Turner 
11779c40264fSZachary Turner PythonFile::~PythonFile()
11789c40264fSZachary Turner {
11799c40264fSZachary Turner }
11809c40264fSZachary Turner 
11819c40264fSZachary Turner bool
11829c40264fSZachary Turner PythonFile::Check(PyObject *py_obj)
11839c40264fSZachary Turner {
11849c40264fSZachary Turner #if PY_MAJOR_VERSION < 3
11859c40264fSZachary Turner     return PyFile_Check(py_obj);
11869c40264fSZachary Turner #else
11879c40264fSZachary Turner     // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
11889c40264fSZachary Turner     // first-class object type anymore.  `PyFile_FromFd` is just a thin wrapper
11899c40264fSZachary Turner     // over `io.open()`, which returns some object derived from `io.IOBase`.
11909c40264fSZachary Turner     // As a result, the only way to detect a file in Python 3 is to check whether
11919c40264fSZachary Turner     // it inherits from `io.IOBase`.  Since it is possible for non-files to also
11929c40264fSZachary Turner     // inherit from `io.IOBase`, we additionally verify that it has the `fileno`
11939c40264fSZachary Turner     // attribute, which should guarantee that it is backed by the file system.
11949c40264fSZachary Turner     PythonObject io_module(PyRefType::Owned, PyImport_ImportModule("io"));
11959c40264fSZachary Turner     PythonDictionary io_dict(PyRefType::Borrowed, PyModule_GetDict(io_module.get()));
11969c40264fSZachary Turner     PythonObject io_base_class = io_dict.GetItemForKey(PythonString("IOBase"));
11979c40264fSZachary Turner 
11989c40264fSZachary Turner     PythonObject object_type(PyRefType::Owned, PyObject_Type(py_obj));
11999c40264fSZachary Turner 
12009c40264fSZachary Turner     if (1 != PyObject_IsSubclass(object_type.get(), io_base_class.get()))
12019c40264fSZachary Turner         return false;
12029c40264fSZachary Turner     if (!object_type.HasAttribute("fileno"))
12039c40264fSZachary Turner         return false;
12049c40264fSZachary Turner 
12059c40264fSZachary Turner     return true;
12069c40264fSZachary Turner #endif
12079c40264fSZachary Turner }
12089c40264fSZachary Turner 
12099c40264fSZachary Turner void
12109c40264fSZachary Turner PythonFile::Reset(PyRefType type, PyObject *py_obj)
12119c40264fSZachary Turner {
12129c40264fSZachary Turner     // Grab the desired reference type so that if we end up rejecting
12139c40264fSZachary Turner     // `py_obj` it still gets decremented if necessary.
12149c40264fSZachary Turner     PythonObject result(type, py_obj);
12159c40264fSZachary Turner 
12169c40264fSZachary Turner     if (!PythonFile::Check(py_obj))
12179c40264fSZachary Turner     {
12189c40264fSZachary Turner         PythonObject::Reset();
12199c40264fSZachary Turner         return;
12209c40264fSZachary Turner     }
12219c40264fSZachary Turner 
12229c40264fSZachary Turner     // Calling PythonObject::Reset(const PythonObject&) will lead to stack
12239c40264fSZachary Turner     // overflow since it calls back into the virtual implementation.
12249c40264fSZachary Turner     PythonObject::Reset(PyRefType::Borrowed, result.get());
12259c40264fSZachary Turner }
12269c40264fSZachary Turner 
12279c40264fSZachary Turner void
12289c40264fSZachary Turner PythonFile::Reset(File &file, const char *mode)
12299c40264fSZachary Turner {
123032ac147bSZachary Turner     if (!file.IsValid())
123132ac147bSZachary Turner     {
123232ac147bSZachary Turner         Reset();
123332ac147bSZachary Turner         return;
123432ac147bSZachary Turner     }
123532ac147bSZachary Turner 
12369c40264fSZachary Turner     char *cmode = const_cast<char *>(mode);
12379c40264fSZachary Turner #if PY_MAJOR_VERSION >= 3
12389c40264fSZachary Turner     Reset(PyRefType::Owned,
12399c40264fSZachary Turner         PyFile_FromFd(file.GetDescriptor(), nullptr, cmode, -1, nullptr, "ignore", nullptr, 0));
12409c40264fSZachary Turner #else
12419c40264fSZachary Turner     // Read through the Python source, doesn't seem to modify these strings
12429c40264fSZachary Turner     Reset(PyRefType::Owned,
12439c40264fSZachary Turner         PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, nullptr));
12449c40264fSZachary Turner #endif
12459c40264fSZachary Turner }
12469c40264fSZachary Turner 
1247744959b9SEnrico Granata uint32_t
1248744959b9SEnrico Granata PythonFile::GetOptionsFromMode(llvm::StringRef mode)
1249744959b9SEnrico Granata {
1250744959b9SEnrico Granata     if (mode.empty())
1251744959b9SEnrico Granata         return 0;
1252744959b9SEnrico Granata 
1253744959b9SEnrico Granata     return llvm::StringSwitch<uint32_t>(mode.str().c_str())
1254744959b9SEnrico Granata     .Case("r",   File::eOpenOptionRead)
1255744959b9SEnrico Granata     .Case("w",   File::eOpenOptionWrite)
1256744959b9SEnrico Granata     .Case("a",   File::eOpenOptionAppend|File::eOpenOptionCanCreate)
1257744959b9SEnrico Granata     .Case("r+",  File::eOpenOptionRead|File::eOpenOptionWrite)
1258744959b9SEnrico Granata     .Case("w+",  File::eOpenOptionRead|File::eOpenOptionWrite|File::eOpenOptionCanCreate|File::eOpenOptionTruncate)
1259744959b9SEnrico Granata     .Case("a+",  File::eOpenOptionRead|File::eOpenOptionWrite|File::eOpenOptionCanCreate)
1260744959b9SEnrico Granata     .Default(0);
1261744959b9SEnrico Granata }
1262744959b9SEnrico Granata 
1263eda01c31SZachary Turner bool
1264eda01c31SZachary Turner PythonFile::GetUnderlyingFile(File &file) const
1265eda01c31SZachary Turner {
1266eda01c31SZachary Turner     if (!IsValid())
1267eda01c31SZachary Turner         return false;
1268eda01c31SZachary Turner 
1269eda01c31SZachary Turner     file.Close();
1270eda01c31SZachary Turner     // We don't own the file descriptor returned by this function, make sure the
1271eda01c31SZachary Turner     // File object knows about that.
1272eda01c31SZachary Turner     file.SetDescriptor(PyObject_AsFileDescriptor(m_py_obj), false);
1273744959b9SEnrico Granata     PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>();
1274744959b9SEnrico Granata     file.SetOptions(PythonFile::GetOptionsFromMode(py_mode.GetString()));
1275eda01c31SZachary Turner     return file.IsValid();
1276eda01c31SZachary Turner }
1277eda01c31SZachary Turner 
1278eda01c31SZachary Turner 
12792c1f46dcSZachary Turner #endif
1280