//===-- PythonDataObjects.h--------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H #ifndef LLDB_DISABLE_PYTHON // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/lldb-defines.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/Flags.h" #include "lldb/Host/File.h" #include "lldb/Interpreter/OptionValue.h" #include "llvm/ADT/ArrayRef.h" namespace lldb_private { class PythonBytes; class PythonString; class PythonList; class PythonDictionary; class PythonInteger; class StructuredPythonObject : public StructuredData::Generic { public: StructuredPythonObject() : StructuredData::Generic() { } StructuredPythonObject(void *obj) : StructuredData::Generic(obj) { Py_XINCREF(GetValue()); } ~StructuredPythonObject() override { if (Py_IsInitialized()) Py_XDECREF(GetValue()); SetValue(nullptr); } bool IsValid() const override { return GetValue() && GetValue() != Py_None; } void Dump(Stream &s) const override; private: DISALLOW_COPY_AND_ASSIGN(StructuredPythonObject); }; enum class PyObjectType { Unknown, None, Integer, Dictionary, List, String, Bytes, Module, Callable, Tuple, File }; enum class PyRefType { Borrowed, // We are not given ownership of the incoming PyObject. // We cannot safely hold it without calling Py_INCREF. Owned // We have ownership of the incoming PyObject. We should // not call Py_INCREF. }; enum class PyInitialValue { Invalid, Empty }; class PythonObject { public: PythonObject() : m_py_obj(nullptr) { } PythonObject(PyRefType type, PyObject *py_obj) : m_py_obj(nullptr) { Reset(type, py_obj); } PythonObject(const PythonObject &rhs) : m_py_obj(nullptr) { Reset(rhs); } virtual ~PythonObject() { Reset(); } void Reset() { // Avoid calling the virtual method since it's not necessary // to actually validate the type of the PyObject if we're // just setting to null. if (Py_IsInitialized()) Py_XDECREF(m_py_obj); m_py_obj = nullptr; } void Reset(const PythonObject &rhs) { // Avoid calling the virtual method if it's not necessary // to actually validate the type of the PyObject. if (!rhs.IsValid()) Reset(); else Reset(PyRefType::Borrowed, rhs.m_py_obj); } // PythonObject is implicitly convertible to PyObject *, which will call the // wrong overload. We want to explicitly disallow this, since a PyObject // *always* owns its reference. Therefore the overload which takes a // PyRefType doesn't make sense, and the copy constructor should be used. void Reset(PyRefType type, const PythonObject &ref) = delete; virtual void Reset(PyRefType type, PyObject *py_obj) { if (py_obj == m_py_obj) return; if (Py_IsInitialized()) Py_XDECREF(m_py_obj); m_py_obj = py_obj; // If this is a borrowed reference, we need to convert it to // an owned reference by incrementing it. If it is an owned // reference (for example the caller allocated it with PyDict_New() // then we must *not* increment it. if (Py_IsInitialized() && type == PyRefType::Borrowed) Py_XINCREF(m_py_obj); } void Dump () const { if (m_py_obj) _PyObject_Dump (m_py_obj); else puts ("NULL"); } void Dump (Stream &strm) const; PyObject* get() const { return m_py_obj; } PyObject* release() { PyObject *result = m_py_obj; m_py_obj = nullptr; return result; } PythonObject & operator=(const PythonObject &other) { Reset(PyRefType::Borrowed, other.get()); return *this; } PyObjectType GetObjectType() const; PythonString Repr() const; PythonString Str() const; static PythonObject ResolveNameWithDictionary(llvm::StringRef name, const PythonDictionary &dict); template static T ResolveNameWithDictionary(llvm::StringRef name, const PythonDictionary &dict) { return ResolveNameWithDictionary(name, dict).AsType(); } PythonObject ResolveName(llvm::StringRef name) const; template T ResolveName(llvm::StringRef name) const { return ResolveName(name).AsType(); } bool HasAttribute(llvm::StringRef attribute) const; PythonObject GetAttributeValue(llvm::StringRef attribute) const; bool IsValid() const; bool IsAllocated() const; bool IsNone() const; template T AsType() const { if (!T::Check(m_py_obj)) return T(); return T(PyRefType::Borrowed, m_py_obj); } StructuredData::ObjectSP CreateStructuredObject() const; protected: PyObject* m_py_obj; }; class PythonBytes : public PythonObject { public: PythonBytes(); explicit PythonBytes(llvm::ArrayRef bytes); PythonBytes(const uint8_t *bytes, size_t length); PythonBytes(PyRefType type, PyObject *o); PythonBytes(const PythonBytes &object); ~PythonBytes() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; llvm::ArrayRef GetBytes() const; size_t GetSize() const; void SetBytes(llvm::ArrayRef stringbytes); StructuredData::StringSP CreateStructuredString() const; }; class PythonString : public PythonObject { public: PythonString(); explicit PythonString(llvm::StringRef string); explicit PythonString(const char *string); PythonString(PyRefType type, PyObject *o); PythonString(const PythonString &object); ~PythonString() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; llvm::StringRef GetString() const; size_t GetSize() const; void SetString(llvm::StringRef string); StructuredData::StringSP CreateStructuredString() const; }; class PythonInteger : public PythonObject { public: PythonInteger(); explicit PythonInteger(int64_t value); PythonInteger(PyRefType type, PyObject *o); PythonInteger(const PythonInteger &object); ~PythonInteger() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; int64_t GetInteger() const; void SetInteger (int64_t value); StructuredData::IntegerSP CreateStructuredInteger() const; }; class PythonList : public PythonObject { public: PythonList() {} explicit PythonList(PyInitialValue value); explicit PythonList(int list_size); PythonList(PyRefType type, PyObject *o); PythonList(const PythonList &list); ~PythonList() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; uint32_t GetSize() const; PythonObject GetItemAtIndex(uint32_t index) const; void SetItemAtIndex(uint32_t index, const PythonObject &object); void AppendItem(const PythonObject &object); StructuredData::ArraySP CreateStructuredArray() const; }; class PythonTuple : public PythonObject { public: PythonTuple() {} explicit PythonTuple(PyInitialValue value); explicit PythonTuple(int tuple_size); PythonTuple(PyRefType type, PyObject *o); PythonTuple(const PythonTuple &tuple); PythonTuple(std::initializer_list objects); PythonTuple(std::initializer_list objects); ~PythonTuple() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; uint32_t GetSize() const; PythonObject GetItemAtIndex(uint32_t index) const; void SetItemAtIndex(uint32_t index, const PythonObject &object); StructuredData::ArraySP CreateStructuredArray() const; }; class PythonDictionary : public PythonObject { public: PythonDictionary() {} explicit PythonDictionary(PyInitialValue value); PythonDictionary(PyRefType type, PyObject *o); PythonDictionary(const PythonDictionary &dict); ~PythonDictionary() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; uint32_t GetSize() const; PythonList GetKeys() const; PythonObject GetItemForKey(const PythonObject &key) const; void SetItemForKey(const PythonObject &key, const PythonObject &value); StructuredData::DictionarySP CreateStructuredDictionary() const; }; class PythonModule : public PythonObject { public: PythonModule(); PythonModule(PyRefType type, PyObject *o); PythonModule(const PythonModule &dict); ~PythonModule() override; static bool Check(PyObject *py_obj); static PythonModule BuiltinsModule(); static PythonModule MainModule(); static PythonModule AddModule(llvm::StringRef module); static PythonModule ImportModule(llvm::StringRef module); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; PythonDictionary GetDictionary() const; }; class PythonCallable : public PythonObject { public: struct ArgInfo { size_t count; bool has_varargs : 1; bool has_kwargs : 1; }; PythonCallable(); PythonCallable(PyRefType type, PyObject *o); PythonCallable(const PythonCallable &dict); ~PythonCallable() override; static bool Check(PyObject *py_obj); // Bring in the no-argument base class version using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; ArgInfo GetNumArguments() const; PythonObject operator ()(); PythonObject operator ()(std::initializer_list args); PythonObject operator ()(std::initializer_list args); template PythonObject operator ()(const Arg &arg, Args... args) { return operator()({ arg, args... }); } }; class PythonFile : public PythonObject { public: PythonFile(); PythonFile(File &file, const char *mode); PythonFile(const char *path, const char *mode); PythonFile(PyRefType type, PyObject *o); ~PythonFile() override; static bool Check(PyObject *py_obj); using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; void Reset(File &file, const char *mode); bool GetUnderlyingFile(File &file) const; }; } // namespace lldb_private #endif #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H