view trunk/src/dil/lexer/IdTable.d @ 707:efa5fcb9aa14

Added semantic code related to enums. Added member symbol to EnumMemberDeclaration. Added genAnonEnumID() to IdTable. Added class EnumMember. Wrote code for SemanticPass2.visit(EnumDeclaration). Revised code in SemanticPass1.visit(EnumDeclaration).
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Tue, 29 Jan 2008 01:07:39 +0100
parents 07946b379006
children 140469ecb90e
line wrap: on
line source

/++
  Author: Aziz Köksal
  License: GPL3
+/
module dil.lexer.IdTable;

import dil.lexer.TokensEnum;
import dil.lexer.IdentsGenerator;
import dil.lexer.Keywords;
import common;

public import dil.lexer.Identifier;
public import dil.lexer.IdentsEnum;

struct Ident
{
  const static
  {
    mixin(generateIdentMembers());
  }

  static Identifier*[] allIds()
  {
    return __allIds;
  }
}

/++
  Global table for hoarding and retrieving identifiers.
+/
struct IdTable
{
static:
  /// A set of common, predefined identifiers for fast lookups.
  private Identifier*[string] staticTable;
  /// A table that grows with every newly found, unique identifier.
  /// Access must be synchronized.
  private Identifier*[string] growingTable;

  /// Initializes the static table.
  static this()
  {
    // Load keywords and pre-defined identifiers into the static table.
    foreach (ref k; keywords)
      staticTable[k.str] = &k;
    foreach (id; Ident.allIds())
      staticTable[id.str] = id;
    staticTable.rehash;
  }

  /// Looks in both tables.
  Identifier* lookup(string idString)
  {
    auto id = inStatic(idString);
    if (id)
      return id;
    return inGrowing(idString);
  }

  /// Look up idString in the static table.
  Identifier* inStatic(string idString)
  {
    auto id = idString in staticTable;
    return id ? *id : null;
  }

  alias Identifier* function(string idString) LookupFunction;
  /// Look up idString in the growing table.
  LookupFunction inGrowing = &_inGrowing_unsafe; // Default to unsafe function.

  /++
    Set the thread safety mode of this table.
    Call this function only if you can be sure
    that this table is not being accessed
    (like during lexing, parsing and semantic phase.)
  +/
  void setThreadsafe(bool b)
  {
    if (b)
      IdTable.inGrowing = &_inGrowing_safe;
    else
      IdTable.inGrowing = &_inGrowing_unsafe;
  }

  /++
    Returns the Identifier for idString.
    Adds idString to the table if not found.
  +/
  private Identifier* _inGrowing_unsafe(string idString)
  out(id)
  { assert(id !is null); }
  body
  {
    auto id = idString in growingTable;
    if (id)
      return *id;
    auto newID = Identifier(idString, TOK.Identifier);
    growingTable[idString] = newID;
    return newID;
  }

  /++
    Returns the Identifier for idString.
    Adds idString to the table if not found.
    Access to the data structure is synchronized.
  +/
  private Identifier* _inGrowing_safe(string idString)
  {
    synchronized
      return _inGrowing_unsafe(idString);
  }

  /+
  Identifier* addIdentifiers(char[][] idStrings)
  {
    auto ids = new Identifier*[idStrings.length];
    foreach (i, idString; idStrings)
    {
      Identifier** id = idString in tabulatedIds;
      if (!id)
      {
        auto newID = Identifier(TOK.Identifier, idString);
        tabulatedIds[idString] = newID;
        id = &newID;
      }
      ids[i] = *id;
    }
  }
  +/

  static uint anonCount;
  Identifier* genAnonymousID(char[] str)
  {
    ++anonCount;
    auto x = anonCount;
    // Convert count to a string and append it to str.
    do
      str = cast(char)('0' + (x % 10)) ~ str;
    while (x /= 10)
    return Identifier(str, TOK.Identifier);
  }

  Identifier* genAnonEnumID()
  {
    return genAnonymousID("__anonenum");
  }
}

unittest
{
  // TODO: write benchmark.
  // Single table

  // Single table. synchronized

  // Two tables.

  // Two tables. synchronized
}