package edu.brown.cs.debugger.symboltable;

public interface SymbolTable
{
  /** Internal structure for symbols:-
   * Hashtable:
   *   key = symbolName
   *   value = List of InternalSymbolInfo
   ** Lookup:-
   * Given a symbolName and the current or given address, find the
   * InternalSymbolInfo instance in the hashtable, such that:
   * 1. scope.startAddr <= (current or given address) < scope.startAddr + scope.size, and
   * 2. scope.size is the smallest
   ** Internal structure for types:-
   * Hashtable:
   *   key = type id
   *   value = TypeInfo
   *   1:1 mapping
   ** Examples of representation of types:-
   * 1. Representation of an int
   *     PrimitiveTypeInfo intRepresentation = new PrimitiveTypeInfo();
   *     intRepresentation.typeId   = "(0,1)"; // (as given by stabs)
   *     intRepresentation.typeName = "int";
   *     intRepresentation.size     = 4; // (as given by stabs)
   * 2. Representation of an array, e.g. int arr[5];
   *     ArrayTypeInfo arrRepresentation = new ArrayTypeInfo();
   *     arrRepresentation.typeId   = "ar(0,1)"; // (as given by stabs)
   *     arrRepresentation.typeName = "int[]"; // (Not given by stabs, but constructed by us)
   *     arrRepresentation.size     = 20; // 4*5
   *     arrRepresentation.elementTypeId = "(0,1)";
   *     arrRepresentation.numElements   = 5;
   * 3. Representation of a struct, e.g.
   * typedef struct my_struct
   * {
   *   int a;
   *   int b;
   * } my_struct_t;
   * my_struct_t s;
   *     StructTypeInfo structRepresentation = new StructTypeInfo();
   *     structRepresentation.typeId   = "(1,1)"; // (as given by stabs)
   *     structRepresentation.typeName = "my_struct_t";
   *     structRepresentation.size     = 8; 4*2
   *     structRepresentation.numMembers = 2;
   *     structRepresentation.numMembers = new MemberInfo[structRepresentation.numMembers];
   *     structRepresentation.numMembers[0] = new MemberInfo();
   *     structRepresentation.numMembers[0].memberName = "a";
   *     structRepresentation.numMembers[0].typeId = "(0,1)";
   *     structRepresentation.numMembers[0].offset = 0;
   *     structRepresentation.numMembers[1] = new MemberInfo();
   *     structRepresentation.numMembers[1].memberName = "b";
   *     structRepresentation.numMembers[1].typeId = "(0,1)";
   *     structRepresentation.numMembers[1].offset = 4;
   *
   */

  // Scope of a block
  protected class ScopeInfo
  {
    public long startAddr;
    public long size;
  }

  protected class InternalSymbolInfo extends SymbolInfo
  {
    public ScopeInfo scope;
  }

  public class SymbolInfo
  {
    public String symbolName;
    public long addr;
    public long size;
    /* To Be Determined? Currently, we see types in the form (x, y) where x
     * and y are integers */
    public String typeId; // Internal definition
  }

  public abstract class TypeInfo
  {
    public String typeId;
    public String typeName; // e.g. "int", "float", etc
    public int size;
  }

  // Primitives
  public class PrimitiveTypeInfo extends TypeInfo
  {
  }

  // Functions
  public class FunctionTypeInfo extends TypeInfo
  {
  }

  // Pointers
  public class PointerTypeInfo extends TypeInfo
  {
    public String pointedToTypeId; // The type of the data pointed to.
  }

  // Structs
  public class MemberInfo
  {
    public String memberName;
    public String typeId;
    public long offset; // Offset from start of struct
  }

  public class StructTypeInfo extends TypeInfo
  {
    public int numMembers;
    public MemberInfo []members;
  }

  // Classes
  public class ClassTypeInfo extends StructTypeInfo
  {
  }

  // Arrays
  public class ArrayTypeInfo extends TypeInfo
  {
    public String elementTypeId; // Type of each element in the array (x,y)
    public int numElements;
  }

  /** TO DO: Enumerations, Unions */

  /** Source information: filename, line number */
  public class SourceInfo
  {
    public String fileName;
    public int lineno;
  }

  /** Given the name of a symbol, return the SymbolInfo.
   *  - Requires an interface to get the current address, which determines the
   *    current scope.
   * @throws SymbolTableException if there is no symbol with this name in the current scope. */
  public SymbolInfo lookupSymbol(String name);

  /** Given the name of a symbol and an address inside some scope, return the
   * SymbolInfo for the symbol inside that scope.
   * @throws SymbolTableException if there is no symbol with this name in the given scope. */
  public SymbolInfo lookupSymbol(String name, long addr) throws SymbolTableException;

  /** Given a string representing the type, return the TypeInfo associated with it. */
  public TypeInfo lookupType(String typeId) throws SymbolTableException;

  /** Loads the symbols for the given binary file
   *  - Requires registering for such an event. */
  public void loadBinary(String binaryFile);

  /** Given a filename and a line number, return the address of the first instruction
   * that corresponds to it */
  public long lookupAddr(String filename, int lineno);

  /** Given a filename and a line number, return the address of the first instruction
   * that corresponds to it */
  public long lookupAddr(SourceInfo srcInfo);

  /** Given an address, return the source file name and the line number that
   * correspond to it */
  public SourceInfo lookupSource(long addr);
}
