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