idents.nim 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Identifier handling
  10. # An identifier is a shared immutable string that can be compared by its
  11. # id. This module is essential for the compiler's performance.
  12. import
  13. hashes, strutils, wordrecg
  14. type
  15. TIdObj* = object of RootObj
  16. id*: int # unique id; use this for comparisons and not the pointers
  17. PIdObj* = ref TIdObj
  18. PIdent* = ref TIdent
  19. TIdent*{.acyclic.} = object of TIdObj
  20. s*: string
  21. next*: PIdent # for hash-table chaining
  22. h*: Hash # hash value of s
  23. IdentCache* = ref object
  24. buckets: array[0..4096 * 2 - 1, PIdent]
  25. wordCounter: int
  26. idAnon*, idDelegator*, emptyIdent*: PIdent
  27. proc resetIdentCache*() = discard
  28. proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
  29. if a[0] != b[0]: return 1
  30. var i = 0
  31. var j = 0
  32. result = 1
  33. while j < blen:
  34. while a[i] == '_': inc(i)
  35. while b[j] == '_': inc(j)
  36. # tolower inlined:
  37. var aa = a[i]
  38. var bb = b[j]
  39. if aa >= 'A' and aa <= 'Z': aa = chr(ord(aa) + (ord('a') - ord('A')))
  40. if bb >= 'A' and bb <= 'Z': bb = chr(ord(bb) + (ord('a') - ord('A')))
  41. result = ord(aa) - ord(bb)
  42. if (result != 0) or (aa == '\0'): break
  43. inc(i)
  44. inc(j)
  45. if result == 0:
  46. if a[i] != '\0': result = 1
  47. proc cmpExact(a, b: cstring, blen: int): int =
  48. var i = 0
  49. var j = 0
  50. result = 1
  51. while j < blen:
  52. var aa = a[i]
  53. var bb = b[j]
  54. result = ord(aa) - ord(bb)
  55. if (result != 0) or (aa == '\0'): break
  56. inc(i)
  57. inc(j)
  58. if result == 0:
  59. if a[i] != '\0': result = 1
  60. proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
  61. var idx = h and high(ic.buckets)
  62. result = ic.buckets[idx]
  63. var last: PIdent = nil
  64. var id = 0
  65. while result != nil:
  66. if cmpExact(cstring(result.s), identifier, length) == 0:
  67. if last != nil:
  68. # make access to last looked up identifier faster:
  69. last.next = result.next
  70. result.next = ic.buckets[idx]
  71. ic.buckets[idx] = result
  72. return
  73. elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
  74. assert((id == 0) or (id == result.id))
  75. id = result.id
  76. last = result
  77. result = result.next
  78. new(result)
  79. result.h = h
  80. result.s = newString(length)
  81. for i in 0 ..< length: result.s[i] = identifier[i]
  82. result.next = ic.buckets[idx]
  83. ic.buckets[idx] = result
  84. if id == 0:
  85. inc(ic.wordCounter)
  86. result.id = -ic.wordCounter
  87. else:
  88. result.id = id
  89. proc getIdent*(ic: IdentCache; identifier: string): PIdent =
  90. result = getIdent(ic, cstring(identifier), len(identifier),
  91. hashIgnoreStyle(identifier))
  92. proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent =
  93. result = getIdent(ic, cstring(identifier), len(identifier), h)
  94. proc newIdentCache*(): IdentCache =
  95. result = IdentCache()
  96. result.idAnon = result.getIdent":anonymous"
  97. result.wordCounter = 1
  98. result.idDelegator = result.getIdent":delegator"
  99. result.emptyIdent = result.getIdent("")
  100. # initialize the keywords:
  101. for s in succ(low(specialWords)) .. high(specialWords):
  102. result.getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
  103. proc whichKeyword*(id: PIdent): TSpecialWord =
  104. if id.id < 0: result = wInvalid
  105. else: result = TSpecialWord(id.id)