#ifndef __SYMBOL_HPP__
#define __SYMBOL_HPP__

#include <map>
#include <vector>

#include "lexer.hpp"

enum Type { TYPE_int, TYPE_bool };

struct SymTabEntry {
  Type type;
  SymTabEntry() {}
  SymTabEntry(Type t) : type(t) {}
};

class Scope {
 public:
  Scope() {}
  void insert(char v, Type t) {
    if (locals.find(v) != locals.end())
      yyerror("Duplicate variable declaration");
    locals[v] = SymTabEntry(t);
  }
  SymTabEntry *lookup(char v) {
    if (locals.find(v) == locals.end()) return nullptr;
    return &(locals[v]);
  }
 private:
  std::map<char, SymTabEntry> locals;
};

class SymbolTable {
 public:
  void insert(char v, Type t) {
    scopes.back().insert(v, t);
  }
  SymTabEntry *lookup(char v) {
    for (auto s = scopes.rbegin(); s != scopes.rend(); ++s) {
      SymTabEntry *e = s->lookup(v);
      if (e != nullptr) return e;
    }
    yyerror("Variable not found");
    return nullptr;
  }
  void enter_scope() {
    scopes.push_back(Scope());
  }
  void exit_scope() {
    scopes.pop_back();
  }
 private:
  std::vector<Scope> scopes;
};

extern SymbolTable st;

#endif
