layeredtable.nim 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import std/tables
  2. import ast
  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. proc currentLen*(pt: LayeredIdTable): int =
  27. ## the sum of the cached total binding count of the parents and
  28. ## the current binding count, just used to track if bindings were added
  29. pt.previousLen + pt.topLayer.len
  30. proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
  31. result = LayeredIdTable(topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen)
  32. when useRef:
  33. result.nextLayer = pt
  34. else:
  35. new(result.nextLayer)
  36. result.nextLayer[] = pt
  37. proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
  38. when useRef:
  39. pt = pt.nextLayer
  40. else:
  41. when defined(gcDestructors):
  42. pt = pt.nextLayer[]
  43. else:
  44. # workaround refc
  45. let tmp = pt.nextLayer[]
  46. pt = tmp
  47. proc lookup(typeMap: ref LayeredIdTableObj, key: ItemId): PType =
  48. result = nil
  49. var tm = typeMap
  50. while tm != nil:
  51. result = getOrDefault(tm.topLayer, key)
  52. if result != nil: return
  53. tm = tm.nextLayer
  54. template lookup*(typeMap: ref LayeredIdTableObj, key: PType): PType =
  55. ## recursively looks up binding of `key` in all parent layers
  56. lookup(typeMap, key.itemId)
  57. when not useRef:
  58. proc lookup(typeMap: LayeredIdTableObj, key: ItemId): PType {.inline.} =
  59. result = getOrDefault(typeMap.topLayer, key)
  60. if result == nil and typeMap.nextLayer != nil:
  61. result = lookup(typeMap.nextLayer, key)
  62. template lookup*(typeMap: LayeredIdTableObj, key: PType): PType =
  63. lookup(typeMap, key.itemId)
  64. proc put(typeMap: var LayeredIdTable, key: ItemId, value: PType) {.inline.} =
  65. typeMap.topLayer[key] = value
  66. template put*(typeMap: var LayeredIdTable, key, value: PType) =
  67. ## binds `key` to `value` only in current layer
  68. put(typeMap, key.itemId, value)