idents.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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, wordrecg
  14. type
  15. PIdent* = ref TIdent
  16. TIdent*{.acyclic.} = object
  17. id*: int # unique id; use this for comparisons and not the pointers
  18. s*: string
  19. next*: PIdent # for hash-table chaining
  20. h*: Hash # hash value of s
  21. IdentCache* = ref object
  22. buckets: array[0..4096 * 2 - 1, PIdent]
  23. wordCounter: int
  24. idAnon*, idDelegator*, emptyIdent*: PIdent
  25. proc resetIdentCache*() = discard
  26. proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
  27. if a[0] != b[0]: return 1
  28. var i = 0
  29. var j = 0
  30. result = 1
  31. while j < blen:
  32. while a[i] == '_': inc(i)
  33. while b[j] == '_': inc(j)
  34. # tolower inlined:
  35. var aa = a[i]
  36. var bb = b[j]
  37. if aa >= 'A' and aa <= 'Z': aa = chr(ord(aa) + (ord('a') - ord('A')))
  38. if bb >= 'A' and bb <= 'Z': bb = chr(ord(bb) + (ord('a') - ord('A')))
  39. result = ord(aa) - ord(bb)
  40. if (result != 0) or (aa == '\0'): break
  41. inc(i)
  42. inc(j)
  43. if result == 0:
  44. if a[i] != '\0': result = 1
  45. proc cmpExact(a, b: cstring, blen: int): int =
  46. var i = 0
  47. var j = 0
  48. result = 1
  49. while j < blen:
  50. var aa = a[i]
  51. var bb = b[j]
  52. result = ord(aa) - ord(bb)
  53. if (result != 0) or (aa == '\0'): break
  54. inc(i)
  55. inc(j)
  56. if result == 0:
  57. if a[i] != '\0': result = 1
  58. proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
  59. var idx = h and high(ic.buckets)
  60. result = ic.buckets[idx]
  61. var last: PIdent = nil
  62. var id = 0
  63. while result != nil:
  64. if cmpExact(cstring(result.s), identifier, length) == 0:
  65. if last != nil:
  66. # make access to last looked up identifier faster:
  67. last.next = result.next
  68. result.next = ic.buckets[idx]
  69. ic.buckets[idx] = result
  70. return
  71. elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
  72. assert((id == 0) or (id == result.id))
  73. id = result.id
  74. last = result
  75. result = result.next
  76. new(result)
  77. result.h = h
  78. result.s = newString(length)
  79. for i in 0..<length: result.s[i] = identifier[i]
  80. result.next = ic.buckets[idx]
  81. ic.buckets[idx] = result
  82. if id == 0:
  83. inc(ic.wordCounter)
  84. result.id = -ic.wordCounter
  85. else:
  86. result.id = id
  87. proc getIdent*(ic: IdentCache; identifier: string): PIdent =
  88. result = getIdent(ic, cstring(identifier), identifier.len,
  89. hashIgnoreStyle(identifier))
  90. proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent =
  91. result = getIdent(ic, cstring(identifier), identifier.len, h)
  92. proc newIdentCache*(): IdentCache =
  93. result = IdentCache()
  94. result.idAnon = result.getIdent":anonymous"
  95. result.wordCounter = 1
  96. result.idDelegator = result.getIdent":delegator"
  97. result.emptyIdent = result.getIdent("")
  98. # initialize the keywords:
  99. for s in succ(low(TSpecialWord))..high(TSpecialWord):
  100. result.getIdent($s, hashIgnoreStyle($s)).id = ord(s)
  101. proc whichKeyword*(id: PIdent): TSpecialWord =
  102. if id.id < 0: result = wInvalid
  103. else: result = TSpecialWord(id.id)