1b9c1b51eSKate Stone //===-- PythonDataObjects.cpp ------------------------------------*- C++
2b9c1b51eSKate Stone //-*-===//
32c1f46dcSZachary Turner //
42c1f46dcSZachary Turner //                     The LLVM Compiler Infrastructure
52c1f46dcSZachary Turner //
62c1f46dcSZachary Turner // This file is distributed under the University of Illinois Open Source
72c1f46dcSZachary Turner // License. See LICENSE.TXT for details.
82c1f46dcSZachary Turner //
92c1f46dcSZachary Turner //===----------------------------------------------------------------------===//
102c1f46dcSZachary Turner 
112c1f46dcSZachary Turner #ifdef LLDB_DISABLE_PYTHON
122c1f46dcSZachary Turner 
132c1f46dcSZachary Turner // Python is disabled in this build
142c1f46dcSZachary Turner 
152c1f46dcSZachary Turner #else
162c1f46dcSZachary Turner 
172c1f46dcSZachary Turner #include "PythonDataObjects.h"
182c1f46dcSZachary Turner #include "ScriptInterpreterPython.h"
192c1f46dcSZachary Turner 
202c1f46dcSZachary Turner #include "lldb/Host/File.h"
21190fadcdSZachary Turner #include "lldb/Host/FileSystem.h"
222c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h"
23*bf9a7730SZachary Turner #include "lldb/Utility/Stream.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 
34b9c1b51eSKate Stone void StructuredPythonObject::Dump(Stream &s, bool pretty_print) const {
352c1f46dcSZachary Turner   s << "Python Obj: 0x" << GetValue();
362c1f46dcSZachary Turner }
372c1f46dcSZachary Turner 
382c1f46dcSZachary Turner //----------------------------------------------------------------------
392c1f46dcSZachary Turner // PythonObject
402c1f46dcSZachary Turner //----------------------------------------------------------------------
412c1f46dcSZachary Turner 
42b9c1b51eSKate Stone void PythonObject::Dump(Stream &strm) const {
43b9c1b51eSKate Stone   if (m_py_obj) {
442c1f46dcSZachary Turner     FILE *file = ::tmpfile();
45b9c1b51eSKate Stone     if (file) {
462c1f46dcSZachary Turner       ::PyObject_Print(m_py_obj, file, 0);
472c1f46dcSZachary Turner       const long length = ftell(file);
48b9c1b51eSKate Stone       if (length) {
492c1f46dcSZachary Turner         ::rewind(file);
502c1f46dcSZachary Turner         std::vector<char> file_contents(length, '\0');
51b9c1b51eSKate Stone         const size_t length_read =
52b9c1b51eSKate Stone             ::fread(file_contents.data(), 1, file_contents.size(), file);
532c1f46dcSZachary Turner         if (length_read > 0)
542c1f46dcSZachary Turner           strm.Write(file_contents.data(), length_read);
552c1f46dcSZachary Turner       }
562c1f46dcSZachary Turner       ::fclose(file);
572c1f46dcSZachary Turner     }
58b9c1b51eSKate Stone   } else
592c1f46dcSZachary Turner     strm.PutCString("NULL");
602c1f46dcSZachary Turner }
612c1f46dcSZachary Turner 
62b9c1b51eSKate Stone PyObjectType PythonObject::GetObjectType() const {
63f8b22f8fSZachary Turner   if (!IsAllocated())
642c1f46dcSZachary Turner     return PyObjectType::None;
652c1f46dcSZachary Turner 
667841efbbSZachary Turner   if (PythonModule::Check(m_py_obj))
677841efbbSZachary Turner     return PyObjectType::Module;
6818426935SZachary Turner   if (PythonList::Check(m_py_obj))
692c1f46dcSZachary Turner     return PyObjectType::List;
70a1405147SZachary Turner   if (PythonTuple::Check(m_py_obj))
71a1405147SZachary Turner     return PyObjectType::Tuple;
7218426935SZachary Turner   if (PythonDictionary::Check(m_py_obj))
732c1f46dcSZachary Turner     return PyObjectType::Dictionary;
7418426935SZachary Turner   if (PythonString::Check(m_py_obj))
7522c8efcdSZachary Turner     return PyObjectType::String;
765a72c02bSZachary Turner #if PY_MAJOR_VERSION >= 3
775a72c02bSZachary Turner   if (PythonBytes::Check(m_py_obj))
785a72c02bSZachary Turner     return PyObjectType::Bytes;
795a72c02bSZachary Turner #endif
80f9d6d204SZachary Turner   if (PythonByteArray::Check(m_py_obj))
81f9d6d204SZachary Turner     return PyObjectType::ByteArray;
8218426935SZachary Turner   if (PythonInteger::Check(m_py_obj))
8322c8efcdSZachary Turner     return PyObjectType::Integer;
849c40264fSZachary Turner   if (PythonFile::Check(m_py_obj))
859c40264fSZachary Turner     return PyObjectType::File;
86a1405147SZachary Turner   if (PythonCallable::Check(m_py_obj))
87a1405147SZachary Turner     return PyObjectType::Callable;
882c1f46dcSZachary Turner   return PyObjectType::Unknown;
892c1f46dcSZachary Turner }
902c1f46dcSZachary Turner 
91b9c1b51eSKate Stone PythonString PythonObject::Repr() const {
922c1f46dcSZachary Turner   if (!m_py_obj)
932c1f46dcSZachary Turner     return PythonString();
942c1f46dcSZachary Turner   PyObject *repr = PyObject_Repr(m_py_obj);
952c1f46dcSZachary Turner   if (!repr)
962c1f46dcSZachary Turner     return PythonString();
97f8b22f8fSZachary Turner   return PythonString(PyRefType::Owned, repr);
982c1f46dcSZachary Turner }
992c1f46dcSZachary Turner 
100b9c1b51eSKate Stone PythonString PythonObject::Str() const {
1012c1f46dcSZachary Turner   if (!m_py_obj)
1022c1f46dcSZachary Turner     return PythonString();
1032c1f46dcSZachary Turner   PyObject *str = PyObject_Str(m_py_obj);
1042c1f46dcSZachary Turner   if (!str)
1052c1f46dcSZachary Turner     return PythonString();
106f8b22f8fSZachary Turner   return PythonString(PyRefType::Owned, str);
1072c1f46dcSZachary Turner }
1082c1f46dcSZachary Turner 
1097841efbbSZachary Turner PythonObject
110b9c1b51eSKate Stone PythonObject::ResolveNameWithDictionary(llvm::StringRef name,
111b9c1b51eSKate Stone                                         const PythonDictionary &dict) {
112a1405147SZachary Turner   size_t dot_pos = name.find_first_of('.');
113a1405147SZachary Turner   llvm::StringRef piece = name.substr(0, dot_pos);
114a1405147SZachary Turner   PythonObject result = dict.GetItemForKey(PythonString(piece));
115b9c1b51eSKate Stone   if (dot_pos == llvm::StringRef::npos) {
116a1405147SZachary Turner     // There was no dot, we're done.
117a1405147SZachary Turner     return result;
118a1405147SZachary Turner   }
119a1405147SZachary Turner 
120a1405147SZachary Turner   // There was a dot.  The remaining portion of the name should be looked up in
121a1405147SZachary Turner   // the context of the object that was found in the dictionary.
122a1405147SZachary Turner   return result.ResolveName(name.substr(dot_pos + 1));
1237841efbbSZachary Turner }
1247841efbbSZachary Turner 
125b9c1b51eSKate Stone PythonObject PythonObject::ResolveName(llvm::StringRef name) const {
1267841efbbSZachary Turner   // Resolve the name in the context of the specified object.  If,
1277841efbbSZachary Turner   // for example, `this` refers to a PyModule, then this will look for
1287841efbbSZachary Turner   // `name` in this module.  If `this` refers to a PyType, then it will
1297841efbbSZachary Turner   // resolve `name` as an attribute of that type.  If `this` refers to
1307841efbbSZachary Turner   // an instance of an object, then it will resolve `name` as the value
1317841efbbSZachary Turner   // of the specified field.
1327841efbbSZachary Turner   //
1337841efbbSZachary Turner   // This function handles dotted names so that, for example, if `m_py_obj`
1347841efbbSZachary Turner   // refers to the `sys` module, and `name` == "path.append", then it
1357841efbbSZachary Turner   // will find the function `sys.path.append`.
1367841efbbSZachary Turner 
1377841efbbSZachary Turner   size_t dot_pos = name.find_first_of('.');
138b9c1b51eSKate Stone   if (dot_pos == llvm::StringRef::npos) {
1397841efbbSZachary Turner     // No dots in the name, we should be able to find the value immediately
140a1405147SZachary Turner     // as an attribute of `m_py_obj`.
1417841efbbSZachary Turner     return GetAttributeValue(name);
1427841efbbSZachary Turner   }
1437841efbbSZachary Turner 
144b9c1b51eSKate Stone   // Look up the first piece of the name, and resolve the rest as a child of
145b9c1b51eSKate Stone   // that.
1467841efbbSZachary Turner   PythonObject parent = ResolveName(name.substr(0, dot_pos));
1477841efbbSZachary Turner   if (!parent.IsAllocated())
1487841efbbSZachary Turner     return PythonObject();
1497841efbbSZachary Turner 
1507841efbbSZachary Turner   // Tail recursion.. should be optimized by the compiler
1517841efbbSZachary Turner   return parent.ResolveName(name.substr(dot_pos + 1));
1527841efbbSZachary Turner }
1537841efbbSZachary Turner 
154b9c1b51eSKate Stone bool PythonObject::HasAttribute(llvm::StringRef attr) const {
1559c40264fSZachary Turner   if (!IsValid())
1569c40264fSZachary Turner     return false;
1579c40264fSZachary Turner   PythonString py_attr(attr);
1589c40264fSZachary Turner   return !!PyObject_HasAttr(m_py_obj, py_attr.get());
1599c40264fSZachary Turner }
1609c40264fSZachary Turner 
161b9c1b51eSKate Stone PythonObject PythonObject::GetAttributeValue(llvm::StringRef attr) const {
1627d6d218eSZachary Turner   if (!IsValid())
1637d6d218eSZachary Turner     return PythonObject();
1647d6d218eSZachary Turner 
1657d6d218eSZachary Turner   PythonString py_attr(attr);
1667d6d218eSZachary Turner   if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
1677d6d218eSZachary Turner     return PythonObject();
1687d6d218eSZachary Turner 
1697d6d218eSZachary Turner   return PythonObject(PyRefType::Owned,
1707d6d218eSZachary Turner                       PyObject_GetAttr(m_py_obj, py_attr.get()));
1717d6d218eSZachary Turner }
1727d6d218eSZachary Turner 
173b9c1b51eSKate Stone bool PythonObject::IsNone() const { return m_py_obj == Py_None; }
174f8b22f8fSZachary Turner 
175b9c1b51eSKate Stone bool PythonObject::IsValid() const { return m_py_obj != nullptr; }
176f8b22f8fSZachary Turner 
177b9c1b51eSKate Stone bool PythonObject::IsAllocated() const { return IsValid() && !IsNone(); }
1782c1f46dcSZachary Turner 
179b9c1b51eSKate Stone StructuredData::ObjectSP PythonObject::CreateStructuredObject() const {
180b9c1b51eSKate Stone   switch (GetObjectType()) {
1812c1f46dcSZachary Turner   case PyObjectType::Dictionary:
182b9c1b51eSKate Stone     return PythonDictionary(PyRefType::Borrowed, m_py_obj)
183b9c1b51eSKate Stone         .CreateStructuredDictionary();
1842c1f46dcSZachary Turner   case PyObjectType::Integer:
185b9c1b51eSKate Stone     return PythonInteger(PyRefType::Borrowed, m_py_obj)
186b9c1b51eSKate Stone         .CreateStructuredInteger();
1872c1f46dcSZachary Turner   case PyObjectType::List:
188f8b22f8fSZachary Turner     return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
1892c1f46dcSZachary Turner   case PyObjectType::String:
190f8b22f8fSZachary Turner     return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
1915a72c02bSZachary Turner   case PyObjectType::Bytes:
1925a72c02bSZachary Turner     return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
193f9d6d204SZachary Turner   case PyObjectType::ByteArray:
194b9c1b51eSKate Stone     return PythonByteArray(PyRefType::Borrowed, m_py_obj)
195b9c1b51eSKate Stone         .CreateStructuredString();
1962c1f46dcSZachary Turner   case PyObjectType::None:
1972c1f46dcSZachary Turner     return StructuredData::ObjectSP();
1982c1f46dcSZachary Turner   default:
1992c1f46dcSZachary Turner     return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj));
2002c1f46dcSZachary Turner   }
2012c1f46dcSZachary Turner }
2022c1f46dcSZachary Turner 
2032c1f46dcSZachary Turner //----------------------------------------------------------------------
2042c1f46dcSZachary Turner // PythonString
2052c1f46dcSZachary Turner //----------------------------------------------------------------------
206b9c1b51eSKate Stone PythonBytes::PythonBytes() : PythonObject() {}
2075a72c02bSZachary Turner 
208b9c1b51eSKate Stone PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject() {
2095a72c02bSZachary Turner   SetBytes(bytes);
2105a72c02bSZachary Turner }
2115a72c02bSZachary Turner 
212b9c1b51eSKate Stone PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject() {
2135a72c02bSZachary Turner   SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
2145a72c02bSZachary Turner }
2155a72c02bSZachary Turner 
216b9c1b51eSKate Stone PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject() {
2175a72c02bSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
2185a72c02bSZachary Turner }
2195a72c02bSZachary Turner 
220b9c1b51eSKate Stone PythonBytes::PythonBytes(const PythonBytes &object) : PythonObject(object) {}
2215a72c02bSZachary Turner 
222b9c1b51eSKate Stone PythonBytes::~PythonBytes() {}
2235a72c02bSZachary Turner 
224b9c1b51eSKate Stone bool PythonBytes::Check(PyObject *py_obj) {
2255a72c02bSZachary Turner   if (!py_obj)
2265a72c02bSZachary Turner     return false;
2275a72c02bSZachary Turner   if (PyBytes_Check(py_obj))
2285a72c02bSZachary Turner     return true;
2295a72c02bSZachary Turner   return false;
2305a72c02bSZachary Turner }
2315a72c02bSZachary Turner 
232b9c1b51eSKate Stone void PythonBytes::Reset(PyRefType type, PyObject *py_obj) {
2335a72c02bSZachary Turner   // Grab the desired reference type so that if we end up rejecting
2345a72c02bSZachary Turner   // `py_obj` it still gets decremented if necessary.
2355a72c02bSZachary Turner   PythonObject result(type, py_obj);
2365a72c02bSZachary Turner 
237b9c1b51eSKate Stone   if (!PythonBytes::Check(py_obj)) {
2385a72c02bSZachary Turner     PythonObject::Reset();
2395a72c02bSZachary Turner     return;
2405a72c02bSZachary Turner   }
2415a72c02bSZachary Turner 
242b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
243b9c1b51eSKate Stone   // overflow since it calls
2445a72c02bSZachary Turner   // back into the virtual implementation.
2455a72c02bSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
2465a72c02bSZachary Turner }
2475a72c02bSZachary Turner 
248b9c1b51eSKate Stone llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {
2495a72c02bSZachary Turner   if (!IsValid())
2505a72c02bSZachary Turner     return llvm::ArrayRef<uint8_t>();
2515a72c02bSZachary Turner 
2525a72c02bSZachary Turner   Py_ssize_t size;
2535a72c02bSZachary Turner   char *c;
2545a72c02bSZachary Turner 
2555a72c02bSZachary Turner   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
2565a72c02bSZachary Turner   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
2575a72c02bSZachary Turner }
2585a72c02bSZachary Turner 
259b9c1b51eSKate Stone size_t PythonBytes::GetSize() const {
2605a72c02bSZachary Turner   if (!IsValid())
2615a72c02bSZachary Turner     return 0;
2625a72c02bSZachary Turner   return PyBytes_Size(m_py_obj);
2635a72c02bSZachary Turner }
2645a72c02bSZachary Turner 
265b9c1b51eSKate Stone void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {
2665a72c02bSZachary Turner   const char *data = reinterpret_cast<const char *>(bytes.data());
2675a72c02bSZachary Turner   PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size());
2685a72c02bSZachary Turner   PythonObject::Reset(PyRefType::Owned, py_bytes);
2695a72c02bSZachary Turner }
2705a72c02bSZachary Turner 
271b9c1b51eSKate Stone StructuredData::StringSP PythonBytes::CreateStructuredString() const {
2725a72c02bSZachary Turner   StructuredData::StringSP result(new StructuredData::String);
2735a72c02bSZachary Turner   Py_ssize_t size;
2745a72c02bSZachary Turner   char *c;
2755a72c02bSZachary Turner   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
2765a72c02bSZachary Turner   result->SetValue(std::string(c, size));
2775a72c02bSZachary Turner   return result;
2785a72c02bSZachary Turner }
2795a72c02bSZachary Turner 
280b9c1b51eSKate Stone PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes)
281b9c1b51eSKate Stone     : PythonByteArray(bytes.data(), bytes.size()) {}
282f9d6d204SZachary Turner 
283b9c1b51eSKate Stone PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {
284f9d6d204SZachary Turner   const char *str = reinterpret_cast<const char *>(bytes);
285f9d6d204SZachary Turner   Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length));
286f9d6d204SZachary Turner }
287f9d6d204SZachary Turner 
288b9c1b51eSKate Stone PythonByteArray::PythonByteArray(PyRefType type, PyObject *o) {
289f9d6d204SZachary Turner   Reset(type, o);
290f9d6d204SZachary Turner }
291f9d6d204SZachary Turner 
292b9c1b51eSKate Stone PythonByteArray::PythonByteArray(const PythonBytes &object)
293b9c1b51eSKate Stone     : PythonObject(object) {}
294f9d6d204SZachary Turner 
295b9c1b51eSKate Stone PythonByteArray::~PythonByteArray() {}
296f9d6d204SZachary Turner 
297b9c1b51eSKate Stone bool PythonByteArray::Check(PyObject *py_obj) {
298f9d6d204SZachary Turner   if (!py_obj)
299f9d6d204SZachary Turner     return false;
300f9d6d204SZachary Turner   if (PyByteArray_Check(py_obj))
301f9d6d204SZachary Turner     return true;
302f9d6d204SZachary Turner   return false;
303f9d6d204SZachary Turner }
304f9d6d204SZachary Turner 
305b9c1b51eSKate Stone void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) {
306f9d6d204SZachary Turner   // Grab the desired reference type so that if we end up rejecting
307f9d6d204SZachary Turner   // `py_obj` it still gets decremented if necessary.
308f9d6d204SZachary Turner   PythonObject result(type, py_obj);
309f9d6d204SZachary Turner 
310b9c1b51eSKate Stone   if (!PythonByteArray::Check(py_obj)) {
311f9d6d204SZachary Turner     PythonObject::Reset();
312f9d6d204SZachary Turner     return;
313f9d6d204SZachary Turner   }
314f9d6d204SZachary Turner 
315b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
316b9c1b51eSKate Stone   // overflow since it calls
317f9d6d204SZachary Turner   // back into the virtual implementation.
318f9d6d204SZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
319f9d6d204SZachary Turner }
320f9d6d204SZachary Turner 
321b9c1b51eSKate Stone llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {
322f9d6d204SZachary Turner   if (!IsValid())
323f9d6d204SZachary Turner     return llvm::ArrayRef<uint8_t>();
324f9d6d204SZachary Turner 
325f9d6d204SZachary Turner   char *c = PyByteArray_AsString(m_py_obj);
326f9d6d204SZachary Turner   size_t size = GetSize();
327f9d6d204SZachary Turner   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
328f9d6d204SZachary Turner }
329f9d6d204SZachary Turner 
330b9c1b51eSKate Stone size_t PythonByteArray::GetSize() const {
331f9d6d204SZachary Turner   if (!IsValid())
332f9d6d204SZachary Turner     return 0;
333f9d6d204SZachary Turner 
334f9d6d204SZachary Turner   return PyByteArray_Size(m_py_obj);
335f9d6d204SZachary Turner }
336f9d6d204SZachary Turner 
337b9c1b51eSKate Stone StructuredData::StringSP PythonByteArray::CreateStructuredString() const {
338f9d6d204SZachary Turner   StructuredData::StringSP result(new StructuredData::String);
339f9d6d204SZachary Turner   llvm::ArrayRef<uint8_t> bytes = GetBytes();
340f9d6d204SZachary Turner   const char *str = reinterpret_cast<const char *>(bytes.data());
341f9d6d204SZachary Turner   result->SetValue(std::string(str, bytes.size()));
342f9d6d204SZachary Turner   return result;
343f9d6d204SZachary Turner }
344f9d6d204SZachary Turner 
3455a72c02bSZachary Turner //----------------------------------------------------------------------
3465a72c02bSZachary Turner // PythonString
3475a72c02bSZachary Turner //----------------------------------------------------------------------
3482c1f46dcSZachary Turner 
349b9c1b51eSKate Stone PythonString::PythonString(PyRefType type, PyObject *py_obj) : PythonObject() {
350f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
3512c1f46dcSZachary Turner }
3522c1f46dcSZachary Turner 
353b9c1b51eSKate Stone PythonString::PythonString(const PythonString &object) : PythonObject(object) {}
3542c1f46dcSZachary Turner 
355b9c1b51eSKate Stone PythonString::PythonString(llvm::StringRef string) : PythonObject() {
35622c8efcdSZachary Turner   SetString(string);
3572c1f46dcSZachary Turner }
3582c1f46dcSZachary Turner 
359b9c1b51eSKate Stone PythonString::PythonString(const char *string) : PythonObject() {
36022c8efcdSZachary Turner   SetString(llvm::StringRef(string));
3612c1f46dcSZachary Turner }
3622c1f46dcSZachary Turner 
363b9c1b51eSKate Stone PythonString::PythonString() : PythonObject() {}
3642c1f46dcSZachary Turner 
365b9c1b51eSKate Stone PythonString::~PythonString() {}
3662c1f46dcSZachary Turner 
367b9c1b51eSKate Stone bool PythonString::Check(PyObject *py_obj) {
36822c8efcdSZachary Turner   if (!py_obj)
36922c8efcdSZachary Turner     return false;
37018426935SZachary Turner 
3717d6d218eSZachary Turner   if (PyUnicode_Check(py_obj))
3727d6d218eSZachary Turner     return true;
3737d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
3747d6d218eSZachary Turner   if (PyString_Check(py_obj))
3757d6d218eSZachary Turner     return true;
37622c8efcdSZachary Turner #endif
3777d6d218eSZachary Turner   return false;
37822c8efcdSZachary Turner }
37922c8efcdSZachary Turner 
380b9c1b51eSKate Stone void PythonString::Reset(PyRefType type, PyObject *py_obj) {
381f8b22f8fSZachary Turner   // Grab the desired reference type so that if we end up rejecting
382f8b22f8fSZachary Turner   // `py_obj` it still gets decremented if necessary.
383f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
384f8b22f8fSZachary Turner 
385b9c1b51eSKate Stone   if (!PythonString::Check(py_obj)) {
386f8b22f8fSZachary Turner     PythonObject::Reset();
387f8b22f8fSZachary Turner     return;
38822c8efcdSZachary Turner   }
3897d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
3907d6d218eSZachary Turner   // In Python 2, Don't store PyUnicode objects directly, because we need
3917d6d218eSZachary Turner   // access to their underlying character buffers which Python 2 doesn't
3927d6d218eSZachary Turner   // provide.
3937d6d218eSZachary Turner   if (PyUnicode_Check(py_obj))
3947d6d218eSZachary Turner     result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(result.get()));
3957d6d218eSZachary Turner #endif
396b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
397b9c1b51eSKate Stone   // overflow since it calls
398f8b22f8fSZachary Turner   // back into the virtual implementation.
399f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
4002c1f46dcSZachary Turner }
4012c1f46dcSZachary Turner 
402b9c1b51eSKate Stone llvm::StringRef PythonString::GetString() const {
40318426935SZachary Turner   if (!IsValid())
40418426935SZachary Turner     return llvm::StringRef();
40518426935SZachary Turner 
40622c8efcdSZachary Turner   Py_ssize_t size;
40722c8efcdSZachary Turner   char *c;
40818426935SZachary Turner 
40918426935SZachary Turner #if PY_MAJOR_VERSION >= 3
41018426935SZachary Turner   c = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
41118426935SZachary Turner #else
41218426935SZachary Turner   PyString_AsStringAndSize(m_py_obj, &c, &size);
41318426935SZachary Turner #endif
41422c8efcdSZachary Turner   return llvm::StringRef(c, size);
41522c8efcdSZachary Turner }
4162c1f46dcSZachary Turner 
417b9c1b51eSKate Stone size_t PythonString::GetSize() const {
418b9c1b51eSKate Stone   if (IsValid()) {
41918426935SZachary Turner #if PY_MAJOR_VERSION >= 3
42018426935SZachary Turner     return PyUnicode_GetSize(m_py_obj);
42118426935SZachary Turner #else
42218426935SZachary Turner     return PyString_Size(m_py_obj);
42318426935SZachary Turner #endif
42418426935SZachary Turner   }
4252c1f46dcSZachary Turner   return 0;
4262c1f46dcSZachary Turner }
4272c1f46dcSZachary Turner 
428b9c1b51eSKate Stone void PythonString::SetString(llvm::StringRef string) {
42922c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
43022c8efcdSZachary Turner   PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
43118426935SZachary Turner   PythonObject::Reset(PyRefType::Owned, unicode);
43222c8efcdSZachary Turner #else
43318426935SZachary Turner   PyObject *str = PyString_FromStringAndSize(string.data(), string.size());
43418426935SZachary Turner   PythonObject::Reset(PyRefType::Owned, str);
43522c8efcdSZachary Turner #endif
4362c1f46dcSZachary Turner }
4372c1f46dcSZachary Turner 
438b9c1b51eSKate Stone StructuredData::StringSP PythonString::CreateStructuredString() const {
4392c1f46dcSZachary Turner   StructuredData::StringSP result(new StructuredData::String);
4402c1f46dcSZachary Turner   result->SetValue(GetString());
4412c1f46dcSZachary Turner   return result;
4422c1f46dcSZachary Turner }
4432c1f46dcSZachary Turner 
4442c1f46dcSZachary Turner //----------------------------------------------------------------------
4452c1f46dcSZachary Turner // PythonInteger
4462c1f46dcSZachary Turner //----------------------------------------------------------------------
4472c1f46dcSZachary Turner 
448b9c1b51eSKate Stone PythonInteger::PythonInteger() : PythonObject() {}
4497d6d218eSZachary Turner 
450f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
451b9c1b51eSKate Stone     : PythonObject() {
452f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
4532c1f46dcSZachary Turner }
4542c1f46dcSZachary Turner 
455f8b22f8fSZachary Turner PythonInteger::PythonInteger(const PythonInteger &object)
456b9c1b51eSKate Stone     : PythonObject(object) {}
4572c1f46dcSZachary Turner 
458b9c1b51eSKate Stone PythonInteger::PythonInteger(int64_t value) : PythonObject() {
4592c1f46dcSZachary Turner   SetInteger(value);
4602c1f46dcSZachary Turner }
4612c1f46dcSZachary Turner 
462b9c1b51eSKate Stone PythonInteger::~PythonInteger() {}
4632c1f46dcSZachary Turner 
464b9c1b51eSKate Stone bool PythonInteger::Check(PyObject *py_obj) {
46522c8efcdSZachary Turner   if (!py_obj)
46622c8efcdSZachary Turner     return false;
46722c8efcdSZachary Turner 
46822c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
46922c8efcdSZachary Turner   // Python 3 does not have PyInt_Check.  There is only one type of
47022c8efcdSZachary Turner   // integral value, long.
47122c8efcdSZachary Turner   return PyLong_Check(py_obj);
47222c8efcdSZachary Turner #else
47322c8efcdSZachary Turner   return PyLong_Check(py_obj) || PyInt_Check(py_obj);
47422c8efcdSZachary Turner #endif
4752c1f46dcSZachary Turner }
4762c1f46dcSZachary Turner 
477b9c1b51eSKate Stone void PythonInteger::Reset(PyRefType type, PyObject *py_obj) {
478f8b22f8fSZachary Turner   // Grab the desired reference type so that if we end up rejecting
479f8b22f8fSZachary Turner   // `py_obj` it still gets decremented if necessary.
480f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
481f8b22f8fSZachary Turner 
482b9c1b51eSKate Stone   if (!PythonInteger::Check(py_obj)) {
483f8b22f8fSZachary Turner     PythonObject::Reset();
484f8b22f8fSZachary Turner     return;
48522c8efcdSZachary Turner   }
48622c8efcdSZachary Turner 
48722c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3
48822c8efcdSZachary Turner   // Always store this as a PyLong, which makes interoperability between
48922c8efcdSZachary Turner   // Python 2.x and Python 3.x easier.  This is only necessary in 2.x,
49022c8efcdSZachary Turner   // since 3.x doesn't even have a PyInt.
491b9c1b51eSKate Stone   if (PyInt_Check(py_obj)) {
492f8b22f8fSZachary Turner     // Since we converted the original object to a different type, the new
493f8b22f8fSZachary Turner     // object is an owned object regardless of the ownership semantics requested
494f8b22f8fSZachary Turner     // by the user.
495f8b22f8fSZachary Turner     result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
49622c8efcdSZachary Turner   }
49722c8efcdSZachary Turner #endif
49822c8efcdSZachary Turner 
499b9c1b51eSKate Stone   assert(PyLong_Check(result.get()) &&
500b9c1b51eSKate Stone          "Couldn't get a PyLong from this PyObject");
50122c8efcdSZachary Turner 
502b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
503b9c1b51eSKate Stone   // overflow since it calls
504f8b22f8fSZachary Turner   // back into the virtual implementation.
505f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
5062c1f46dcSZachary Turner }
5072c1f46dcSZachary Turner 
508b9c1b51eSKate Stone int64_t PythonInteger::GetInteger() const {
509b9c1b51eSKate Stone   if (m_py_obj) {
510b9c1b51eSKate Stone     assert(PyLong_Check(m_py_obj) &&
511b9c1b51eSKate Stone            "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
51222c8efcdSZachary Turner 
513008ec446SGreg Clayton     int overflow = 0;
514008ec446SGreg Clayton     int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
515b9c1b51eSKate Stone     if (overflow != 0) {
516008ec446SGreg Clayton       // We got an integer that overflows, like 18446744072853913392L
517008ec446SGreg Clayton       // we can't use PyLong_AsLongLong() as it will return
518008ec446SGreg Clayton       // 0xffffffffffffffff. If we use the unsigned long long
519008ec446SGreg Clayton       // it will work as expected.
520008ec446SGreg Clayton       const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
5214f730dc7SIlia K       result = static_cast<int64_t>(uval);
522008ec446SGreg Clayton     }
523008ec446SGreg Clayton     return result;
5242c1f46dcSZachary Turner   }
5252c1f46dcSZachary Turner   return UINT64_MAX;
5262c1f46dcSZachary Turner }
5272c1f46dcSZachary Turner 
528b9c1b51eSKate Stone void PythonInteger::SetInteger(int64_t value) {
529f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
5302c1f46dcSZachary Turner }
5312c1f46dcSZachary Turner 
532b9c1b51eSKate Stone StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
5332c1f46dcSZachary Turner   StructuredData::IntegerSP result(new StructuredData::Integer);
5342c1f46dcSZachary Turner   result->SetValue(GetInteger());
5352c1f46dcSZachary Turner   return result;
5362c1f46dcSZachary Turner }
5372c1f46dcSZachary Turner 
5382c1f46dcSZachary Turner //----------------------------------------------------------------------
5392c1f46dcSZachary Turner // PythonList
5402c1f46dcSZachary Turner //----------------------------------------------------------------------
5412c1f46dcSZachary Turner 
542b9c1b51eSKate Stone PythonList::PythonList(PyInitialValue value) : PythonObject() {
543f8b22f8fSZachary Turner   if (value == PyInitialValue::Empty)
544f8b22f8fSZachary Turner     Reset(PyRefType::Owned, PyList_New(0));
5452c1f46dcSZachary Turner }
5462c1f46dcSZachary Turner 
547b9c1b51eSKate Stone PythonList::PythonList(int list_size) : PythonObject() {
54887f47729SZachary Turner   Reset(PyRefType::Owned, PyList_New(list_size));
54987f47729SZachary Turner }
55087f47729SZachary Turner 
551b9c1b51eSKate Stone PythonList::PythonList(PyRefType type, PyObject *py_obj) : PythonObject() {
552f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
5532c1f46dcSZachary Turner }
5542c1f46dcSZachary Turner 
555b9c1b51eSKate Stone PythonList::PythonList(const PythonList &list) : PythonObject(list) {}
5562c1f46dcSZachary Turner 
557b9c1b51eSKate Stone PythonList::~PythonList() {}
5582c1f46dcSZachary Turner 
559b9c1b51eSKate Stone bool PythonList::Check(PyObject *py_obj) {
56022c8efcdSZachary Turner   if (!py_obj)
56122c8efcdSZachary Turner     return false;
56222c8efcdSZachary Turner   return PyList_Check(py_obj);
56322c8efcdSZachary Turner }
56422c8efcdSZachary Turner 
565b9c1b51eSKate Stone void PythonList::Reset(PyRefType type, PyObject *py_obj) {
566f8b22f8fSZachary Turner   // Grab the desired reference type so that if we end up rejecting
567f8b22f8fSZachary Turner   // `py_obj` it still gets decremented if necessary.
568f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
569f8b22f8fSZachary Turner 
570b9c1b51eSKate Stone   if (!PythonList::Check(py_obj)) {
571f8b22f8fSZachary Turner     PythonObject::Reset();
572f8b22f8fSZachary Turner     return;
57322c8efcdSZachary Turner   }
57422c8efcdSZachary Turner 
575b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
576b9c1b51eSKate Stone   // overflow since it calls
577f8b22f8fSZachary Turner   // back into the virtual implementation.
578f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
5792c1f46dcSZachary Turner }
5802c1f46dcSZachary Turner 
581b9c1b51eSKate Stone uint32_t PythonList::GetSize() const {
582f8b22f8fSZachary Turner   if (IsValid())
5832c1f46dcSZachary Turner     return PyList_GET_SIZE(m_py_obj);
5842c1f46dcSZachary Turner   return 0;
5852c1f46dcSZachary Turner }
5862c1f46dcSZachary Turner 
587b9c1b51eSKate Stone PythonObject PythonList::GetItemAtIndex(uint32_t index) const {
588f8b22f8fSZachary Turner   if (IsValid())
589f8b22f8fSZachary Turner     return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
5902c1f46dcSZachary Turner   return PythonObject();
5912c1f46dcSZachary Turner }
5922c1f46dcSZachary Turner 
593b9c1b51eSKate Stone void PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) {
594b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
595f8b22f8fSZachary Turner     // PyList_SetItem is documented to "steal" a reference, so we need to
596f8b22f8fSZachary Turner     // convert it to an owned reference by incrementing it.
597f8b22f8fSZachary Turner     Py_INCREF(object.get());
5982c1f46dcSZachary Turner     PyList_SetItem(m_py_obj, index, object.get());
5992c1f46dcSZachary Turner   }
600f8b22f8fSZachary Turner }
6012c1f46dcSZachary Turner 
602b9c1b51eSKate Stone void PythonList::AppendItem(const PythonObject &object) {
603b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
604f8b22f8fSZachary Turner     // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
605f8b22f8fSZachary Turner     // here like we do with `PyList_SetItem`.
6062c1f46dcSZachary Turner     PyList_Append(m_py_obj, object.get());
6072c1f46dcSZachary Turner   }
608f8b22f8fSZachary Turner }
6092c1f46dcSZachary Turner 
610b9c1b51eSKate Stone StructuredData::ArraySP PythonList::CreateStructuredArray() const {
6112c1f46dcSZachary Turner   StructuredData::ArraySP result(new StructuredData::Array);
6122c1f46dcSZachary Turner   uint32_t count = GetSize();
613b9c1b51eSKate Stone   for (uint32_t i = 0; i < count; ++i) {
6142c1f46dcSZachary Turner     PythonObject obj = GetItemAtIndex(i);
6152c1f46dcSZachary Turner     result->AddItem(obj.CreateStructuredObject());
6162c1f46dcSZachary Turner   }
6172c1f46dcSZachary Turner   return result;
6182c1f46dcSZachary Turner }
6192c1f46dcSZachary Turner 
6202c1f46dcSZachary Turner //----------------------------------------------------------------------
621a1405147SZachary Turner // PythonTuple
622a1405147SZachary Turner //----------------------------------------------------------------------
623a1405147SZachary Turner 
624b9c1b51eSKate Stone PythonTuple::PythonTuple(PyInitialValue value) : PythonObject() {
625a1405147SZachary Turner   if (value == PyInitialValue::Empty)
626a1405147SZachary Turner     Reset(PyRefType::Owned, PyTuple_New(0));
627a1405147SZachary Turner }
628a1405147SZachary Turner 
629b9c1b51eSKate Stone PythonTuple::PythonTuple(int tuple_size) : PythonObject() {
630a1405147SZachary Turner   Reset(PyRefType::Owned, PyTuple_New(tuple_size));
631a1405147SZachary Turner }
632a1405147SZachary Turner 
633b9c1b51eSKate Stone PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj) : PythonObject() {
634a1405147SZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple
635a1405147SZachary Turner }
636a1405147SZachary Turner 
637b9c1b51eSKate Stone PythonTuple::PythonTuple(const PythonTuple &tuple) : PythonObject(tuple) {}
638a1405147SZachary Turner 
639b9c1b51eSKate Stone PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
640a1405147SZachary Turner   m_py_obj = PyTuple_New(objects.size());
641a1405147SZachary Turner 
642a1405147SZachary Turner   uint32_t idx = 0;
643b9c1b51eSKate Stone   for (auto object : objects) {
644a1405147SZachary Turner     if (object.IsValid())
645a1405147SZachary Turner       SetItemAtIndex(idx, object);
646a1405147SZachary Turner     idx++;
647a1405147SZachary Turner   }
648a1405147SZachary Turner }
649a1405147SZachary Turner 
650b9c1b51eSKate Stone PythonTuple::PythonTuple(std::initializer_list<PyObject *> objects) {
651a1405147SZachary Turner   m_py_obj = PyTuple_New(objects.size());
652a1405147SZachary Turner 
653a1405147SZachary Turner   uint32_t idx = 0;
654b9c1b51eSKate Stone   for (auto py_object : objects) {
655a1405147SZachary Turner     PythonObject object(PyRefType::Borrowed, py_object);
656a1405147SZachary Turner     if (object.IsValid())
657a1405147SZachary Turner       SetItemAtIndex(idx, object);
658a1405147SZachary Turner     idx++;
659a1405147SZachary Turner   }
660a1405147SZachary Turner }
661a1405147SZachary Turner 
662b9c1b51eSKate Stone PythonTuple::~PythonTuple() {}
663a1405147SZachary Turner 
664b9c1b51eSKate Stone bool PythonTuple::Check(PyObject *py_obj) {
665a1405147SZachary Turner   if (!py_obj)
666a1405147SZachary Turner     return false;
667a1405147SZachary Turner   return PyTuple_Check(py_obj);
668a1405147SZachary Turner }
669a1405147SZachary Turner 
670b9c1b51eSKate Stone void PythonTuple::Reset(PyRefType type, PyObject *py_obj) {
671a1405147SZachary Turner   // Grab the desired reference type so that if we end up rejecting
672a1405147SZachary Turner   // `py_obj` it still gets decremented if necessary.
673a1405147SZachary Turner   PythonObject result(type, py_obj);
674a1405147SZachary Turner 
675b9c1b51eSKate Stone   if (!PythonTuple::Check(py_obj)) {
676a1405147SZachary Turner     PythonObject::Reset();
677a1405147SZachary Turner     return;
678a1405147SZachary Turner   }
679a1405147SZachary Turner 
680b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
681b9c1b51eSKate Stone   // overflow since it calls
682a1405147SZachary Turner   // back into the virtual implementation.
683a1405147SZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
684a1405147SZachary Turner }
685a1405147SZachary Turner 
686b9c1b51eSKate Stone uint32_t PythonTuple::GetSize() const {
687a1405147SZachary Turner   if (IsValid())
688a1405147SZachary Turner     return PyTuple_GET_SIZE(m_py_obj);
689a1405147SZachary Turner   return 0;
690a1405147SZachary Turner }
691a1405147SZachary Turner 
692b9c1b51eSKate Stone PythonObject PythonTuple::GetItemAtIndex(uint32_t index) const {
693a1405147SZachary Turner   if (IsValid())
694a1405147SZachary Turner     return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
695a1405147SZachary Turner   return PythonObject();
696a1405147SZachary Turner }
697a1405147SZachary Turner 
698b9c1b51eSKate Stone void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) {
699b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
700a1405147SZachary Turner     // PyTuple_SetItem is documented to "steal" a reference, so we need to
701a1405147SZachary Turner     // convert it to an owned reference by incrementing it.
702a1405147SZachary Turner     Py_INCREF(object.get());
703a1405147SZachary Turner     PyTuple_SetItem(m_py_obj, index, object.get());
704a1405147SZachary Turner   }
705a1405147SZachary Turner }
706a1405147SZachary Turner 
707b9c1b51eSKate Stone StructuredData::ArraySP PythonTuple::CreateStructuredArray() const {
708a1405147SZachary Turner   StructuredData::ArraySP result(new StructuredData::Array);
709a1405147SZachary Turner   uint32_t count = GetSize();
710b9c1b51eSKate Stone   for (uint32_t i = 0; i < count; ++i) {
711a1405147SZachary Turner     PythonObject obj = GetItemAtIndex(i);
712a1405147SZachary Turner     result->AddItem(obj.CreateStructuredObject());
713a1405147SZachary Turner   }
714a1405147SZachary Turner   return result;
715a1405147SZachary Turner }
716a1405147SZachary Turner 
717a1405147SZachary Turner //----------------------------------------------------------------------
7182c1f46dcSZachary Turner // PythonDictionary
7192c1f46dcSZachary Turner //----------------------------------------------------------------------
7202c1f46dcSZachary Turner 
721b9c1b51eSKate Stone PythonDictionary::PythonDictionary(PyInitialValue value) : PythonObject() {
722f8b22f8fSZachary Turner   if (value == PyInitialValue::Empty)
723f8b22f8fSZachary Turner     Reset(PyRefType::Owned, PyDict_New());
7242c1f46dcSZachary Turner }
7252c1f46dcSZachary Turner 
726f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
727b9c1b51eSKate Stone     : PythonObject() {
728f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
7292c1f46dcSZachary Turner }
7302c1f46dcSZachary Turner 
731f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object)
732b9c1b51eSKate Stone     : PythonObject(object) {}
7332c1f46dcSZachary Turner 
734b9c1b51eSKate Stone PythonDictionary::~PythonDictionary() {}
7352c1f46dcSZachary Turner 
736b9c1b51eSKate Stone bool PythonDictionary::Check(PyObject *py_obj) {
73722c8efcdSZachary Turner   if (!py_obj)
73822c8efcdSZachary Turner     return false;
73922c8efcdSZachary Turner 
74022c8efcdSZachary Turner   return PyDict_Check(py_obj);
74122c8efcdSZachary Turner }
74222c8efcdSZachary Turner 
743b9c1b51eSKate Stone void PythonDictionary::Reset(PyRefType type, PyObject *py_obj) {
744f8b22f8fSZachary Turner   // Grab the desired reference type so that if we end up rejecting
745f8b22f8fSZachary Turner   // `py_obj` it still gets decremented if necessary.
746f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
747f8b22f8fSZachary Turner 
748b9c1b51eSKate Stone   if (!PythonDictionary::Check(py_obj)) {
749f8b22f8fSZachary Turner     PythonObject::Reset();
750f8b22f8fSZachary Turner     return;
75122c8efcdSZachary Turner   }
75222c8efcdSZachary Turner 
753b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
754b9c1b51eSKate Stone   // overflow since it calls
755f8b22f8fSZachary Turner   // back into the virtual implementation.
756f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
7572c1f46dcSZachary Turner }
7582c1f46dcSZachary Turner 
759b9c1b51eSKate Stone uint32_t PythonDictionary::GetSize() const {
760f8b22f8fSZachary Turner   if (IsValid())
7612c1f46dcSZachary Turner     return PyDict_Size(m_py_obj);
7622c1f46dcSZachary Turner   return 0;
7632c1f46dcSZachary Turner }
7642c1f46dcSZachary Turner 
765b9c1b51eSKate Stone PythonList PythonDictionary::GetKeys() const {
766f8b22f8fSZachary Turner   if (IsValid())
767f8b22f8fSZachary Turner     return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
768f8b22f8fSZachary Turner   return PythonList(PyInitialValue::Invalid);
7692c1f46dcSZachary Turner }
7702c1f46dcSZachary Turner 
771b9c1b51eSKate Stone PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {
772f8b22f8fSZachary Turner   if (IsAllocated() && key.IsValid())
773b9c1b51eSKate Stone     return PythonObject(PyRefType::Borrowed,
774b9c1b51eSKate Stone                         PyDict_GetItem(m_py_obj, key.get()));
7752c1f46dcSZachary Turner   return PythonObject();
7762c1f46dcSZachary Turner }
7772c1f46dcSZachary Turner 
778b9c1b51eSKate Stone void PythonDictionary::SetItemForKey(const PythonObject &key,
779b9c1b51eSKate Stone                                      const PythonObject &value) {
780f8b22f8fSZachary Turner   if (IsAllocated() && key.IsValid() && value.IsValid())
7812c1f46dcSZachary Turner     PyDict_SetItem(m_py_obj, key.get(), value.get());
7822c1f46dcSZachary Turner }
7832c1f46dcSZachary Turner 
7842c1f46dcSZachary Turner StructuredData::DictionarySP
785b9c1b51eSKate Stone PythonDictionary::CreateStructuredDictionary() const {
7862c1f46dcSZachary Turner   StructuredData::DictionarySP result(new StructuredData::Dictionary);
7872c1f46dcSZachary Turner   PythonList keys(GetKeys());
7882c1f46dcSZachary Turner   uint32_t num_keys = keys.GetSize();
789b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_keys; ++i) {
7902c1f46dcSZachary Turner     PythonObject key = keys.GetItemAtIndex(i);
7912c1f46dcSZachary Turner     PythonObject value = GetItemForKey(key);
7922c1f46dcSZachary Turner     StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
793f8b22f8fSZachary Turner     result->AddItem(key.Str().GetString(), structured_value);
7942c1f46dcSZachary Turner   }
7952c1f46dcSZachary Turner   return result;
7962c1f46dcSZachary Turner }
7972c1f46dcSZachary Turner 
798b9c1b51eSKate Stone PythonModule::PythonModule() : PythonObject() {}
7997841efbbSZachary Turner 
800b9c1b51eSKate Stone PythonModule::PythonModule(PyRefType type, PyObject *py_obj) {
8017841efbbSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
8027841efbbSZachary Turner }
8037841efbbSZachary Turner 
804b9c1b51eSKate Stone PythonModule::PythonModule(const PythonModule &dict) : PythonObject(dict) {}
8057841efbbSZachary Turner 
806b9c1b51eSKate Stone PythonModule::~PythonModule() {}
8077841efbbSZachary Turner 
808b9c1b51eSKate Stone PythonModule PythonModule::BuiltinsModule() {
809a1405147SZachary Turner #if PY_MAJOR_VERSION >= 3
810a1405147SZachary Turner   return AddModule("builtins");
811a1405147SZachary Turner #else
812a1405147SZachary Turner   return AddModule("__builtin__");
813a1405147SZachary Turner #endif
814a1405147SZachary Turner }
815a1405147SZachary Turner 
816b9c1b51eSKate Stone PythonModule PythonModule::MainModule() { return AddModule("__main__"); }
817a1405147SZachary Turner 
818b9c1b51eSKate Stone PythonModule PythonModule::AddModule(llvm::StringRef module) {
819a1405147SZachary Turner   std::string str = module.str();
820a1405147SZachary Turner   return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
8217841efbbSZachary Turner }
8227841efbbSZachary Turner 
823b9c1b51eSKate Stone PythonModule PythonModule::ImportModule(llvm::StringRef module) {
8242419f1d5SZachary Turner   std::string str = module.str();
8252419f1d5SZachary Turner   return PythonModule(PyRefType::Owned, PyImport_ImportModule(str.c_str()));
8262419f1d5SZachary Turner }
8272419f1d5SZachary Turner 
828b9c1b51eSKate Stone bool PythonModule::Check(PyObject *py_obj) {
8297841efbbSZachary Turner   if (!py_obj)
8307841efbbSZachary Turner     return false;
8317841efbbSZachary Turner 
8327841efbbSZachary Turner   return PyModule_Check(py_obj);
8337841efbbSZachary Turner }
8347841efbbSZachary Turner 
835b9c1b51eSKate Stone void PythonModule::Reset(PyRefType type, PyObject *py_obj) {
8367841efbbSZachary Turner   // Grab the desired reference type so that if we end up rejecting
8377841efbbSZachary Turner   // `py_obj` it still gets decremented if necessary.
8387841efbbSZachary Turner   PythonObject result(type, py_obj);
8397841efbbSZachary Turner 
840b9c1b51eSKate Stone   if (!PythonModule::Check(py_obj)) {
8417841efbbSZachary Turner     PythonObject::Reset();
8427841efbbSZachary Turner     return;
8437841efbbSZachary Turner   }
8447841efbbSZachary Turner 
845b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
846b9c1b51eSKate Stone   // overflow since it calls
8477841efbbSZachary Turner   // back into the virtual implementation.
8487841efbbSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
8497841efbbSZachary Turner }
8507841efbbSZachary Turner 
851b9c1b51eSKate Stone PythonDictionary PythonModule::GetDictionary() const {
8527841efbbSZachary Turner   return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
8537841efbbSZachary Turner }
8547841efbbSZachary Turner 
855b9c1b51eSKate Stone PythonCallable::PythonCallable() : PythonObject() {}
856a1405147SZachary Turner 
857b9c1b51eSKate Stone PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj) {
858a1405147SZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable
859a1405147SZachary Turner }
860a1405147SZachary Turner 
861a1405147SZachary Turner PythonCallable::PythonCallable(const PythonCallable &callable)
862b9c1b51eSKate Stone     : PythonObject(callable) {}
863a1405147SZachary Turner 
864b9c1b51eSKate Stone PythonCallable::~PythonCallable() {}
865a1405147SZachary Turner 
866b9c1b51eSKate Stone bool PythonCallable::Check(PyObject *py_obj) {
867a1405147SZachary Turner   if (!py_obj)
868a1405147SZachary Turner     return false;
869a1405147SZachary Turner 
870a1405147SZachary Turner   return PyCallable_Check(py_obj);
871a1405147SZachary Turner }
872a1405147SZachary Turner 
873b9c1b51eSKate Stone void PythonCallable::Reset(PyRefType type, PyObject *py_obj) {
874a1405147SZachary Turner   // Grab the desired reference type so that if we end up rejecting
875a1405147SZachary Turner   // `py_obj` it still gets decremented if necessary.
876a1405147SZachary Turner   PythonObject result(type, py_obj);
877a1405147SZachary Turner 
878b9c1b51eSKate Stone   if (!PythonCallable::Check(py_obj)) {
879a1405147SZachary Turner     PythonObject::Reset();
880a1405147SZachary Turner     return;
881a1405147SZachary Turner   }
882a1405147SZachary Turner 
883b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
884b9c1b51eSKate Stone   // overflow since it calls
885a1405147SZachary Turner   // back into the virtual implementation.
886a1405147SZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
887a1405147SZachary Turner }
888a1405147SZachary Turner 
889b9c1b51eSKate Stone PythonCallable::ArgInfo PythonCallable::GetNumArguments() const {
890a5d6765cSEnrico Granata   ArgInfo result = {0, false, false, false};
891a1405147SZachary Turner   if (!IsValid())
892b58fb2f4SZachary Turner     return result;
893a1405147SZachary Turner 
894a1405147SZachary Turner   PyObject *py_func_obj = m_py_obj;
895b9c1b51eSKate Stone   if (PyMethod_Check(py_func_obj)) {
896a1405147SZachary Turner     py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
897a5d6765cSEnrico Granata     PythonObject im_self = GetAttributeValue("im_self");
898a5d6765cSEnrico Granata     if (im_self.IsValid() && !im_self.IsNone())
899a5d6765cSEnrico Granata       result.is_bound_method = true;
900b9c1b51eSKate Stone   } else {
901a5d6765cSEnrico Granata     // see if this is a callable object with an __call__ method
902b9c1b51eSKate Stone     if (!PyFunction_Check(py_func_obj)) {
903a5d6765cSEnrico Granata       PythonObject __call__ = GetAttributeValue("__call__");
904b9c1b51eSKate Stone       if (__call__.IsValid()) {
905a5d6765cSEnrico Granata         auto __callable__ = __call__.AsType<PythonCallable>();
906b9c1b51eSKate Stone         if (__callable__.IsValid()) {
907a5d6765cSEnrico Granata           py_func_obj = PyMethod_GET_FUNCTION(__callable__.get());
908a5d6765cSEnrico Granata           PythonObject im_self = GetAttributeValue("im_self");
909a5d6765cSEnrico Granata           if (im_self.IsValid() && !im_self.IsNone())
910a5d6765cSEnrico Granata             result.is_bound_method = true;
911a5d6765cSEnrico Granata         }
912a5d6765cSEnrico Granata       }
913a5d6765cSEnrico Granata     }
914a5d6765cSEnrico Granata   }
915a1405147SZachary Turner 
916a1405147SZachary Turner   if (!py_func_obj)
917b58fb2f4SZachary Turner     return result;
918a1405147SZachary Turner 
919a1405147SZachary Turner   PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(py_func_obj);
920a1405147SZachary Turner   if (!code)
921b58fb2f4SZachary Turner     return result;
922a1405147SZachary Turner 
923b58fb2f4SZachary Turner   result.count = code->co_argcount;
924b58fb2f4SZachary Turner   result.has_varargs = !!(code->co_flags & CO_VARARGS);
925b58fb2f4SZachary Turner   result.has_kwargs = !!(code->co_flags & CO_VARKEYWORDS);
926b58fb2f4SZachary Turner   return result;
927b58fb2f4SZachary Turner }
928b58fb2f4SZachary Turner 
929b9c1b51eSKate Stone PythonObject PythonCallable::operator()() {
930b9c1b51eSKate Stone   return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));
931a1405147SZachary Turner }
932a1405147SZachary Turner 
933b9c1b51eSKate Stone PythonObject PythonCallable::
934b9c1b51eSKate Stone operator()(std::initializer_list<PyObject *> args) {
935a1405147SZachary Turner   PythonTuple arg_tuple(args);
936a1405147SZachary Turner   return PythonObject(PyRefType::Owned,
937a1405147SZachary Turner                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
938a1405147SZachary Turner }
939a1405147SZachary Turner 
940b9c1b51eSKate Stone PythonObject PythonCallable::
941b9c1b51eSKate Stone operator()(std::initializer_list<PythonObject> args) {
942a1405147SZachary Turner   PythonTuple arg_tuple(args);
943a1405147SZachary Turner   return PythonObject(PyRefType::Owned,
944a1405147SZachary Turner                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
945a1405147SZachary Turner }
946a1405147SZachary Turner 
947b9c1b51eSKate Stone PythonFile::PythonFile() : PythonObject() {}
94832064024SZachary Turner 
949b9c1b51eSKate Stone PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); }
9509c40264fSZachary Turner 
951b9c1b51eSKate Stone PythonFile::PythonFile(const char *path, const char *mode) {
952190fadcdSZachary Turner   lldb_private::File file(path, GetOptionsFromMode(mode));
953eda01c31SZachary Turner   Reset(file, mode);
954eda01c31SZachary Turner }
955eda01c31SZachary Turner 
956b9c1b51eSKate Stone PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); }
9579c40264fSZachary Turner 
958b9c1b51eSKate Stone PythonFile::~PythonFile() {}
9599c40264fSZachary Turner 
960b9c1b51eSKate Stone bool PythonFile::Check(PyObject *py_obj) {
9619c40264fSZachary Turner #if PY_MAJOR_VERSION < 3
9629c40264fSZachary Turner   return PyFile_Check(py_obj);
9639c40264fSZachary Turner #else
9649c40264fSZachary Turner   // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
9659c40264fSZachary Turner   // first-class object type anymore.  `PyFile_FromFd` is just a thin wrapper
9669c40264fSZachary Turner   // over `io.open()`, which returns some object derived from `io.IOBase`.
9679c40264fSZachary Turner   // As a result, the only way to detect a file in Python 3 is to check whether
9689c40264fSZachary Turner   // it inherits from `io.IOBase`.  Since it is possible for non-files to also
9699c40264fSZachary Turner   // inherit from `io.IOBase`, we additionally verify that it has the `fileno`
9709c40264fSZachary Turner   // attribute, which should guarantee that it is backed by the file system.
9719c40264fSZachary Turner   PythonObject io_module(PyRefType::Owned, PyImport_ImportModule("io"));
972b9c1b51eSKate Stone   PythonDictionary io_dict(PyRefType::Borrowed,
973b9c1b51eSKate Stone                            PyModule_GetDict(io_module.get()));
9749c40264fSZachary Turner   PythonObject io_base_class = io_dict.GetItemForKey(PythonString("IOBase"));
9759c40264fSZachary Turner 
9769c40264fSZachary Turner   PythonObject object_type(PyRefType::Owned, PyObject_Type(py_obj));
9779c40264fSZachary Turner 
9789c40264fSZachary Turner   if (1 != PyObject_IsSubclass(object_type.get(), io_base_class.get()))
9799c40264fSZachary Turner     return false;
9809c40264fSZachary Turner   if (!object_type.HasAttribute("fileno"))
9819c40264fSZachary Turner     return false;
9829c40264fSZachary Turner 
9839c40264fSZachary Turner   return true;
9849c40264fSZachary Turner #endif
9859c40264fSZachary Turner }
9869c40264fSZachary Turner 
987b9c1b51eSKate Stone void PythonFile::Reset(PyRefType type, PyObject *py_obj) {
9889c40264fSZachary Turner   // Grab the desired reference type so that if we end up rejecting
9899c40264fSZachary Turner   // `py_obj` it still gets decremented if necessary.
9909c40264fSZachary Turner   PythonObject result(type, py_obj);
9919c40264fSZachary Turner 
992b9c1b51eSKate Stone   if (!PythonFile::Check(py_obj)) {
9939c40264fSZachary Turner     PythonObject::Reset();
9949c40264fSZachary Turner     return;
9959c40264fSZachary Turner   }
9969c40264fSZachary Turner 
9979c40264fSZachary Turner   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
9989c40264fSZachary Turner   // overflow since it calls back into the virtual implementation.
9999c40264fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
10009c40264fSZachary Turner }
10019c40264fSZachary Turner 
1002b9c1b51eSKate Stone void PythonFile::Reset(File &file, const char *mode) {
1003b9c1b51eSKate Stone   if (!file.IsValid()) {
100432ac147bSZachary Turner     Reset();
100532ac147bSZachary Turner     return;
100632ac147bSZachary Turner   }
100732ac147bSZachary Turner 
10089c40264fSZachary Turner   char *cmode = const_cast<char *>(mode);
10099c40264fSZachary Turner #if PY_MAJOR_VERSION >= 3
1010b9c1b51eSKate Stone   Reset(PyRefType::Owned, PyFile_FromFd(file.GetDescriptor(), nullptr, cmode,
1011b9c1b51eSKate Stone                                         -1, nullptr, "ignore", nullptr, 0));
10129c40264fSZachary Turner #else
10139c40264fSZachary Turner   // Read through the Python source, doesn't seem to modify these strings
10149c40264fSZachary Turner   Reset(PyRefType::Owned,
1015b9c1b51eSKate Stone         PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode,
1016b9c1b51eSKate Stone                         nullptr));
10179c40264fSZachary Turner #endif
10189c40264fSZachary Turner }
10199c40264fSZachary Turner 
1020b9c1b51eSKate Stone uint32_t PythonFile::GetOptionsFromMode(llvm::StringRef mode) {
1021744959b9SEnrico Granata   if (mode.empty())
1022744959b9SEnrico Granata     return 0;
1023744959b9SEnrico Granata 
1024771ef6d4SMalcolm Parsons   return llvm::StringSwitch<uint32_t>(mode.str())
1025744959b9SEnrico Granata       .Case("r", File::eOpenOptionRead)
1026744959b9SEnrico Granata       .Case("w", File::eOpenOptionWrite)
1027b9c1b51eSKate Stone       .Case("a", File::eOpenOptionWrite | File::eOpenOptionAppend |
1028b9c1b51eSKate Stone                      File::eOpenOptionCanCreate)
1029744959b9SEnrico Granata       .Case("r+", File::eOpenOptionRead | File::eOpenOptionWrite)
1030b9c1b51eSKate Stone       .Case("w+", File::eOpenOptionRead | File::eOpenOptionWrite |
1031b9c1b51eSKate Stone                       File::eOpenOptionCanCreate | File::eOpenOptionTruncate)
1032b9c1b51eSKate Stone       .Case("a+", File::eOpenOptionRead | File::eOpenOptionWrite |
1033b9c1b51eSKate Stone                       File::eOpenOptionAppend | File::eOpenOptionCanCreate)
1034744959b9SEnrico Granata       .Default(0);
1035744959b9SEnrico Granata }
1036744959b9SEnrico Granata 
1037b9c1b51eSKate Stone bool PythonFile::GetUnderlyingFile(File &file) const {
1038eda01c31SZachary Turner   if (!IsValid())
1039eda01c31SZachary Turner     return false;
1040eda01c31SZachary Turner 
1041eda01c31SZachary Turner   file.Close();
1042eda01c31SZachary Turner   // We don't own the file descriptor returned by this function, make sure the
1043eda01c31SZachary Turner   // File object knows about that.
1044eda01c31SZachary Turner   file.SetDescriptor(PyObject_AsFileDescriptor(m_py_obj), false);
1045744959b9SEnrico Granata   PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>();
1046744959b9SEnrico Granata   file.SetOptions(PythonFile::GetOptionsFromMode(py_mode.GetString()));
1047eda01c31SZachary Turner   return file.IsValid();
1048eda01c31SZachary Turner }
1049eda01c31SZachary Turner 
10502c1f46dcSZachary Turner #endif
1051