xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- PythonDataObjects.cpp -----------------------------------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #ifdef LLDB_DISABLE_PYTHON
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric // Python is disabled in this build
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #else
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric #include "PythonDataObjects.h"
16*0b57cec5SDimitry Andric #include "ScriptInterpreterPython.h"
17*0b57cec5SDimitry Andric 
18*0b57cec5SDimitry Andric #include "lldb/Host/File.h"
19*0b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
20*0b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
21*0b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
24*0b57cec5SDimitry Andric #include "llvm/Support/ConvertUTF.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric #include <stdio.h>
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric using namespace lldb_private;
30*0b57cec5SDimitry Andric using namespace lldb;
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric void StructuredPythonObject::Dump(Stream &s, bool pretty_print) const {
33*0b57cec5SDimitry Andric   s << "Python Obj: 0x" << GetValue();
34*0b57cec5SDimitry Andric }
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric // PythonObject
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric void PythonObject::Dump(Stream &strm) const {
39*0b57cec5SDimitry Andric   if (m_py_obj) {
40*0b57cec5SDimitry Andric     FILE *file = llvm::sys::RetryAfterSignal(nullptr, ::tmpfile);
41*0b57cec5SDimitry Andric     if (file) {
42*0b57cec5SDimitry Andric       ::PyObject_Print(m_py_obj, file, 0);
43*0b57cec5SDimitry Andric       const long length = ftell(file);
44*0b57cec5SDimitry Andric       if (length) {
45*0b57cec5SDimitry Andric         ::rewind(file);
46*0b57cec5SDimitry Andric         std::vector<char> file_contents(length, '\0');
47*0b57cec5SDimitry Andric         const size_t length_read =
48*0b57cec5SDimitry Andric             ::fread(file_contents.data(), 1, file_contents.size(), file);
49*0b57cec5SDimitry Andric         if (length_read > 0)
50*0b57cec5SDimitry Andric           strm.Write(file_contents.data(), length_read);
51*0b57cec5SDimitry Andric       }
52*0b57cec5SDimitry Andric       ::fclose(file);
53*0b57cec5SDimitry Andric     }
54*0b57cec5SDimitry Andric   } else
55*0b57cec5SDimitry Andric     strm.PutCString("NULL");
56*0b57cec5SDimitry Andric }
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric PyObjectType PythonObject::GetObjectType() const {
59*0b57cec5SDimitry Andric   if (!IsAllocated())
60*0b57cec5SDimitry Andric     return PyObjectType::None;
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric   if (PythonModule::Check(m_py_obj))
63*0b57cec5SDimitry Andric     return PyObjectType::Module;
64*0b57cec5SDimitry Andric   if (PythonList::Check(m_py_obj))
65*0b57cec5SDimitry Andric     return PyObjectType::List;
66*0b57cec5SDimitry Andric   if (PythonTuple::Check(m_py_obj))
67*0b57cec5SDimitry Andric     return PyObjectType::Tuple;
68*0b57cec5SDimitry Andric   if (PythonDictionary::Check(m_py_obj))
69*0b57cec5SDimitry Andric     return PyObjectType::Dictionary;
70*0b57cec5SDimitry Andric   if (PythonString::Check(m_py_obj))
71*0b57cec5SDimitry Andric     return PyObjectType::String;
72*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
73*0b57cec5SDimitry Andric   if (PythonBytes::Check(m_py_obj))
74*0b57cec5SDimitry Andric     return PyObjectType::Bytes;
75*0b57cec5SDimitry Andric #endif
76*0b57cec5SDimitry Andric   if (PythonByteArray::Check(m_py_obj))
77*0b57cec5SDimitry Andric     return PyObjectType::ByteArray;
78*0b57cec5SDimitry Andric   if (PythonBoolean::Check(m_py_obj))
79*0b57cec5SDimitry Andric     return PyObjectType::Boolean;
80*0b57cec5SDimitry Andric   if (PythonInteger::Check(m_py_obj))
81*0b57cec5SDimitry Andric     return PyObjectType::Integer;
82*0b57cec5SDimitry Andric   if (PythonFile::Check(m_py_obj))
83*0b57cec5SDimitry Andric     return PyObjectType::File;
84*0b57cec5SDimitry Andric   if (PythonCallable::Check(m_py_obj))
85*0b57cec5SDimitry Andric     return PyObjectType::Callable;
86*0b57cec5SDimitry Andric   return PyObjectType::Unknown;
87*0b57cec5SDimitry Andric }
88*0b57cec5SDimitry Andric 
89*0b57cec5SDimitry Andric PythonString PythonObject::Repr() const {
90*0b57cec5SDimitry Andric   if (!m_py_obj)
91*0b57cec5SDimitry Andric     return PythonString();
92*0b57cec5SDimitry Andric   PyObject *repr = PyObject_Repr(m_py_obj);
93*0b57cec5SDimitry Andric   if (!repr)
94*0b57cec5SDimitry Andric     return PythonString();
95*0b57cec5SDimitry Andric   return PythonString(PyRefType::Owned, repr);
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric PythonString PythonObject::Str() const {
99*0b57cec5SDimitry Andric   if (!m_py_obj)
100*0b57cec5SDimitry Andric     return PythonString();
101*0b57cec5SDimitry Andric   PyObject *str = PyObject_Str(m_py_obj);
102*0b57cec5SDimitry Andric   if (!str)
103*0b57cec5SDimitry Andric     return PythonString();
104*0b57cec5SDimitry Andric   return PythonString(PyRefType::Owned, str);
105*0b57cec5SDimitry Andric }
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric PythonObject
108*0b57cec5SDimitry Andric PythonObject::ResolveNameWithDictionary(llvm::StringRef name,
109*0b57cec5SDimitry Andric                                         const PythonDictionary &dict) {
110*0b57cec5SDimitry Andric   size_t dot_pos = name.find('.');
111*0b57cec5SDimitry Andric   llvm::StringRef piece = name.substr(0, dot_pos);
112*0b57cec5SDimitry Andric   PythonObject result = dict.GetItemForKey(PythonString(piece));
113*0b57cec5SDimitry Andric   if (dot_pos == llvm::StringRef::npos) {
114*0b57cec5SDimitry Andric     // There was no dot, we're done.
115*0b57cec5SDimitry Andric     return result;
116*0b57cec5SDimitry Andric   }
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric   // There was a dot.  The remaining portion of the name should be looked up in
119*0b57cec5SDimitry Andric   // the context of the object that was found in the dictionary.
120*0b57cec5SDimitry Andric   return result.ResolveName(name.substr(dot_pos + 1));
121*0b57cec5SDimitry Andric }
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric PythonObject PythonObject::ResolveName(llvm::StringRef name) const {
124*0b57cec5SDimitry Andric   // Resolve the name in the context of the specified object.  If, for example,
125*0b57cec5SDimitry Andric   // `this` refers to a PyModule, then this will look for `name` in this
126*0b57cec5SDimitry Andric   // module.  If `this` refers to a PyType, then it will resolve `name` as an
127*0b57cec5SDimitry Andric   // attribute of that type.  If `this` refers to an instance of an object,
128*0b57cec5SDimitry Andric   // then it will resolve `name` as the value of the specified field.
129*0b57cec5SDimitry Andric   //
130*0b57cec5SDimitry Andric   // This function handles dotted names so that, for example, if `m_py_obj`
131*0b57cec5SDimitry Andric   // refers to the `sys` module, and `name` == "path.append", then it will find
132*0b57cec5SDimitry Andric   // the function `sys.path.append`.
133*0b57cec5SDimitry Andric 
134*0b57cec5SDimitry Andric   size_t dot_pos = name.find('.');
135*0b57cec5SDimitry Andric   if (dot_pos == llvm::StringRef::npos) {
136*0b57cec5SDimitry Andric     // No dots in the name, we should be able to find the value immediately as
137*0b57cec5SDimitry Andric     // an attribute of `m_py_obj`.
138*0b57cec5SDimitry Andric     return GetAttributeValue(name);
139*0b57cec5SDimitry Andric   }
140*0b57cec5SDimitry Andric 
141*0b57cec5SDimitry Andric   // Look up the first piece of the name, and resolve the rest as a child of
142*0b57cec5SDimitry Andric   // that.
143*0b57cec5SDimitry Andric   PythonObject parent = ResolveName(name.substr(0, dot_pos));
144*0b57cec5SDimitry Andric   if (!parent.IsAllocated())
145*0b57cec5SDimitry Andric     return PythonObject();
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric   // Tail recursion.. should be optimized by the compiler
148*0b57cec5SDimitry Andric   return parent.ResolveName(name.substr(dot_pos + 1));
149*0b57cec5SDimitry Andric }
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric bool PythonObject::HasAttribute(llvm::StringRef attr) const {
152*0b57cec5SDimitry Andric   if (!IsValid())
153*0b57cec5SDimitry Andric     return false;
154*0b57cec5SDimitry Andric   PythonString py_attr(attr);
155*0b57cec5SDimitry Andric   return !!PyObject_HasAttr(m_py_obj, py_attr.get());
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric PythonObject PythonObject::GetAttributeValue(llvm::StringRef attr) const {
159*0b57cec5SDimitry Andric   if (!IsValid())
160*0b57cec5SDimitry Andric     return PythonObject();
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric   PythonString py_attr(attr);
163*0b57cec5SDimitry Andric   if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
164*0b57cec5SDimitry Andric     return PythonObject();
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric   return PythonObject(PyRefType::Owned,
167*0b57cec5SDimitry Andric                       PyObject_GetAttr(m_py_obj, py_attr.get()));
168*0b57cec5SDimitry Andric }
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric bool PythonObject::IsNone() const { return m_py_obj == Py_None; }
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric bool PythonObject::IsValid() const { return m_py_obj != nullptr; }
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric bool PythonObject::IsAllocated() const { return IsValid() && !IsNone(); }
175*0b57cec5SDimitry Andric 
176*0b57cec5SDimitry Andric StructuredData::ObjectSP PythonObject::CreateStructuredObject() const {
177*0b57cec5SDimitry Andric   switch (GetObjectType()) {
178*0b57cec5SDimitry Andric   case PyObjectType::Dictionary:
179*0b57cec5SDimitry Andric     return PythonDictionary(PyRefType::Borrowed, m_py_obj)
180*0b57cec5SDimitry Andric         .CreateStructuredDictionary();
181*0b57cec5SDimitry Andric   case PyObjectType::Boolean:
182*0b57cec5SDimitry Andric     return PythonBoolean(PyRefType::Borrowed, m_py_obj)
183*0b57cec5SDimitry Andric         .CreateStructuredBoolean();
184*0b57cec5SDimitry Andric   case PyObjectType::Integer:
185*0b57cec5SDimitry Andric     return PythonInteger(PyRefType::Borrowed, m_py_obj)
186*0b57cec5SDimitry Andric         .CreateStructuredInteger();
187*0b57cec5SDimitry Andric   case PyObjectType::List:
188*0b57cec5SDimitry Andric     return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
189*0b57cec5SDimitry Andric   case PyObjectType::String:
190*0b57cec5SDimitry Andric     return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
191*0b57cec5SDimitry Andric   case PyObjectType::Bytes:
192*0b57cec5SDimitry Andric     return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
193*0b57cec5SDimitry Andric   case PyObjectType::ByteArray:
194*0b57cec5SDimitry Andric     return PythonByteArray(PyRefType::Borrowed, m_py_obj)
195*0b57cec5SDimitry Andric         .CreateStructuredString();
196*0b57cec5SDimitry Andric   case PyObjectType::None:
197*0b57cec5SDimitry Andric     return StructuredData::ObjectSP();
198*0b57cec5SDimitry Andric   default:
199*0b57cec5SDimitry Andric     return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj));
200*0b57cec5SDimitry Andric   }
201*0b57cec5SDimitry Andric }
202*0b57cec5SDimitry Andric 
203*0b57cec5SDimitry Andric // PythonString
204*0b57cec5SDimitry Andric PythonBytes::PythonBytes() : PythonObject() {}
205*0b57cec5SDimitry Andric 
206*0b57cec5SDimitry Andric PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject() {
207*0b57cec5SDimitry Andric   SetBytes(bytes);
208*0b57cec5SDimitry Andric }
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject() {
211*0b57cec5SDimitry Andric   SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
212*0b57cec5SDimitry Andric }
213*0b57cec5SDimitry Andric 
214*0b57cec5SDimitry Andric PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject() {
215*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
216*0b57cec5SDimitry Andric }
217*0b57cec5SDimitry Andric 
218*0b57cec5SDimitry Andric PythonBytes::~PythonBytes() {}
219*0b57cec5SDimitry Andric 
220*0b57cec5SDimitry Andric bool PythonBytes::Check(PyObject *py_obj) {
221*0b57cec5SDimitry Andric   if (!py_obj)
222*0b57cec5SDimitry Andric     return false;
223*0b57cec5SDimitry Andric   return PyBytes_Check(py_obj);
224*0b57cec5SDimitry Andric }
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric void PythonBytes::Reset(PyRefType type, PyObject *py_obj) {
227*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
228*0b57cec5SDimitry Andric   // still gets decremented if necessary.
229*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric   if (!PythonBytes::Check(py_obj)) {
232*0b57cec5SDimitry Andric     PythonObject::Reset();
233*0b57cec5SDimitry Andric     return;
234*0b57cec5SDimitry Andric   }
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
237*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
238*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
239*0b57cec5SDimitry Andric }
240*0b57cec5SDimitry Andric 
241*0b57cec5SDimitry Andric llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {
242*0b57cec5SDimitry Andric   if (!IsValid())
243*0b57cec5SDimitry Andric     return llvm::ArrayRef<uint8_t>();
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric   Py_ssize_t size;
246*0b57cec5SDimitry Andric   char *c;
247*0b57cec5SDimitry Andric 
248*0b57cec5SDimitry Andric   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
249*0b57cec5SDimitry Andric   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
250*0b57cec5SDimitry Andric }
251*0b57cec5SDimitry Andric 
252*0b57cec5SDimitry Andric size_t PythonBytes::GetSize() const {
253*0b57cec5SDimitry Andric   if (!IsValid())
254*0b57cec5SDimitry Andric     return 0;
255*0b57cec5SDimitry Andric   return PyBytes_Size(m_py_obj);
256*0b57cec5SDimitry Andric }
257*0b57cec5SDimitry Andric 
258*0b57cec5SDimitry Andric void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {
259*0b57cec5SDimitry Andric   const char *data = reinterpret_cast<const char *>(bytes.data());
260*0b57cec5SDimitry Andric   PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size());
261*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Owned, py_bytes);
262*0b57cec5SDimitry Andric }
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric StructuredData::StringSP PythonBytes::CreateStructuredString() const {
265*0b57cec5SDimitry Andric   StructuredData::StringSP result(new StructuredData::String);
266*0b57cec5SDimitry Andric   Py_ssize_t size;
267*0b57cec5SDimitry Andric   char *c;
268*0b57cec5SDimitry Andric   PyBytes_AsStringAndSize(m_py_obj, &c, &size);
269*0b57cec5SDimitry Andric   result->SetValue(std::string(c, size));
270*0b57cec5SDimitry Andric   return result;
271*0b57cec5SDimitry Andric }
272*0b57cec5SDimitry Andric 
273*0b57cec5SDimitry Andric PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes)
274*0b57cec5SDimitry Andric     : PythonByteArray(bytes.data(), bytes.size()) {}
275*0b57cec5SDimitry Andric 
276*0b57cec5SDimitry Andric PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {
277*0b57cec5SDimitry Andric   const char *str = reinterpret_cast<const char *>(bytes);
278*0b57cec5SDimitry Andric   Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length));
279*0b57cec5SDimitry Andric }
280*0b57cec5SDimitry Andric 
281*0b57cec5SDimitry Andric PythonByteArray::PythonByteArray(PyRefType type, PyObject *o) {
282*0b57cec5SDimitry Andric   Reset(type, o);
283*0b57cec5SDimitry Andric }
284*0b57cec5SDimitry Andric 
285*0b57cec5SDimitry Andric PythonByteArray::PythonByteArray(const PythonBytes &object)
286*0b57cec5SDimitry Andric     : PythonObject(object) {}
287*0b57cec5SDimitry Andric 
288*0b57cec5SDimitry Andric PythonByteArray::~PythonByteArray() {}
289*0b57cec5SDimitry Andric 
290*0b57cec5SDimitry Andric bool PythonByteArray::Check(PyObject *py_obj) {
291*0b57cec5SDimitry Andric   if (!py_obj)
292*0b57cec5SDimitry Andric     return false;
293*0b57cec5SDimitry Andric   return PyByteArray_Check(py_obj);
294*0b57cec5SDimitry Andric }
295*0b57cec5SDimitry Andric 
296*0b57cec5SDimitry Andric void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) {
297*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
298*0b57cec5SDimitry Andric   // still gets decremented if necessary.
299*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
300*0b57cec5SDimitry Andric 
301*0b57cec5SDimitry Andric   if (!PythonByteArray::Check(py_obj)) {
302*0b57cec5SDimitry Andric     PythonObject::Reset();
303*0b57cec5SDimitry Andric     return;
304*0b57cec5SDimitry Andric   }
305*0b57cec5SDimitry Andric 
306*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
307*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
308*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
309*0b57cec5SDimitry Andric }
310*0b57cec5SDimitry Andric 
311*0b57cec5SDimitry Andric llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {
312*0b57cec5SDimitry Andric   if (!IsValid())
313*0b57cec5SDimitry Andric     return llvm::ArrayRef<uint8_t>();
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric   char *c = PyByteArray_AsString(m_py_obj);
316*0b57cec5SDimitry Andric   size_t size = GetSize();
317*0b57cec5SDimitry Andric   return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
318*0b57cec5SDimitry Andric }
319*0b57cec5SDimitry Andric 
320*0b57cec5SDimitry Andric size_t PythonByteArray::GetSize() const {
321*0b57cec5SDimitry Andric   if (!IsValid())
322*0b57cec5SDimitry Andric     return 0;
323*0b57cec5SDimitry Andric 
324*0b57cec5SDimitry Andric   return PyByteArray_Size(m_py_obj);
325*0b57cec5SDimitry Andric }
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric StructuredData::StringSP PythonByteArray::CreateStructuredString() const {
328*0b57cec5SDimitry Andric   StructuredData::StringSP result(new StructuredData::String);
329*0b57cec5SDimitry Andric   llvm::ArrayRef<uint8_t> bytes = GetBytes();
330*0b57cec5SDimitry Andric   const char *str = reinterpret_cast<const char *>(bytes.data());
331*0b57cec5SDimitry Andric   result->SetValue(std::string(str, bytes.size()));
332*0b57cec5SDimitry Andric   return result;
333*0b57cec5SDimitry Andric }
334*0b57cec5SDimitry Andric 
335*0b57cec5SDimitry Andric // PythonString
336*0b57cec5SDimitry Andric 
337*0b57cec5SDimitry Andric PythonString::PythonString(PyRefType type, PyObject *py_obj) : PythonObject() {
338*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
339*0b57cec5SDimitry Andric }
340*0b57cec5SDimitry Andric 
341*0b57cec5SDimitry Andric PythonString::PythonString(llvm::StringRef string) : PythonObject() {
342*0b57cec5SDimitry Andric   SetString(string);
343*0b57cec5SDimitry Andric }
344*0b57cec5SDimitry Andric 
345*0b57cec5SDimitry Andric PythonString::PythonString(const char *string) : PythonObject() {
346*0b57cec5SDimitry Andric   SetString(llvm::StringRef(string));
347*0b57cec5SDimitry Andric }
348*0b57cec5SDimitry Andric 
349*0b57cec5SDimitry Andric PythonString::PythonString() : PythonObject() {}
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric PythonString::~PythonString() {}
352*0b57cec5SDimitry Andric 
353*0b57cec5SDimitry Andric bool PythonString::Check(PyObject *py_obj) {
354*0b57cec5SDimitry Andric   if (!py_obj)
355*0b57cec5SDimitry Andric     return false;
356*0b57cec5SDimitry Andric 
357*0b57cec5SDimitry Andric   if (PyUnicode_Check(py_obj))
358*0b57cec5SDimitry Andric     return true;
359*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION < 3
360*0b57cec5SDimitry Andric   if (PyString_Check(py_obj))
361*0b57cec5SDimitry Andric     return true;
362*0b57cec5SDimitry Andric #endif
363*0b57cec5SDimitry Andric   return false;
364*0b57cec5SDimitry Andric }
365*0b57cec5SDimitry Andric 
366*0b57cec5SDimitry Andric void PythonString::Reset(PyRefType type, PyObject *py_obj) {
367*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
368*0b57cec5SDimitry Andric   // still gets decremented if necessary.
369*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
370*0b57cec5SDimitry Andric 
371*0b57cec5SDimitry Andric   if (!PythonString::Check(py_obj)) {
372*0b57cec5SDimitry Andric     PythonObject::Reset();
373*0b57cec5SDimitry Andric     return;
374*0b57cec5SDimitry Andric   }
375*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION < 3
376*0b57cec5SDimitry Andric   // In Python 2, Don't store PyUnicode objects directly, because we need
377*0b57cec5SDimitry Andric   // access to their underlying character buffers which Python 2 doesn't
378*0b57cec5SDimitry Andric   // provide.
379*0b57cec5SDimitry Andric   if (PyUnicode_Check(py_obj))
380*0b57cec5SDimitry Andric     result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(result.get()));
381*0b57cec5SDimitry Andric #endif
382*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
383*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
384*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
385*0b57cec5SDimitry Andric }
386*0b57cec5SDimitry Andric 
387*0b57cec5SDimitry Andric llvm::StringRef PythonString::GetString() const {
388*0b57cec5SDimitry Andric   if (!IsValid())
389*0b57cec5SDimitry Andric     return llvm::StringRef();
390*0b57cec5SDimitry Andric 
391*0b57cec5SDimitry Andric   Py_ssize_t size;
392*0b57cec5SDimitry Andric   const char *data;
393*0b57cec5SDimitry Andric 
394*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
395*0b57cec5SDimitry Andric   data = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
396*0b57cec5SDimitry Andric #else
397*0b57cec5SDimitry Andric   char *c;
398*0b57cec5SDimitry Andric   PyString_AsStringAndSize(m_py_obj, &c, &size);
399*0b57cec5SDimitry Andric   data = c;
400*0b57cec5SDimitry Andric #endif
401*0b57cec5SDimitry Andric   return llvm::StringRef(data, size);
402*0b57cec5SDimitry Andric }
403*0b57cec5SDimitry Andric 
404*0b57cec5SDimitry Andric size_t PythonString::GetSize() const {
405*0b57cec5SDimitry Andric   if (IsValid()) {
406*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
407*0b57cec5SDimitry Andric     return PyUnicode_GetSize(m_py_obj);
408*0b57cec5SDimitry Andric #else
409*0b57cec5SDimitry Andric     return PyString_Size(m_py_obj);
410*0b57cec5SDimitry Andric #endif
411*0b57cec5SDimitry Andric   }
412*0b57cec5SDimitry Andric   return 0;
413*0b57cec5SDimitry Andric }
414*0b57cec5SDimitry Andric 
415*0b57cec5SDimitry Andric void PythonString::SetString(llvm::StringRef string) {
416*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
417*0b57cec5SDimitry Andric   PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
418*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Owned, unicode);
419*0b57cec5SDimitry Andric #else
420*0b57cec5SDimitry Andric   PyObject *str = PyString_FromStringAndSize(string.data(), string.size());
421*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Owned, str);
422*0b57cec5SDimitry Andric #endif
423*0b57cec5SDimitry Andric }
424*0b57cec5SDimitry Andric 
425*0b57cec5SDimitry Andric StructuredData::StringSP PythonString::CreateStructuredString() const {
426*0b57cec5SDimitry Andric   StructuredData::StringSP result(new StructuredData::String);
427*0b57cec5SDimitry Andric   result->SetValue(GetString());
428*0b57cec5SDimitry Andric   return result;
429*0b57cec5SDimitry Andric }
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric // PythonInteger
432*0b57cec5SDimitry Andric 
433*0b57cec5SDimitry Andric PythonInteger::PythonInteger() : PythonObject() {}
434*0b57cec5SDimitry Andric 
435*0b57cec5SDimitry Andric PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
436*0b57cec5SDimitry Andric     : PythonObject() {
437*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
438*0b57cec5SDimitry Andric }
439*0b57cec5SDimitry Andric 
440*0b57cec5SDimitry Andric PythonInteger::PythonInteger(int64_t value) : PythonObject() {
441*0b57cec5SDimitry Andric   SetInteger(value);
442*0b57cec5SDimitry Andric }
443*0b57cec5SDimitry Andric 
444*0b57cec5SDimitry Andric PythonInteger::~PythonInteger() {}
445*0b57cec5SDimitry Andric 
446*0b57cec5SDimitry Andric bool PythonInteger::Check(PyObject *py_obj) {
447*0b57cec5SDimitry Andric   if (!py_obj)
448*0b57cec5SDimitry Andric     return false;
449*0b57cec5SDimitry Andric 
450*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
451*0b57cec5SDimitry Andric   // Python 3 does not have PyInt_Check.  There is only one type of integral
452*0b57cec5SDimitry Andric   // value, long.
453*0b57cec5SDimitry Andric   return PyLong_Check(py_obj);
454*0b57cec5SDimitry Andric #else
455*0b57cec5SDimitry Andric   return PyLong_Check(py_obj) || PyInt_Check(py_obj);
456*0b57cec5SDimitry Andric #endif
457*0b57cec5SDimitry Andric }
458*0b57cec5SDimitry Andric 
459*0b57cec5SDimitry Andric void PythonInteger::Reset(PyRefType type, PyObject *py_obj) {
460*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
461*0b57cec5SDimitry Andric   // still gets decremented if necessary.
462*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
463*0b57cec5SDimitry Andric 
464*0b57cec5SDimitry Andric   if (!PythonInteger::Check(py_obj)) {
465*0b57cec5SDimitry Andric     PythonObject::Reset();
466*0b57cec5SDimitry Andric     return;
467*0b57cec5SDimitry Andric   }
468*0b57cec5SDimitry Andric 
469*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION < 3
470*0b57cec5SDimitry Andric   // Always store this as a PyLong, which makes interoperability between Python
471*0b57cec5SDimitry Andric   // 2.x and Python 3.x easier.  This is only necessary in 2.x, since 3.x
472*0b57cec5SDimitry Andric   // doesn't even have a PyInt.
473*0b57cec5SDimitry Andric   if (PyInt_Check(py_obj)) {
474*0b57cec5SDimitry Andric     // Since we converted the original object to a different type, the new
475*0b57cec5SDimitry Andric     // object is an owned object regardless of the ownership semantics
476*0b57cec5SDimitry Andric     // requested by the user.
477*0b57cec5SDimitry Andric     result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
478*0b57cec5SDimitry Andric   }
479*0b57cec5SDimitry Andric #endif
480*0b57cec5SDimitry Andric 
481*0b57cec5SDimitry Andric   assert(PyLong_Check(result.get()) &&
482*0b57cec5SDimitry Andric          "Couldn't get a PyLong from this PyObject");
483*0b57cec5SDimitry Andric 
484*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
485*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
486*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
487*0b57cec5SDimitry Andric }
488*0b57cec5SDimitry Andric 
489*0b57cec5SDimitry Andric int64_t PythonInteger::GetInteger() const {
490*0b57cec5SDimitry Andric   if (m_py_obj) {
491*0b57cec5SDimitry Andric     assert(PyLong_Check(m_py_obj) &&
492*0b57cec5SDimitry Andric            "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
493*0b57cec5SDimitry Andric 
494*0b57cec5SDimitry Andric     int overflow = 0;
495*0b57cec5SDimitry Andric     int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
496*0b57cec5SDimitry Andric     if (overflow != 0) {
497*0b57cec5SDimitry Andric       // We got an integer that overflows, like 18446744072853913392L we can't
498*0b57cec5SDimitry Andric       // use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we
499*0b57cec5SDimitry Andric       // use the unsigned long long it will work as expected.
500*0b57cec5SDimitry Andric       const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
501*0b57cec5SDimitry Andric       result = static_cast<int64_t>(uval);
502*0b57cec5SDimitry Andric     }
503*0b57cec5SDimitry Andric     return result;
504*0b57cec5SDimitry Andric   }
505*0b57cec5SDimitry Andric   return UINT64_MAX;
506*0b57cec5SDimitry Andric }
507*0b57cec5SDimitry Andric 
508*0b57cec5SDimitry Andric void PythonInteger::SetInteger(int64_t value) {
509*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
510*0b57cec5SDimitry Andric }
511*0b57cec5SDimitry Andric 
512*0b57cec5SDimitry Andric StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
513*0b57cec5SDimitry Andric   StructuredData::IntegerSP result(new StructuredData::Integer);
514*0b57cec5SDimitry Andric   result->SetValue(GetInteger());
515*0b57cec5SDimitry Andric   return result;
516*0b57cec5SDimitry Andric }
517*0b57cec5SDimitry Andric 
518*0b57cec5SDimitry Andric // PythonBoolean
519*0b57cec5SDimitry Andric 
520*0b57cec5SDimitry Andric PythonBoolean::PythonBoolean(PyRefType type, PyObject *py_obj)
521*0b57cec5SDimitry Andric     : PythonObject() {
522*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a boolean type
523*0b57cec5SDimitry Andric }
524*0b57cec5SDimitry Andric 
525*0b57cec5SDimitry Andric PythonBoolean::PythonBoolean(bool value) {
526*0b57cec5SDimitry Andric   SetValue(value);
527*0b57cec5SDimitry Andric }
528*0b57cec5SDimitry Andric 
529*0b57cec5SDimitry Andric bool PythonBoolean::Check(PyObject *py_obj) {
530*0b57cec5SDimitry Andric   return py_obj ? PyBool_Check(py_obj) : false;
531*0b57cec5SDimitry Andric }
532*0b57cec5SDimitry Andric 
533*0b57cec5SDimitry Andric void PythonBoolean::Reset(PyRefType type, PyObject *py_obj) {
534*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
535*0b57cec5SDimitry Andric   // still gets decremented if necessary.
536*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
537*0b57cec5SDimitry Andric 
538*0b57cec5SDimitry Andric   if (!PythonBoolean::Check(py_obj)) {
539*0b57cec5SDimitry Andric     PythonObject::Reset();
540*0b57cec5SDimitry Andric     return;
541*0b57cec5SDimitry Andric   }
542*0b57cec5SDimitry Andric 
543*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
544*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
545*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
546*0b57cec5SDimitry Andric }
547*0b57cec5SDimitry Andric 
548*0b57cec5SDimitry Andric bool PythonBoolean::GetValue() const {
549*0b57cec5SDimitry Andric   return m_py_obj ? PyObject_IsTrue(m_py_obj) : false;
550*0b57cec5SDimitry Andric }
551*0b57cec5SDimitry Andric 
552*0b57cec5SDimitry Andric void PythonBoolean::SetValue(bool value) {
553*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Owned, PyBool_FromLong(value));
554*0b57cec5SDimitry Andric }
555*0b57cec5SDimitry Andric 
556*0b57cec5SDimitry Andric StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const {
557*0b57cec5SDimitry Andric   StructuredData::BooleanSP result(new StructuredData::Boolean);
558*0b57cec5SDimitry Andric   result->SetValue(GetValue());
559*0b57cec5SDimitry Andric   return result;
560*0b57cec5SDimitry Andric }
561*0b57cec5SDimitry Andric 
562*0b57cec5SDimitry Andric // PythonList
563*0b57cec5SDimitry Andric 
564*0b57cec5SDimitry Andric PythonList::PythonList(PyInitialValue value) : PythonObject() {
565*0b57cec5SDimitry Andric   if (value == PyInitialValue::Empty)
566*0b57cec5SDimitry Andric     Reset(PyRefType::Owned, PyList_New(0));
567*0b57cec5SDimitry Andric }
568*0b57cec5SDimitry Andric 
569*0b57cec5SDimitry Andric PythonList::PythonList(int list_size) : PythonObject() {
570*0b57cec5SDimitry Andric   Reset(PyRefType::Owned, PyList_New(list_size));
571*0b57cec5SDimitry Andric }
572*0b57cec5SDimitry Andric 
573*0b57cec5SDimitry Andric PythonList::PythonList(PyRefType type, PyObject *py_obj) : PythonObject() {
574*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
575*0b57cec5SDimitry Andric }
576*0b57cec5SDimitry Andric 
577*0b57cec5SDimitry Andric PythonList::~PythonList() {}
578*0b57cec5SDimitry Andric 
579*0b57cec5SDimitry Andric bool PythonList::Check(PyObject *py_obj) {
580*0b57cec5SDimitry Andric   if (!py_obj)
581*0b57cec5SDimitry Andric     return false;
582*0b57cec5SDimitry Andric   return PyList_Check(py_obj);
583*0b57cec5SDimitry Andric }
584*0b57cec5SDimitry Andric 
585*0b57cec5SDimitry Andric void PythonList::Reset(PyRefType type, PyObject *py_obj) {
586*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
587*0b57cec5SDimitry Andric   // still gets decremented if necessary.
588*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
589*0b57cec5SDimitry Andric 
590*0b57cec5SDimitry Andric   if (!PythonList::Check(py_obj)) {
591*0b57cec5SDimitry Andric     PythonObject::Reset();
592*0b57cec5SDimitry Andric     return;
593*0b57cec5SDimitry Andric   }
594*0b57cec5SDimitry Andric 
595*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
596*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
597*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
598*0b57cec5SDimitry Andric }
599*0b57cec5SDimitry Andric 
600*0b57cec5SDimitry Andric uint32_t PythonList::GetSize() const {
601*0b57cec5SDimitry Andric   if (IsValid())
602*0b57cec5SDimitry Andric     return PyList_GET_SIZE(m_py_obj);
603*0b57cec5SDimitry Andric   return 0;
604*0b57cec5SDimitry Andric }
605*0b57cec5SDimitry Andric 
606*0b57cec5SDimitry Andric PythonObject PythonList::GetItemAtIndex(uint32_t index) const {
607*0b57cec5SDimitry Andric   if (IsValid())
608*0b57cec5SDimitry Andric     return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
609*0b57cec5SDimitry Andric   return PythonObject();
610*0b57cec5SDimitry Andric }
611*0b57cec5SDimitry Andric 
612*0b57cec5SDimitry Andric void PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) {
613*0b57cec5SDimitry Andric   if (IsAllocated() && object.IsValid()) {
614*0b57cec5SDimitry Andric     // PyList_SetItem is documented to "steal" a reference, so we need to
615*0b57cec5SDimitry Andric     // convert it to an owned reference by incrementing it.
616*0b57cec5SDimitry Andric     Py_INCREF(object.get());
617*0b57cec5SDimitry Andric     PyList_SetItem(m_py_obj, index, object.get());
618*0b57cec5SDimitry Andric   }
619*0b57cec5SDimitry Andric }
620*0b57cec5SDimitry Andric 
621*0b57cec5SDimitry Andric void PythonList::AppendItem(const PythonObject &object) {
622*0b57cec5SDimitry Andric   if (IsAllocated() && object.IsValid()) {
623*0b57cec5SDimitry Andric     // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
624*0b57cec5SDimitry Andric     // here like we do with `PyList_SetItem`.
625*0b57cec5SDimitry Andric     PyList_Append(m_py_obj, object.get());
626*0b57cec5SDimitry Andric   }
627*0b57cec5SDimitry Andric }
628*0b57cec5SDimitry Andric 
629*0b57cec5SDimitry Andric StructuredData::ArraySP PythonList::CreateStructuredArray() const {
630*0b57cec5SDimitry Andric   StructuredData::ArraySP result(new StructuredData::Array);
631*0b57cec5SDimitry Andric   uint32_t count = GetSize();
632*0b57cec5SDimitry Andric   for (uint32_t i = 0; i < count; ++i) {
633*0b57cec5SDimitry Andric     PythonObject obj = GetItemAtIndex(i);
634*0b57cec5SDimitry Andric     result->AddItem(obj.CreateStructuredObject());
635*0b57cec5SDimitry Andric   }
636*0b57cec5SDimitry Andric   return result;
637*0b57cec5SDimitry Andric }
638*0b57cec5SDimitry Andric 
639*0b57cec5SDimitry Andric // PythonTuple
640*0b57cec5SDimitry Andric 
641*0b57cec5SDimitry Andric PythonTuple::PythonTuple(PyInitialValue value) : PythonObject() {
642*0b57cec5SDimitry Andric   if (value == PyInitialValue::Empty)
643*0b57cec5SDimitry Andric     Reset(PyRefType::Owned, PyTuple_New(0));
644*0b57cec5SDimitry Andric }
645*0b57cec5SDimitry Andric 
646*0b57cec5SDimitry Andric PythonTuple::PythonTuple(int tuple_size) : PythonObject() {
647*0b57cec5SDimitry Andric   Reset(PyRefType::Owned, PyTuple_New(tuple_size));
648*0b57cec5SDimitry Andric }
649*0b57cec5SDimitry Andric 
650*0b57cec5SDimitry Andric PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj) : PythonObject() {
651*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple
652*0b57cec5SDimitry Andric }
653*0b57cec5SDimitry Andric 
654*0b57cec5SDimitry Andric PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
655*0b57cec5SDimitry Andric   m_py_obj = PyTuple_New(objects.size());
656*0b57cec5SDimitry Andric 
657*0b57cec5SDimitry Andric   uint32_t idx = 0;
658*0b57cec5SDimitry Andric   for (auto object : objects) {
659*0b57cec5SDimitry Andric     if (object.IsValid())
660*0b57cec5SDimitry Andric       SetItemAtIndex(idx, object);
661*0b57cec5SDimitry Andric     idx++;
662*0b57cec5SDimitry Andric   }
663*0b57cec5SDimitry Andric }
664*0b57cec5SDimitry Andric 
665*0b57cec5SDimitry Andric PythonTuple::PythonTuple(std::initializer_list<PyObject *> objects) {
666*0b57cec5SDimitry Andric   m_py_obj = PyTuple_New(objects.size());
667*0b57cec5SDimitry Andric 
668*0b57cec5SDimitry Andric   uint32_t idx = 0;
669*0b57cec5SDimitry Andric   for (auto py_object : objects) {
670*0b57cec5SDimitry Andric     PythonObject object(PyRefType::Borrowed, py_object);
671*0b57cec5SDimitry Andric     if (object.IsValid())
672*0b57cec5SDimitry Andric       SetItemAtIndex(idx, object);
673*0b57cec5SDimitry Andric     idx++;
674*0b57cec5SDimitry Andric   }
675*0b57cec5SDimitry Andric }
676*0b57cec5SDimitry Andric 
677*0b57cec5SDimitry Andric PythonTuple::~PythonTuple() {}
678*0b57cec5SDimitry Andric 
679*0b57cec5SDimitry Andric bool PythonTuple::Check(PyObject *py_obj) {
680*0b57cec5SDimitry Andric   if (!py_obj)
681*0b57cec5SDimitry Andric     return false;
682*0b57cec5SDimitry Andric   return PyTuple_Check(py_obj);
683*0b57cec5SDimitry Andric }
684*0b57cec5SDimitry Andric 
685*0b57cec5SDimitry Andric void PythonTuple::Reset(PyRefType type, PyObject *py_obj) {
686*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
687*0b57cec5SDimitry Andric   // still gets decremented if necessary.
688*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
689*0b57cec5SDimitry Andric 
690*0b57cec5SDimitry Andric   if (!PythonTuple::Check(py_obj)) {
691*0b57cec5SDimitry Andric     PythonObject::Reset();
692*0b57cec5SDimitry Andric     return;
693*0b57cec5SDimitry Andric   }
694*0b57cec5SDimitry Andric 
695*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
696*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
697*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
698*0b57cec5SDimitry Andric }
699*0b57cec5SDimitry Andric 
700*0b57cec5SDimitry Andric uint32_t PythonTuple::GetSize() const {
701*0b57cec5SDimitry Andric   if (IsValid())
702*0b57cec5SDimitry Andric     return PyTuple_GET_SIZE(m_py_obj);
703*0b57cec5SDimitry Andric   return 0;
704*0b57cec5SDimitry Andric }
705*0b57cec5SDimitry Andric 
706*0b57cec5SDimitry Andric PythonObject PythonTuple::GetItemAtIndex(uint32_t index) const {
707*0b57cec5SDimitry Andric   if (IsValid())
708*0b57cec5SDimitry Andric     return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
709*0b57cec5SDimitry Andric   return PythonObject();
710*0b57cec5SDimitry Andric }
711*0b57cec5SDimitry Andric 
712*0b57cec5SDimitry Andric void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) {
713*0b57cec5SDimitry Andric   if (IsAllocated() && object.IsValid()) {
714*0b57cec5SDimitry Andric     // PyTuple_SetItem is documented to "steal" a reference, so we need to
715*0b57cec5SDimitry Andric     // convert it to an owned reference by incrementing it.
716*0b57cec5SDimitry Andric     Py_INCREF(object.get());
717*0b57cec5SDimitry Andric     PyTuple_SetItem(m_py_obj, index, object.get());
718*0b57cec5SDimitry Andric   }
719*0b57cec5SDimitry Andric }
720*0b57cec5SDimitry Andric 
721*0b57cec5SDimitry Andric StructuredData::ArraySP PythonTuple::CreateStructuredArray() const {
722*0b57cec5SDimitry Andric   StructuredData::ArraySP result(new StructuredData::Array);
723*0b57cec5SDimitry Andric   uint32_t count = GetSize();
724*0b57cec5SDimitry Andric   for (uint32_t i = 0; i < count; ++i) {
725*0b57cec5SDimitry Andric     PythonObject obj = GetItemAtIndex(i);
726*0b57cec5SDimitry Andric     result->AddItem(obj.CreateStructuredObject());
727*0b57cec5SDimitry Andric   }
728*0b57cec5SDimitry Andric   return result;
729*0b57cec5SDimitry Andric }
730*0b57cec5SDimitry Andric 
731*0b57cec5SDimitry Andric // PythonDictionary
732*0b57cec5SDimitry Andric 
733*0b57cec5SDimitry Andric PythonDictionary::PythonDictionary(PyInitialValue value) : PythonObject() {
734*0b57cec5SDimitry Andric   if (value == PyInitialValue::Empty)
735*0b57cec5SDimitry Andric     Reset(PyRefType::Owned, PyDict_New());
736*0b57cec5SDimitry Andric }
737*0b57cec5SDimitry Andric 
738*0b57cec5SDimitry Andric PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
739*0b57cec5SDimitry Andric     : PythonObject() {
740*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
741*0b57cec5SDimitry Andric }
742*0b57cec5SDimitry Andric 
743*0b57cec5SDimitry Andric PythonDictionary::~PythonDictionary() {}
744*0b57cec5SDimitry Andric 
745*0b57cec5SDimitry Andric bool PythonDictionary::Check(PyObject *py_obj) {
746*0b57cec5SDimitry Andric   if (!py_obj)
747*0b57cec5SDimitry Andric     return false;
748*0b57cec5SDimitry Andric 
749*0b57cec5SDimitry Andric   return PyDict_Check(py_obj);
750*0b57cec5SDimitry Andric }
751*0b57cec5SDimitry Andric 
752*0b57cec5SDimitry Andric void PythonDictionary::Reset(PyRefType type, PyObject *py_obj) {
753*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
754*0b57cec5SDimitry Andric   // still gets decremented if necessary.
755*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
756*0b57cec5SDimitry Andric 
757*0b57cec5SDimitry Andric   if (!PythonDictionary::Check(py_obj)) {
758*0b57cec5SDimitry Andric     PythonObject::Reset();
759*0b57cec5SDimitry Andric     return;
760*0b57cec5SDimitry Andric   }
761*0b57cec5SDimitry Andric 
762*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
763*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
764*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
765*0b57cec5SDimitry Andric }
766*0b57cec5SDimitry Andric 
767*0b57cec5SDimitry Andric uint32_t PythonDictionary::GetSize() const {
768*0b57cec5SDimitry Andric   if (IsValid())
769*0b57cec5SDimitry Andric     return PyDict_Size(m_py_obj);
770*0b57cec5SDimitry Andric   return 0;
771*0b57cec5SDimitry Andric }
772*0b57cec5SDimitry Andric 
773*0b57cec5SDimitry Andric PythonList PythonDictionary::GetKeys() const {
774*0b57cec5SDimitry Andric   if (IsValid())
775*0b57cec5SDimitry Andric     return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
776*0b57cec5SDimitry Andric   return PythonList(PyInitialValue::Invalid);
777*0b57cec5SDimitry Andric }
778*0b57cec5SDimitry Andric 
779*0b57cec5SDimitry Andric PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {
780*0b57cec5SDimitry Andric   if (IsAllocated() && key.IsValid())
781*0b57cec5SDimitry Andric     return PythonObject(PyRefType::Borrowed,
782*0b57cec5SDimitry Andric                         PyDict_GetItem(m_py_obj, key.get()));
783*0b57cec5SDimitry Andric   return PythonObject();
784*0b57cec5SDimitry Andric }
785*0b57cec5SDimitry Andric 
786*0b57cec5SDimitry Andric void PythonDictionary::SetItemForKey(const PythonObject &key,
787*0b57cec5SDimitry Andric                                      const PythonObject &value) {
788*0b57cec5SDimitry Andric   if (IsAllocated() && key.IsValid() && value.IsValid())
789*0b57cec5SDimitry Andric     PyDict_SetItem(m_py_obj, key.get(), value.get());
790*0b57cec5SDimitry Andric }
791*0b57cec5SDimitry Andric 
792*0b57cec5SDimitry Andric StructuredData::DictionarySP
793*0b57cec5SDimitry Andric PythonDictionary::CreateStructuredDictionary() const {
794*0b57cec5SDimitry Andric   StructuredData::DictionarySP result(new StructuredData::Dictionary);
795*0b57cec5SDimitry Andric   PythonList keys(GetKeys());
796*0b57cec5SDimitry Andric   uint32_t num_keys = keys.GetSize();
797*0b57cec5SDimitry Andric   for (uint32_t i = 0; i < num_keys; ++i) {
798*0b57cec5SDimitry Andric     PythonObject key = keys.GetItemAtIndex(i);
799*0b57cec5SDimitry Andric     PythonObject value = GetItemForKey(key);
800*0b57cec5SDimitry Andric     StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
801*0b57cec5SDimitry Andric     result->AddItem(key.Str().GetString(), structured_value);
802*0b57cec5SDimitry Andric   }
803*0b57cec5SDimitry Andric   return result;
804*0b57cec5SDimitry Andric }
805*0b57cec5SDimitry Andric 
806*0b57cec5SDimitry Andric PythonModule::PythonModule() : PythonObject() {}
807*0b57cec5SDimitry Andric 
808*0b57cec5SDimitry Andric PythonModule::PythonModule(PyRefType type, PyObject *py_obj) {
809*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
810*0b57cec5SDimitry Andric }
811*0b57cec5SDimitry Andric 
812*0b57cec5SDimitry Andric PythonModule::~PythonModule() {}
813*0b57cec5SDimitry Andric 
814*0b57cec5SDimitry Andric PythonModule PythonModule::BuiltinsModule() {
815*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
816*0b57cec5SDimitry Andric   return AddModule("builtins");
817*0b57cec5SDimitry Andric #else
818*0b57cec5SDimitry Andric   return AddModule("__builtin__");
819*0b57cec5SDimitry Andric #endif
820*0b57cec5SDimitry Andric }
821*0b57cec5SDimitry Andric 
822*0b57cec5SDimitry Andric PythonModule PythonModule::MainModule() { return AddModule("__main__"); }
823*0b57cec5SDimitry Andric 
824*0b57cec5SDimitry Andric PythonModule PythonModule::AddModule(llvm::StringRef module) {
825*0b57cec5SDimitry Andric   std::string str = module.str();
826*0b57cec5SDimitry Andric   return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
827*0b57cec5SDimitry Andric }
828*0b57cec5SDimitry Andric 
829*0b57cec5SDimitry Andric PythonModule PythonModule::ImportModule(llvm::StringRef module) {
830*0b57cec5SDimitry Andric   std::string str = module.str();
831*0b57cec5SDimitry Andric   return PythonModule(PyRefType::Owned, PyImport_ImportModule(str.c_str()));
832*0b57cec5SDimitry Andric }
833*0b57cec5SDimitry Andric 
834*0b57cec5SDimitry Andric bool PythonModule::Check(PyObject *py_obj) {
835*0b57cec5SDimitry Andric   if (!py_obj)
836*0b57cec5SDimitry Andric     return false;
837*0b57cec5SDimitry Andric 
838*0b57cec5SDimitry Andric   return PyModule_Check(py_obj);
839*0b57cec5SDimitry Andric }
840*0b57cec5SDimitry Andric 
841*0b57cec5SDimitry Andric void PythonModule::Reset(PyRefType type, PyObject *py_obj) {
842*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
843*0b57cec5SDimitry Andric   // still gets decremented if necessary.
844*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
845*0b57cec5SDimitry Andric 
846*0b57cec5SDimitry Andric   if (!PythonModule::Check(py_obj)) {
847*0b57cec5SDimitry Andric     PythonObject::Reset();
848*0b57cec5SDimitry Andric     return;
849*0b57cec5SDimitry Andric   }
850*0b57cec5SDimitry Andric 
851*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
852*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
853*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
854*0b57cec5SDimitry Andric }
855*0b57cec5SDimitry Andric 
856*0b57cec5SDimitry Andric PythonDictionary PythonModule::GetDictionary() const {
857*0b57cec5SDimitry Andric   return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
858*0b57cec5SDimitry Andric }
859*0b57cec5SDimitry Andric 
860*0b57cec5SDimitry Andric PythonCallable::PythonCallable() : PythonObject() {}
861*0b57cec5SDimitry Andric 
862*0b57cec5SDimitry Andric PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj) {
863*0b57cec5SDimitry Andric   Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable
864*0b57cec5SDimitry Andric }
865*0b57cec5SDimitry Andric 
866*0b57cec5SDimitry Andric PythonCallable::~PythonCallable() {}
867*0b57cec5SDimitry Andric 
868*0b57cec5SDimitry Andric bool PythonCallable::Check(PyObject *py_obj) {
869*0b57cec5SDimitry Andric   if (!py_obj)
870*0b57cec5SDimitry Andric     return false;
871*0b57cec5SDimitry Andric 
872*0b57cec5SDimitry Andric   return PyCallable_Check(py_obj);
873*0b57cec5SDimitry Andric }
874*0b57cec5SDimitry Andric 
875*0b57cec5SDimitry Andric void PythonCallable::Reset(PyRefType type, PyObject *py_obj) {
876*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
877*0b57cec5SDimitry Andric   // still gets decremented if necessary.
878*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
879*0b57cec5SDimitry Andric 
880*0b57cec5SDimitry Andric   if (!PythonCallable::Check(py_obj)) {
881*0b57cec5SDimitry Andric     PythonObject::Reset();
882*0b57cec5SDimitry Andric     return;
883*0b57cec5SDimitry Andric   }
884*0b57cec5SDimitry Andric 
885*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
886*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
887*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
888*0b57cec5SDimitry Andric }
889*0b57cec5SDimitry Andric 
890*0b57cec5SDimitry Andric PythonCallable::ArgInfo PythonCallable::GetNumArguments() const {
891*0b57cec5SDimitry Andric   ArgInfo result = {0, false, false, false};
892*0b57cec5SDimitry Andric   if (!IsValid())
893*0b57cec5SDimitry Andric     return result;
894*0b57cec5SDimitry Andric 
895*0b57cec5SDimitry Andric   PyObject *py_func_obj = m_py_obj;
896*0b57cec5SDimitry Andric   if (PyMethod_Check(py_func_obj)) {
897*0b57cec5SDimitry Andric     py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
898*0b57cec5SDimitry Andric     PythonObject im_self = GetAttributeValue("im_self");
899*0b57cec5SDimitry Andric     if (im_self.IsValid() && !im_self.IsNone())
900*0b57cec5SDimitry Andric       result.is_bound_method = true;
901*0b57cec5SDimitry Andric   } else {
902*0b57cec5SDimitry Andric     // see if this is a callable object with an __call__ method
903*0b57cec5SDimitry Andric     if (!PyFunction_Check(py_func_obj)) {
904*0b57cec5SDimitry Andric       PythonObject __call__ = GetAttributeValue("__call__");
905*0b57cec5SDimitry Andric       if (__call__.IsValid()) {
906*0b57cec5SDimitry Andric         auto __callable__ = __call__.AsType<PythonCallable>();
907*0b57cec5SDimitry Andric         if (__callable__.IsValid()) {
908*0b57cec5SDimitry Andric           py_func_obj = PyMethod_GET_FUNCTION(__callable__.get());
909*0b57cec5SDimitry Andric           PythonObject im_self = GetAttributeValue("im_self");
910*0b57cec5SDimitry Andric           if (im_self.IsValid() && !im_self.IsNone())
911*0b57cec5SDimitry Andric             result.is_bound_method = true;
912*0b57cec5SDimitry Andric         }
913*0b57cec5SDimitry Andric       }
914*0b57cec5SDimitry Andric     }
915*0b57cec5SDimitry Andric   }
916*0b57cec5SDimitry Andric 
917*0b57cec5SDimitry Andric   if (!py_func_obj)
918*0b57cec5SDimitry Andric     return result;
919*0b57cec5SDimitry Andric 
920*0b57cec5SDimitry Andric   PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(py_func_obj);
921*0b57cec5SDimitry Andric   if (!code)
922*0b57cec5SDimitry Andric     return result;
923*0b57cec5SDimitry Andric 
924*0b57cec5SDimitry Andric   result.count = code->co_argcount;
925*0b57cec5SDimitry Andric   result.has_varargs = !!(code->co_flags & CO_VARARGS);
926*0b57cec5SDimitry Andric   result.has_kwargs = !!(code->co_flags & CO_VARKEYWORDS);
927*0b57cec5SDimitry Andric   return result;
928*0b57cec5SDimitry Andric }
929*0b57cec5SDimitry Andric 
930*0b57cec5SDimitry Andric PythonObject PythonCallable::operator()() {
931*0b57cec5SDimitry Andric   return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));
932*0b57cec5SDimitry Andric }
933*0b57cec5SDimitry Andric 
934*0b57cec5SDimitry Andric PythonObject PythonCallable::
935*0b57cec5SDimitry Andric operator()(std::initializer_list<PyObject *> args) {
936*0b57cec5SDimitry Andric   PythonTuple arg_tuple(args);
937*0b57cec5SDimitry Andric   return PythonObject(PyRefType::Owned,
938*0b57cec5SDimitry Andric                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
939*0b57cec5SDimitry Andric }
940*0b57cec5SDimitry Andric 
941*0b57cec5SDimitry Andric PythonObject PythonCallable::
942*0b57cec5SDimitry Andric operator()(std::initializer_list<PythonObject> args) {
943*0b57cec5SDimitry Andric   PythonTuple arg_tuple(args);
944*0b57cec5SDimitry Andric   return PythonObject(PyRefType::Owned,
945*0b57cec5SDimitry Andric                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
946*0b57cec5SDimitry Andric }
947*0b57cec5SDimitry Andric 
948*0b57cec5SDimitry Andric PythonFile::PythonFile() : PythonObject() {}
949*0b57cec5SDimitry Andric 
950*0b57cec5SDimitry Andric PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); }
951*0b57cec5SDimitry Andric 
952*0b57cec5SDimitry Andric PythonFile::PythonFile(const char *path, const char *mode) {
953*0b57cec5SDimitry Andric   lldb_private::File file;
954*0b57cec5SDimitry Andric   FileSystem::Instance().Open(file, FileSpec(path), GetOptionsFromMode(mode));
955*0b57cec5SDimitry Andric   Reset(file, mode);
956*0b57cec5SDimitry Andric }
957*0b57cec5SDimitry Andric 
958*0b57cec5SDimitry Andric PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); }
959*0b57cec5SDimitry Andric 
960*0b57cec5SDimitry Andric PythonFile::~PythonFile() {}
961*0b57cec5SDimitry Andric 
962*0b57cec5SDimitry Andric bool PythonFile::Check(PyObject *py_obj) {
963*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION < 3
964*0b57cec5SDimitry Andric   return PyFile_Check(py_obj);
965*0b57cec5SDimitry Andric #else
966*0b57cec5SDimitry Andric   // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
967*0b57cec5SDimitry Andric   // first-class object type anymore.  `PyFile_FromFd` is just a thin wrapper
968*0b57cec5SDimitry Andric   // over `io.open()`, which returns some object derived from `io.IOBase`. As a
969*0b57cec5SDimitry Andric   // result, the only way to detect a file in Python 3 is to check whether it
970*0b57cec5SDimitry Andric   // inherits from `io.IOBase`.  Since it is possible for non-files to also
971*0b57cec5SDimitry Andric   // inherit from `io.IOBase`, we additionally verify that it has the `fileno`
972*0b57cec5SDimitry Andric   // attribute, which should guarantee that it is backed by the file system.
973*0b57cec5SDimitry Andric   PythonObject io_module(PyRefType::Owned, PyImport_ImportModule("io"));
974*0b57cec5SDimitry Andric   PythonDictionary io_dict(PyRefType::Borrowed,
975*0b57cec5SDimitry Andric                            PyModule_GetDict(io_module.get()));
976*0b57cec5SDimitry Andric   PythonObject io_base_class = io_dict.GetItemForKey(PythonString("IOBase"));
977*0b57cec5SDimitry Andric 
978*0b57cec5SDimitry Andric   PythonObject object_type(PyRefType::Owned, PyObject_Type(py_obj));
979*0b57cec5SDimitry Andric 
980*0b57cec5SDimitry Andric   if (1 != PyObject_IsSubclass(object_type.get(), io_base_class.get()))
981*0b57cec5SDimitry Andric     return false;
982*0b57cec5SDimitry Andric   if (!object_type.HasAttribute("fileno"))
983*0b57cec5SDimitry Andric     return false;
984*0b57cec5SDimitry Andric 
985*0b57cec5SDimitry Andric   return true;
986*0b57cec5SDimitry Andric #endif
987*0b57cec5SDimitry Andric }
988*0b57cec5SDimitry Andric 
989*0b57cec5SDimitry Andric void PythonFile::Reset(PyRefType type, PyObject *py_obj) {
990*0b57cec5SDimitry Andric   // Grab the desired reference type so that if we end up rejecting `py_obj` it
991*0b57cec5SDimitry Andric   // still gets decremented if necessary.
992*0b57cec5SDimitry Andric   PythonObject result(type, py_obj);
993*0b57cec5SDimitry Andric 
994*0b57cec5SDimitry Andric   if (!PythonFile::Check(py_obj)) {
995*0b57cec5SDimitry Andric     PythonObject::Reset();
996*0b57cec5SDimitry Andric     return;
997*0b57cec5SDimitry Andric   }
998*0b57cec5SDimitry Andric 
999*0b57cec5SDimitry Andric   // Calling PythonObject::Reset(const PythonObject&) will lead to stack
1000*0b57cec5SDimitry Andric   // overflow since it calls back into the virtual implementation.
1001*0b57cec5SDimitry Andric   PythonObject::Reset(PyRefType::Borrowed, result.get());
1002*0b57cec5SDimitry Andric }
1003*0b57cec5SDimitry Andric 
1004*0b57cec5SDimitry Andric void PythonFile::Reset(File &file, const char *mode) {
1005*0b57cec5SDimitry Andric   if (!file.IsValid()) {
1006*0b57cec5SDimitry Andric     Reset();
1007*0b57cec5SDimitry Andric     return;
1008*0b57cec5SDimitry Andric   }
1009*0b57cec5SDimitry Andric 
1010*0b57cec5SDimitry Andric   char *cmode = const_cast<char *>(mode);
1011*0b57cec5SDimitry Andric #if PY_MAJOR_VERSION >= 3
1012*0b57cec5SDimitry Andric   Reset(PyRefType::Owned, PyFile_FromFd(file.GetDescriptor(), nullptr, cmode,
1013*0b57cec5SDimitry Andric                                         -1, nullptr, "ignore", nullptr, 0));
1014*0b57cec5SDimitry Andric #else
1015*0b57cec5SDimitry Andric   // Read through the Python source, doesn't seem to modify these strings
1016*0b57cec5SDimitry Andric   Reset(PyRefType::Owned,
1017*0b57cec5SDimitry Andric         PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode,
1018*0b57cec5SDimitry Andric                         nullptr));
1019*0b57cec5SDimitry Andric #endif
1020*0b57cec5SDimitry Andric }
1021*0b57cec5SDimitry Andric 
1022*0b57cec5SDimitry Andric uint32_t PythonFile::GetOptionsFromMode(llvm::StringRef mode) {
1023*0b57cec5SDimitry Andric   if (mode.empty())
1024*0b57cec5SDimitry Andric     return 0;
1025*0b57cec5SDimitry Andric 
1026*0b57cec5SDimitry Andric   return llvm::StringSwitch<uint32_t>(mode.str())
1027*0b57cec5SDimitry Andric       .Case("r", File::eOpenOptionRead)
1028*0b57cec5SDimitry Andric       .Case("w", File::eOpenOptionWrite)
1029*0b57cec5SDimitry Andric       .Case("a", File::eOpenOptionWrite | File::eOpenOptionAppend |
1030*0b57cec5SDimitry Andric                      File::eOpenOptionCanCreate)
1031*0b57cec5SDimitry Andric       .Case("r+", File::eOpenOptionRead | File::eOpenOptionWrite)
1032*0b57cec5SDimitry Andric       .Case("w+", File::eOpenOptionRead | File::eOpenOptionWrite |
1033*0b57cec5SDimitry Andric                       File::eOpenOptionCanCreate | File::eOpenOptionTruncate)
1034*0b57cec5SDimitry Andric       .Case("a+", File::eOpenOptionRead | File::eOpenOptionWrite |
1035*0b57cec5SDimitry Andric                       File::eOpenOptionAppend | File::eOpenOptionCanCreate)
1036*0b57cec5SDimitry Andric       .Default(0);
1037*0b57cec5SDimitry Andric }
1038*0b57cec5SDimitry Andric 
1039*0b57cec5SDimitry Andric bool PythonFile::GetUnderlyingFile(File &file) const {
1040*0b57cec5SDimitry Andric   if (!IsValid())
1041*0b57cec5SDimitry Andric     return false;
1042*0b57cec5SDimitry Andric 
1043*0b57cec5SDimitry Andric   file.Close();
1044*0b57cec5SDimitry Andric   // We don't own the file descriptor returned by this function, make sure the
1045*0b57cec5SDimitry Andric   // File object knows about that.
1046*0b57cec5SDimitry Andric   file.SetDescriptor(PyObject_AsFileDescriptor(m_py_obj), false);
1047*0b57cec5SDimitry Andric   PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>();
1048*0b57cec5SDimitry Andric   file.SetOptions(PythonFile::GetOptionsFromMode(py_mode.GetString()));
1049*0b57cec5SDimitry Andric   return file.IsValid();
1050*0b57cec5SDimitry Andric }
1051*0b57cec5SDimitry Andric 
1052*0b57cec5SDimitry Andric #endif
1053