123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import std/[tables]
- import ast, astalgo
- type
- LayeredIdTableObj* {.acyclic.} = object
- ## stack of type binding contexts implemented as a linked list
- topLayer*: TypeMapping
- ## the mappings on the current layer
- nextLayer*: ref LayeredIdTableObj
- ## the parent type binding context, possibly `nil`
- previousLen*: int
- ## total length of the bindings up to the parent layer,
- ## used to track if new bindings were added
- const useRef = not defined(gcDestructors)
- # implementation detail, only arc/orc doesn't cause issues when
- # using LayeredIdTable as an object and not a ref
- when useRef:
- type LayeredIdTable* = ref LayeredIdTableObj
- else:
- type LayeredIdTable* = LayeredIdTableObj
- proc initLayeredTypeMap*(pt: sink TypeMapping = initTypeMapping()): LayeredIdTable =
- result = LayeredIdTable(topLayer: pt, nextLayer: nil)
- proc shallowCopy*(pt: LayeredIdTable): LayeredIdTable {.inline.} =
- ## copies only the type bindings of the current layer, but not any parent layers,
- ## useful for write-only bindings
- result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
- #copyIdTable(result.topLayer, pt.topLayer)
- proc currentLen*(pt: LayeredIdTable): int =
- ## the sum of the cached total binding count of the parents and
- ## the current binding count, just used to track if bindings were added
- pt.previousLen + pt.topLayer.counter
- proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
- result = LayeredIdTable(topLayer: initTypeMapping(), previousLen: pt.currentLen)
- when useRef:
- result.nextLayer = pt
- else:
- new(result.nextLayer)
- result.nextLayer[] = pt
- proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
- when useRef:
- pt = pt.nextLayer
- else:
- when defined(gcDestructors):
- pt = pt.nextLayer[]
- else:
- # workaround refc
- let tmp = pt.nextLayer[]
- pt = tmp
- iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
- var tm = pt
- while true:
- for (k, v) in idTablePairs(tm.topLayer):
- yield (k, v)
- if tm.nextLayer == nil:
- break
- tm.setToPreviousLayer
- proc lookup(typeMap: ref LayeredIdTableObj, key: ItemId): PType =
- result = nil
- var tm = typeMap
- while tm != nil:
- result = getOrDefault(tm.topLayer, key)
- if result != nil: return
- tm = tm.nextLayer
- template lookup*(typeMap: ref LayeredIdTableObj, key: PType): PType =
- ## recursively looks up binding of `key` in all parent layers
- lookup(typeMap, key.itemId)
- when not useRef:
- proc lookup(typeMap: LayeredIdTableObj, key: ItemId): PType {.inline.} =
- result = getOrDefault(typeMap.topLayer, key)
- if result == nil and typeMap.nextLayer != nil:
- result = lookup(typeMap.nextLayer, key)
- template lookup*(typeMap: LayeredIdTableObj, key: PType): PType =
- lookup(typeMap, key.itemId)
- proc put(typeMap: var LayeredIdTable, key: ItemId, value: PType) {.inline.} =
- typeMap.topLayer[key] = value
- template put*(typeMap: var LayeredIdTable, key, value: PType) =
- ## binds `key` to `value` only in current layer
- put(typeMap, key.itemId, value)
|