export class UndefinedSymbolError extends Error {}

export class SymbolTable {
  private knownSymbols: Set<string>;
  private parent: SymbolTable | null;
  private depth: number;

  constructor(parent: SymbolTable | null = null) {
    this.knownSymbols = new Set();
    this.parent = parent;
    this.depth = parent ? parent.getDepth() + 1 : 0;
  }

  public getDepth() {
    return this.depth;
  }

  public add(name: string) {
    this.knownSymbols.add(name);
  }

  public get(name: string): number {
    if (this.knownSymbols.has(name)) {
      return 1;
    }

    if (this.parent) {
      return 1 + this.parent.get(name);
    }

    throw new UndefinedSymbolError(`Undefined variable: ${name}`);
  }

  public has(name: string): boolean {
    if (this.knownSymbols.has(name)) {
      return true;
    }

    if (this.parent) {
      return this.parent.has(name);
    }

    return false;
  }

  public createChild(): SymbolTable {
    return new SymbolTable(this);
  }
}
