<commit_before>#ifndef AST_HPP
#define AST_HPP

#include <string>
#include <vector>
#include <set>
#include <memory>
#include <numeric>
#include <typeinfo>

#include "error.hpp"
#include "token.hpp"
#include "util.hpp"
#include "operator.hpp"

typedef std::set<std::string> TypeList;

class ASTNode: public std::enable_shared_from_this<ASTNode> {
public:
  typedef std::shared_ptr<ASTNode> Link;
  typedef std::weak_ptr<ASTNode> WeakLink;
  typedef std::vector<Link> Children;
protected:
  WeakLink parent = WeakLink();
  Children children {};
  uint64 lineNumber = 0;
  
  static void printIndent(uint level) {
    for (uint i = 0; i < level; i++) print("  ");
  }
public:
  ASTNode(uint64 lineNumber = 0): lineNumber(lineNumber) {}
  virtual ~ASTNode() {};
  
  virtual void addChild(Link child) {
    child->setParent(shared_from_this());
    children.push_back(child);
  }
  
  Children getChildren() const {
    return children;
  }
  
  Link at(int64 pos) const {
    if (pos < 0) {
      pos = children.size() + pos; // Negative indices count from the end of the vector
    }
    if (abs(pos) > children.size() || pos < 0) {
      throw InternalError("Index out of array bounds", {METADATA_PAIRS, {"index", std::to_string(pos)}});
    }
    return children[pos];
  }
  
  void setParent(WeakLink newParent) {parent = newParent;}
  WeakLink getParent() const {return parent;}
  
  void inline setLineNumber(uint64 newLineNumber) {
    lineNumber = newLineNumber;
  }
  uint64 inline getLineNumber() const {
    return lineNumber;
  }
  
  virtual void printTree(uint level) const {
    printIndent(level);
    println("Base ASTNode");
    for (auto& child : children) child->printTree(level + 1);
  }
  
  virtual bool operator==(const ASTNode& rhs) const {
    if (typeid(*this) != typeid(rhs)) return false;
    if (children.size() != rhs.getChildren().size()) return false;
    for (uint64 i = 0; i < children.size(); i++) {
      if (*(this->at(i)) != *(rhs.at(i))) return false;
    }
    return true;
  }
  
  virtual bool operator!=(const ASTNode& rhs) const {
    return !operator==(rhs);
  }
};

template<typename T, typename std::enable_if<std::is_base_of<ASTNode, T>::value>::type* = nullptr>
struct Node: public PtrUtil<T> {
  typedef typename PtrUtil<T>::Link Link;
  typedef typename PtrUtil<T>::WeakLink WeakLink;
  
  
  static inline bool isSameType(ASTNode::Link node) {
    return typeid(T) == typeid(*node);
  }
  
  static inline Link dynPtrCast(ASTNode::Link node) {
    return std::dynamic_pointer_cast<T>(node);
  }
};

class BlockNode: public ASTNode {
public:
  void printTree(uint level) const {
    printIndent(level);
    println("Block Node");
    for (auto& child : children) child->printTree(level + 1);
  }
  bool operator==(const ASTNode& rhs) const {
    return ASTNode::operator==(rhs);
  }
  bool operator!=(const ASTNode& rhs) const {
    return !operator==(rhs);
  }
};

class ExpressionNode: public ASTNode {
private:
  Token tok = Token(UNPROCESSED, 0);
public:
  ExpressionNode() {}
  ExpressionNode(Token token): tok(token) {
    switch (tok.type) {
      case IDENTIFIER:
      case OPERATOR:
      case L_INTEGER:
      case L_FLOAT:
      case L_STRING:
      case L_BOOLEAN:
        break;
      default: throw InternalError("Trying to add unsupported token to ExpressionNode", {METADATA_PAIRS, {"token", token.toString()}});
    }
  }
  
  std::shared_ptr<ExpressionNode> at(int64 pos) {
    return std::dynamic_pointer_cast<ExpressionNode>(ASTNode::at(pos));
  }
  
  Token getToken() const {
    return tok;
  }
  
