text: //===-- 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<typename T>
      static T
      ResolveNameWithDictionary(llvm::StringRef name, const PythonDictionary &dict)
      {
          return ResolveNameWithDictionary(name, dict).AsType<T>();
      }
  
      PythonObject
      ResolveName(llvm::StringRef name) const;
  
      template<typename T>
      T
      ResolveName(llvm::StringRef name) const
      {
          return ResolveName(name).AsType<T>();
      }
  
      bool
      HasAttribute(llvm::StringRef attribute) const;
  
      PythonObject
      GetAttributeValue(llvm::StringRef attribute) const;
  
      bool
      IsValid() const;
  
      bool
      IsAllocated() const;
  
      bool
      IsNone() const;
  
      template<typename T>
      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<uint8_t> 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<uint8_t>
      GetBytes() const;
  
      size_t
      GetSize() const;
  
      void
      SetBytes(llvm::ArrayRef<uint8_t> 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<PythonObject> objects);
      PythonTuple(std::initializer_list<PyObject*> 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<PyObject*> args);
  
      PythonObject
      operator ()(std::initializer_list<PythonObject> args);
  
      template<typename Arg, typename... Args>
      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
  