layeredtable.nim 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import std/[tables]
  2. import ast, astalgo
  3. type
  4. LayeredIdTableObj* {.acyclic.} = object
  5. ## stack of type binding contexts implemented as a linked list
  6. topLayer*: TypeMapping
  7. ## the mappings on the current layer
  8. nextLayer*: ref LayeredIdTableObj
  9. ## the parent type binding context, possibly `nil`
  10. previousLen*: int
  11. ## total length of the bindings up to the parent layer,
  12. ## used to track if new bindings were added
  13. const useRef = not defined(gcDestructors)
  14. # implementation detail, only arc/orc doesn't cause issues when
  15. # using LayeredIdTable as an object and not a ref
  16. when useRef:
  17. type LayeredIdTable* = ref LayeredIdTableObj
  18. else:
  19. type LayeredIdTable* = LayeredIdTableObj
  20. proc initLayeredTypeMap*(pt: sink TypeMapping = initTypeMapping()): LayeredIdTable =
  21. result = LayeredIdTable(topLayer: pt, nextLayer: nil)
  22. proc shallowCopy*(pt: LayeredIdTable): LayeredIdTable {.inline.} =
  23. ## copies only the type bindings of the current layer, but not any parent layers,
  24. ## useful for write-only bindings
  25. result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
  26. #copyIdTable(result.topLayer, pt.topLayer)
  27. proc currentLen*(pt: LayeredIdTable): int =
  28. ## the sum of the cached total binding count of the parents and
  29. ## the current binding count, just used to track if bindings were added
  30. pt.previousLen + pt.topLayer.counter
  31. proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
  32. result = LayeredIdTable(topLayer: initTypeMapping(), previousLen: pt.currentLen)
  33. when useRef:
  34. result.nextLayer = pt
  35. else:
  36. new(result.nextLayer)
  37. result.nextLayer[] = pt
  38. proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
  39. when useRef:
  40. pt = pt.nextLayer
  41. else:
  42. when defined(gcDestructors):
  43. pt = pt.nextLayer[]
  44. else:
  45. # workaround refc
  46. let tmp = pt.nextLayer[]
  47. pt = tmp
  48. iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
  49. var tm = pt
  50. while true:
  51. for (k, v) in idTablePairs(tm.topLayer):
  52. yield (k, v)
  53. if tm.nextLayer == nil:
  54. break
  55. tm.setToPreviousLayer
  56. proc lookup(typeMap: ref LayeredIdTableObj, key: ItemId): PType =
  57. result = nil
  58. var tm = typeMap
  59. while tm != nil:
  60. result = getOrDefault(tm.topLayer, key)
  61. if result != nil: return
  62. tm = tm.nextLayer
  63. template lookup*(typeMap: ref LayeredIdTableObj, key: PType): PType =
  64. ## recursively looks up binding of `key` in all parent layers
  65. lookup(typeMap, key.itemId)
  66. when not useRef:
  67. proc lookup(typeMap: LayeredIdTableObj, key: ItemId): PType {.inline.} =
  68. result = getOrDefault(typeMap.topLayer, key)
  69. if result == nil and typeMap.nextLayer != nil:
  70. result = lookup(typeMap.nextLayer, key)
  71. template lookup*(typeMap: LayeredIdTableObj, key: PType): PType =
  72. lookup(typeMap, key.itemId)
  73. proc put(typeMap: var LayeredIdTable, key: ItemId, value: PType) {.inline.} =
  74. typeMap.topLayer[key] = value
  75. template put*(typeMap: var LayeredIdTable, key, value: PType) =
  76. ## binds `key` to `value` only in current layer
  77. put(typeMap, key.itemId, value)