  void printTree(uint level) const {
    printIndent(level);
    println("Expression Node:", tok);
    for (auto& child : children) child->printTree(level + 1);
  }
  
  bool operator==(const ASTNode& rhs) const {
    if (!ASTNode::operator==(rhs)) return false;
    if (this->tok != dynamic_cast<const ExpressionNode&>(rhs).tok) return false;
    return true;
  }
  bool operator!=(const ASTNode& rhs) const {
    return !operator==(rhs);
  }
};

class DeclarationNode: public ASTNode {
private:
  std::string identifier;
  TypeList typeList;
  bool dynamic;
public:
  DeclarationNode(std::string identifier, TypeList typeList):
    identifier(identifier), typeList(typeList), dynamic(false) {}
  DeclarationNode(std::string identifier):
    identifier(identifier), typeList({}), dynamic(true) {}
    
  std::string getIdentifier() const {
    return identifier;
  }
  
  TypeList getTypeList() const {
    return typeList;
  }
  
  bool isDynamic() const {
    return dynamic;
  }
  
  void addChild(Link child) {
    if (children.size() >= 1) throw InternalError("Trying to add more than one child to a DeclarationNode", {METADATA_PAIRS});
    if (Node<ExpressionNode>::dynPtrCast(child)) throw InternalError("DeclarationNode only supports ExpressionNode as its child", {METADATA_PAIRS});
    ASTNode::addChild(child);
  }
  
  void printTree(uint level) const {
    printIndent(level);
    std::string collatedTypes = std::accumulate(++typeList.begin(), typeList.end(), *typeList.begin(),
    [](const std::string& prev, const std::string& current) {
      return prev + ", " + current;
    });
    println("Declaration Node: " + identifier + " (valid types: " + collatedTypes + ")");
    if (children.size() > 0) children[0]->printTree(level + 1);
  }<commit_msg>Fixed wrong condition, added convenience methods<commit_after>#ifndef AST_HPP
#define AST_HPP

#include <string>
#include <vector>
#include <set>
#include <memory>
#include <numeric>
#include <typeinfo>

#include "error.hpp"
#include "token.hpp"
#include "util.hpp"
#include "operator.hpp"

typedef std::set<std::string> TypeList;

class ASTNode: public std::enable_shared_from_this<ASTNode> {
public:
  typedef std::shared_ptr<ASTNode> Link;
  typedef std::weak_ptr<ASTNode> WeakLink;
  typedef std::vector<Link> Children;
protected:
  WeakLink parent = WeakLink();
  Children children {};
  uint64 lineNumber = 0;
  
  static void printIndent(uint level) {
    for (uint i = 0; i < level; i++) print("  ");
  }
public:
  ASTNode(uint64 lineNumber = 0): lineNumber(lineNumber) {}
  virtual ~ASTNode() {};
  
  virtual void addChild(Link child) {
    child->setParent(shared_from_this());
    children.push_back(child);
  }
  
  Children getChildren() const {
    return children;
  }
  
  Link at(int64 pos) const {
    if (pos < 0) {
      pos = children.size() + pos; // Negative indices count from the end of the vector
    }
    if (abs(pos) > children.size() || pos < 0) {
      throw InternalError("Index out of array bounds", {METADATA_PAIRS, {"index", std::to_string(pos)}});
    }
    return children[pos];
  }
  
  void setParent(WeakLink newParent) {parent = newParent;}
  WeakLink getParent() const {return parent;}
  
  void inline setLineNumber(uint64 newLineNumber) {
    lineNumber = newLineNumber;
  }
  uint64 inline getLineNumber() const {
    return lineNumber;
  }
  
  virtual void printTree(uint level) const {
    printIndent(level);
    println("Base ASTNode");
    for (auto& child : children) child->printTree(level + 1);
  }
  
  virtual bool operator==(const ASTNode& rhs) const {
    if (typeid(*this) != typeid(rhs)) return false;
    if (children.size() != rhs.getChildren().size()) return false;
    for (uint64 i = 0; i < children.size(); i++) {
      if (*(this->at(i)) != *(rhs.at(i))) return false;
    }
    return true;
  }
  
