180814287SRaphael Isemann //===-- PythonDataObjects.cpp ---------------------------------------------===//
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 
959998b7bSJonas Devlieghere #include "lldb/Host/Config.h"
10d68983e3SPavel Labath 
114e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
12d68983e3SPavel Labath 
132c1f46dcSZachary Turner #include "PythonDataObjects.h"
142c1f46dcSZachary Turner #include "ScriptInterpreterPython.h"
152c1f46dcSZachary Turner 
162c1f46dcSZachary Turner #include "lldb/Host/File.h"
17190fadcdSZachary Turner #include "lldb/Host/FileSystem.h"
182c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h"
19*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
20085328eeSLawrence D'Anna #include "lldb/Utility/Log.h"
21bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
222c1f46dcSZachary Turner 
239a6c7572SJonas Devlieghere #include "llvm/ADT/StringSwitch.h"
24d9b553ecSLawrence D'Anna #include "llvm/Support/Casting.h"
25190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h"
262819136fSMichal Gorny #include "llvm/Support/Errno.h"
27190fadcdSZachary Turner 
2876e47d48SRaphael Isemann #include <cstdio>
292c1f46dcSZachary Turner 
302c1f46dcSZachary Turner using namespace lldb_private;
312c1f46dcSZachary Turner using namespace lldb;
32085328eeSLawrence D'Anna using namespace lldb_private::python;
33c86a6acaSLawrence D'Anna using llvm::cantFail;
34085328eeSLawrence D'Anna using llvm::Error;
35085328eeSLawrence D'Anna using llvm::Expected;
36722b6189SLawrence D'Anna using llvm::Twine;
37085328eeSLawrence D'Anna 
38085328eeSLawrence D'Anna template <> Expected<bool> python::As<bool>(Expected<PythonObject> &&obj) {
39085328eeSLawrence D'Anna   if (!obj)
40085328eeSLawrence D'Anna     return obj.takeError();
41085328eeSLawrence D'Anna   return obj.get().IsTrue();
42085328eeSLawrence D'Anna }
43085328eeSLawrence D'Anna 
44085328eeSLawrence D'Anna template <>
45085328eeSLawrence D'Anna Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) {
46085328eeSLawrence D'Anna   if (!obj)
47085328eeSLawrence D'Anna     return obj.takeError();
4852712d3fSLawrence D'Anna   return obj->AsLongLong();
4952712d3fSLawrence D'Anna }
5052712d3fSLawrence D'Anna 
5152712d3fSLawrence D'Anna template <>
5252712d3fSLawrence D'Anna Expected<unsigned long long>
5352712d3fSLawrence D'Anna python::As<unsigned long long>(Expected<PythonObject> &&obj) {
5452712d3fSLawrence D'Anna   if (!obj)
5552712d3fSLawrence D'Anna     return obj.takeError();
5652712d3fSLawrence D'Anna   return obj->AsUnsignedLongLong();
57085328eeSLawrence D'Anna }
582c1f46dcSZachary Turner 
59c86a6acaSLawrence D'Anna template <>
60c86a6acaSLawrence D'Anna Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) {
61c86a6acaSLawrence D'Anna   if (!obj)
62c86a6acaSLawrence D'Anna     return obj.takeError();
63c86a6acaSLawrence D'Anna   PyObject *str_obj = PyObject_Str(obj.get().get());
64c86a6acaSLawrence D'Anna   if (!obj)
65c86a6acaSLawrence D'Anna     return llvm::make_error<PythonException>();
66c86a6acaSLawrence D'Anna   auto str = Take<PythonString>(str_obj);
67c86a6acaSLawrence D'Anna   auto utf8 = str.AsUTF8();
68c86a6acaSLawrence D'Anna   if (!utf8)
69c86a6acaSLawrence D'Anna     return utf8.takeError();
7019580c37SBenjamin Kramer   return std::string(utf8.get());
71c86a6acaSLawrence D'Anna }
72c86a6acaSLawrence D'Anna 
736ff4af8eSPavel Labath static bool python_is_finalizing() {
7416bff067SJonas Devlieghere #if PY_MAJOR_VERSION == 2
7516bff067SJonas Devlieghere   return false;
7616bff067SJonas Devlieghere #elif PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7
776ff4af8eSPavel Labath   return _Py_Finalizing != nullptr;
786ff4af8eSPavel Labath #else
796ff4af8eSPavel Labath   return _Py_IsFinalizing();
806ff4af8eSPavel Labath #endif
816ff4af8eSPavel Labath }
826ff4af8eSPavel Labath 
836ff4af8eSPavel Labath void PythonObject::Reset() {
846ff4af8eSPavel Labath   if (m_py_obj && Py_IsInitialized()) {
856ff4af8eSPavel Labath     if (python_is_finalizing()) {
866ff4af8eSPavel Labath       // Leak m_py_obj rather than crashing the process.
876ff4af8eSPavel Labath       // https://docs.python.org/3/c-api/init.html#c.PyGILState_Ensure
886ff4af8eSPavel Labath     } else {
896ff4af8eSPavel Labath       PyGILState_STATE state = PyGILState_Ensure();
906ff4af8eSPavel Labath       Py_DECREF(m_py_obj);
916ff4af8eSPavel Labath       PyGILState_Release(state);
926ff4af8eSPavel Labath     }
936ff4af8eSPavel Labath   }
946ff4af8eSPavel Labath   m_py_obj = nullptr;
956ff4af8eSPavel Labath }
966ff4af8eSPavel Labath 
9752712d3fSLawrence D'Anna Expected<long long> PythonObject::AsLongLong() const {
9852712d3fSLawrence D'Anna   if (!m_py_obj)
9952712d3fSLawrence D'Anna     return nullDeref();
10052712d3fSLawrence D'Anna #if PY_MAJOR_VERSION < 3
10152712d3fSLawrence D'Anna   if (!PyLong_Check(m_py_obj)) {
10252712d3fSLawrence D'Anna     PythonInteger i(PyRefType::Borrowed, m_py_obj);
10352712d3fSLawrence D'Anna     return i.AsLongLong();
10452712d3fSLawrence D'Anna   }
10552712d3fSLawrence D'Anna #endif
10652712d3fSLawrence D'Anna   assert(!PyErr_Occurred());
10752712d3fSLawrence D'Anna   long long r = PyLong_AsLongLong(m_py_obj);
10852712d3fSLawrence D'Anna   if (PyErr_Occurred())
10952712d3fSLawrence D'Anna     return exception();
11052712d3fSLawrence D'Anna   return r;
11152712d3fSLawrence D'Anna }
11252712d3fSLawrence D'Anna 
11352712d3fSLawrence D'Anna Expected<long long> PythonObject::AsUnsignedLongLong() const {
11452712d3fSLawrence D'Anna   if (!m_py_obj)
11552712d3fSLawrence D'Anna     return nullDeref();
11652712d3fSLawrence D'Anna #if PY_MAJOR_VERSION < 3
11752712d3fSLawrence D'Anna   if (!PyLong_Check(m_py_obj)) {
11852712d3fSLawrence D'Anna     PythonInteger i(PyRefType::Borrowed, m_py_obj);
11952712d3fSLawrence D'Anna     return i.AsUnsignedLongLong();
12052712d3fSLawrence D'Anna   }
12152712d3fSLawrence D'Anna #endif
12252712d3fSLawrence D'Anna   assert(!PyErr_Occurred());
12352712d3fSLawrence D'Anna   long long r = PyLong_AsUnsignedLongLong(m_py_obj);
12452712d3fSLawrence D'Anna   if (PyErr_Occurred())
12552712d3fSLawrence D'Anna     return exception();
12652712d3fSLawrence D'Anna   return r;
12752712d3fSLawrence D'Anna }
12852712d3fSLawrence D'Anna 
12952712d3fSLawrence D'Anna // wraps on overflow, instead of raising an error.
13052712d3fSLawrence D'Anna Expected<unsigned long long> PythonObject::AsModuloUnsignedLongLong() const {
13152712d3fSLawrence D'Anna   if (!m_py_obj)
13252712d3fSLawrence D'Anna     return nullDeref();
13352712d3fSLawrence D'Anna #if PY_MAJOR_VERSION < 3
13452712d3fSLawrence D'Anna   if (!PyLong_Check(m_py_obj)) {
13552712d3fSLawrence D'Anna     PythonInteger i(PyRefType::Borrowed, m_py_obj);
13652712d3fSLawrence D'Anna     return i.AsModuloUnsignedLongLong();
13752712d3fSLawrence D'Anna   }
13852712d3fSLawrence D'Anna #endif
13952712d3fSLawrence D'Anna   assert(!PyErr_Occurred());
14052712d3fSLawrence D'Anna   unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj);
14152712d3fSLawrence D'Anna   if (PyErr_Occurred())
14252712d3fSLawrence D'Anna     return exception();
14352712d3fSLawrence D'Anna   return r;
14452712d3fSLawrence D'Anna }
14552712d3fSLawrence D'Anna 
1462783d817SJonas Devlieghere void StructuredPythonObject::Serialize(llvm::json::OStream &s) const {
1472783d817SJonas Devlieghere   s.value(llvm::formatv("Python Obj: {0:X}", GetValue()).str());
1482c1f46dcSZachary Turner }
1492c1f46dcSZachary Turner 
1502c1f46dcSZachary Turner // PythonObject
1512c1f46dcSZachary Turner 
152b9c1b51eSKate Stone void PythonObject::Dump(Stream &strm) const {
153b9c1b51eSKate Stone   if (m_py_obj) {
1542819136fSMichal Gorny     FILE *file = llvm::sys::RetryAfterSignal(nullptr, ::tmpfile);
155b9c1b51eSKate Stone     if (file) {
1562c1f46dcSZachary Turner       ::PyObject_Print(m_py_obj, file, 0);
1572c1f46dcSZachary Turner       const long length = ftell(file);
158b9c1b51eSKate Stone       if (length) {
1592c1f46dcSZachary Turner         ::rewind(file);
1602c1f46dcSZachary Turner         std::vector<char> file_contents(length, '\0');
161b9c1b51eSKate Stone         const size_t length_read =
162b9c1b51eSKate Stone             ::fread(file_contents.data(), 1, file_contents.size(), file);
1632c1f46dcSZachary Turner         if (length_read > 0)
1642c1f46dcSZachary Turner           strm.Write(file_contents.data(), length_read);
1652c1f46dcSZachary Turner       }
1662c1f46dcSZachary Turner       ::fclose(file);
1672c1f46dcSZachary Turner     }
168b9c1b51eSKate Stone   } else
1692c1f46dcSZachary Turner     strm.PutCString("NULL");
1702c1f46dcSZachary Turner }
1712c1f46dcSZachary Turner 
172b9c1b51eSKate Stone PyObjectType PythonObject::GetObjectType() const {
173f8b22f8fSZachary Turner   if (!IsAllocated())
1742c1f46dcSZachary Turner     return PyObjectType::None;
1752c1f46dcSZachary Turner 
1767841efbbSZachary Turner   if (PythonModule::Check(m_py_obj))
1777841efbbSZachary Turner     return PyObjectType::Module;
17818426935SZachary Turner   if (PythonList::Check(m_py_obj))
1792c1f46dcSZachary Turner     return PyObjectType::List;
180a1405147SZachary Turner   if (PythonTuple::Check(m_py_obj))
181a1405147SZachary Turner     return PyObjectType::Tuple;
18218426935SZachary Turner   if (PythonDictionary::Check(m_py_obj))
1832c1f46dcSZachary Turner     return PyObjectType::Dictionary;
18418426935SZachary Turner   if (PythonString::Check(m_py_obj))
18522c8efcdSZachary Turner     return PyObjectType::String;
1865a72c02bSZachary Turner #if PY_MAJOR_VERSION >= 3
1875a72c02bSZachary Turner   if (PythonBytes::Check(m_py_obj))
1885a72c02bSZachary Turner     return PyObjectType::Bytes;
1895a72c02bSZachary Turner #endif
190f9d6d204SZachary Turner   if (PythonByteArray::Check(m_py_obj))
191f9d6d204SZachary Turner     return PyObjectType::ByteArray;
192b81d715cSTatyana Krasnukha   if (PythonBoolean::Check(m_py_obj))
193b81d715cSTatyana Krasnukha     return PyObjectType::Boolean;
19418426935SZachary Turner   if (PythonInteger::Check(m_py_obj))
19522c8efcdSZachary Turner     return PyObjectType::Integer;
1969c40264fSZachary Turner   if (PythonFile::Check(m_py_obj))
1979c40264fSZachary Turner     return PyObjectType::File;
198a1405147SZachary Turner   if (PythonCallable::Check(m_py_obj))
199a1405147SZachary Turner     return PyObjectType::Callable;
2002c1f46dcSZachary Turner   return PyObjectType::Unknown;
2012c1f46dcSZachary Turner }
2022c1f46dcSZachary Turner 
203b9c1b51eSKate Stone PythonString PythonObject::Repr() const {
2042c1f46dcSZachary Turner   if (!m_py_obj)
2052c1f46dcSZachary Turner     return PythonString();
2062c1f46dcSZachary Turner   PyObject *repr = PyObject_Repr(m_py_obj);
2072c1f46dcSZachary Turner   if (!repr)
2082c1f46dcSZachary Turner     return PythonString();
209f8b22f8fSZachary Turner   return PythonString(PyRefType::Owned, repr);
2102c1f46dcSZachary Turner }
2112c1f46dcSZachary Turner 
212b9c1b51eSKate Stone PythonString PythonObject::Str() const {
2132c1f46dcSZachary Turner   if (!m_py_obj)
2142c1f46dcSZachary Turner     return PythonString();
2152c1f46dcSZachary Turner   PyObject *str = PyObject_Str(m_py_obj);
2162c1f46dcSZachary Turner   if (!str)
2172c1f46dcSZachary Turner     return PythonString();
218f8b22f8fSZachary Turner   return PythonString(PyRefType::Owned, str);
2192c1f46dcSZachary Turner }
2202c1f46dcSZachary Turner 
2217841efbbSZachary Turner PythonObject
222b9c1b51eSKate Stone PythonObject::ResolveNameWithDictionary(llvm::StringRef name,
223b9c1b51eSKate Stone                                         const PythonDictionary &dict) {
224c712bac7SJonas Devlieghere   size_t dot_pos = name.find('.');
225a1405147SZachary Turner   llvm::StringRef piece = name.substr(0, dot_pos);
226a1405147SZachary Turner   PythonObject result = dict.GetItemForKey(PythonString(piece));
227b9c1b51eSKate Stone   if (dot_pos == llvm::StringRef::npos) {
228a1405147SZachary Turner     // There was no dot, we're done.
229a1405147SZachary Turner     return result;
230a1405147SZachary Turner   }
231a1405147SZachary Turner 
232a1405147SZachary Turner   // There was a dot.  The remaining portion of the name should be looked up in
233a1405147SZachary Turner   // the context of the object that was found in the dictionary.
234a1405147SZachary Turner   return result.ResolveName(name.substr(dot_pos + 1));
2357841efbbSZachary Turner }
2367841efbbSZachary Turner 
237b9c1b51eSKate Stone PythonObject PythonObject::ResolveName(llvm::StringRef name) const {
23805097246SAdrian Prantl   // Resolve the name in the context of the specified object.  If, for example,
23905097246SAdrian Prantl   // `this` refers to a PyModule, then this will look for `name` in this
24005097246SAdrian Prantl   // module.  If `this` refers to a PyType, then it will resolve `name` as an
24105097246SAdrian Prantl   // attribute of that type.  If `this` refers to an instance of an object,
24205097246SAdrian Prantl   // then it will resolve `name` as the value of the specified field.
2437841efbbSZachary Turner   //
2447841efbbSZachary Turner   // This function handles dotted names so that, for example, if `m_py_obj`
24505097246SAdrian Prantl   // refers to the `sys` module, and `name` == "path.append", then it will find
24605097246SAdrian Prantl   // the function `sys.path.append`.
2477841efbbSZachary Turner 
248c712bac7SJonas Devlieghere   size_t dot_pos = name.find('.');
249b9c1b51eSKate Stone   if (dot_pos == llvm::StringRef::npos) {
25005097246SAdrian Prantl     // No dots in the name, we should be able to find the value immediately as
25105097246SAdrian Prantl     // an attribute of `m_py_obj`.
2527841efbbSZachary Turner     return GetAttributeValue(name);
2537841efbbSZachary Turner   }
2547841efbbSZachary Turner 
255b9c1b51eSKate Stone   // Look up the first piece of the name, and resolve the rest as a child of
256b9c1b51eSKate Stone   // that.
2577841efbbSZachary Turner   PythonObject parent = ResolveName(name.substr(0, dot_pos));
2587841efbbSZachary Turner   if (!parent.IsAllocated())
2597841efbbSZachary Turner     return PythonObject();
2607841efbbSZachary Turner 
2617841efbbSZachary Turner   // Tail recursion.. should be optimized by the compiler
2627841efbbSZachary Turner   return parent.ResolveName(name.substr(dot_pos + 1));
2637841efbbSZachary Turner }
2647841efbbSZachary Turner 
265b9c1b51eSKate Stone bool PythonObject::HasAttribute(llvm::StringRef attr) const {
2669c40264fSZachary Turner   if (!IsValid())
2679c40264fSZachary Turner     return false;
2689c40264fSZachary Turner   PythonString py_attr(attr);
2699c40264fSZachary Turner   return !!PyObject_HasAttr(m_py_obj, py_attr.get());
2709c40264fSZachary Turner }
2719c40264fSZachary Turner 
272b9c1b51eSKate Stone PythonObject PythonObject::GetAttributeValue(llvm::StringRef attr) const {
2737d6d218eSZachary Turner   if (!IsValid())
2747d6d218eSZachary Turner     return PythonObject();
2757d6d218eSZachary Turner 
2767d6d218eSZachary Turner   PythonString py_attr(attr);
2777d6d218eSZachary Turner   if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
2787d6d218eSZachary Turner     return PythonObject();
2797d6d218eSZachary Turner 
2807d6d218eSZachary Turner   return PythonObject(PyRefType::Owned,
2817d6d218eSZachary Turner                       PyObject_GetAttr(m_py_obj, py_attr.get()));
2827d6d218eSZachary Turner }
2837d6d218eSZachary Turner 
284b9c1b51eSKate Stone StructuredData::ObjectSP PythonObject::CreateStructuredObject() const {
28516bff067SJonas Devlieghere #if PY_MAJOR_VERSION >= 3
286a6598575SRalf Grosse-Kunstleve   assert(PyGILState_Check());
28716bff067SJonas Devlieghere #endif
288b9c1b51eSKate Stone   switch (GetObjectType()) {
2892c1f46dcSZachary Turner   case PyObjectType::Dictionary:
290b9c1b51eSKate Stone     return PythonDictionary(PyRefType::Borrowed, m_py_obj)
291b9c1b51eSKate Stone         .CreateStructuredDictionary();
292b81d715cSTatyana Krasnukha   case PyObjectType::Boolean:
293b81d715cSTatyana Krasnukha     return PythonBoolean(PyRefType::Borrowed, m_py_obj)
294b81d715cSTatyana Krasnukha         .CreateStructuredBoolean();
2952c1f46dcSZachary Turner   case PyObjectType::Integer:
296b9c1b51eSKate Stone     return PythonInteger(PyRefType::Borrowed, m_py_obj)
297b9c1b51eSKate Stone         .CreateStructuredInteger();
2982c1f46dcSZachary Turner   case PyObjectType::List:
299f8b22f8fSZachary Turner     return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
3002c1f46dcSZachary Turner   case PyObjectType::String:
301f8b22f8fSZachary Turner     return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
3025a72c02bSZachary Turner   case PyObjectType::Bytes:
3035a72c02bSZachary Turner     return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
304f9d6d204SZachary Turner   case PyObjectType::ByteArray:
305b9c1b51eSKate Stone     return PythonByteArray(PyRefType::Borrowed, m_py_obj)
306b9c1b51eSKate Stone         .CreateStructuredString();
3072c1f46dcSZachary Turner   case PyObjectType::None:
3082c1f46dcSZachary Turner     return StructuredData::ObjectSP();
3092c1f46dcSZachary Turner   default:
310c154f397SPavel Labath     return StructuredData::ObjectSP(new StructuredPythonObject(
311c154f397SPavel Labath         PythonObject(PyRefType::Borrowed, m_py_obj)));
3122c1f46dcSZachary Turner   }
3132c1f46dcSZachary Turner }
3142c1f46dcSZachary Turner 
3152c1f46dcSZachary Turner // PythonString
3165a72c02bSZachary Turner 
317d3bd5b3dSLawrence D'Anna PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) { SetBytes(bytes); }
3185a72c02bSZachary Turner 
319d3bd5b3dSLawrence D'Anna PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) {
3205a72c02bSZachary Turner   SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
3215a72c02bSZachary Turner }
3225a72c02bSZachary Turner 
323b9c1b51eSKate Stone bool PythonBytes::Check(PyObject *py_obj) {
3245a72c02bSZachary Turner   if (!py_obj)
3255a72c02bSZachary Turner     return false;
326a6682a41SJonas Devlieghere   return PyBytes_Check(py_obj);
3275a72c02bSZachary Turner }
3285a72c02bSZachary Turner 
329b9c1b51eSKate Stone llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {
3305a72c02bSZachary Turner   if (!IsValid())
3315a72c02bSZachary Turner     return llvm::ArrayRef<uint8_t>();
3325a72c02bSZachary Turner 
3335a72c02bSZachary Turner   Py_ssize_t size;
3345a72c02bSZachary Turner   char *c;
3355a72c02bSZachary Turner 
3365a72c02bSZachary Turner   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
3375a72c02bSZachary Turner   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
3385a72c02bSZachary Turner }
3395a72c02bSZachary Turner 
340b9c1b51eSKate Stone size_t PythonBytes::GetSize() const {
3415a72c02bSZachary Turner   if (!IsValid())
3425a72c02bSZachary Turner     return 0;
3435a72c02bSZachary Turner   return PyBytes_Size(m_py_obj);
3445a72c02bSZachary Turner }
3455a72c02bSZachary Turner 
346b9c1b51eSKate Stone void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {
3475a72c02bSZachary Turner   const char *data = reinterpret_cast<const char *>(bytes.data());
34804edd189SLawrence D'Anna   *this = Take<PythonBytes>(PyBytes_FromStringAndSize(data, bytes.size()));
3495a72c02bSZachary Turner }
3505a72c02bSZachary Turner 
351b9c1b51eSKate Stone StructuredData::StringSP PythonBytes::CreateStructuredString() const {
3525a72c02bSZachary Turner   StructuredData::StringSP result(new StructuredData::String);
3535a72c02bSZachary Turner   Py_ssize_t size;
3545a72c02bSZachary Turner   char *c;
3555a72c02bSZachary Turner   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
3565a72c02bSZachary Turner   result->SetValue(std::string(c, size));
3575a72c02bSZachary Turner   return result;
3585a72c02bSZachary Turner }
3595a72c02bSZachary Turner 
360b9c1b51eSKate Stone PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes)
361b9c1b51eSKate Stone     : PythonByteArray(bytes.data(), bytes.size()) {}
362f9d6d204SZachary Turner 
363b9c1b51eSKate Stone PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {
364f9d6d204SZachary Turner   const char *str = reinterpret_cast<const char *>(bytes);
365722b6189SLawrence D'Anna   *this = Take<PythonByteArray>(PyByteArray_FromStringAndSize(str, length));
366f9d6d204SZachary Turner }
367f9d6d204SZachary Turner 
368b9c1b51eSKate Stone bool PythonByteArray::Check(PyObject *py_obj) {
369f9d6d204SZachary Turner   if (!py_obj)
370f9d6d204SZachary Turner     return false;
371a6682a41SJonas Devlieghere   return PyByteArray_Check(py_obj);
372f9d6d204SZachary Turner }
373f9d6d204SZachary Turner 
374b9c1b51eSKate Stone llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {
375f9d6d204SZachary Turner   if (!IsValid())
376f9d6d204SZachary Turner     return llvm::ArrayRef<uint8_t>();
377f9d6d204SZachary Turner 
378f9d6d204SZachary Turner   char *c = PyByteArray_AsString(m_py_obj);
379f9d6d204SZachary Turner   size_t size = GetSize();
380f9d6d204SZachary Turner   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
381f9d6d204SZachary Turner }
382f9d6d204SZachary Turner 
383b9c1b51eSKate Stone size_t PythonByteArray::GetSize() const {
384f9d6d204SZachary Turner   if (!IsValid())
385f9d6d204SZachary Turner     return 0;
386f9d6d204SZachary Turner 
387f9d6d204SZachary Turner   return PyByteArray_Size(m_py_obj);
388f9d6d204SZachary Turner }
389f9d6d204SZachary Turner 
390b9c1b51eSKate Stone StructuredData::StringSP PythonByteArray::CreateStructuredString() const {
391f9d6d204SZachary Turner   StructuredData::StringSP result(new StructuredData::String);
392f9d6d204SZachary Turner   llvm::ArrayRef<uint8_t> bytes = GetBytes();
393f9d6d204SZachary Turner   const char *str = reinterpret_cast<const char *>(bytes.data());
394f9d6d204SZachary Turner   result->SetValue(std::string(str, bytes.size()));
395f9d6d204SZachary Turner   return result;
396f9d6d204SZachary Turner }
397f9d6d204SZachary Turner 
3985a72c02bSZachary Turner // PythonString
3992c1f46dcSZachary Turner 
400085328eeSLawrence D'Anna Expected<PythonString> PythonString::FromUTF8(llvm::StringRef string) {
401085328eeSLawrence D'Anna #if PY_MAJOR_VERSION >= 3
402085328eeSLawrence D'Anna   PyObject *str = PyUnicode_FromStringAndSize(string.data(), string.size());
403085328eeSLawrence D'Anna #else
404085328eeSLawrence D'Anna   PyObject *str = PyString_FromStringAndSize(string.data(), string.size());
405085328eeSLawrence D'Anna #endif
406085328eeSLawrence D'Anna   if (!str)
407085328eeSLawrence D'Anna     return llvm::make_error<PythonException>();
408085328eeSLawrence D'Anna   return Take<PythonString>(str);
409085328eeSLawrence D'Anna }
410085328eeSLawrence D'Anna 
411d3bd5b3dSLawrence D'Anna PythonString::PythonString(llvm::StringRef string) { SetString(string); }
4122c1f46dcSZachary Turner 
413b9c1b51eSKate Stone bool PythonString::Check(PyObject *py_obj) {
41422c8efcdSZachary Turner   if (!py_obj)
41522c8efcdSZachary Turner     return false;
41618426935SZachary Turner 
4177d6d218eSZachary Turner   if (PyUnicode_Check(py_obj))
4187d6d218eSZachary Turner     return true;
4197d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
4207d6d218eSZachary Turner   if (PyString_Check(py_obj))
4217d6d218eSZachary Turner     return true;
42222c8efcdSZachary Turner #endif
4237d6d218eSZachary Turner   return false;
42422c8efcdSZachary Turner }
42522c8efcdSZachary Turner 
426d3bd5b3dSLawrence D'Anna void PythonString::Convert(PyRefType &type, PyObject *&py_obj) {
4277d6d218eSZachary Turner #if PY_MAJOR_VERSION < 3
4287d6d218eSZachary Turner   // In Python 2, Don't store PyUnicode objects directly, because we need
4297d6d218eSZachary Turner   // access to their underlying character buffers which Python 2 doesn't
4307d6d218eSZachary Turner   // provide.
431085328eeSLawrence D'Anna   if (PyUnicode_Check(py_obj)) {
432d3bd5b3dSLawrence D'Anna     PyObject *s = PyUnicode_AsUTF8String(py_obj);
433d3bd5b3dSLawrence D'Anna     if (s == nullptr) {
434085328eeSLawrence D'Anna       PyErr_Clear();
435d3bd5b3dSLawrence D'Anna       if (type == PyRefType::Owned)
436d3bd5b3dSLawrence D'Anna         Py_DECREF(py_obj);
437d3bd5b3dSLawrence D'Anna       return;
438d3bd5b3dSLawrence D'Anna     }
439d3bd5b3dSLawrence D'Anna     if (type == PyRefType::Owned)
440d3bd5b3dSLawrence D'Anna       Py_DECREF(py_obj);
441d3bd5b3dSLawrence D'Anna     else
442d3bd5b3dSLawrence D'Anna       type = PyRefType::Owned;
443d3bd5b3dSLawrence D'Anna     py_obj = s;
444085328eeSLawrence D'Anna   }
4457d6d218eSZachary Turner #endif
4462c1f46dcSZachary Turner }
4472c1f46dcSZachary Turner 
448b9c1b51eSKate Stone llvm::StringRef PythonString::GetString() const {
449085328eeSLawrence D'Anna   auto s = AsUTF8();
450085328eeSLawrence D'Anna   if (!s) {
451085328eeSLawrence D'Anna     llvm::consumeError(s.takeError());
452085328eeSLawrence D'Anna     return llvm::StringRef("");
453085328eeSLawrence D'Anna   }
454085328eeSLawrence D'Anna   return s.get();
455085328eeSLawrence D'Anna }
456085328eeSLawrence D'Anna 
457085328eeSLawrence D'Anna Expected<llvm::StringRef> PythonString::AsUTF8() const {
45818426935SZachary Turner   if (!IsValid())
459085328eeSLawrence D'Anna     return nullDeref();
46018426935SZachary Turner 
46122c8efcdSZachary Turner   Py_ssize_t size;
4625457b426SPavel Labath   const char *data;
46318426935SZachary Turner 
46418426935SZachary Turner #if PY_MAJOR_VERSION >= 3
4655457b426SPavel Labath   data = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
46618426935SZachary Turner #else
467085328eeSLawrence D'Anna   char *c = NULL;
468085328eeSLawrence D'Anna   int r = PyString_AsStringAndSize(m_py_obj, &c, &size);
469085328eeSLawrence D'Anna   if (r < 0)
470085328eeSLawrence D'Anna     c = NULL;
4715457b426SPavel Labath   data = c;
47218426935SZachary Turner #endif
473085328eeSLawrence D'Anna 
474085328eeSLawrence D'Anna   if (!data)
475085328eeSLawrence D'Anna     return exception();
476085328eeSLawrence D'Anna 
4775457b426SPavel Labath   return llvm::StringRef(data, size);
47822c8efcdSZachary Turner }
4792c1f46dcSZachary Turner 
480b9c1b51eSKate Stone size_t PythonString::GetSize() const {
481b9c1b51eSKate Stone   if (IsValid()) {
48218426935SZachary Turner #if PY_MAJOR_VERSION >= 3
48375012a80STatyana Krasnukha #if PY_MINOR_VERSION >= 3
48475012a80STatyana Krasnukha     return PyUnicode_GetLength(m_py_obj);
48575012a80STatyana Krasnukha #else
48618426935SZachary Turner     return PyUnicode_GetSize(m_py_obj);
48775012a80STatyana Krasnukha #endif
48818426935SZachary Turner #else
48918426935SZachary Turner     return PyString_Size(m_py_obj);
49018426935SZachary Turner #endif
49118426935SZachary Turner   }
4922c1f46dcSZachary Turner   return 0;
4932c1f46dcSZachary Turner }
4942c1f46dcSZachary Turner 
495b9c1b51eSKate Stone void PythonString::SetString(llvm::StringRef string) {
496085328eeSLawrence D'Anna   auto s = FromUTF8(string);
497085328eeSLawrence D'Anna   if (!s) {
498085328eeSLawrence D'Anna     llvm::consumeError(s.takeError());
499085328eeSLawrence D'Anna     Reset();
500085328eeSLawrence D'Anna   } else {
50103819d1cSLawrence D'Anna     *this = std::move(s.get());
502085328eeSLawrence D'Anna   }
5032c1f46dcSZachary Turner }
5042c1f46dcSZachary Turner 
505b9c1b51eSKate Stone StructuredData::StringSP PythonString::CreateStructuredString() const {
5062c1f46dcSZachary Turner   StructuredData::StringSP result(new StructuredData::String);
5072c1f46dcSZachary Turner   result->SetValue(GetString());
5082c1f46dcSZachary Turner   return result;
5092c1f46dcSZachary Turner }
5102c1f46dcSZachary Turner 
5112c1f46dcSZachary Turner // PythonInteger
5122c1f46dcSZachary Turner 
513d3bd5b3dSLawrence D'Anna PythonInteger::PythonInteger(int64_t value) { SetInteger(value); }
5142c1f46dcSZachary Turner 
515b9c1b51eSKate Stone bool PythonInteger::Check(PyObject *py_obj) {
51622c8efcdSZachary Turner   if (!py_obj)
51722c8efcdSZachary Turner     return false;
51822c8efcdSZachary Turner 
51922c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3
52005097246SAdrian Prantl   // Python 3 does not have PyInt_Check.  There is only one type of integral
52105097246SAdrian Prantl   // value, long.
52222c8efcdSZachary Turner   return PyLong_Check(py_obj);
52322c8efcdSZachary Turner #else
52422c8efcdSZachary Turner   return PyLong_Check(py_obj) || PyInt_Check(py_obj);
52522c8efcdSZachary Turner #endif
5262c1f46dcSZachary Turner }
5272c1f46dcSZachary Turner 
528d3bd5b3dSLawrence D'Anna void PythonInteger::Convert(PyRefType &type, PyObject *&py_obj) {
52922c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3
53005097246SAdrian Prantl   // Always store this as a PyLong, which makes interoperability between Python
53105097246SAdrian Prantl   // 2.x and Python 3.x easier.  This is only necessary in 2.x, since 3.x
53205097246SAdrian Prantl   // doesn't even have a PyInt.
533b9c1b51eSKate Stone   if (PyInt_Check(py_obj)) {
534f8b22f8fSZachary Turner     // Since we converted the original object to a different type, the new
53505097246SAdrian Prantl     // object is an owned object regardless of the ownership semantics
53605097246SAdrian Prantl     // requested by the user.
537d3bd5b3dSLawrence D'Anna     long long value = PyInt_AsLong(py_obj);
538d3bd5b3dSLawrence D'Anna     PyObject *l = nullptr;
539d3bd5b3dSLawrence D'Anna     if (!PyErr_Occurred())
540d3bd5b3dSLawrence D'Anna       l = PyLong_FromLongLong(value);
541d3bd5b3dSLawrence D'Anna     if (l == nullptr) {
542d3bd5b3dSLawrence D'Anna       PyErr_Clear();
543d3bd5b3dSLawrence D'Anna       if (type == PyRefType::Owned)
544d3bd5b3dSLawrence D'Anna         Py_DECREF(py_obj);
545d3bd5b3dSLawrence D'Anna       return;
546d3bd5b3dSLawrence D'Anna     }
547d3bd5b3dSLawrence D'Anna     if (type == PyRefType::Owned)
548d3bd5b3dSLawrence D'Anna       Py_DECREF(py_obj);
549d3bd5b3dSLawrence D'Anna     else
550d3bd5b3dSLawrence D'Anna       type = PyRefType::Owned;
551d3bd5b3dSLawrence D'Anna     py_obj = l;
55222c8efcdSZachary Turner   }
55322c8efcdSZachary Turner #endif
5542c1f46dcSZachary Turner }
5552c1f46dcSZachary Turner 
556b9c1b51eSKate Stone void PythonInteger::SetInteger(int64_t value) {
55704edd189SLawrence D'Anna   *this = Take<PythonInteger>(PyLong_FromLongLong(value));
5582c1f46dcSZachary Turner }
5592c1f46dcSZachary Turner 
560b9c1b51eSKate Stone StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
5612c1f46dcSZachary Turner   StructuredData::IntegerSP result(new StructuredData::Integer);
56252712d3fSLawrence D'Anna   // FIXME this is really not ideal.   Errors are silently converted to 0
56352712d3fSLawrence D'Anna   // and overflows are silently wrapped.   But we'd need larger changes
56452712d3fSLawrence D'Anna   // to StructuredData to fix it, so that's how it is for now.
56552712d3fSLawrence D'Anna   llvm::Expected<unsigned long long> value = AsModuloUnsignedLongLong();
56652712d3fSLawrence D'Anna   if (!value) {
56752712d3fSLawrence D'Anna     llvm::consumeError(value.takeError());
56852712d3fSLawrence D'Anna     result->SetValue(0);
56952712d3fSLawrence D'Anna   } else {
57052712d3fSLawrence D'Anna     result->SetValue(value.get());
57152712d3fSLawrence D'Anna   }
5722c1f46dcSZachary Turner   return result;
5732c1f46dcSZachary Turner }
5742c1f46dcSZachary Turner 
575b81d715cSTatyana Krasnukha // PythonBoolean
576b81d715cSTatyana Krasnukha 
577b81d715cSTatyana Krasnukha PythonBoolean::PythonBoolean(bool value) {
578b81d715cSTatyana Krasnukha   SetValue(value);
579b81d715cSTatyana Krasnukha }
580b81d715cSTatyana Krasnukha 
581b81d715cSTatyana Krasnukha bool PythonBoolean::Check(PyObject *py_obj) {
582b81d715cSTatyana Krasnukha   return py_obj ? PyBool_Check(py_obj) : false;
583b81d715cSTatyana Krasnukha }
584b81d715cSTatyana Krasnukha 
585b81d715cSTatyana Krasnukha bool PythonBoolean::GetValue() const {
586b81d715cSTatyana Krasnukha   return m_py_obj ? PyObject_IsTrue(m_py_obj) : false;
587b81d715cSTatyana Krasnukha }
588b81d715cSTatyana Krasnukha 
589b81d715cSTatyana Krasnukha void PythonBoolean::SetValue(bool value) {
59004edd189SLawrence D'Anna   *this = Take<PythonBoolean>(PyBool_FromLong(value));
591b81d715cSTatyana Krasnukha }
592b81d715cSTatyana Krasnukha 
593b81d715cSTatyana Krasnukha StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const {
594b81d715cSTatyana Krasnukha   StructuredData::BooleanSP result(new StructuredData::Boolean);
595b81d715cSTatyana Krasnukha   result->SetValue(GetValue());
596b81d715cSTatyana Krasnukha   return result;
597b81d715cSTatyana Krasnukha }
598b81d715cSTatyana Krasnukha 
5992c1f46dcSZachary Turner // PythonList
6002c1f46dcSZachary Turner 
601d3bd5b3dSLawrence D'Anna PythonList::PythonList(PyInitialValue value) {
602f8b22f8fSZachary Turner   if (value == PyInitialValue::Empty)
603722b6189SLawrence D'Anna     *this = Take<PythonList>(PyList_New(0));
6042c1f46dcSZachary Turner }
6052c1f46dcSZachary Turner 
606d3bd5b3dSLawrence D'Anna PythonList::PythonList(int list_size) {
607722b6189SLawrence D'Anna   *this = Take<PythonList>(PyList_New(list_size));
60887f47729SZachary Turner }
60987f47729SZachary Turner 
610b9c1b51eSKate Stone bool PythonList::Check(PyObject *py_obj) {
61122c8efcdSZachary Turner   if (!py_obj)
61222c8efcdSZachary Turner     return false;
61322c8efcdSZachary Turner   return PyList_Check(py_obj);
61422c8efcdSZachary Turner }
61522c8efcdSZachary Turner 
616b9c1b51eSKate Stone uint32_t PythonList::GetSize() const {
617f8b22f8fSZachary Turner   if (IsValid())
6182c1f46dcSZachary Turner     return PyList_GET_SIZE(m_py_obj);
6192c1f46dcSZachary Turner   return 0;
6202c1f46dcSZachary Turner }
6212c1f46dcSZachary Turner 
622b9c1b51eSKate Stone PythonObject PythonList::GetItemAtIndex(uint32_t index) const {
623f8b22f8fSZachary Turner   if (IsValid())
624f8b22f8fSZachary Turner     return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
6252c1f46dcSZachary Turner   return PythonObject();
6262c1f46dcSZachary Turner }
6272c1f46dcSZachary Turner 
628b9c1b51eSKate Stone void PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) {
629b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
630f8b22f8fSZachary Turner     // PyList_SetItem is documented to "steal" a reference, so we need to
631f8b22f8fSZachary Turner     // convert it to an owned reference by incrementing it.
632f8b22f8fSZachary Turner     Py_INCREF(object.get());
6332c1f46dcSZachary Turner     PyList_SetItem(m_py_obj, index, object.get());
6342c1f46dcSZachary Turner   }
635f8b22f8fSZachary Turner }
6362c1f46dcSZachary Turner 
637b9c1b51eSKate Stone void PythonList::AppendItem(const PythonObject &object) {
638b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
639f8b22f8fSZachary Turner     // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
640f8b22f8fSZachary Turner     // here like we do with `PyList_SetItem`.
6412c1f46dcSZachary Turner     PyList_Append(m_py_obj, object.get());
6422c1f46dcSZachary Turner   }
643f8b22f8fSZachary Turner }
6442c1f46dcSZachary Turner 
645b9c1b51eSKate Stone StructuredData::ArraySP PythonList::CreateStructuredArray() const {
6462c1f46dcSZachary Turner   StructuredData::ArraySP result(new StructuredData::Array);
6472c1f46dcSZachary Turner   uint32_t count = GetSize();
648b9c1b51eSKate Stone   for (uint32_t i = 0; i < count; ++i) {
6492c1f46dcSZachary Turner     PythonObject obj = GetItemAtIndex(i);
6502c1f46dcSZachary Turner     result->AddItem(obj.CreateStructuredObject());
6512c1f46dcSZachary Turner   }
6522c1f46dcSZachary Turner   return result;
6532c1f46dcSZachary Turner }
6542c1f46dcSZachary Turner 
655a1405147SZachary Turner // PythonTuple
656a1405147SZachary Turner 
657d3bd5b3dSLawrence D'Anna PythonTuple::PythonTuple(PyInitialValue value) {
658a1405147SZachary Turner   if (value == PyInitialValue::Empty)
659722b6189SLawrence D'Anna     *this = Take<PythonTuple>(PyTuple_New(0));
660a1405147SZachary Turner }
661a1405147SZachary Turner 
662d3bd5b3dSLawrence D'Anna PythonTuple::PythonTuple(int tuple_size) {
663722b6189SLawrence D'Anna   *this = Take<PythonTuple>(PyTuple_New(tuple_size));
664a1405147SZachary Turner }
665a1405147SZachary Turner 
666b9c1b51eSKate Stone PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
667a1405147SZachary Turner   m_py_obj = PyTuple_New(objects.size());
668a1405147SZachary Turner 
669a1405147SZachary Turner   uint32_t idx = 0;
670b9c1b51eSKate Stone   for (auto object : objects) {
671a1405147SZachary Turner     if (object.IsValid())
672a1405147SZachary Turner       SetItemAtIndex(idx, object);
673a1405147SZachary Turner     idx++;
674a1405147SZachary Turner   }
675a1405147SZachary Turner }
676a1405147SZachary Turner 
677b9c1b51eSKate Stone PythonTuple::PythonTuple(std::initializer_list<PyObject *> objects) {
678a1405147SZachary Turner   m_py_obj = PyTuple_New(objects.size());
679a1405147SZachary Turner 
680a1405147SZachary Turner   uint32_t idx = 0;
681b9c1b51eSKate Stone   for (auto py_object : objects) {
682a1405147SZachary Turner     PythonObject object(PyRefType::Borrowed, py_object);
683a1405147SZachary Turner     if (object.IsValid())
684a1405147SZachary Turner       SetItemAtIndex(idx, object);
685a1405147SZachary Turner     idx++;
686a1405147SZachary Turner   }
687a1405147SZachary Turner }
688a1405147SZachary Turner 
689b9c1b51eSKate Stone bool PythonTuple::Check(PyObject *py_obj) {
690a1405147SZachary Turner   if (!py_obj)
691a1405147SZachary Turner     return false;
692a1405147SZachary Turner   return PyTuple_Check(py_obj);
693a1405147SZachary Turner }
694a1405147SZachary Turner 
695b9c1b51eSKate Stone uint32_t PythonTuple::GetSize() const {
696a1405147SZachary Turner   if (IsValid())
697a1405147SZachary Turner     return PyTuple_GET_SIZE(m_py_obj);
698a1405147SZachary Turner   return 0;
699a1405147SZachary Turner }
700a1405147SZachary Turner 
701b9c1b51eSKate Stone PythonObject PythonTuple::GetItemAtIndex(uint32_t index) const {
702a1405147SZachary Turner   if (IsValid())
703a1405147SZachary Turner     return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
704a1405147SZachary Turner   return PythonObject();
705a1405147SZachary Turner }
706a1405147SZachary Turner 
707b9c1b51eSKate Stone void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) {
708b9c1b51eSKate Stone   if (IsAllocated() && object.IsValid()) {
709a1405147SZachary Turner     // PyTuple_SetItem is documented to "steal" a reference, so we need to
710a1405147SZachary Turner     // convert it to an owned reference by incrementing it.
711a1405147SZachary Turner     Py_INCREF(object.get());
712a1405147SZachary Turner     PyTuple_SetItem(m_py_obj, index, object.get());
713a1405147SZachary Turner   }
714a1405147SZachary Turner }
715a1405147SZachary Turner 
716b9c1b51eSKate Stone StructuredData::ArraySP PythonTuple::CreateStructuredArray() const {
717a1405147SZachary Turner   StructuredData::ArraySP result(new StructuredData::Array);
718a1405147SZachary Turner   uint32_t count = GetSize();
719b9c1b51eSKate Stone   for (uint32_t i = 0; i < count; ++i) {
720a1405147SZachary Turner     PythonObject obj = GetItemAtIndex(i);
721a1405147SZachary Turner     result->AddItem(obj.CreateStructuredObject());
722a1405147SZachary Turner   }
723a1405147SZachary Turner   return result;
724a1405147SZachary Turner }
725a1405147SZachary Turner 
7262c1f46dcSZachary Turner // PythonDictionary
7272c1f46dcSZachary Turner 
728d3bd5b3dSLawrence D'Anna PythonDictionary::PythonDictionary(PyInitialValue value) {
729f8b22f8fSZachary Turner   if (value == PyInitialValue::Empty)
730722b6189SLawrence D'Anna     *this = Take<PythonDictionary>(PyDict_New());
7312c1f46dcSZachary Turner }
7322c1f46dcSZachary Turner 
733b9c1b51eSKate Stone bool PythonDictionary::Check(PyObject *py_obj) {
73422c8efcdSZachary Turner   if (!py_obj)
73522c8efcdSZachary Turner     return false;
73622c8efcdSZachary Turner 
73722c8efcdSZachary Turner   return PyDict_Check(py_obj);
73822c8efcdSZachary Turner }
73922c8efcdSZachary Turner 
740b9c1b51eSKate Stone uint32_t PythonDictionary::GetSize() const {
741f8b22f8fSZachary Turner   if (IsValid())
7422c1f46dcSZachary Turner     return PyDict_Size(m_py_obj);
7432c1f46dcSZachary Turner   return 0;
7442c1f46dcSZachary Turner }
7452c1f46dcSZachary Turner 
746b9c1b51eSKate Stone PythonList PythonDictionary::GetKeys() const {
747f8b22f8fSZachary Turner   if (IsValid())
748f8b22f8fSZachary Turner     return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
749f8b22f8fSZachary Turner   return PythonList(PyInitialValue::Invalid);
7502c1f46dcSZachary Turner }
7512c1f46dcSZachary Turner 
752b9c1b51eSKate Stone PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {
753c86a6acaSLawrence D'Anna   auto item = GetItem(key);
754c86a6acaSLawrence D'Anna   if (!item) {
755c86a6acaSLawrence D'Anna     llvm::consumeError(item.takeError());
7562c1f46dcSZachary Turner     return PythonObject();
7572c1f46dcSZachary Turner   }
758c86a6acaSLawrence D'Anna   return std::move(item.get());
759c86a6acaSLawrence D'Anna }
760c86a6acaSLawrence D'Anna 
761c86a6acaSLawrence D'Anna Expected<PythonObject>
762c86a6acaSLawrence D'Anna PythonDictionary::GetItem(const PythonObject &key) const {
763c86a6acaSLawrence D'Anna   if (!IsValid())
764c86a6acaSLawrence D'Anna     return nullDeref();
765c86a6acaSLawrence D'Anna #if PY_MAJOR_VERSION >= 3
766c86a6acaSLawrence D'Anna   PyObject *o = PyDict_GetItemWithError(m_py_obj, key.get());
767c86a6acaSLawrence D'Anna   if (PyErr_Occurred())
768c86a6acaSLawrence D'Anna     return exception();
769c86a6acaSLawrence D'Anna #else
770c86a6acaSLawrence D'Anna   PyObject *o = PyDict_GetItem(m_py_obj, key.get());
771c86a6acaSLawrence D'Anna #endif
772c86a6acaSLawrence D'Anna   if (!o)
773c86a6acaSLawrence D'Anna     return keyError();
774c86a6acaSLawrence D'Anna   return Retain<PythonObject>(o);
775c86a6acaSLawrence D'Anna }
776c86a6acaSLawrence D'Anna 
777722b6189SLawrence D'Anna Expected<PythonObject> PythonDictionary::GetItem(const Twine &key) const {
778c86a6acaSLawrence D'Anna   if (!IsValid())
779c86a6acaSLawrence D'Anna     return nullDeref();
780722b6189SLawrence D'Anna   PyObject *o = PyDict_GetItemString(m_py_obj, NullTerminated(key));
781c86a6acaSLawrence D'Anna   if (PyErr_Occurred())
782c86a6acaSLawrence D'Anna     return exception();
783c86a6acaSLawrence D'Anna   if (!o)
784c86a6acaSLawrence D'Anna     return keyError();
785c86a6acaSLawrence D'Anna   return Retain<PythonObject>(o);
786c86a6acaSLawrence D'Anna }
787c86a6acaSLawrence D'Anna 
788c86a6acaSLawrence D'Anna Error PythonDictionary::SetItem(const PythonObject &key,
789c86a6acaSLawrence D'Anna                                 const PythonObject &value) const {
790c86a6acaSLawrence D'Anna   if (!IsValid() || !value.IsValid())
791c86a6acaSLawrence D'Anna     return nullDeref();
792c86a6acaSLawrence D'Anna   int r = PyDict_SetItem(m_py_obj, key.get(), value.get());
793c86a6acaSLawrence D'Anna   if (r < 0)
794c86a6acaSLawrence D'Anna     return exception();
795c86a6acaSLawrence D'Anna   return Error::success();
796c86a6acaSLawrence D'Anna }
797c86a6acaSLawrence D'Anna 
798722b6189SLawrence D'Anna Error PythonDictionary::SetItem(const Twine &key,
799c86a6acaSLawrence D'Anna                                 const PythonObject &value) const {
800c86a6acaSLawrence D'Anna   if (!IsValid() || !value.IsValid())
801c86a6acaSLawrence D'Anna     return nullDeref();
802722b6189SLawrence D'Anna   int r = PyDict_SetItemString(m_py_obj, NullTerminated(key), value.get());
803c86a6acaSLawrence D'Anna   if (r < 0)
804c86a6acaSLawrence D'Anna     return exception();
805c86a6acaSLawrence D'Anna   return Error::success();
806c86a6acaSLawrence D'Anna }
8072c1f46dcSZachary Turner 
808b9c1b51eSKate Stone void PythonDictionary::SetItemForKey(const PythonObject &key,
809b9c1b51eSKate Stone                                      const PythonObject &value) {
810c86a6acaSLawrence D'Anna   Error error = SetItem(key, value);
811c86a6acaSLawrence D'Anna   if (error)
812c86a6acaSLawrence D'Anna     llvm::consumeError(std::move(error));
8132c1f46dcSZachary Turner }
8142c1f46dcSZachary Turner 
8152c1f46dcSZachary Turner StructuredData::DictionarySP
816b9c1b51eSKate Stone PythonDictionary::CreateStructuredDictionary() const {
8172c1f46dcSZachary Turner   StructuredData::DictionarySP result(new StructuredData::Dictionary);
8182c1f46dcSZachary Turner   PythonList keys(GetKeys());
8192c1f46dcSZachary Turner   uint32_t num_keys = keys.GetSize();
820b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_keys; ++i) {
8212c1f46dcSZachary Turner     PythonObject key = keys.GetItemAtIndex(i);
8222c1f46dcSZachary Turner     PythonObject value = GetItemForKey(key);
8232c1f46dcSZachary Turner     StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
824f8b22f8fSZachary Turner     result->AddItem(key.Str().GetString(), structured_value);
8252c1f46dcSZachary Turner   }
8262c1f46dcSZachary Turner   return result;
8272c1f46dcSZachary Turner }
8282c1f46dcSZachary Turner 
829b9c1b51eSKate Stone PythonModule PythonModule::BuiltinsModule() {
830a1405147SZachary Turner #if PY_MAJOR_VERSION >= 3
831a1405147SZachary Turner   return AddModule("builtins");
832a1405147SZachary Turner #else
833a1405147SZachary Turner   return AddModule("__builtin__");
834a1405147SZachary Turner #endif
835a1405147SZachary Turner }
836a1405147SZachary Turner 
837b9c1b51eSKate Stone PythonModule PythonModule::MainModule() { return AddModule("__main__"); }
838a1405147SZachary Turner 
839b9c1b51eSKate Stone PythonModule PythonModule::AddModule(llvm::StringRef module) {
840a1405147SZachary Turner   std::string str = module.str();
841a1405147SZachary Turner   return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
8427841efbbSZachary Turner }
8437841efbbSZachary Turner 
844722b6189SLawrence D'Anna Expected<PythonModule> PythonModule::Import(const Twine &name) {
845722b6189SLawrence D'Anna   PyObject *mod = PyImport_ImportModule(NullTerminated(name));
846085328eeSLawrence D'Anna   if (!mod)
847085328eeSLawrence D'Anna     return exception();
848085328eeSLawrence D'Anna   return Take<PythonModule>(mod);
849085328eeSLawrence D'Anna }
850085328eeSLawrence D'Anna 
851722b6189SLawrence D'Anna Expected<PythonObject> PythonModule::Get(const Twine &name) {
852085328eeSLawrence D'Anna   if (!IsValid())
853085328eeSLawrence D'Anna     return nullDeref();
854085328eeSLawrence D'Anna   PyObject *dict = PyModule_GetDict(m_py_obj);
855085328eeSLawrence D'Anna   if (!dict)
856085328eeSLawrence D'Anna     return exception();
857722b6189SLawrence D'Anna   PyObject *item = PyDict_GetItemString(dict, NullTerminated(name));
858085328eeSLawrence D'Anna   if (!item)
859085328eeSLawrence D'Anna     return exception();
860085328eeSLawrence D'Anna   return Retain<PythonObject>(item);
8612419f1d5SZachary Turner }
8622419f1d5SZachary Turner 
863b9c1b51eSKate Stone bool PythonModule::Check(PyObject *py_obj) {
8647841efbbSZachary Turner   if (!py_obj)
8657841efbbSZachary Turner     return false;
8667841efbbSZachary Turner 
8677841efbbSZachary Turner   return PyModule_Check(py_obj);
8687841efbbSZachary Turner }
8697841efbbSZachary Turner 
870b9c1b51eSKate Stone PythonDictionary PythonModule::GetDictionary() const {
871722b6189SLawrence D'Anna   if (!IsValid())
872722b6189SLawrence D'Anna     return PythonDictionary();
873722b6189SLawrence D'Anna   return Retain<PythonDictionary>(PyModule_GetDict(m_py_obj));
8747841efbbSZachary Turner }
8757841efbbSZachary Turner 
876b9c1b51eSKate Stone bool PythonCallable::Check(PyObject *py_obj) {
877a1405147SZachary Turner   if (!py_obj)
878a1405147SZachary Turner     return false;
879a1405147SZachary Turner 
880a1405147SZachary Turner   return PyCallable_Check(py_obj);
881a1405147SZachary Turner }
882a1405147SZachary Turner 
883c86a6acaSLawrence D'Anna #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
884c86a6acaSLawrence D'Anna static const char get_arg_info_script[] = R"(
885c86a6acaSLawrence D'Anna from inspect import signature, Parameter, ismethod
886c86a6acaSLawrence D'Anna from collections import namedtuple
887adbf64ccSLawrence D'Anna ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs'])
88804edd189SLawrence D'Anna def main(f):
889c86a6acaSLawrence D'Anna     count = 0
890c86a6acaSLawrence D'Anna     varargs = False
891c86a6acaSLawrence D'Anna     for parameter in signature(f).parameters.values():
892c86a6acaSLawrence D'Anna         kind = parameter.kind
893c86a6acaSLawrence D'Anna         if kind in (Parameter.POSITIONAL_ONLY,
894c86a6acaSLawrence D'Anna                     Parameter.POSITIONAL_OR_KEYWORD):
895c86a6acaSLawrence D'Anna             count += 1
896c86a6acaSLawrence D'Anna         elif kind == Parameter.VAR_POSITIONAL:
897c86a6acaSLawrence D'Anna             varargs = True
898c86a6acaSLawrence D'Anna         elif kind in (Parameter.KEYWORD_ONLY,
899c86a6acaSLawrence D'Anna                       Parameter.VAR_KEYWORD):
900c86a6acaSLawrence D'Anna             pass
901c86a6acaSLawrence D'Anna         else:
902c86a6acaSLawrence D'Anna             raise Exception(f'unknown parameter kind: {kind}')
903adbf64ccSLawrence D'Anna     return ArgInfo(count, varargs)
904c86a6acaSLawrence D'Anna )";
905c86a6acaSLawrence D'Anna #endif
906c86a6acaSLawrence D'Anna 
907c86a6acaSLawrence D'Anna Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
908c86a6acaSLawrence D'Anna   ArgInfo result = {};
909c86a6acaSLawrence D'Anna   if (!IsValid())
910c86a6acaSLawrence D'Anna     return nullDeref();
911c86a6acaSLawrence D'Anna 
912c86a6acaSLawrence D'Anna #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
913c86a6acaSLawrence D'Anna 
91404edd189SLawrence D'Anna   // no need to synchronize access to this global, we already have the GIL
91504edd189SLawrence D'Anna   static PythonScript get_arg_info(get_arg_info_script);
91604edd189SLawrence D'Anna   Expected<PythonObject> pyarginfo = get_arg_info(*this);
917c86a6acaSLawrence D'Anna   if (!pyarginfo)
918c86a6acaSLawrence D'Anna     return pyarginfo.takeError();
919adbf64ccSLawrence D'Anna   long long count =
920adbf64ccSLawrence D'Anna       cantFail(As<long long>(pyarginfo.get().GetAttribute("count")));
921adbf64ccSLawrence D'Anna   bool has_varargs =
922c86a6acaSLawrence D'Anna       cantFail(As<bool>(pyarginfo.get().GetAttribute("has_varargs")));
923adbf64ccSLawrence D'Anna   result.max_positional_args = has_varargs ? ArgInfo::UNBOUNDED : count;
924c86a6acaSLawrence D'Anna 
925c86a6acaSLawrence D'Anna #else
926adbf64ccSLawrence D'Anna   PyObject *py_func_obj;
9272386537cSLawrence D'Anna   bool is_bound_method = false;
928adbf64ccSLawrence D'Anna   bool is_class = false;
929adbf64ccSLawrence D'Anna 
930adbf64ccSLawrence D'Anna   if (PyType_Check(m_py_obj) || PyClass_Check(m_py_obj)) {
931adbf64ccSLawrence D'Anna     auto init = GetAttribute("__init__");
932adbf64ccSLawrence D'Anna     if (!init)
933adbf64ccSLawrence D'Anna       return init.takeError();
934adbf64ccSLawrence D'Anna     py_func_obj = init.get().get();
935adbf64ccSLawrence D'Anna     is_class = true;
936adbf64ccSLawrence D'Anna   } else {
937adbf64ccSLawrence D'Anna     py_func_obj = m_py_obj;
938adbf64ccSLawrence D'Anna   }
939adbf64ccSLawrence D'Anna 
940b9c1b51eSKate Stone   if (PyMethod_Check(py_func_obj)) {
941a1405147SZachary Turner     py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
942a5d6765cSEnrico Granata     PythonObject im_self = GetAttributeValue("im_self");
943a5d6765cSEnrico Granata     if (im_self.IsValid() && !im_self.IsNone())
9442386537cSLawrence D'Anna       is_bound_method = true;
945b9c1b51eSKate Stone   } else {
946a5d6765cSEnrico Granata     // see if this is a callable object with an __call__ method
947b9c1b51eSKate Stone     if (!PyFunction_Check(py_func_obj)) {
948a5d6765cSEnrico Granata       PythonObject __call__ = GetAttributeValue("__call__");
949b9c1b51eSKate Stone       if (__call__.IsValid()) {
950a5d6765cSEnrico Granata         auto __callable__ = __call__.AsType<PythonCallable>();
951b9c1b51eSKate Stone         if (__callable__.IsValid()) {
952a5d6765cSEnrico Granata           py_func_obj = PyMethod_GET_FUNCTION(__callable__.get());
9532386537cSLawrence D'Anna           PythonObject im_self = __callable__.GetAttributeValue("im_self");
954a5d6765cSEnrico Granata           if (im_self.IsValid() && !im_self.IsNone())
9552386537cSLawrence D'Anna             is_bound_method = true;
956a5d6765cSEnrico Granata         }
957a5d6765cSEnrico Granata       }
958a5d6765cSEnrico Granata     }
959a5d6765cSEnrico Granata   }
960a1405147SZachary Turner 
961a1405147SZachary Turner   if (!py_func_obj)
962b58fb2f4SZachary Turner     return result;
963a1405147SZachary Turner 
964a1405147SZachary Turner   PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(py_func_obj);
965a1405147SZachary Turner   if (!code)
966b58fb2f4SZachary Turner     return result;
967a1405147SZachary Turner 
968adbf64ccSLawrence D'Anna   auto count = code->co_argcount;
969adbf64ccSLawrence D'Anna   bool has_varargs = !!(code->co_flags & CO_VARARGS);
970adbf64ccSLawrence D'Anna   result.max_positional_args =
971adbf64ccSLawrence D'Anna       has_varargs ? ArgInfo::UNBOUNDED
972adbf64ccSLawrence D'Anna                   : (count - (int)is_bound_method) - (int)is_class;
973c86a6acaSLawrence D'Anna 
974c86a6acaSLawrence D'Anna #endif
975c86a6acaSLawrence D'Anna 
976b58fb2f4SZachary Turner   return result;
977b58fb2f4SZachary Turner }
978b58fb2f4SZachary Turner 
9792386537cSLawrence D'Anna constexpr unsigned
9802386537cSLawrence D'Anna     PythonCallable::ArgInfo::UNBOUNDED; // FIXME delete after c++17
9812386537cSLawrence D'Anna 
982b9c1b51eSKate Stone PythonObject PythonCallable::operator()() {
983b9c1b51eSKate Stone   return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));
984a1405147SZachary Turner }
985a1405147SZachary Turner 
986b9c1b51eSKate Stone PythonObject PythonCallable::
987b9c1b51eSKate Stone operator()(std::initializer_list<PyObject *> args) {
988a1405147SZachary Turner   PythonTuple arg_tuple(args);
989a1405147SZachary Turner   return PythonObject(PyRefType::Owned,
990a1405147SZachary Turner                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
991a1405147SZachary Turner }
992a1405147SZachary Turner 
993b9c1b51eSKate Stone PythonObject PythonCallable::
994b9c1b51eSKate Stone operator()(std::initializer_list<PythonObject> args) {
995a1405147SZachary Turner   PythonTuple arg_tuple(args);
996a1405147SZachary Turner   return PythonObject(PyRefType::Owned,
997a1405147SZachary Turner                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
998a1405147SZachary Turner }
999a1405147SZachary Turner 
1000b9c1b51eSKate Stone bool PythonFile::Check(PyObject *py_obj) {
100196898eb6SLawrence D'Anna   if (!py_obj)
100296898eb6SLawrence D'Anna     return false;
10039c40264fSZachary Turner #if PY_MAJOR_VERSION < 3
100423502721SJason Molenda   return PyFile_Check(py_obj);
100523502721SJason Molenda #else
10069c40264fSZachary Turner   // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
10079c40264fSZachary Turner   // first-class object type anymore.  `PyFile_FromFd` is just a thin wrapper
100805097246SAdrian Prantl   // over `io.open()`, which returns some object derived from `io.IOBase`. As a
100905097246SAdrian Prantl   // result, the only way to detect a file in Python 3 is to check whether it
101021b8a8aeSLawrence D'Anna   // inherits from `io.IOBase`.
101121b8a8aeSLawrence D'Anna   auto io_module = PythonModule::Import("io");
101221b8a8aeSLawrence D'Anna   if (!io_module) {
101321b8a8aeSLawrence D'Anna     llvm::consumeError(io_module.takeError());
10149c40264fSZachary Turner     return false;
101521b8a8aeSLawrence D'Anna   }
101621b8a8aeSLawrence D'Anna   auto iobase = io_module.get().Get("IOBase");
101721b8a8aeSLawrence D'Anna   if (!iobase) {
101821b8a8aeSLawrence D'Anna     llvm::consumeError(iobase.takeError());
10199c40264fSZachary Turner     return false;
102021b8a8aeSLawrence D'Anna   }
102121b8a8aeSLawrence D'Anna   int r = PyObject_IsInstance(py_obj, iobase.get().get());
102221b8a8aeSLawrence D'Anna   if (r < 0) {
102321b8a8aeSLawrence D'Anna     llvm::consumeError(exception()); // clear the exception and log it.
102421b8a8aeSLawrence D'Anna     return false;
102521b8a8aeSLawrence D'Anna   }
102621b8a8aeSLawrence D'Anna   return !!r;
102723502721SJason Molenda #endif
10289c40264fSZachary Turner }
10299c40264fSZachary Turner 
1030085328eeSLawrence D'Anna const char *PythonException::toCString() const {
1031085328eeSLawrence D'Anna   if (!m_repr_bytes)
1032085328eeSLawrence D'Anna     return "unknown exception";
1033085328eeSLawrence D'Anna   return PyBytes_AS_STRING(m_repr_bytes);
1034085328eeSLawrence D'Anna }
1035085328eeSLawrence D'Anna 
1036085328eeSLawrence D'Anna PythonException::PythonException(const char *caller) {
1037085328eeSLawrence D'Anna   assert(PyErr_Occurred());
1038085328eeSLawrence D'Anna   m_exception_type = m_exception = m_traceback = m_repr_bytes = NULL;
1039085328eeSLawrence D'Anna   PyErr_Fetch(&m_exception_type, &m_exception, &m_traceback);
1040085328eeSLawrence D'Anna   PyErr_NormalizeException(&m_exception_type, &m_exception, &m_traceback);
1041085328eeSLawrence D'Anna   PyErr_Clear();
1042085328eeSLawrence D'Anna   if (m_exception) {
1043085328eeSLawrence D'Anna     PyObject *repr = PyObject_Repr(m_exception);
1044085328eeSLawrence D'Anna     if (repr) {
1045085328eeSLawrence D'Anna       m_repr_bytes = PyUnicode_AsEncodedString(repr, "utf-8", nullptr);
1046085328eeSLawrence D'Anna       if (!m_repr_bytes) {
1047085328eeSLawrence D'Anna         PyErr_Clear();
1048085328eeSLawrence D'Anna       }
1049085328eeSLawrence D'Anna       Py_XDECREF(repr);
1050085328eeSLawrence D'Anna     } else {
1051085328eeSLawrence D'Anna       PyErr_Clear();
1052085328eeSLawrence D'Anna     }
1053085328eeSLawrence D'Anna   }
1054a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Script);
1055085328eeSLawrence D'Anna   if (caller)
1056085328eeSLawrence D'Anna     LLDB_LOGF(log, "%s failed with exception: %s", caller, toCString());
1057085328eeSLawrence D'Anna   else
1058085328eeSLawrence D'Anna     LLDB_LOGF(log, "python exception: %s", toCString());
1059085328eeSLawrence D'Anna }
1060085328eeSLawrence D'Anna void PythonException::Restore() {
1061085328eeSLawrence D'Anna   if (m_exception_type && m_exception) {
1062085328eeSLawrence D'Anna     PyErr_Restore(m_exception_type, m_exception, m_traceback);
1063085328eeSLawrence D'Anna   } else {
1064085328eeSLawrence D'Anna     PyErr_SetString(PyExc_Exception, toCString());
1065085328eeSLawrence D'Anna   }
1066085328eeSLawrence D'Anna   m_exception_type = m_exception = m_traceback = NULL;
1067085328eeSLawrence D'Anna }
1068085328eeSLawrence D'Anna 
1069085328eeSLawrence D'Anna PythonException::~PythonException() {
1070085328eeSLawrence D'Anna   Py_XDECREF(m_exception_type);
1071085328eeSLawrence D'Anna   Py_XDECREF(m_exception);
1072085328eeSLawrence D'Anna   Py_XDECREF(m_traceback);
1073085328eeSLawrence D'Anna   Py_XDECREF(m_repr_bytes);
1074085328eeSLawrence D'Anna }
1075085328eeSLawrence D'Anna 
1076085328eeSLawrence D'Anna void PythonException::log(llvm::raw_ostream &OS) const { OS << toCString(); }
1077085328eeSLawrence D'Anna 
1078085328eeSLawrence D'Anna std::error_code PythonException::convertToErrorCode() const {
1079085328eeSLawrence D'Anna   return llvm::inconvertibleErrorCode();
1080085328eeSLawrence D'Anna }
1081085328eeSLawrence D'Anna 
108204edd189SLawrence D'Anna bool PythonException::Matches(PyObject *exc) const {
108304edd189SLawrence D'Anna   return PyErr_GivenExceptionMatches(m_exception_type, exc);
108404edd189SLawrence D'Anna }
108504edd189SLawrence D'Anna 
108604edd189SLawrence D'Anna const char read_exception_script[] = R"(
108704edd189SLawrence D'Anna import sys
108804edd189SLawrence D'Anna from traceback import print_exception
108904edd189SLawrence D'Anna if sys.version_info.major < 3:
109004edd189SLawrence D'Anna   from StringIO import StringIO
109104edd189SLawrence D'Anna else:
109204edd189SLawrence D'Anna   from io import StringIO
109304edd189SLawrence D'Anna def main(exc_type, exc_value, tb):
109404edd189SLawrence D'Anna   f = StringIO()
109504edd189SLawrence D'Anna   print_exception(exc_type, exc_value, tb, file=f)
109604edd189SLawrence D'Anna   return f.getvalue()
109704edd189SLawrence D'Anna )";
109804edd189SLawrence D'Anna 
109904edd189SLawrence D'Anna std::string PythonException::ReadBacktrace() const {
110004edd189SLawrence D'Anna 
110104edd189SLawrence D'Anna   if (!m_traceback)
110204edd189SLawrence D'Anna     return toCString();
110304edd189SLawrence D'Anna 
110404edd189SLawrence D'Anna   // no need to synchronize access to this global, we already have the GIL
110504edd189SLawrence D'Anna   static PythonScript read_exception(read_exception_script);
110604edd189SLawrence D'Anna 
110704edd189SLawrence D'Anna   Expected<std::string> backtrace = As<std::string>(
110804edd189SLawrence D'Anna       read_exception(m_exception_type, m_exception, m_traceback));
110904edd189SLawrence D'Anna 
111004edd189SLawrence D'Anna   if (!backtrace) {
111104edd189SLawrence D'Anna     std::string message =
111204edd189SLawrence D'Anna         std::string(toCString()) + "\n" +
1113e9264b74SKazuaki Ishizaki         "Traceback unavailable, an error occurred while reading it:\n";
111404edd189SLawrence D'Anna     return (message + llvm::toString(backtrace.takeError()));
111504edd189SLawrence D'Anna   }
111604edd189SLawrence D'Anna 
111704edd189SLawrence D'Anna   return std::move(backtrace.get());
111804edd189SLawrence D'Anna }
111904edd189SLawrence D'Anna 
1120085328eeSLawrence D'Anna char PythonException::ID = 0;
1121085328eeSLawrence D'Anna 
112262c9fe42SLawrence D'Anna llvm::Expected<File::OpenOptions>
112362c9fe42SLawrence D'Anna GetOptionsForPyObject(const PythonObject &obj) {
112421b8a8aeSLawrence D'Anna #if PY_MAJOR_VERSION >= 3
112562c9fe42SLawrence D'Anna   auto options = File::OpenOptions(0);
112621b8a8aeSLawrence D'Anna   auto readable = As<bool>(obj.CallMethod("readable"));
112721b8a8aeSLawrence D'Anna   if (!readable)
112821b8a8aeSLawrence D'Anna     return readable.takeError();
112921b8a8aeSLawrence D'Anna   auto writable = As<bool>(obj.CallMethod("writable"));
113021b8a8aeSLawrence D'Anna   if (!writable)
113121b8a8aeSLawrence D'Anna     return writable.takeError();
113214735cabSMichał Górny   if (readable.get() && writable.get())
113314735cabSMichał Górny     options |= File::eOpenOptionReadWrite;
113414735cabSMichał Górny   else if (writable.get())
113514735cabSMichał Górny     options |= File::eOpenOptionWriteOnly;
113614735cabSMichał Górny   else if (readable.get())
113714735cabSMichał Górny     options |= File::eOpenOptionReadOnly;
113862c9fe42SLawrence D'Anna   return options;
113921b8a8aeSLawrence D'Anna #else
114021b8a8aeSLawrence D'Anna   PythonString py_mode = obj.GetAttributeValue("mode").AsType<PythonString>();
114162c9fe42SLawrence D'Anna   return File::GetOptionsFromMode(py_mode.GetString());
114221b8a8aeSLawrence D'Anna #endif
114321b8a8aeSLawrence D'Anna }
114421b8a8aeSLawrence D'Anna 
114521b8a8aeSLawrence D'Anna // Base class template for python files.   All it knows how to do
114621b8a8aeSLawrence D'Anna // is hold a reference to the python object and close or flush it
114721b8a8aeSLawrence D'Anna // when the File is closed.
114821b8a8aeSLawrence D'Anna namespace {
114921b8a8aeSLawrence D'Anna template <typename Base> class OwnedPythonFile : public Base {
115021b8a8aeSLawrence D'Anna public:
115121b8a8aeSLawrence D'Anna   template <typename... Args>
115221b8a8aeSLawrence D'Anna   OwnedPythonFile(const PythonFile &file, bool borrowed, Args... args)
115321b8a8aeSLawrence D'Anna       : Base(args...), m_py_obj(file), m_borrowed(borrowed) {
115421b8a8aeSLawrence D'Anna     assert(m_py_obj);
115521b8a8aeSLawrence D'Anna   }
115621b8a8aeSLawrence D'Anna 
115721b8a8aeSLawrence D'Anna   ~OwnedPythonFile() override {
115821b8a8aeSLawrence D'Anna     assert(m_py_obj);
115921b8a8aeSLawrence D'Anna     GIL takeGIL;
116021b8a8aeSLawrence D'Anna     Close();
1161722b6189SLawrence D'Anna     // we need to ensure the python object is released while we still
1162722b6189SLawrence D'Anna     // hold the GIL
116321b8a8aeSLawrence D'Anna     m_py_obj.Reset();
116421b8a8aeSLawrence D'Anna   }
116521b8a8aeSLawrence D'Anna 
116621b8a8aeSLawrence D'Anna   bool IsPythonSideValid() const {
116721b8a8aeSLawrence D'Anna     GIL takeGIL;
116821b8a8aeSLawrence D'Anna     auto closed = As<bool>(m_py_obj.GetAttribute("closed"));
116921b8a8aeSLawrence D'Anna     if (!closed) {
117021b8a8aeSLawrence D'Anna       llvm::consumeError(closed.takeError());
117121b8a8aeSLawrence D'Anna       return false;
117221b8a8aeSLawrence D'Anna     }
117321b8a8aeSLawrence D'Anna     return !closed.get();
117421b8a8aeSLawrence D'Anna   }
117521b8a8aeSLawrence D'Anna 
117621b8a8aeSLawrence D'Anna   bool IsValid() const override {
117721b8a8aeSLawrence D'Anna     return IsPythonSideValid() && Base::IsValid();
117821b8a8aeSLawrence D'Anna   }
117921b8a8aeSLawrence D'Anna 
118021b8a8aeSLawrence D'Anna   Status Close() override {
118121b8a8aeSLawrence D'Anna     assert(m_py_obj);
118221b8a8aeSLawrence D'Anna     Status py_error, base_error;
118321b8a8aeSLawrence D'Anna     GIL takeGIL;
118421b8a8aeSLawrence D'Anna     if (!m_borrowed) {
118521b8a8aeSLawrence D'Anna       auto r = m_py_obj.CallMethod("close");
118621b8a8aeSLawrence D'Anna       if (!r)
118721b8a8aeSLawrence D'Anna         py_error = Status(r.takeError());
118821b8a8aeSLawrence D'Anna     }
118921b8a8aeSLawrence D'Anna     base_error = Base::Close();
119021b8a8aeSLawrence D'Anna     if (py_error.Fail())
119121b8a8aeSLawrence D'Anna       return py_error;
119221b8a8aeSLawrence D'Anna     return base_error;
119321b8a8aeSLawrence D'Anna   };
119421b8a8aeSLawrence D'Anna 
1195d9b553ecSLawrence D'Anna   PyObject *GetPythonObject() const {
1196d9b553ecSLawrence D'Anna     assert(m_py_obj.IsValid());
1197d9b553ecSLawrence D'Anna     return m_py_obj.get();
1198d9b553ecSLawrence D'Anna   }
1199d9b553ecSLawrence D'Anna 
1200d9b553ecSLawrence D'Anna   static bool classof(const File *file) = delete;
1201d9b553ecSLawrence D'Anna 
120221b8a8aeSLawrence D'Anna protected:
120321b8a8aeSLawrence D'Anna   PythonFile m_py_obj;
120421b8a8aeSLawrence D'Anna   bool m_borrowed;
120521b8a8aeSLawrence D'Anna };
120621b8a8aeSLawrence D'Anna } // namespace
120721b8a8aeSLawrence D'Anna 
120821b8a8aeSLawrence D'Anna // A SimplePythonFile is a OwnedPythonFile that just does all I/O as
120921b8a8aeSLawrence D'Anna // a NativeFile
121021b8a8aeSLawrence D'Anna namespace {
121121b8a8aeSLawrence D'Anna class SimplePythonFile : public OwnedPythonFile<NativeFile> {
121221b8a8aeSLawrence D'Anna public:
121321b8a8aeSLawrence D'Anna   SimplePythonFile(const PythonFile &file, bool borrowed, int fd,
121462c9fe42SLawrence D'Anna                    File::OpenOptions options)
121521b8a8aeSLawrence D'Anna       : OwnedPythonFile(file, borrowed, fd, options, false) {}
1216d9b553ecSLawrence D'Anna 
1217d9b553ecSLawrence D'Anna   static char ID;
1218d9b553ecSLawrence D'Anna   bool isA(const void *classID) const override {
1219d9b553ecSLawrence D'Anna     return classID == &ID || NativeFile::isA(classID);
1220d9b553ecSLawrence D'Anna   }
1221d9b553ecSLawrence D'Anna   static bool classof(const File *file) { return file->isA(&ID); }
122221b8a8aeSLawrence D'Anna };
1223d9b553ecSLawrence D'Anna char SimplePythonFile::ID = 0;
122421b8a8aeSLawrence D'Anna } // namespace
122521b8a8aeSLawrence D'Anna 
122621b8a8aeSLawrence D'Anna #if PY_MAJOR_VERSION >= 3
122721b8a8aeSLawrence D'Anna 
122821b8a8aeSLawrence D'Anna namespace {
122921b8a8aeSLawrence D'Anna class PythonBuffer {
123021b8a8aeSLawrence D'Anna public:
123121b8a8aeSLawrence D'Anna   PythonBuffer &operator=(const PythonBuffer &) = delete;
123221b8a8aeSLawrence D'Anna   PythonBuffer(const PythonBuffer &) = delete;
123321b8a8aeSLawrence D'Anna 
123421b8a8aeSLawrence D'Anna   static Expected<PythonBuffer> Create(PythonObject &obj,
123521b8a8aeSLawrence D'Anna                                        int flags = PyBUF_SIMPLE) {
123621b8a8aeSLawrence D'Anna     Py_buffer py_buffer = {};
123721b8a8aeSLawrence D'Anna     PyObject_GetBuffer(obj.get(), &py_buffer, flags);
123821b8a8aeSLawrence D'Anna     if (!py_buffer.obj)
123921b8a8aeSLawrence D'Anna       return llvm::make_error<PythonException>();
124021b8a8aeSLawrence D'Anna     return PythonBuffer(py_buffer);
124121b8a8aeSLawrence D'Anna   }
124221b8a8aeSLawrence D'Anna 
124321b8a8aeSLawrence D'Anna   PythonBuffer(PythonBuffer &&other) {
124421b8a8aeSLawrence D'Anna     m_buffer = other.m_buffer;
124521b8a8aeSLawrence D'Anna     other.m_buffer.obj = nullptr;
124621b8a8aeSLawrence D'Anna   }
124721b8a8aeSLawrence D'Anna 
124821b8a8aeSLawrence D'Anna   ~PythonBuffer() {
124921b8a8aeSLawrence D'Anna     if (m_buffer.obj)
125021b8a8aeSLawrence D'Anna       PyBuffer_Release(&m_buffer);
125121b8a8aeSLawrence D'Anna   }
125221b8a8aeSLawrence D'Anna 
125321b8a8aeSLawrence D'Anna   Py_buffer &get() { return m_buffer; }
125421b8a8aeSLawrence D'Anna 
125521b8a8aeSLawrence D'Anna private:
125621b8a8aeSLawrence D'Anna   // takes ownership of the buffer.
125721b8a8aeSLawrence D'Anna   PythonBuffer(const Py_buffer &py_buffer) : m_buffer(py_buffer) {}
125821b8a8aeSLawrence D'Anna   Py_buffer m_buffer;
125921b8a8aeSLawrence D'Anna };
126021b8a8aeSLawrence D'Anna } // namespace
126121b8a8aeSLawrence D'Anna 
126221b8a8aeSLawrence D'Anna // Shared methods between TextPythonFile and BinaryPythonFile
126321b8a8aeSLawrence D'Anna namespace {
126421b8a8aeSLawrence D'Anna class PythonIOFile : public OwnedPythonFile<File> {
126521b8a8aeSLawrence D'Anna public:
126621b8a8aeSLawrence D'Anna   PythonIOFile(const PythonFile &file, bool borrowed)
126721b8a8aeSLawrence D'Anna       : OwnedPythonFile(file, borrowed) {}
126821b8a8aeSLawrence D'Anna 
126921b8a8aeSLawrence D'Anna   ~PythonIOFile() override { Close(); }
127021b8a8aeSLawrence D'Anna 
127121b8a8aeSLawrence D'Anna   bool IsValid() const override { return IsPythonSideValid(); }
127221b8a8aeSLawrence D'Anna 
127321b8a8aeSLawrence D'Anna   Status Close() override {
127421b8a8aeSLawrence D'Anna     assert(m_py_obj);
127521b8a8aeSLawrence D'Anna     GIL takeGIL;
127621b8a8aeSLawrence D'Anna     if (m_borrowed)
127721b8a8aeSLawrence D'Anna       return Flush();
127821b8a8aeSLawrence D'Anna     auto r = m_py_obj.CallMethod("close");
127921b8a8aeSLawrence D'Anna     if (!r)
128021b8a8aeSLawrence D'Anna       return Status(r.takeError());
128121b8a8aeSLawrence D'Anna     return Status();
128221b8a8aeSLawrence D'Anna   }
128321b8a8aeSLawrence D'Anna 
128421b8a8aeSLawrence D'Anna   Status Flush() override {
128521b8a8aeSLawrence D'Anna     GIL takeGIL;
128621b8a8aeSLawrence D'Anna     auto r = m_py_obj.CallMethod("flush");
128721b8a8aeSLawrence D'Anna     if (!r)
128821b8a8aeSLawrence D'Anna       return Status(r.takeError());
128921b8a8aeSLawrence D'Anna     return Status();
129021b8a8aeSLawrence D'Anna   }
129121b8a8aeSLawrence D'Anna 
1292d9b553ecSLawrence D'Anna   Expected<File::OpenOptions> GetOptions() const override {
1293d9b553ecSLawrence D'Anna     GIL takeGIL;
1294d9b553ecSLawrence D'Anna     return GetOptionsForPyObject(m_py_obj);
1295d9b553ecSLawrence D'Anna   }
1296d9b553ecSLawrence D'Anna 
1297d9b553ecSLawrence D'Anna   static char ID;
1298d9b553ecSLawrence D'Anna   bool isA(const void *classID) const override {
1299d9b553ecSLawrence D'Anna     return classID == &ID || File::isA(classID);
1300d9b553ecSLawrence D'Anna   }
1301d9b553ecSLawrence D'Anna   static bool classof(const File *file) { return file->isA(&ID); }
130221b8a8aeSLawrence D'Anna };
1303d9b553ecSLawrence D'Anna char PythonIOFile::ID = 0;
130421b8a8aeSLawrence D'Anna } // namespace
130521b8a8aeSLawrence D'Anna 
130621b8a8aeSLawrence D'Anna namespace {
130721b8a8aeSLawrence D'Anna class BinaryPythonFile : public PythonIOFile {
130821b8a8aeSLawrence D'Anna protected:
130921b8a8aeSLawrence D'Anna   int m_descriptor;
131021b8a8aeSLawrence D'Anna 
131121b8a8aeSLawrence D'Anna public:
131221b8a8aeSLawrence D'Anna   BinaryPythonFile(int fd, const PythonFile &file, bool borrowed)
131321b8a8aeSLawrence D'Anna       : PythonIOFile(file, borrowed),
131421b8a8aeSLawrence D'Anna         m_descriptor(File::DescriptorIsValid(fd) ? fd
131521b8a8aeSLawrence D'Anna                                                  : File::kInvalidDescriptor) {}
131621b8a8aeSLawrence D'Anna 
131721b8a8aeSLawrence D'Anna   int GetDescriptor() const override { return m_descriptor; }
131821b8a8aeSLawrence D'Anna 
131921b8a8aeSLawrence D'Anna   Status Write(const void *buf, size_t &num_bytes) override {
132021b8a8aeSLawrence D'Anna     GIL takeGIL;
132121b8a8aeSLawrence D'Anna     PyObject *pybuffer_p = PyMemoryView_FromMemory(
132221b8a8aeSLawrence D'Anna         const_cast<char *>((const char *)buf), num_bytes, PyBUF_READ);
132321b8a8aeSLawrence D'Anna     if (!pybuffer_p)
132421b8a8aeSLawrence D'Anna       return Status(llvm::make_error<PythonException>());
132521b8a8aeSLawrence D'Anna     auto pybuffer = Take<PythonObject>(pybuffer_p);
132621b8a8aeSLawrence D'Anna     num_bytes = 0;
132721b8a8aeSLawrence D'Anna     auto bytes_written = As<long long>(m_py_obj.CallMethod("write", pybuffer));
132821b8a8aeSLawrence D'Anna     if (!bytes_written)
132921b8a8aeSLawrence D'Anna       return Status(bytes_written.takeError());
133021b8a8aeSLawrence D'Anna     if (bytes_written.get() < 0)
133121b8a8aeSLawrence D'Anna       return Status(".write() method returned a negative number!");
133221b8a8aeSLawrence D'Anna     static_assert(sizeof(long long) >= sizeof(size_t), "overflow");
133321b8a8aeSLawrence D'Anna     num_bytes = bytes_written.get();
133421b8a8aeSLawrence D'Anna     return Status();
133521b8a8aeSLawrence D'Anna   }
133621b8a8aeSLawrence D'Anna 
133721b8a8aeSLawrence D'Anna   Status Read(void *buf, size_t &num_bytes) override {
133821b8a8aeSLawrence D'Anna     GIL takeGIL;
133921b8a8aeSLawrence D'Anna     static_assert(sizeof(long long) >= sizeof(size_t), "overflow");
134021b8a8aeSLawrence D'Anna     auto pybuffer_obj =
134121b8a8aeSLawrence D'Anna         m_py_obj.CallMethod("read", (unsigned long long)num_bytes);
134221b8a8aeSLawrence D'Anna     if (!pybuffer_obj)
134321b8a8aeSLawrence D'Anna       return Status(pybuffer_obj.takeError());
134421b8a8aeSLawrence D'Anna     num_bytes = 0;
134521b8a8aeSLawrence D'Anna     if (pybuffer_obj.get().IsNone()) {
134621b8a8aeSLawrence D'Anna       // EOF
134721b8a8aeSLawrence D'Anna       num_bytes = 0;
134821b8a8aeSLawrence D'Anna       return Status();
134921b8a8aeSLawrence D'Anna     }
135021b8a8aeSLawrence D'Anna     auto pybuffer = PythonBuffer::Create(pybuffer_obj.get());
135121b8a8aeSLawrence D'Anna     if (!pybuffer)
135221b8a8aeSLawrence D'Anna       return Status(pybuffer.takeError());
135321b8a8aeSLawrence D'Anna     memcpy(buf, pybuffer.get().get().buf, pybuffer.get().get().len);
135421b8a8aeSLawrence D'Anna     num_bytes = pybuffer.get().get().len;
135521b8a8aeSLawrence D'Anna     return Status();
135621b8a8aeSLawrence D'Anna   }
135721b8a8aeSLawrence D'Anna };
135821b8a8aeSLawrence D'Anna } // namespace
135921b8a8aeSLawrence D'Anna 
136021b8a8aeSLawrence D'Anna namespace {
136121b8a8aeSLawrence D'Anna class TextPythonFile : public PythonIOFile {
136221b8a8aeSLawrence D'Anna protected:
136321b8a8aeSLawrence D'Anna   int m_descriptor;
136421b8a8aeSLawrence D'Anna 
136521b8a8aeSLawrence D'Anna public:
136621b8a8aeSLawrence D'Anna   TextPythonFile(int fd, const PythonFile &file, bool borrowed)
136721b8a8aeSLawrence D'Anna       : PythonIOFile(file, borrowed),
136821b8a8aeSLawrence D'Anna         m_descriptor(File::DescriptorIsValid(fd) ? fd
136921b8a8aeSLawrence D'Anna                                                  : File::kInvalidDescriptor) {}
137021b8a8aeSLawrence D'Anna 
137121b8a8aeSLawrence D'Anna   int GetDescriptor() const override { return m_descriptor; }
137221b8a8aeSLawrence D'Anna 
137321b8a8aeSLawrence D'Anna   Status Write(const void *buf, size_t &num_bytes) override {
137421b8a8aeSLawrence D'Anna     GIL takeGIL;
137521b8a8aeSLawrence D'Anna     auto pystring =
137621b8a8aeSLawrence D'Anna         PythonString::FromUTF8(llvm::StringRef((const char *)buf, num_bytes));
137721b8a8aeSLawrence D'Anna     if (!pystring)
137821b8a8aeSLawrence D'Anna       return Status(pystring.takeError());
137921b8a8aeSLawrence D'Anna     num_bytes = 0;
138021b8a8aeSLawrence D'Anna     auto bytes_written =
138121b8a8aeSLawrence D'Anna         As<long long>(m_py_obj.CallMethod("write", pystring.get()));
138221b8a8aeSLawrence D'Anna     if (!bytes_written)
138321b8a8aeSLawrence D'Anna       return Status(bytes_written.takeError());
138421b8a8aeSLawrence D'Anna     if (bytes_written.get() < 0)
138521b8a8aeSLawrence D'Anna       return Status(".write() method returned a negative number!");
138621b8a8aeSLawrence D'Anna     static_assert(sizeof(long long) >= sizeof(size_t), "overflow");
138721b8a8aeSLawrence D'Anna     num_bytes = bytes_written.get();
138821b8a8aeSLawrence D'Anna     return Status();
138921b8a8aeSLawrence D'Anna   }
139021b8a8aeSLawrence D'Anna 
139121b8a8aeSLawrence D'Anna   Status Read(void *buf, size_t &num_bytes) override {
139221b8a8aeSLawrence D'Anna     GIL takeGIL;
139321b8a8aeSLawrence D'Anna     size_t num_chars = num_bytes / 6;
139421b8a8aeSLawrence D'Anna     size_t orig_num_bytes = num_bytes;
139521b8a8aeSLawrence D'Anna     num_bytes = 0;
139621b8a8aeSLawrence D'Anna     if (orig_num_bytes < 6) {
139721b8a8aeSLawrence D'Anna       return Status("can't read less than 6 bytes from a utf8 text stream");
139821b8a8aeSLawrence D'Anna     }
139921b8a8aeSLawrence D'Anna     auto pystring = As<PythonString>(
140021b8a8aeSLawrence D'Anna         m_py_obj.CallMethod("read", (unsigned long long)num_chars));
140121b8a8aeSLawrence D'Anna     if (!pystring)
140221b8a8aeSLawrence D'Anna       return Status(pystring.takeError());
140321b8a8aeSLawrence D'Anna     if (pystring.get().IsNone()) {
140421b8a8aeSLawrence D'Anna       // EOF
140521b8a8aeSLawrence D'Anna       return Status();
140621b8a8aeSLawrence D'Anna     }
140721b8a8aeSLawrence D'Anna     auto stringref = pystring.get().AsUTF8();
140821b8a8aeSLawrence D'Anna     if (!stringref)
140921b8a8aeSLawrence D'Anna       return Status(stringref.takeError());
141021b8a8aeSLawrence D'Anna     num_bytes = stringref.get().size();
141121b8a8aeSLawrence D'Anna     memcpy(buf, stringref.get().begin(), num_bytes);
141221b8a8aeSLawrence D'Anna     return Status();
141321b8a8aeSLawrence D'Anna   }
141421b8a8aeSLawrence D'Anna };
141521b8a8aeSLawrence D'Anna } // namespace
141621b8a8aeSLawrence D'Anna 
141721b8a8aeSLawrence D'Anna #endif
141821b8a8aeSLawrence D'Anna 
141921b8a8aeSLawrence D'Anna llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) {
142021b8a8aeSLawrence D'Anna   if (!IsValid())
142121b8a8aeSLawrence D'Anna     return llvm::createStringError(llvm::inconvertibleErrorCode(),
142221b8a8aeSLawrence D'Anna                                    "invalid PythonFile");
142321b8a8aeSLawrence D'Anna 
142421b8a8aeSLawrence D'Anna   int fd = PyObject_AsFileDescriptor(m_py_obj);
142521b8a8aeSLawrence D'Anna   if (fd < 0) {
142621b8a8aeSLawrence D'Anna     PyErr_Clear();
142721b8a8aeSLawrence D'Anna     return ConvertToFileForcingUseOfScriptingIOMethods(borrowed);
142821b8a8aeSLawrence D'Anna   }
142921b8a8aeSLawrence D'Anna   auto options = GetOptionsForPyObject(*this);
143021b8a8aeSLawrence D'Anna   if (!options)
143121b8a8aeSLawrence D'Anna     return options.takeError();
143221b8a8aeSLawrence D'Anna 
143314735cabSMichał Górny   File::OpenOptions rw =
143414735cabSMichał Górny       options.get() & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
143514735cabSMichał Górny                        File::eOpenOptionReadWrite);
143614735cabSMichał Górny   if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {
143721b8a8aeSLawrence D'Anna     // LLDB and python will not share I/O buffers.  We should probably
143821b8a8aeSLawrence D'Anna     // flush the python buffers now.
143921b8a8aeSLawrence D'Anna     auto r = CallMethod("flush");
144021b8a8aeSLawrence D'Anna     if (!r)
144121b8a8aeSLawrence D'Anna       return r.takeError();
1442267cc329SMichal Gorny   }
144321b8a8aeSLawrence D'Anna 
144421b8a8aeSLawrence D'Anna   FileSP file_sp;
144521b8a8aeSLawrence D'Anna   if (borrowed) {
144621b8a8aeSLawrence D'Anna     // In this case we we don't need to retain the python
144721b8a8aeSLawrence D'Anna     // object at all.
144821b8a8aeSLawrence D'Anna     file_sp = std::make_shared<NativeFile>(fd, options.get(), false);
144921b8a8aeSLawrence D'Anna   } else {
145021b8a8aeSLawrence D'Anna     file_sp = std::static_pointer_cast<File>(
145121b8a8aeSLawrence D'Anna         std::make_shared<SimplePythonFile>(*this, borrowed, fd, options.get()));
145221b8a8aeSLawrence D'Anna   }
145321b8a8aeSLawrence D'Anna   if (!file_sp->IsValid())
145421b8a8aeSLawrence D'Anna     return llvm::createStringError(llvm::inconvertibleErrorCode(),
145521b8a8aeSLawrence D'Anna                                    "invalid File");
145621b8a8aeSLawrence D'Anna 
145721b8a8aeSLawrence D'Anna   return file_sp;
145821b8a8aeSLawrence D'Anna }
145921b8a8aeSLawrence D'Anna 
146021b8a8aeSLawrence D'Anna llvm::Expected<FileSP>
146121b8a8aeSLawrence D'Anna PythonFile::ConvertToFileForcingUseOfScriptingIOMethods(bool borrowed) {
146221b8a8aeSLawrence D'Anna 
146321b8a8aeSLawrence D'Anna   assert(!PyErr_Occurred());
146421b8a8aeSLawrence D'Anna 
146521b8a8aeSLawrence D'Anna   if (!IsValid())
146621b8a8aeSLawrence D'Anna     return llvm::createStringError(llvm::inconvertibleErrorCode(),
146721b8a8aeSLawrence D'Anna                                    "invalid PythonFile");
146821b8a8aeSLawrence D'Anna 
146921b8a8aeSLawrence D'Anna #if PY_MAJOR_VERSION < 3
147021b8a8aeSLawrence D'Anna 
147121b8a8aeSLawrence D'Anna   return llvm::createStringError(llvm::inconvertibleErrorCode(),
147221b8a8aeSLawrence D'Anna                                  "not supported on python 2");
147321b8a8aeSLawrence D'Anna 
147421b8a8aeSLawrence D'Anna #else
147521b8a8aeSLawrence D'Anna 
147621b8a8aeSLawrence D'Anna   int fd = PyObject_AsFileDescriptor(m_py_obj);
147721b8a8aeSLawrence D'Anna   if (fd < 0) {
147821b8a8aeSLawrence D'Anna     PyErr_Clear();
147921b8a8aeSLawrence D'Anna     fd = File::kInvalidDescriptor;
148021b8a8aeSLawrence D'Anna   }
148121b8a8aeSLawrence D'Anna 
148221b8a8aeSLawrence D'Anna   auto io_module = PythonModule::Import("io");
148321b8a8aeSLawrence D'Anna   if (!io_module)
148421b8a8aeSLawrence D'Anna     return io_module.takeError();
148521b8a8aeSLawrence D'Anna   auto textIOBase = io_module.get().Get("TextIOBase");
148621b8a8aeSLawrence D'Anna   if (!textIOBase)
148721b8a8aeSLawrence D'Anna     return textIOBase.takeError();
148821b8a8aeSLawrence D'Anna   auto rawIOBase = io_module.get().Get("RawIOBase");
148921b8a8aeSLawrence D'Anna   if (!rawIOBase)
149021b8a8aeSLawrence D'Anna     return rawIOBase.takeError();
149121b8a8aeSLawrence D'Anna   auto bufferedIOBase = io_module.get().Get("BufferedIOBase");
149221b8a8aeSLawrence D'Anna   if (!bufferedIOBase)
149321b8a8aeSLawrence D'Anna     return bufferedIOBase.takeError();
149421b8a8aeSLawrence D'Anna 
149521b8a8aeSLawrence D'Anna   FileSP file_sp;
149621b8a8aeSLawrence D'Anna 
149721b8a8aeSLawrence D'Anna   auto isTextIO = IsInstance(textIOBase.get());
149821b8a8aeSLawrence D'Anna   if (!isTextIO)
149921b8a8aeSLawrence D'Anna     return isTextIO.takeError();
150021b8a8aeSLawrence D'Anna   if (isTextIO.get())
150121b8a8aeSLawrence D'Anna     file_sp = std::static_pointer_cast<File>(
150221b8a8aeSLawrence D'Anna         std::make_shared<TextPythonFile>(fd, *this, borrowed));
150321b8a8aeSLawrence D'Anna 
150421b8a8aeSLawrence D'Anna   auto isRawIO = IsInstance(rawIOBase.get());
150521b8a8aeSLawrence D'Anna   if (!isRawIO)
150621b8a8aeSLawrence D'Anna     return isRawIO.takeError();
150721b8a8aeSLawrence D'Anna   auto isBufferedIO = IsInstance(bufferedIOBase.get());
150821b8a8aeSLawrence D'Anna   if (!isBufferedIO)
150921b8a8aeSLawrence D'Anna     return isBufferedIO.takeError();
151021b8a8aeSLawrence D'Anna 
151121b8a8aeSLawrence D'Anna   if (isRawIO.get() || isBufferedIO.get()) {
151221b8a8aeSLawrence D'Anna     file_sp = std::static_pointer_cast<File>(
151321b8a8aeSLawrence D'Anna         std::make_shared<BinaryPythonFile>(fd, *this, borrowed));
151421b8a8aeSLawrence D'Anna   }
151521b8a8aeSLawrence D'Anna 
151621b8a8aeSLawrence D'Anna   if (!file_sp)
151721b8a8aeSLawrence D'Anna     return llvm::createStringError(llvm::inconvertibleErrorCode(),
151821b8a8aeSLawrence D'Anna                                    "python file is neither text nor binary");
151921b8a8aeSLawrence D'Anna 
152021b8a8aeSLawrence D'Anna   if (!file_sp->IsValid())
152121b8a8aeSLawrence D'Anna     return llvm::createStringError(llvm::inconvertibleErrorCode(),
152221b8a8aeSLawrence D'Anna                                    "invalid File");
152321b8a8aeSLawrence D'Anna 
152421b8a8aeSLawrence D'Anna   return file_sp;
152521b8a8aeSLawrence D'Anna 
152621b8a8aeSLawrence D'Anna #endif
152721b8a8aeSLawrence D'Anna }
152821b8a8aeSLawrence D'Anna 
1529d9b553ecSLawrence D'Anna Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) {
1530d9b553ecSLawrence D'Anna   if (!file.IsValid())
1531d9b553ecSLawrence D'Anna     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1532d9b553ecSLawrence D'Anna                                    "invalid file");
1533d9b553ecSLawrence D'Anna 
1534d9b553ecSLawrence D'Anna   if (auto *simple = llvm::dyn_cast<SimplePythonFile>(&file))
1535d9b553ecSLawrence D'Anna     return Retain<PythonFile>(simple->GetPythonObject());
1536d9b553ecSLawrence D'Anna #if PY_MAJOR_VERSION >= 3
1537d9b553ecSLawrence D'Anna   if (auto *pythonio = llvm::dyn_cast<PythonIOFile>(&file))
1538d9b553ecSLawrence D'Anna     return Retain<PythonFile>(pythonio->GetPythonObject());
1539d9b553ecSLawrence D'Anna #endif
1540d9b553ecSLawrence D'Anna 
1541d9b553ecSLawrence D'Anna   if (!mode) {
1542d9b553ecSLawrence D'Anna     auto m = file.GetOpenMode();
1543d9b553ecSLawrence D'Anna     if (!m)
1544d9b553ecSLawrence D'Anna       return m.takeError();
1545d9b553ecSLawrence D'Anna     mode = m.get();
1546d9b553ecSLawrence D'Anna   }
1547d9b553ecSLawrence D'Anna 
1548d9b553ecSLawrence D'Anna   PyObject *file_obj;
1549d9b553ecSLawrence D'Anna #if PY_MAJOR_VERSION >= 3
1550d9b553ecSLawrence D'Anna   file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr,
15513071ebf7SLawrence D'Anna                            "ignore", nullptr, /*closefd=*/0);
1552d9b553ecSLawrence D'Anna #else
15533071ebf7SLawrence D'Anna   // I'd like to pass ::fflush here if the file is writable,  so that
15543071ebf7SLawrence D'Anna   // when the python side destructs the file object it will be flushed.
15553071ebf7SLawrence D'Anna   // However, this would be dangerous.    It can cause fflush to be called
15563071ebf7SLawrence D'Anna   // after fclose if the python program keeps a reference to the file after
15573071ebf7SLawrence D'Anna   // the original lldb_private::File has been destructed.
15583071ebf7SLawrence D'Anna   //
15593071ebf7SLawrence D'Anna   // It's all well and good to ask a python program not to use a closed file
15603071ebf7SLawrence D'Anna   // but asking a python program to make sure objects get released in a
15613071ebf7SLawrence D'Anna   // particular order is not safe.
15623071ebf7SLawrence D'Anna   //
15633071ebf7SLawrence D'Anna   // The tradeoff here is that if a python 2 program wants to make sure this
15643071ebf7SLawrence D'Anna   // file gets flushed, they'll have to do it explicitly or wait untill the
15653071ebf7SLawrence D'Anna   // original lldb File itself gets flushed.
15666a93a12aSLawrence D'Anna   file_obj = PyFile_FromFile(file.GetStream(), py2_const_cast(""),
15673071ebf7SLawrence D'Anna                              py2_const_cast(mode), [](FILE *) { return 0; });
1568d9b553ecSLawrence D'Anna #endif
1569d9b553ecSLawrence D'Anna 
1570d9b553ecSLawrence D'Anna   if (!file_obj)
1571d9b553ecSLawrence D'Anna     return exception();
1572d9b553ecSLawrence D'Anna 
1573d9b553ecSLawrence D'Anna   return Take<PythonFile>(file_obj);
1574d9b553ecSLawrence D'Anna }
1575d9b553ecSLawrence D'Anna 
157604edd189SLawrence D'Anna Error PythonScript::Init() {
157704edd189SLawrence D'Anna   if (function.IsValid())
157804edd189SLawrence D'Anna     return Error::success();
157904edd189SLawrence D'Anna 
158004edd189SLawrence D'Anna   PythonDictionary globals(PyInitialValue::Empty);
158104edd189SLawrence D'Anna   auto builtins = PythonModule::BuiltinsModule();
158204edd189SLawrence D'Anna   if (Error error = globals.SetItem("__builtins__", builtins))
158304edd189SLawrence D'Anna     return error;
158404edd189SLawrence D'Anna   PyObject *o =
158504edd189SLawrence D'Anna       PyRun_String(script, Py_file_input, globals.get(), globals.get());
158604edd189SLawrence D'Anna   if (!o)
158704edd189SLawrence D'Anna     return exception();
158804edd189SLawrence D'Anna   Take<PythonObject>(o);
158904edd189SLawrence D'Anna   auto f = As<PythonCallable>(globals.GetItem("main"));
159004edd189SLawrence D'Anna   if (!f)
159104edd189SLawrence D'Anna     return f.takeError();
159204edd189SLawrence D'Anna   function = std::move(f.get());
159304edd189SLawrence D'Anna 
159404edd189SLawrence D'Anna   return Error::success();
159504edd189SLawrence D'Anna }
159604edd189SLawrence D'Anna 
159704edd189SLawrence D'Anna llvm::Expected<PythonObject>
159804edd189SLawrence D'Anna python::runStringOneLine(const llvm::Twine &string,
159904edd189SLawrence D'Anna                          const PythonDictionary &globals,
160004edd189SLawrence D'Anna                          const PythonDictionary &locals) {
160104edd189SLawrence D'Anna   if (!globals.IsValid() || !locals.IsValid())
160204edd189SLawrence D'Anna     return nullDeref();
160304edd189SLawrence D'Anna 
160404edd189SLawrence D'Anna   PyObject *code =
160504edd189SLawrence D'Anna       Py_CompileString(NullTerminated(string), "<string>", Py_eval_input);
160604edd189SLawrence D'Anna   if (!code) {
160704edd189SLawrence D'Anna     PyErr_Clear();
160804edd189SLawrence D'Anna     code =
160904edd189SLawrence D'Anna         Py_CompileString(NullTerminated(string), "<string>", Py_single_input);
161004edd189SLawrence D'Anna   }
161104edd189SLawrence D'Anna   if (!code)
161204edd189SLawrence D'Anna     return exception();
161304edd189SLawrence D'Anna   auto code_ref = Take<PythonObject>(code);
161404edd189SLawrence D'Anna 
161504edd189SLawrence D'Anna #if PY_MAJOR_VERSION < 3
161604edd189SLawrence D'Anna   PyObject *result =
161704edd189SLawrence D'Anna       PyEval_EvalCode((PyCodeObject *)code, globals.get(), locals.get());
161804edd189SLawrence D'Anna #else
161904edd189SLawrence D'Anna   PyObject *result = PyEval_EvalCode(code, globals.get(), locals.get());
162004edd189SLawrence D'Anna #endif
162104edd189SLawrence D'Anna 
162204edd189SLawrence D'Anna   if (!result)
162304edd189SLawrence D'Anna     return exception();
162404edd189SLawrence D'Anna 
162504edd189SLawrence D'Anna   return Take<PythonObject>(result);
162604edd189SLawrence D'Anna }
162704edd189SLawrence D'Anna 
162804edd189SLawrence D'Anna llvm::Expected<PythonObject>
162904edd189SLawrence D'Anna python::runStringMultiLine(const llvm::Twine &string,
163004edd189SLawrence D'Anna                            const PythonDictionary &globals,
163104edd189SLawrence D'Anna                            const PythonDictionary &locals) {
163204edd189SLawrence D'Anna   if (!globals.IsValid() || !locals.IsValid())
163304edd189SLawrence D'Anna     return nullDeref();
163404edd189SLawrence D'Anna   PyObject *result = PyRun_String(NullTerminated(string), Py_file_input,
163504edd189SLawrence D'Anna                                   globals.get(), locals.get());
163604edd189SLawrence D'Anna   if (!result)
163704edd189SLawrence D'Anna     return exception();
163804edd189SLawrence D'Anna   return Take<PythonObject>(result);
163904edd189SLawrence D'Anna }
164004edd189SLawrence D'Anna 
1641d68983e3SPavel Labath #endif
1642