1bcadb5a3SPavel Labath //===-- PythonDataObjects.cpp -----------------------------------*- C++ -*-===//
22c1f46dcSZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62c1f46dcSZachary Turner //
72c1f46dcSZachary Turner //===----------------------------------------------------------------------===//
82c1f46dcSZachary Turner 
9d68983e3SPavel Labath #ifdef LLDB_DISABLE_PYTHON
10d68983e3SPavel Labath 
11d68983e3SPavel Labath // Python is disabled in this build
12d68983e3SPavel Labath 
13d68983e3SPavel Labath #else
14d68983e3SPavel Labath 
152c1f46dcSZachary Turner #include "PythonDataObjects.h"
162c1f46dcSZachary Turner #include "ScriptInterpreterPython.h"
172c1f46dcSZachary Turner 
182c1f46dcSZachary Turner #include "lldb/Host/File.h"
19190fadcdSZachary Turner #include "lldb/Host/FileSystem.h"
202c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h"
21bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
222c1f46dcSZachary Turner 
239a6c7572SJonas Devlieghere #include "llvm/ADT/StringSwitch.h"
24190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h"
252819136fSMichal Gorny #include "llvm/Support/Errno.h"
26190fadcdSZachary Turner 
272c1f46dcSZachary Turner #include <stdio.h>
282c1f46dcSZachary Turner 
292c1f46dcSZachary Turner using namespace lldb_private;
302c1f46dcSZachary Turner using namespace lldb;
312c1f46dcSZachary Turner 
322783d817SJonas Devlieghere void StructuredPythonObject::Serialize(llvm::json::OStream &s) const {
332783d817SJonas Devlieghere   s.value(llvm::formatv("Python Obj: {0:X}", GetValue()).str());
342c1f46dcSZachary Turner }
352c1f46dcSZachary Turner 
362c1f46dcSZachary Turner // PythonObject
372c1f46dcSZachary Turner 
38b9c1b51eSKate Stone void PythonObject::Dump(Stream &strm) const {
39b9c1b51eSKate Stone   if (m_py_obj) {
402819136fSMichal Gorny     FILE *file = llvm::sys::RetryAfterSignal(nullptr, ::tmpfile);
41b9c1b51eSKate Stone     if (file) {
422c1f46dcSZachary Turner       ::PyObject_Print(m_py_obj, file, 0);
432c1f46dcSZachary Turner       const long length = ftell(file);
44b9c1b51eSKate Stone       if (length) {
452c1f46dcSZachary Turner         ::rewind(file);
462c1f46dcSZachary Turner         std::vector<char> file_contents(length, '\0');
47b9c1b51eSKate Stone         const size_t length_read =
48b9c1b51eSKate Stone             ::fread(file_contents.data(), 1, file_contents.size(), file);
492c1f46dcSZachary Turner         if (length_read > 0)
502c1f46dcSZachary Turner           strm.Write(file_contents.data(), length_read);
512c1f46dcSZachary Turner       }
522c1f46dcSZachary Turner       ::fclose(file);
532c1f46dcSZachary Turner     }
54b9c1b51eSKate Stone   } else
552c1f46dcSZachary Turner     strm.PutCString("NULL");
562c1f46dcSZachary Turner }
572c1f46dcSZachary Turner 
58b9c1b51eSKate Stone PyObjectType PythonObject::GetObjectType() const {
59f8b22f8fSZachary Turner   if (!IsAllocated())
602c1f46dcSZachary Turner     return PyObjectType::None;
612c1f46dcSZachary Turner 
627841efbbSZachary Turner   if (PythonModule::Check(m_py_obj))
637841efbbSZachary Turner     return PyObjectType::Module;
6418426935SZachary Turner   if (PythonList::Check(m_py_obj))
652c1f46dcSZachary Turner     return PyObjectType::List;
66a1405147SZachary Turner   if (PythonTuple::Check(m_py_obj))
67a1405147SZachary Turner     return PyObjectType::Tuple;
6818426935SZachary Turner   if (PythonDictionary::Check(m_py_obj))
692c1f46dcSZachary Turner     return PyObjectType::Dictionary;
7018426935SZachary Turner   if (PythonString::Check(m_py_obj))
7122c8efcdSZachary Turner     return PyObjectType::String;
725a72c02bSZachary Turner #if PY_MAJOR_VERSION >= 3
735a72c02bSZachary Turner   if (PythonBytes::Check(m_py_obj))
745a72c02bSZachary Turner     return PyObjectType::Bytes;
755a72c02bSZachary Turner #endif
76f9d6d204SZachary Turner   if (PythonByteArray::Check(m_py_obj))
77f9d6d204SZachary Turner     return PyObjectType::ByteArray;
78b81d715cSTatyana Krasnukha   if (PythonBoolean::Check(m_py_obj))
79b81d715cSTatyana Krasnukha     return PyObjectType::Boolean;
8018426935SZachary Turner   if (PythonInteger::Check(m_py_obj))
8122c8efcdSZachary Turner     return PyObjectType::Integer;
829c40264fSZachary Turner   if (PythonFile::Check(m_py_obj))
839c40264fSZachary Turner     return PyObjectType::File;
84a1405147SZachary Turner   if (PythonCallable::Check(m_py_obj))
85a1405147SZachary Turner     return PyObjectType::Callable;
862c1f46dcSZachary Turner   return PyObjectType::Unknown;
872c1f46dcSZachary Turner }
882c1f46dcSZachary Turner 
89b9c1b51eSKate Stone PythonString PythonObject::Repr() const {
902c1f46dcSZachary Turner   if (!m_py_obj)
912c1f46dcSZachary Turner     return PythonString();
922c1f46dcSZachary Turner   PyObject *repr = PyObject_Repr(m_py_obj);
932c1f46dcSZachary Turner   if (!repr)
942c1f46dcSZachary Turner     return PythonString();
95f8b22f8fSZachary Turner   return PythonString(PyRefType::Owned, repr);
962c1f46dcSZachary Turner }
972c1f46dcSZachary Turner 
98b9c1b51eSKate Stone PythonString PythonObject::Str() const {
992c1f46dcSZachary Turner   if (!m_py_obj)
1002c1f46dcSZachary Turner     return PythonString();
1012c1f46dcSZachary Turner   PyObject *str = PyObject_Str(m_py_obj);
1022c1f46dcSZachary Turner   if (!str)
1032c1f46dcSZachary Turner     return PythonString();
104f8b22f8fSZachary Turner   return PythonString(PyRefType::Owned, str);
1052c1f46dcSZachary Turner }
1062c1f46dcSZachary Turner 
1077841efbbSZachary Turner PythonObject
108b9c1b51eSKate Stone PythonObject::ResolveNameWithDictionary(llvm::StringRef name,
109b9c1b51eSKate Stone                                         const PythonDictionary &dict) {
110c712bac7SJonas Devlieghere   size_t dot_pos = name.find('.');
111a1405147SZachary Turner   llvm::StringRef piece = name.substr(0, dot_pos);
112a1405147SZachary Turner   PythonObject result = dict.GetItemForKey(PythonString(piece));
113b9c1b51eSKate Stone   if (dot_pos == llvm::StringRef::npos) {
114a1405147SZachary Turner     // There was no dot, we're done.
115a1405147SZachary Turner     return result;
116a1405147SZachary Turner   }
117a1405147SZachary Turner 
118a1405147SZachary Turner   // There was a dot.  The remaining portion of the name should be looked up in
119a1405147SZachary Turner   // the context of the object that was found in the dictionary.
120a1405147SZachary Turner   return result.ResolveName(name.substr(dot_pos + 1));
1217841efbbSZachary Turner }
1227841efbbSZachary Turner 
123b9c1b51eSKate Stone PythonObject PythonObject::ResolveName(llvm::StringRef name) const {
12405097246SAdrian Prantl   // Resolve the name in the context of the specified object.  If, for example,
12505097246SAdrian Prantl   // `this` refers to a PyModule, then this will look for `name` in this
12605097246SAdrian Prantl   // module.  If `this` refers to a PyType, then it will resolve `name` as an
12705097246SAdrian Prantl   // attribute of that type.  If `this` refers to an instance of an object,
12805097246SAdrian Prantl   // then it will resolve `name` as the value of the specified field.
1297841efbbSZachary Turner   //
1307841efbbSZachary Turner   // This function handles dotted names so that, for example, if `m_py_obj`
13105097246SAdrian Prantl   // refers to the `sys` module, and `name` == "path.append", then it will find
13205097246SAdrian Prantl   // the function `sys.path.append`.
1337841efbbSZachary Turner 
134c712bac7SJonas Devlieghere   size_t dot_pos = name.find('.');
135b9c1b51eSKate Stone   if (dot_pos == llvm::StringRef::npos) {
13605097246SAdrian Prantl     // No dots in the name, we should be able to find the value immediately as
13705097246SAdrian Prantl     // an attribute of `m_py_obj`.
1387841efbbSZachary Turner     return GetAttributeValue(name);
1397841efbbSZachary Turner   }
1407841efbbSZachary Turner 
141b9c1b51eSKate Stone   // Look up the first piece of the name, and resolve the rest as a child of
142b9c1b51eSKate Stone   // that.
1437841efbbSZachary Turner   PythonObject parent = ResolveName(name.substr(0, dot_pos));
1447841efbbSZachary Turner   if (!parent.IsAllocated())
1457841efbbSZachary Turner     return PythonObject();
1467841efbbSZachary Turner 
1477841efbbSZachary Turner   // Tail recursion.. should be optimized by the compiler
1487841efbbSZachary Turner   return parent.ResolveName(name.substr(dot_pos + 1));
1497841efbbSZachary Turner }
1507841efbbSZachary Turner 
151b9c1b51eSKate Stone bool PythonObject::HasAttribute(llvm::StringRef attr) const {
1529c40264fSZachary Turner   if (!IsValid())
1539c40264fSZachary Turner     return false;
1549c40264fSZachary Turner   PythonString py_attr(attr);
1559c40264fSZachary Turner   return !!PyObject_HasAttr(m_py_obj, py_attr.get());
1569c40264fSZachary Turner }
1579c40264fSZachary Turner 
158b9c1b51eSKate Stone PythonObject PythonObject::GetAttributeValue(llvm::StringRef attr) const {
1597d6d218eSZachary Turner   if (!IsValid())
1607d6d218eSZachary Turner     return PythonObject();
1617d6d218eSZachary Turner 
1627d6d218eSZachary Turner   PythonString py_attr(attr);
1637d6d218eSZachary Turner   if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
1647d6d218eSZachary Turner     return PythonObject();
1657d6d218eSZachary Turner 
1667d6d218eSZachary Turner   return PythonObject(PyRefType::Owned,
1677d6d218eSZachary Turner                       PyObject_GetAttr(m_py_obj, py_attr.get()));
1687d6d218eSZachary Turner }
1697d6d218eSZachary Turner 
170b9c1b51eSKate Stone bool PythonObject::IsNone() const { return m_py_obj == Py_None; }
171f8b22f8fSZachary Turner 
172b9c1b51eSKate Stone bool PythonObject::IsValid() const { return m_py_obj != nullptr; }
173f8b22f8fSZachary Turner 
174b9c1b51eSKate Stone bool PythonObject::IsAllocated() const { return IsValid() && !IsNone(); }
1752c1f46dcSZachary Turner 
176b9c1b51eSKate Stone StructuredData::ObjectSP PythonObject::CreateStructuredObject() const {
177b9c1b51eSKate Stone   switch (GetObjectType()) {
1782c1f46dcSZachary Turner   case PyObjectType::Dictionary:
179b9c1b51eSKate Stone     return PythonDictionary(PyRefType::Borrowed, m_py_obj)
180b9c1b51eSKate Stone         .CreateStructuredDictionary();
181b81d715cSTatyana Krasnukha   case PyObjectType::Boolean:
182b81d715cSTatyana Krasnukha     return PythonBoolean(PyRefType::Borrowed, m_py_obj)
183b81d715cSTatyana Krasnukha         .CreateStructuredBoolean();
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 // PythonString
204b9c1b51eSKate Stone PythonBytes::PythonBytes() : PythonObject() {}
2055a72c02bSZachary Turner 
206b9c1b51eSKate Stone PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject() {
2075a72c02bSZachary Turner   SetBytes(bytes);
2085a72c02bSZachary Turner }
2095a72c02bSZachary Turner 
210b9c1b51eSKate Stone PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject() {
2115a72c02bSZachary Turner   SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
2125a72c02bSZachary Turner }
2135a72c02bSZachary Turner 
214b9c1b51eSKate Stone PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject() {
2155a72c02bSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
2165a72c02bSZachary Turner }
2175a72c02bSZachary Turner 
218b9c1b51eSKate Stone PythonBytes::~PythonBytes() {}
2195a72c02bSZachary Turner 
220b9c1b51eSKate Stone bool PythonBytes::Check(PyObject *py_obj) {
2215a72c02bSZachary Turner   if (!py_obj)
2225a72c02bSZachary Turner     return false;
223a6682a41SJonas Devlieghere   return PyBytes_Check(py_obj);
2245a72c02bSZachary Turner }
2255a72c02bSZachary Turner 
226b9c1b51eSKate Stone void PythonBytes::Reset(PyRefType type, PyObject *py_obj) {
22705097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
22805097246SAdrian Prantl   // still gets decremented if necessary.
2295a72c02bSZachary Turner   PythonObject result(type, py_obj);
2305a72c02bSZachary Turner 
231b9c1b51eSKate Stone   if (!PythonBytes::Check(py_obj)) {
2325a72c02bSZachary Turner     PythonObject::Reset();
2335a72c02bSZachary Turner     return;
2345a72c02bSZachary Turner   }
2355a72c02bSZachary Turner 
236b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
23705097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
2385a72c02bSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
2395a72c02bSZachary Turner }
2405a72c02bSZachary Turner 
241b9c1b51eSKate Stone llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {
2425a72c02bSZachary Turner   if (!IsValid())
2435a72c02bSZachary Turner     return llvm::ArrayRef<uint8_t>();
2445a72c02bSZachary Turner 
2455a72c02bSZachary Turner   Py_ssize_t size;
2465a72c02bSZachary Turner   char *c;
2475a72c02bSZachary Turner 
2485a72c02bSZachary Turner   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
2495a72c02bSZachary Turner   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
2505a72c02bSZachary Turner }
2515a72c02bSZachary Turner 
252b9c1b51eSKate Stone size_t PythonBytes::GetSize() const {
2535a72c02bSZachary Turner   if (!IsValid())
2545a72c02bSZachary Turner     return 0;
2555a72c02bSZachary Turner   return PyBytes_Size(m_py_obj);
2565a72c02bSZachary Turner }
2575a72c02bSZachary Turner 
258b9c1b51eSKate Stone void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {
2595a72c02bSZachary Turner   const char *data = reinterpret_cast<const char *>(bytes.data());
2605a72c02bSZachary Turner   PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size());
2615a72c02bSZachary Turner   PythonObject::Reset(PyRefType::Owned, py_bytes);
2625a72c02bSZachary Turner }
2635a72c02bSZachary Turner 
264b9c1b51eSKate Stone StructuredData::StringSP PythonBytes::CreateStructuredString() const {
2655a72c02bSZachary Turner   StructuredData::StringSP result(new StructuredData::String);
2665a72c02bSZachary Turner   Py_ssize_t size;
2675a72c02bSZachary Turner   char *c;
2685a72c02bSZachary Turner   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
2695a72c02bSZachary Turner   result->SetValue(std::string(c, size));
2705a72c02bSZachary Turner   return result;
2715a72c02bSZachary Turner }
2725a72c02bSZachary Turner 
273b9c1b51eSKate Stone PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes)
274b9c1b51eSKate Stone     : PythonByteArray(bytes.data(), bytes.size()) {}
275f9d6d204SZachary Turner 
276b9c1b51eSKate Stone PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {
277f9d6d204SZachary Turner   const char *str = reinterpret_cast<const char *>(bytes);
278f9d6d204SZachary Turner   Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length));
279f9d6d204SZachary Turner }
280f9d6d204SZachary Turner 
281b9c1b51eSKate Stone PythonByteArray::PythonByteArray(PyRefType type, PyObject *o) {
282f9d6d204SZachary Turner   Reset(type, o);
283f9d6d204SZachary Turner }
284f9d6d204SZachary Turner 
285b9c1b51eSKate Stone PythonByteArray::PythonByteArray(const PythonBytes &object)
286b9c1b51eSKate Stone     : PythonObject(object) {}
287f9d6d204SZachary Turner 
288b9c1b51eSKate Stone PythonByteArray::~PythonByteArray() {}
289f9d6d204SZachary Turner 
290b9c1b51eSKate Stone bool PythonByteArray::Check(PyObject *py_obj) {
291f9d6d204SZachary Turner   if (!py_obj)
292f9d6d204SZachary Turner     return false;
293a6682a41SJonas Devlieghere   return PyByteArray_Check(py_obj);
294f9d6d204SZachary Turner }
295f9d6d204SZachary Turner 
296b9c1b51eSKate Stone void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) {
29705097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
29805097246SAdrian Prantl   // still gets decremented if necessary.
299f9d6d204SZachary Turner   PythonObject result(type, py_obj);
300f9d6d204SZachary Turner 
301b9c1b51eSKate Stone   if (!PythonByteArray::Check(py_obj)) {
302f9d6d204SZachary Turner     PythonObject::Reset();
303f9d6d204SZachary Turner     return;
304f9d6d204SZachary Turner   }
305f9d6d204SZachary Turner 
306b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
30705097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
308f9d6d204SZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
309f9d6d204SZachary Turner }
310f9d6d204SZachary Turner 
311b9c1b51eSKate Stone llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {
312f9d6d204SZachary Turner   if (!IsValid())
313f9d6d204SZachary Turner     return llvm::ArrayRef<uint8_t>();
314f9d6d204SZachary Turner 
315f9d6d204SZachary Turner   char *c = PyByteArray_AsString(m_py_obj);
316f9d6d204SZachary Turner   size_t size = GetSize();
317f9d6d204SZachary Turner   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
318f9d6d204SZachary Turner }
319f9d6d204SZachary Turner 
320b9c1b51eSKate Stone size_t PythonByteArray::GetSize() const {
321f9d6d204SZachary Turner   if (!IsValid())
322f9d6d204SZachary Turner     return 0;
323f9d6d204SZachary Turner 
324f9d6d204SZachary Turner   return PyByteArray_Size(m_py_obj);
325f9d6d204SZachary Turner }
326f9d6d204SZachary Turner 
327b9c1b51eSKate Stone StructuredData::StringSP PythonByteArray::CreateStructuredString() const {
328f9d6d204SZachary Turner   StructuredData::StringSP result(new StructuredData::String);
329f9d6d204SZachary Turner   llvm::ArrayRef<uint8_t> bytes = GetBytes();
330f9d6d204SZachary Turner   const char *str = reinterpret_cast<const char *>(bytes.data());
331f9d6d204SZachary Turner   result->SetValue(std::string(str, bytes.size()));
332f9d6d204SZachary Turner   return result;
333f9d6d204SZachary Turner }
334f9d6d204SZachary Turner 
3355a72c02bSZachary Turner // PythonString
3362c1f46dcSZachary Turner 
337b9c1b51eSKate Stone PythonString::PythonString(PyRefType type, PyObject *py_obj) : PythonObject() {
338f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
3392c1f46dcSZachary Turner }
3402c1f46dcSZachary Turner 
341b9c1b51eSKate Stone PythonString::PythonString(llvm::StringRef string) : PythonObject() {
34222c8efcdSZachary Turner   SetString(string);
3432c1f46dcSZachary Turner }
3442c1f46dcSZachary Turner 
345b9c1b51eSKate Stone PythonString::PythonString(const char *string) : PythonObject() {
34622c8efcdSZachary Turner   SetString(llvm::StringRef(string));
3472c1f46dcSZachary Turner }
3482c1f46dcSZachary Turner 
349b9c1b51eSKate Stone PythonString::PythonString() : PythonObject() {}
3502c1f46dcSZachary Turner 
351b9c1b51eSKate Stone PythonString::~PythonString() {}
3522c1f46dcSZachary Turner 
353b9c1b51eSKate Stone bool PythonString::Check(PyObject *py_obj) {
35422c8efcdSZachary Turner   if (!py_obj)
35522c8efcdSZachary Turner     return false;
35618426935SZachary Turner 
3577d6d218eSZachary Turner   if (PyUnicode_Check(py_obj))
3587d6d218eSZachary Turner     return true;
3597d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
3607d6d218eSZachary Turner   if (PyString_Check(py_obj))
3617d6d218eSZachary Turner     return true;
36222c8efcdSZachary Turner #endif
3637d6d218eSZachary Turner   return false;
36422c8efcdSZachary Turner }
36522c8efcdSZachary Turner 
366b9c1b51eSKate Stone void PythonString::Reset(PyRefType type, PyObject *py_obj) {
36705097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
36805097246SAdrian Prantl   // still gets decremented if necessary.
369f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
370f8b22f8fSZachary Turner 
371b9c1b51eSKate Stone   if (!PythonString::Check(py_obj)) {
372f8b22f8fSZachary Turner     PythonObject::Reset();
373f8b22f8fSZachary Turner     return;
37422c8efcdSZachary Turner   }
3757d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
3767d6d218eSZachary Turner   // In Python 2, Don't store PyUnicode objects directly, because we need
3777d6d218eSZachary Turner   // access to their underlying character buffers which Python 2 doesn't
3787d6d218eSZachary Turner   // provide.
3797d6d218eSZachary Turner   if (PyUnicode_Check(py_obj))
3807d6d218eSZachary Turner     result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(result.get()));
3817d6d218eSZachary Turner #endif
382b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
38305097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
384f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
3852c1f46dcSZachary Turner }
3862c1f46dcSZachary Turner 
387b9c1b51eSKate Stone llvm::StringRef PythonString::GetString() const {
38818426935SZachary Turner   if (!IsValid())
38918426935SZachary Turner     return llvm::StringRef();
39018426935SZachary Turner 
39122c8efcdSZachary Turner   Py_ssize_t size;
3925457b426SPavel Labath   const char *data;
39318426935SZachary Turner 
39418426935SZachary Turner #if PY_MAJOR_VERSION >= 3
3955457b426SPavel Labath   data = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
39618426935SZachary Turner #else
3975457b426SPavel Labath   char *c;
39818426935SZachary Turner   PyString_AsStringAndSize(m_py_obj, &c, &size);
3995457b426SPavel Labath   data = c;
40018426935SZachary Turner #endif
4015457b426SPavel Labath   return llvm::StringRef(data, size);
40222c8efcdSZachary Turner }
4032c1f46dcSZachary Turner 
404b9c1b51eSKate Stone size_t PythonString::GetSize() const {
405b9c1b51eSKate Stone   if (IsValid()) {
40618426935SZachary Turner #if PY_MAJOR_VERSION >= 3
40718426935SZachary Turner     return PyUnicode_GetSize(m_py_obj);
40818426935SZachary Turner #else
40918426935SZachary Turner     return PyString_Size(m_py_obj);
41018426935SZachary Turner #endif
41118426935SZachary Turner   }
4122c1f46dcSZachary Turner   return 0;
4132c1f46dcSZachary Turner }
4142c1f46dcSZachary Turner 
415b9c1b51eSKate Stone void PythonString::SetString(llvm::StringRef string) {
41622c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
41722c8efcdSZachary Turner   PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
41818426935SZachary Turner   PythonObject::Reset(PyRefType::Owned, unicode);
41922c8efcdSZachary Turner #else
42018426935SZachary Turner   PyObject *str = PyString_FromStringAndSize(string.data(), string.size());
42118426935SZachary Turner   PythonObject::Reset(PyRefType::Owned, str);
42222c8efcdSZachary Turner #endif
4232c1f46dcSZachary Turner }
4242c1f46dcSZachary Turner 
425b9c1b51eSKate Stone StructuredData::StringSP PythonString::CreateStructuredString() const {
4262c1f46dcSZachary Turner   StructuredData::StringSP result(new StructuredData::String);
4272c1f46dcSZachary Turner   result->SetValue(GetString());
4282c1f46dcSZachary Turner   return result;
4292c1f46dcSZachary Turner }
4302c1f46dcSZachary Turner 
4312c1f46dcSZachary Turner // PythonInteger
4322c1f46dcSZachary Turner 
433b9c1b51eSKate Stone PythonInteger::PythonInteger() : PythonObject() {}
4347d6d218eSZachary Turner 
435f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
436b9c1b51eSKate Stone     : PythonObject() {
437f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
4382c1f46dcSZachary Turner }
4392c1f46dcSZachary Turner 
440b9c1b51eSKate Stone PythonInteger::PythonInteger(int64_t value) : PythonObject() {
4412c1f46dcSZachary Turner   SetInteger(value);
4422c1f46dcSZachary Turner }
4432c1f46dcSZachary Turner 
444b9c1b51eSKate Stone PythonInteger::~PythonInteger() {}
4452c1f46dcSZachary Turner 
446b9c1b51eSKate Stone bool PythonInteger::Check(PyObject *py_obj) {
44722c8efcdSZachary Turner   if (!py_obj)
44822c8efcdSZachary Turner     return false;
44922c8efcdSZachary Turner 
45022c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
45105097246SAdrian Prantl   // Python 3 does not have PyInt_Check.  There is only one type of integral
45205097246SAdrian Prantl   // value, long.
45322c8efcdSZachary Turner   return PyLong_Check(py_obj);
45422c8efcdSZachary Turner #else
45522c8efcdSZachary Turner   return PyLong_Check(py_obj) || PyInt_Check(py_obj);
45622c8efcdSZachary Turner #endif
4572c1f46dcSZachary Turner }
4582c1f46dcSZachary Turner 
459b9c1b51eSKate Stone void PythonInteger::Reset(PyRefType type, PyObject *py_obj) {
46005097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
46105097246SAdrian Prantl   // still gets decremented if necessary.
462f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
463f8b22f8fSZachary Turner 
464b9c1b51eSKate Stone   if (!PythonInteger::Check(py_obj)) {
465f8b22f8fSZachary Turner     PythonObject::Reset();
466f8b22f8fSZachary Turner     return;
46722c8efcdSZachary Turner   }
46822c8efcdSZachary Turner 
46922c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3
47005097246SAdrian Prantl   // Always store this as a PyLong, which makes interoperability between Python
47105097246SAdrian Prantl   // 2.x and Python 3.x easier.  This is only necessary in 2.x, since 3.x
47205097246SAdrian Prantl   // doesn't even have a PyInt.
473b9c1b51eSKate Stone   if (PyInt_Check(py_obj)) {
474f8b22f8fSZachary Turner     // Since we converted the original object to a different type, the new
47505097246SAdrian Prantl     // object is an owned object regardless of the ownership semantics
47605097246SAdrian Prantl     // requested by the user.
477f8b22f8fSZachary Turner     result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
47822c8efcdSZachary Turner   }
47922c8efcdSZachary Turner #endif
48022c8efcdSZachary Turner 
481b9c1b51eSKate Stone   assert(PyLong_Check(result.get()) &&
482b9c1b51eSKate Stone          "Couldn't get a PyLong from this PyObject");
48322c8efcdSZachary Turner 
484b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
48505097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
486f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
4872c1f46dcSZachary Turner }
4882c1f46dcSZachary Turner 
489b9c1b51eSKate Stone int64_t PythonInteger::GetInteger() const {
490b9c1b51eSKate Stone   if (m_py_obj) {
491b9c1b51eSKate Stone     assert(PyLong_Check(m_py_obj) &&
492b9c1b51eSKate Stone            "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
49322c8efcdSZachary Turner 
494008ec446SGreg Clayton     int overflow = 0;
495008ec446SGreg Clayton     int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
496b9c1b51eSKate Stone     if (overflow != 0) {
49705097246SAdrian Prantl       // We got an integer that overflows, like 18446744072853913392L we can't
49805097246SAdrian Prantl       // use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we
49905097246SAdrian Prantl       // use the unsigned long long it will work as expected.
500008ec446SGreg Clayton       const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
5014f730dc7SIlia K       result = static_cast<int64_t>(uval);
502008ec446SGreg Clayton     }
503008ec446SGreg Clayton     return result;
5042c1f46dcSZachary Turner   }
5052c1f46dcSZachary Turner   return UINT64_MAX;
5062c1f46dcSZachary Turner }
5072c1f46dcSZachary Turner 
508b9c1b51eSKate Stone void PythonInteger::SetInteger(int64_t value) {
509f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
5102c1f46dcSZachary Turner }
5112c1f46dcSZachary Turner 
512b9c1b51eSKate Stone StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
5132c1f46dcSZachary Turner   StructuredData::IntegerSP result(new StructuredData::Integer);
5142c1f46dcSZachary Turner   result->SetValue(GetInteger());
5152c1f46dcSZachary Turner   return result;
5162c1f46dcSZachary Turner }
5172c1f46dcSZachary Turner 
518b81d715cSTatyana Krasnukha // PythonBoolean
519b81d715cSTatyana Krasnukha 
520b81d715cSTatyana Krasnukha PythonBoolean::PythonBoolean(PyRefType type, PyObject *py_obj)
521b81d715cSTatyana Krasnukha     : PythonObject() {
522b81d715cSTatyana Krasnukha   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a boolean type
523b81d715cSTatyana Krasnukha }
524b81d715cSTatyana Krasnukha 
525b81d715cSTatyana Krasnukha PythonBoolean::PythonBoolean(bool value) {
526b81d715cSTatyana Krasnukha   SetValue(value);
527b81d715cSTatyana Krasnukha }
528b81d715cSTatyana Krasnukha 
529b81d715cSTatyana Krasnukha bool PythonBoolean::Check(PyObject *py_obj) {
530b81d715cSTatyana Krasnukha   return py_obj ? PyBool_Check(py_obj) : false;
531b81d715cSTatyana Krasnukha }
532b81d715cSTatyana Krasnukha 
533b81d715cSTatyana Krasnukha void PythonBoolean::Reset(PyRefType type, PyObject *py_obj) {
534b81d715cSTatyana Krasnukha   // Grab the desired reference type so that if we end up rejecting `py_obj` it
535b81d715cSTatyana Krasnukha   // still gets decremented if necessary.
536b81d715cSTatyana Krasnukha   PythonObject result(type, py_obj);
537b81d715cSTatyana Krasnukha 
538b81d715cSTatyana Krasnukha   if (!PythonBoolean::Check(py_obj)) {
539b81d715cSTatyana Krasnukha     PythonObject::Reset();
540b81d715cSTatyana Krasnukha     return;
541b81d715cSTatyana Krasnukha   }
542b81d715cSTatyana Krasnukha 
543b81d715cSTatyana Krasnukha   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
544b81d715cSTatyana Krasnukha   // overflow since it calls back into the virtual implementation.
545b81d715cSTatyana Krasnukha   PythonObject::Reset(PyRefType::Borrowed, result.get());
546b81d715cSTatyana Krasnukha }
547b81d715cSTatyana Krasnukha 
548b81d715cSTatyana Krasnukha bool PythonBoolean::GetValue() const {
549b81d715cSTatyana Krasnukha   return m_py_obj ? PyObject_IsTrue(m_py_obj) : false;
550b81d715cSTatyana Krasnukha }
551b81d715cSTatyana Krasnukha 
552b81d715cSTatyana Krasnukha void PythonBoolean::SetValue(bool value) {
553b81d715cSTatyana Krasnukha   PythonObject::Reset(PyRefType::Owned, PyBool_FromLong(value));
554b81d715cSTatyana Krasnukha }
555b81d715cSTatyana Krasnukha 
556b81d715cSTatyana Krasnukha StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const {
557b81d715cSTatyana Krasnukha   StructuredData::BooleanSP result(new StructuredData::Boolean);
558b81d715cSTatyana Krasnukha   result->SetValue(GetValue());
559b81d715cSTatyana Krasnukha   return result;
560b81d715cSTatyana Krasnukha }
561b81d715cSTatyana Krasnukha 
5622c1f46dcSZachary Turner // PythonList
5632c1f46dcSZachary Turner 
564b9c1b51eSKate Stone PythonList::PythonList(PyInitialValue value) : PythonObject() {
565f8b22f8fSZachary Turner   if (value == PyInitialValue::Empty)
566f8b22f8fSZachary Turner     Reset(PyRefType::Owned, PyList_New(0));
5672c1f46dcSZachary Turner }
5682c1f46dcSZachary Turner 
569b9c1b51eSKate Stone PythonList::PythonList(int list_size) : PythonObject() {
57087f47729SZachary Turner   Reset(PyRefType::Owned, PyList_New(list_size));
57187f47729SZachary Turner }
57287f47729SZachary Turner 
573b9c1b51eSKate Stone PythonList::PythonList(PyRefType type, PyObject *py_obj) : PythonObject() {
574f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
5752c1f46dcSZachary Turner }
5762c1f46dcSZachary Turner 
577b9c1b51eSKate Stone PythonList::~PythonList() {}
5782c1f46dcSZachary Turner 
579b9c1b51eSKate Stone bool PythonList::Check(PyObject *py_obj) {
58022c8efcdSZachary Turner   if (!py_obj)
58122c8efcdSZachary Turner     return false;
58222c8efcdSZachary Turner   return PyList_Check(py_obj);
58322c8efcdSZachary Turner }
58422c8efcdSZachary Turner 
585b9c1b51eSKate Stone void PythonList::Reset(PyRefType type, PyObject *py_obj) {
58605097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
58705097246SAdrian Prantl   // still gets decremented if necessary.
588f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
589f8b22f8fSZachary Turner 
590b9c1b51eSKate Stone   if (!PythonList::Check(py_obj)) {
591f8b22f8fSZachary Turner     PythonObject::Reset();
592f8b22f8fSZachary Turner     return;
59322c8efcdSZachary Turner   }
59422c8efcdSZachary Turner 
595b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
59605097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
597f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
5982c1f46dcSZachary Turner }
5992c1f46dcSZachary Turner 
600b9c1b51eSKate Stone uint32_t PythonList::GetSize() const {
601f8b22f8fSZachary Turner   if (IsValid())
6022c1f46dcSZachary Turner     return PyList_GET_SIZE(m_py_obj);
6032c1f46dcSZachary Turner   return 0;
6042c1f46dcSZachary Turner }
6052c1f46dcSZachary Turner 
606b9c1b51eSKate Stone PythonObject PythonList::GetItemAtIndex(uint32_t index) const {
607f8b22f8fSZachary Turner   if (IsValid())
608f8b22f8fSZachary Turner     return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
6092c1f46dcSZachary Turner   return PythonObject();
6102c1f46dcSZachary Turner }
6112c1f46dcSZachary Turner 
612b9c1b51eSKate Stone void PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) {
613b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
614f8b22f8fSZachary Turner     // PyList_SetItem is documented to "steal" a reference, so we need to
615f8b22f8fSZachary Turner     // convert it to an owned reference by incrementing it.
616f8b22f8fSZachary Turner     Py_INCREF(object.get());
6172c1f46dcSZachary Turner     PyList_SetItem(m_py_obj, index, object.get());
6182c1f46dcSZachary Turner   }
619f8b22f8fSZachary Turner }
6202c1f46dcSZachary Turner 
621b9c1b51eSKate Stone void PythonList::AppendItem(const PythonObject &object) {
622b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
623f8b22f8fSZachary Turner     // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
624f8b22f8fSZachary Turner     // here like we do with `PyList_SetItem`.
6252c1f46dcSZachary Turner     PyList_Append(m_py_obj, object.get());
6262c1f46dcSZachary Turner   }
627f8b22f8fSZachary Turner }
6282c1f46dcSZachary Turner 
629b9c1b51eSKate Stone StructuredData::ArraySP PythonList::CreateStructuredArray() const {
6302c1f46dcSZachary Turner   StructuredData::ArraySP result(new StructuredData::Array);
6312c1f46dcSZachary Turner   uint32_t count = GetSize();
632b9c1b51eSKate Stone   for (uint32_t i = 0; i < count; ++i) {
6332c1f46dcSZachary Turner     PythonObject obj = GetItemAtIndex(i);
6342c1f46dcSZachary Turner     result->AddItem(obj.CreateStructuredObject());
6352c1f46dcSZachary Turner   }
6362c1f46dcSZachary Turner   return result;
6372c1f46dcSZachary Turner }
6382c1f46dcSZachary Turner 
639a1405147SZachary Turner // PythonTuple
640a1405147SZachary Turner 
641b9c1b51eSKate Stone PythonTuple::PythonTuple(PyInitialValue value) : PythonObject() {
642a1405147SZachary Turner   if (value == PyInitialValue::Empty)
643a1405147SZachary Turner     Reset(PyRefType::Owned, PyTuple_New(0));
644a1405147SZachary Turner }
645a1405147SZachary Turner 
646b9c1b51eSKate Stone PythonTuple::PythonTuple(int tuple_size) : PythonObject() {
647a1405147SZachary Turner   Reset(PyRefType::Owned, PyTuple_New(tuple_size));
648a1405147SZachary Turner }
649a1405147SZachary Turner 
650b9c1b51eSKate Stone PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj) : PythonObject() {
651a1405147SZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple
652a1405147SZachary Turner }
653a1405147SZachary Turner 
654b9c1b51eSKate Stone PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
655a1405147SZachary Turner   m_py_obj = PyTuple_New(objects.size());
656a1405147SZachary Turner 
657a1405147SZachary Turner   uint32_t idx = 0;
658b9c1b51eSKate Stone   for (auto object : objects) {
659a1405147SZachary Turner     if (object.IsValid())
660a1405147SZachary Turner       SetItemAtIndex(idx, object);
661a1405147SZachary Turner     idx++;
662a1405147SZachary Turner   }
663a1405147SZachary Turner }
664a1405147SZachary Turner 
665b9c1b51eSKate Stone PythonTuple::PythonTuple(std::initializer_list<PyObject *> objects) {
666a1405147SZachary Turner   m_py_obj = PyTuple_New(objects.size());
667a1405147SZachary Turner 
668a1405147SZachary Turner   uint32_t idx = 0;
669b9c1b51eSKate Stone   for (auto py_object : objects) {
670a1405147SZachary Turner     PythonObject object(PyRefType::Borrowed, py_object);
671a1405147SZachary Turner     if (object.IsValid())
672a1405147SZachary Turner       SetItemAtIndex(idx, object);
673a1405147SZachary Turner     idx++;
674a1405147SZachary Turner   }
675a1405147SZachary Turner }
676a1405147SZachary Turner 
677b9c1b51eSKate Stone PythonTuple::~PythonTuple() {}
678a1405147SZachary Turner 
679b9c1b51eSKate Stone bool PythonTuple::Check(PyObject *py_obj) {
680a1405147SZachary Turner   if (!py_obj)
681a1405147SZachary Turner     return false;
682a1405147SZachary Turner   return PyTuple_Check(py_obj);
683a1405147SZachary Turner }
684a1405147SZachary Turner 
685b9c1b51eSKate Stone void PythonTuple::Reset(PyRefType type, PyObject *py_obj) {
68605097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
68705097246SAdrian Prantl   // still gets decremented if necessary.
688a1405147SZachary Turner   PythonObject result(type, py_obj);
689a1405147SZachary Turner 
690b9c1b51eSKate Stone   if (!PythonTuple::Check(py_obj)) {
691a1405147SZachary Turner     PythonObject::Reset();
692a1405147SZachary Turner     return;
693a1405147SZachary Turner   }
694a1405147SZachary Turner 
695b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
69605097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
697a1405147SZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
698a1405147SZachary Turner }
699a1405147SZachary Turner 
700b9c1b51eSKate Stone uint32_t PythonTuple::GetSize() const {
701a1405147SZachary Turner   if (IsValid())
702a1405147SZachary Turner     return PyTuple_GET_SIZE(m_py_obj);
703a1405147SZachary Turner   return 0;
704a1405147SZachary Turner }
705a1405147SZachary Turner 
706b9c1b51eSKate Stone PythonObject PythonTuple::GetItemAtIndex(uint32_t index) const {
707a1405147SZachary Turner   if (IsValid())
708a1405147SZachary Turner     return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
709a1405147SZachary Turner   return PythonObject();
710a1405147SZachary Turner }
711a1405147SZachary Turner 
712b9c1b51eSKate Stone void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) {
713b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
714a1405147SZachary Turner     // PyTuple_SetItem is documented to "steal" a reference, so we need to
715a1405147SZachary Turner     // convert it to an owned reference by incrementing it.
716a1405147SZachary Turner     Py_INCREF(object.get());
717a1405147SZachary Turner     PyTuple_SetItem(m_py_obj, index, object.get());
718a1405147SZachary Turner   }
719a1405147SZachary Turner }
720a1405147SZachary Turner 
721b9c1b51eSKate Stone StructuredData::ArraySP PythonTuple::CreateStructuredArray() const {
722a1405147SZachary Turner   StructuredData::ArraySP result(new StructuredData::Array);
723a1405147SZachary Turner   uint32_t count = GetSize();
724b9c1b51eSKate Stone   for (uint32_t i = 0; i < count; ++i) {
725a1405147SZachary Turner     PythonObject obj = GetItemAtIndex(i);
726a1405147SZachary Turner     result->AddItem(obj.CreateStructuredObject());
727a1405147SZachary Turner   }
728a1405147SZachary Turner   return result;
729a1405147SZachary Turner }
730a1405147SZachary Turner 
7312c1f46dcSZachary Turner // PythonDictionary
7322c1f46dcSZachary Turner 
733b9c1b51eSKate Stone PythonDictionary::PythonDictionary(PyInitialValue value) : PythonObject() {
734f8b22f8fSZachary Turner   if (value == PyInitialValue::Empty)
735f8b22f8fSZachary Turner     Reset(PyRefType::Owned, PyDict_New());
7362c1f46dcSZachary Turner }
7372c1f46dcSZachary Turner 
738f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
739b9c1b51eSKate Stone     : PythonObject() {
740f8b22f8fSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
7412c1f46dcSZachary Turner }
7422c1f46dcSZachary Turner 
743b9c1b51eSKate Stone PythonDictionary::~PythonDictionary() {}
7442c1f46dcSZachary Turner 
745b9c1b51eSKate Stone bool PythonDictionary::Check(PyObject *py_obj) {
74622c8efcdSZachary Turner   if (!py_obj)
74722c8efcdSZachary Turner     return false;
74822c8efcdSZachary Turner 
74922c8efcdSZachary Turner   return PyDict_Check(py_obj);
75022c8efcdSZachary Turner }
75122c8efcdSZachary Turner 
752b9c1b51eSKate Stone void PythonDictionary::Reset(PyRefType type, PyObject *py_obj) {
75305097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
75405097246SAdrian Prantl   // still gets decremented if necessary.
755f8b22f8fSZachary Turner   PythonObject result(type, py_obj);
756f8b22f8fSZachary Turner 
757b9c1b51eSKate Stone   if (!PythonDictionary::Check(py_obj)) {
758f8b22f8fSZachary Turner     PythonObject::Reset();
759f8b22f8fSZachary Turner     return;
76022c8efcdSZachary Turner   }
76122c8efcdSZachary Turner 
762b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
76305097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
764f8b22f8fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
7652c1f46dcSZachary Turner }
7662c1f46dcSZachary Turner 
767b9c1b51eSKate Stone uint32_t PythonDictionary::GetSize() const {
768f8b22f8fSZachary Turner   if (IsValid())
7692c1f46dcSZachary Turner     return PyDict_Size(m_py_obj);
7702c1f46dcSZachary Turner   return 0;
7712c1f46dcSZachary Turner }
7722c1f46dcSZachary Turner 
773b9c1b51eSKate Stone PythonList PythonDictionary::GetKeys() const {
774f8b22f8fSZachary Turner   if (IsValid())
775f8b22f8fSZachary Turner     return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
776f8b22f8fSZachary Turner   return PythonList(PyInitialValue::Invalid);
7772c1f46dcSZachary Turner }
7782c1f46dcSZachary Turner 
779b9c1b51eSKate Stone PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {
780f8b22f8fSZachary Turner   if (IsAllocated() && key.IsValid())
781b9c1b51eSKate Stone     return PythonObject(PyRefType::Borrowed,
782b9c1b51eSKate Stone                         PyDict_GetItem(m_py_obj, key.get()));
7832c1f46dcSZachary Turner   return PythonObject();
7842c1f46dcSZachary Turner }
7852c1f46dcSZachary Turner 
786b9c1b51eSKate Stone void PythonDictionary::SetItemForKey(const PythonObject &key,
787b9c1b51eSKate Stone                                      const PythonObject &value) {
788f8b22f8fSZachary Turner   if (IsAllocated() && key.IsValid() && value.IsValid())
7892c1f46dcSZachary Turner     PyDict_SetItem(m_py_obj, key.get(), value.get());
7902c1f46dcSZachary Turner }
7912c1f46dcSZachary Turner 
7922c1f46dcSZachary Turner StructuredData::DictionarySP
793b9c1b51eSKate Stone PythonDictionary::CreateStructuredDictionary() const {
7942c1f46dcSZachary Turner   StructuredData::DictionarySP result(new StructuredData::Dictionary);
7952c1f46dcSZachary Turner   PythonList keys(GetKeys());
7962c1f46dcSZachary Turner   uint32_t num_keys = keys.GetSize();
797b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_keys; ++i) {
7982c1f46dcSZachary Turner     PythonObject key = keys.GetItemAtIndex(i);
7992c1f46dcSZachary Turner     PythonObject value = GetItemForKey(key);
8002c1f46dcSZachary Turner     StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
801f8b22f8fSZachary Turner     result->AddItem(key.Str().GetString(), structured_value);
8022c1f46dcSZachary Turner   }
8032c1f46dcSZachary Turner   return result;
8042c1f46dcSZachary Turner }
8052c1f46dcSZachary Turner 
806b9c1b51eSKate Stone PythonModule::PythonModule() : PythonObject() {}
8077841efbbSZachary Turner 
808b9c1b51eSKate Stone PythonModule::PythonModule(PyRefType type, PyObject *py_obj) {
8097841efbbSZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
8107841efbbSZachary Turner }
8117841efbbSZachary Turner 
812b9c1b51eSKate Stone PythonModule::~PythonModule() {}
8137841efbbSZachary Turner 
814b9c1b51eSKate Stone PythonModule PythonModule::BuiltinsModule() {
815a1405147SZachary Turner #if PY_MAJOR_VERSION >= 3
816a1405147SZachary Turner   return AddModule("builtins");
817a1405147SZachary Turner #else
818a1405147SZachary Turner   return AddModule("__builtin__");
819a1405147SZachary Turner #endif
820a1405147SZachary Turner }
821a1405147SZachary Turner 
822b9c1b51eSKate Stone PythonModule PythonModule::MainModule() { return AddModule("__main__"); }
823a1405147SZachary Turner 
824b9c1b51eSKate Stone PythonModule PythonModule::AddModule(llvm::StringRef module) {
825a1405147SZachary Turner   std::string str = module.str();
826a1405147SZachary Turner   return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
8277841efbbSZachary Turner }
8287841efbbSZachary Turner 
829b9c1b51eSKate Stone PythonModule PythonModule::ImportModule(llvm::StringRef module) {
8302419f1d5SZachary Turner   std::string str = module.str();
8312419f1d5SZachary Turner   return PythonModule(PyRefType::Owned, PyImport_ImportModule(str.c_str()));
8322419f1d5SZachary Turner }
8332419f1d5SZachary Turner 
834b9c1b51eSKate Stone bool PythonModule::Check(PyObject *py_obj) {
8357841efbbSZachary Turner   if (!py_obj)
8367841efbbSZachary Turner     return false;
8377841efbbSZachary Turner 
8387841efbbSZachary Turner   return PyModule_Check(py_obj);
8397841efbbSZachary Turner }
8407841efbbSZachary Turner 
841b9c1b51eSKate Stone void PythonModule::Reset(PyRefType type, PyObject *py_obj) {
84205097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
84305097246SAdrian Prantl   // still gets decremented if necessary.
8447841efbbSZachary Turner   PythonObject result(type, py_obj);
8457841efbbSZachary Turner 
846b9c1b51eSKate Stone   if (!PythonModule::Check(py_obj)) {
8477841efbbSZachary Turner     PythonObject::Reset();
8487841efbbSZachary Turner     return;
8497841efbbSZachary Turner   }
8507841efbbSZachary Turner 
851b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
85205097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
8537841efbbSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
8547841efbbSZachary Turner }
8557841efbbSZachary Turner 
856b9c1b51eSKate Stone PythonDictionary PythonModule::GetDictionary() const {
8577841efbbSZachary Turner   return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
8587841efbbSZachary Turner }
8597841efbbSZachary Turner 
860b9c1b51eSKate Stone PythonCallable::PythonCallable() : PythonObject() {}
861a1405147SZachary Turner 
862b9c1b51eSKate Stone PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj) {
863a1405147SZachary Turner   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable
864a1405147SZachary Turner }
865a1405147SZachary Turner 
866b9c1b51eSKate Stone PythonCallable::~PythonCallable() {}
867a1405147SZachary Turner 
868b9c1b51eSKate Stone bool PythonCallable::Check(PyObject *py_obj) {
869a1405147SZachary Turner   if (!py_obj)
870a1405147SZachary Turner     return false;
871a1405147SZachary Turner 
872a1405147SZachary Turner   return PyCallable_Check(py_obj);
873a1405147SZachary Turner }
874a1405147SZachary Turner 
875b9c1b51eSKate Stone void PythonCallable::Reset(PyRefType type, PyObject *py_obj) {
87605097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
87705097246SAdrian Prantl   // still gets decremented if necessary.
878a1405147SZachary Turner   PythonObject result(type, py_obj);
879a1405147SZachary Turner 
880b9c1b51eSKate Stone   if (!PythonCallable::Check(py_obj)) {
881a1405147SZachary Turner     PythonObject::Reset();
882a1405147SZachary Turner     return;
883a1405147SZachary Turner   }
884a1405147SZachary Turner 
885b9c1b51eSKate Stone   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
88605097246SAdrian Prantl   // overflow since it calls back into the virtual implementation.
887a1405147SZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
888a1405147SZachary Turner }
889a1405147SZachary Turner 
890b9c1b51eSKate Stone PythonCallable::ArgInfo PythonCallable::GetNumArguments() const {
891a5d6765cSEnrico Granata   ArgInfo result = {0, false, false, false};
892a1405147SZachary Turner   if (!IsValid())
893b58fb2f4SZachary Turner     return result;
894a1405147SZachary Turner 
895a1405147SZachary Turner   PyObject *py_func_obj = m_py_obj;
896b9c1b51eSKate Stone   if (PyMethod_Check(py_func_obj)) {
897a1405147SZachary Turner     py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
898a5d6765cSEnrico Granata     PythonObject im_self = GetAttributeValue("im_self");
899a5d6765cSEnrico Granata     if (im_self.IsValid() && !im_self.IsNone())
900a5d6765cSEnrico Granata       result.is_bound_method = true;
901b9c1b51eSKate Stone   } else {
902a5d6765cSEnrico Granata     // see if this is a callable object with an __call__ method
903b9c1b51eSKate Stone     if (!PyFunction_Check(py_func_obj)) {
904a5d6765cSEnrico Granata       PythonObject __call__ = GetAttributeValue("__call__");
905b9c1b51eSKate Stone       if (__call__.IsValid()) {
906a5d6765cSEnrico Granata         auto __callable__ = __call__.AsType<PythonCallable>();
907b9c1b51eSKate Stone         if (__callable__.IsValid()) {
908a5d6765cSEnrico Granata           py_func_obj = PyMethod_GET_FUNCTION(__callable__.get());
909a5d6765cSEnrico Granata           PythonObject im_self = GetAttributeValue("im_self");
910a5d6765cSEnrico Granata           if (im_self.IsValid() && !im_self.IsNone())
911a5d6765cSEnrico Granata             result.is_bound_method = true;
912a5d6765cSEnrico Granata         }
913a5d6765cSEnrico Granata       }
914a5d6765cSEnrico Granata     }
915a5d6765cSEnrico Granata   }
916a1405147SZachary Turner 
917a1405147SZachary Turner   if (!py_func_obj)
918b58fb2f4SZachary Turner     return result;
919a1405147SZachary Turner 
920a1405147SZachary Turner   PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(py_func_obj);
921a1405147SZachary Turner   if (!code)
922b58fb2f4SZachary Turner     return result;
923a1405147SZachary Turner 
924b58fb2f4SZachary Turner   result.count = code->co_argcount;
925b58fb2f4SZachary Turner   result.has_varargs = !!(code->co_flags & CO_VARARGS);
926b58fb2f4SZachary Turner   result.has_kwargs = !!(code->co_flags & CO_VARKEYWORDS);
927b58fb2f4SZachary Turner   return result;
928b58fb2f4SZachary Turner }
929b58fb2f4SZachary Turner 
930b9c1b51eSKate Stone PythonObject PythonCallable::operator()() {
931b9c1b51eSKate Stone   return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));
932a1405147SZachary Turner }
933a1405147SZachary Turner 
934b9c1b51eSKate Stone PythonObject PythonCallable::
935b9c1b51eSKate Stone operator()(std::initializer_list<PyObject *> args) {
936a1405147SZachary Turner   PythonTuple arg_tuple(args);
937a1405147SZachary Turner   return PythonObject(PyRefType::Owned,
938a1405147SZachary Turner                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
939a1405147SZachary Turner }
940a1405147SZachary Turner 
941b9c1b51eSKate Stone PythonObject PythonCallable::
942b9c1b51eSKate Stone operator()(std::initializer_list<PythonObject> args) {
943a1405147SZachary Turner   PythonTuple arg_tuple(args);
944a1405147SZachary Turner   return PythonObject(PyRefType::Owned,
945a1405147SZachary Turner                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
946a1405147SZachary Turner }
947a1405147SZachary Turner 
948b9c1b51eSKate Stone PythonFile::PythonFile() : PythonObject() {}
94932064024SZachary Turner 
950b9c1b51eSKate Stone PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); }
9519c40264fSZachary Turner 
952b9c1b51eSKate Stone PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); }
9539c40264fSZachary Turner 
954b9c1b51eSKate Stone PythonFile::~PythonFile() {}
9559c40264fSZachary Turner 
956b9c1b51eSKate Stone bool PythonFile::Check(PyObject *py_obj) {
9579c40264fSZachary Turner #if PY_MAJOR_VERSION < 3
95823502721SJason Molenda   return PyFile_Check(py_obj);
95923502721SJason Molenda #else
9609c40264fSZachary Turner   // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
9619c40264fSZachary Turner   // first-class object type anymore.  `PyFile_FromFd` is just a thin wrapper
96205097246SAdrian Prantl   // over `io.open()`, which returns some object derived from `io.IOBase`. As a
96305097246SAdrian Prantl   // result, the only way to detect a file in Python 3 is to check whether it
96405097246SAdrian Prantl   // inherits from `io.IOBase`.  Since it is possible for non-files to also
9659c40264fSZachary Turner   // inherit from `io.IOBase`, we additionally verify that it has the `fileno`
9669c40264fSZachary Turner   // attribute, which should guarantee that it is backed by the file system.
9679c40264fSZachary Turner   PythonObject io_module(PyRefType::Owned, PyImport_ImportModule("io"));
968b9c1b51eSKate Stone   PythonDictionary io_dict(PyRefType::Borrowed,
969b9c1b51eSKate Stone                            PyModule_GetDict(io_module.get()));
9709c40264fSZachary Turner   PythonObject io_base_class = io_dict.GetItemForKey(PythonString("IOBase"));
9719c40264fSZachary Turner 
9729c40264fSZachary Turner   PythonObject object_type(PyRefType::Owned, PyObject_Type(py_obj));
9739c40264fSZachary Turner 
9749c40264fSZachary Turner   if (1 != PyObject_IsSubclass(object_type.get(), io_base_class.get()))
9759c40264fSZachary Turner     return false;
9769c40264fSZachary Turner   if (!object_type.HasAttribute("fileno"))
9779c40264fSZachary Turner     return false;
9789c40264fSZachary Turner 
9799c40264fSZachary Turner   return true;
98023502721SJason Molenda #endif
9819c40264fSZachary Turner }
9829c40264fSZachary Turner 
983b9c1b51eSKate Stone void PythonFile::Reset(PyRefType type, PyObject *py_obj) {
98405097246SAdrian Prantl   // Grab the desired reference type so that if we end up rejecting `py_obj` it
98505097246SAdrian Prantl   // still gets decremented if necessary.
9869c40264fSZachary Turner   PythonObject result(type, py_obj);
9879c40264fSZachary Turner 
98823502721SJason Molenda   if (!PythonFile::Check(py_obj)) {
9899c40264fSZachary Turner     PythonObject::Reset();
9909c40264fSZachary Turner     return;
9919c40264fSZachary Turner   }
9929c40264fSZachary Turner 
9939c40264fSZachary Turner   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
9949c40264fSZachary Turner   // overflow since it calls back into the virtual implementation.
9959c40264fSZachary Turner   PythonObject::Reset(PyRefType::Borrowed, result.get());
9969c40264fSZachary Turner }
9979c40264fSZachary Turner 
998b9c1b51eSKate Stone void PythonFile::Reset(File &file, const char *mode) {
999b9c1b51eSKate Stone   if (!file.IsValid()) {
100032ac147bSZachary Turner     Reset();
100132ac147bSZachary Turner     return;
100232ac147bSZachary Turner   }
100332ac147bSZachary Turner 
10049c40264fSZachary Turner   char *cmode = const_cast<char *>(mode);
10059c40264fSZachary Turner #if PY_MAJOR_VERSION >= 3
1006b9c1b51eSKate Stone   Reset(PyRefType::Owned, PyFile_FromFd(file.GetDescriptor(), nullptr, cmode,
1007b9c1b51eSKate Stone                                         -1, nullptr, "ignore", nullptr, 0));
10089c40264fSZachary Turner #else
10099c40264fSZachary Turner   // Read through the Python source, doesn't seem to modify these strings
10109c40264fSZachary Turner   Reset(PyRefType::Owned,
1011b9c1b51eSKate Stone         PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode,
1012b9c1b51eSKate Stone                         nullptr));
10139c40264fSZachary Turner #endif
10149c40264fSZachary Turner }
10159c40264fSZachary Turner 
1016744959b9SEnrico Granata 
10172fce1137SLawrence D'Anna FileUP PythonFile::GetUnderlyingFile() const {
1018eda01c31SZachary Turner   if (!IsValid())
10192fce1137SLawrence D'Anna     return nullptr;
1020eda01c31SZachary Turner 
1021eda01c31SZachary Turner   // We don't own the file descriptor returned by this function, make sure the
1022eda01c31SZachary Turner   // File object knows about that.
1023744959b9SEnrico Granata   PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>();
1024*57504530SLawrence D'Anna   auto options = File::GetOptionsFromMode(py_mode.GetString());
10252fce1137SLawrence D'Anna   auto file = std::make_unique<File>(PyObject_AsFileDescriptor(m_py_obj),
10262fce1137SLawrence D'Anna                                      options, false);
10272fce1137SLawrence D'Anna   if (!file->IsValid())
10282fce1137SLawrence D'Anna     return nullptr;
10292fce1137SLawrence D'Anna   return file;
1030eda01c31SZachary Turner }
1031d68983e3SPavel Labath 
1032d68983e3SPavel Labath #endif
1033