  virtual bool operator!=(const ASTNode& rhs) const {
    return !operator==(rhs);
  }
};

template<typename T, typename std::enable_if<std::is_base_of<ASTNode, T>::value>::type* = nullptr>
struct Node: public PtrUtil<T> {
  typedef typename PtrUtil<T>::Link Link;
  typedef typename PtrUtil<T>::WeakLink WeakLink;
  
  
  static inline bool isSameType(ASTNode::Link node) {
    return typeid(T) == typeid(*node);
  }
  
  static inline Link dynPtrCast(ASTNode::Link node) {
    return std::dynamic_pointer_cast<T>(node);
  }
};

class BlockNode: public ASTNode {
public:
  void printTree(uint level) const {
    printIndent(level);
    println("Block Node");
    for (auto& child : children) child->printTree(level + 1);
  }
  bool operator==(const ASTNode& rhs) const {
    return ASTNode::operator==(rhs);
  }
  bool operator!=(const ASTNode& rhs) const {
    return !operator==(rhs);
  }
};

class ExpressionNode: public ASTNode {
private:
  Token tok = Token(UNPROCESSED, 0);
public:
  ExpressionNode() {}
  ExpressionNode(Token token): tok(token) {
    switch (tok.type) {
      case IDENTIFIER:
      case OPERATOR:
      case L_INTEGER:
      case L_FLOAT:
      case L_STRING:
      case L_BOOLEAN:
        break;
      default: throw InternalError("Trying to add unsupported token to ExpressionNode", {METADATA_PAIRS, {"token", token.toString()}});
    }
  }
  
  std::shared_ptr<ExpressionNode> at(int64 pos) {
    return std::dynamic_pointer_cast<ExpressionNode>(ASTNode::at(pos));
  }
  
  Token getToken() const {
    return tok;
  }
  
  void printTree(uint level) const {
    printIndent(level);
    println("Expression Node:", tok);
    for (auto& child : children) child->printTree(level + 1);
  }
  
  bool operator==(const ASTNode& rhs) const {
    if (!ASTNode::operator==(rhs)) return false;
    if (this->tok != dynamic_cast<const ExpressionNode&>(rhs).tok) return false;
    return true;
  }
  bool operator!=(const ASTNode& rhs) const {
    return !operator==(rhs);
  }
};

class DeclarationNode: public ASTNode {
private:
  std::string identifier;
  TypeList typeList;
  bool dynamic;
public:
  DeclarationNode(std::string identifier, TypeList typeList):
    identifier(identifier), typeList(typeList), dynamic(false) {}
  DeclarationNode(std::string identifier):
    identifier(identifier), typeList({}), dynamic(true) {}
    
  std::string getIdentifier() const {
    return identifier;
  }
  
  TypeList getTypeList() const {
    return typeList;
  }
  
  bool isDynamic() const {
    return dynamic;
  }
  
  bool hasInit() const {
    return children.size() == 1;
  }
  
  Node<ExpressionNode>::Link getInit() const {
    return Node<ExpressionNode>::dynPtrCast(children[0]);
  }
  
  void addChild(Link child) {
    if (children.size() >= 1) throw InternalError("Trying to add more than one child to a DeclarationNode", {METADATA_PAIRS});
    if (!Node<ExpressionNode>::dynPtrCast(child)) throw InternalError("DeclarationNode only supports ExpressionNode as its child", {METADATA_PAIRS});
    ASTNode::addChild(child);
  }
  
  void printTree(uint level) const {
    printIndent(level);
    std::string collatedTypes = std::accumulate(++typeList.begin(), typeList.end(), *typeList.begin(),
    [](const std::string& prev, const std::string& current) {
      return prev + ", " + current;
    });
    println("Declaration Node: " + identifier + " (valid types: " + collatedTypes + ")");
    if (children.size() > 0) children[0]->printTree(level + 1);
  }
{'fraction_non_alphanumeric': 0.13873840785970068, 'fraction_numerical': 0.005325498117711872, 'mean_word_length': 3.9173814898419863, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4755207', 'n_tokens_mistral': 3599, 'n_tokens_neox': 3476, 'n_words': 900}