// _gen/asdl/hnode.asdl.h is generated by asdl_main.py

#ifndef HNODE_ASDL
#define HNODE_ASDL

#include <cstdint>

#include "mycpp/runtime.h"
namespace hnode_asdl {

// use struct instead of namespace so 'using' works consistently
#define ASDL_NAMES struct

class Field;
class hnode_t;

enum class color_e {
  TypeName = 1,
  StringConst = 2,
  OtherConst = 3,
  UserType = 4,
  External = 5,
};
typedef color_e color_t;

ASDL_NAMES hnode_e {
  enum no_name {
  AlreadySeen = 1,
  Leaf = 2,
  Array = 3,
  Record = 4,
  };
};

class hnode_t {
 protected:
  hnode_t() {
  }
 public:
  int tag() const {
    return ObjHeader::FromObject(this)->type_tag;
  }
  constexpr int sum_type_id() {
    return 0;
  }

  DISALLOW_COPY_AND_ASSIGN(hnode_t)
};

class hnode__AlreadySeen : public hnode_t {
 public:
  hnode__AlreadySeen(int heap_id)
      : heap_id(heap_id) {
  }

  static hnode__AlreadySeen* CreateNull(bool alloc_lists = false) { 
    return Alloc<hnode__AlreadySeen>(-1);
  }

  int type_id() {
    return this->sum_type_id() + this->tag();
  }
  
  static constexpr ObjHeader obj_header() {
    return ObjHeader::AsdlClass(static_cast<uint16_t>(hnode_e::AlreadySeen), 0);
  }
  int heap_id;

  DISALLOW_COPY_AND_ASSIGN(hnode__AlreadySeen)
};

class hnode__Leaf : public hnode_t {
 public:
  hnode__Leaf(BigStr* s, color_t color)
      : s(s),
        color(color) {
  }

  static hnode__Leaf* CreateNull(bool alloc_lists = false) { 
    return Alloc<hnode__Leaf>(kEmptyString, color_e::TypeName);
  }

  int type_id() {
    return this->sum_type_id() + this->tag();
  }
  
  static constexpr ObjHeader obj_header() {
    return ObjHeader::AsdlClass(static_cast<uint16_t>(hnode_e::Leaf), 1);
  }
  BigStr* s;
  color_t color;

  DISALLOW_COPY_AND_ASSIGN(hnode__Leaf)
};

class hnode__Array : public hnode_t {
 public:
  hnode__Array(List<hnode_t*>* children)
      : children(children) {
  }

  static hnode__Array* CreateNull(bool alloc_lists = false) { 
    return Alloc<hnode__Array>(alloc_lists ? Alloc<List<hnode_t*>>() : nullptr);
  }

  int type_id() {
    return this->sum_type_id() + this->tag();
  }
  
  static constexpr ObjHeader obj_header() {
    return ObjHeader::AsdlClass(static_cast<uint16_t>(hnode_e::Array), 1);
  }
  List<hnode_t*>* children;

  DISALLOW_COPY_AND_ASSIGN(hnode__Array)
};

class hnode__Record : public hnode_t {
 public:
  hnode__Record(BigStr* node_type, BigStr* left, BigStr* right, List<Field*>*
                fields, List<hnode_t*>* unnamed_fields)
      : node_type(node_type),
        left(left),
        right(right),
        fields(fields),
        unnamed_fields(unnamed_fields) {
  }

  static hnode__Record* CreateNull(bool alloc_lists = false) { 
    return Alloc<hnode__Record>(kEmptyString, kEmptyString, kEmptyString,
                                alloc_lists ? Alloc<List<Field*>>() : nullptr,
                                nullptr);
  }

  int type_id() {
    return this->sum_type_id() + this->tag();
  }
  
  static constexpr ObjHeader obj_header() {
    return ObjHeader::AsdlClass(static_cast<uint16_t>(hnode_e::Record), 5);
  }
  BigStr* node_type;
  BigStr* left;
  BigStr* right;
  List<Field*>* fields;
  List<hnode_t*>* unnamed_fields;

  DISALLOW_COPY_AND_ASSIGN(hnode__Record)
};

ASDL_NAMES hnode {
  typedef hnode__AlreadySeen AlreadySeen;
  typedef hnode__Leaf Leaf;
  typedef hnode__Array Array;
  typedef hnode__Record Record;
};

enum class alloc_members_e {
  List = 1,
  Dict = 2,
  Struct = 3,
};
typedef alloc_members_e alloc_members_t;

class Field {
 public:
  Field(BigStr* name, hnode_t* val)
      : name(name),
        val(val) {
  }

  static Field* CreateNull(bool alloc_lists = false) { 
    return Alloc<Field>(kEmptyString, nullptr);
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::AsdlClass(64, 2);
  }
  BigStr* name;
  hnode_t* val;

  DISALLOW_COPY_AND_ASSIGN(Field)
};


}  // namespace hnode_asdl

#endif  // HNODE_ASDL
