about summary refs log tree commit diff stats
path: root/TODO
blob: b33a08d9580a9f674f6adcfadc65a2ecfb19ef4f (plain) (blame)
1
2
3
4
- add a flag to Key to execute the command on release (needed for commands
		affecting the keyboard grab, see scrot -s for example)
- add updategeom() hook for external tools like dzen
- consider onscreenkeyboard hooks for tablet deployment
135'>135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167











                                                                                
                                      

























































































































































                                                                                                        
import ast, modulegraphs, magicsys, lineinfos, options, cgmeth, types
import std/[algorithm, tables, intsets, assertions]



proc genVTableDispatcher(g: ModuleGraph; methods: seq[PSym]; index: int): PSym =
#[
proc dispatch(x: Base, params: ...) =
  cast[proc bar(x: Base, params: ...)](x.vTable[index])(x, params)
]#
  var base = methods[0].ast[dispatcherPos].sym
  result = base
  var paramLen = base.typ.signatureLen
  var body = newNodeI(nkStmtList, base.info)

  var disp = newNodeI(nkIfStmt, base.info)

  var vTableAccess = newNodeIT(nkBracketExpr, base.info, base.typ)
  let nimGetVTableSym = getCompilerProc(g, "nimGetVTable")
  let ptrPNimType = nimGetVTableSym.typ.n[1].sym.typ

  var nTyp = base.typ.n[1].sym.typ
  var dispatchObject = newSymNode(base.typ.n[1].sym)
  if nTyp.kind == tyObject:
    dispatchObject = newTree(nkAddr, dispatchObject)
  else:
    if g.config.backend != backendCpp: # TODO: maybe handle ptr?
      if nTyp.kind == tyVar and nTyp.skipTypes({tyVar}).kind != tyObject:
        dispatchObject = newTree(nkDerefExpr, dispatchObject)

  var getVTableCall = newTree(nkCall,
    newSymNode(nimGetVTableSym),
    dispatchObject,
    newIntNode(nkIntLit, index)
  )
  getVTableCall.typ = base.typ
  var vTableCall = newNodeIT(nkCall, base.info, base.typ.returnType)
  var castNode = newTree(nkCast,
        newNodeIT(nkType, base.info, base.typ),
        getVTableCall)

  castNode.typ = base.typ
  vTableCall.add castNode
  for col in 1..<paramLen:
    let param = base.typ.n[col].sym
    vTableCall.add newSymNode(param)

  var ret: PNode
  if base.typ.returnType != nil:
    var a = newNodeI(nkFastAsgn, base.info)
    a.add newSymNode(base.ast[resultPos].sym)
    a.add vTableCall
    ret = newNodeI(nkReturnStmt, base.info)
    ret.add a
  else:
    ret = vTableCall

  if base.typ.n[1].sym.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
    let ifBranch = newNodeI(nkElifBranch, base.info)
    let boolType = getSysType(g, unknownLineInfo, tyBool)
    var isNil = getSysMagic(g, unknownLineInfo, "isNil", mIsNil)
    let checkSelf = newNodeIT(nkCall, base.info, boolType)
    checkSelf.add newSymNode(isNil)
    checkSelf.add newSymNode(base.typ.n[1].sym)
    ifBranch.add checkSelf
    ifBranch.add newTree(nkCall,
        newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(base.typ.n[1].sym))
    let elseBranch = newTree(nkElifBranch, ret)
    disp.add ifBranch
    disp.add elseBranch
  else:
    disp = ret

  body.add disp
  body.flags.incl nfTransf # should not be further transformed
  result.ast[bodyPos] = body

proc containGenerics(base: PType, s: seq[tuple[depth: int, value: PType]]): bool =
  result = tfHasMeta in base.flags
  for i in s:
    if tfHasMeta in i.value.flags:
      result = true
      break

proc collectVTableDispatchers*(g: ModuleGraph) =
  var itemTable = initTable[ItemId, seq[LazySym]]()
  var rootTypeSeq = newSeq[PType]()
  var rootItemIdCount = initCountTable[ItemId]()
  for bucket in 0..<g.methods.len:
    var relevantCols = initIntSet()
    if relevantCol(g.methods[bucket].methods, 1): incl(relevantCols, 1)
    sortBucket(g.methods[bucket].methods, relevantCols)
    let base = g.methods[bucket].methods[^1]
    let baseType = base.typ.firstParamType.skipTypes(skipPtrs-{tyTypeDesc})
    if baseType.itemId in g.objectTree and not containGenerics(baseType, g.objectTree[baseType.itemId]):
      let methodIndexLen = g.bucketTable[baseType.itemId]
      if baseType.itemId notin itemTable: # once is enough
        rootTypeSeq.add baseType
        itemTable[baseType.itemId] = newSeq[LazySym](methodIndexLen)

        sort(g.objectTree[baseType.itemId], cmp = proc (x, y: tuple[depth: int, value: PType]): int =
          if x.depth >= y.depth: 1
          else: -1
          )

        for item in g.objectTree[baseType.itemId]:
          if item.value.itemId notin itemTable:
            itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen)

      var mIndex = 0 # here is the correpsonding index
      if baseType.itemId notin rootItemIdCount:
        rootItemIdCount[baseType.itemId] = 1
      else:
        mIndex = rootItemIdCount[baseType.itemId]
        rootItemIdCount.inc(baseType.itemId)
      for idx in 0..<g.methods[bucket].methods.len:
        let obj = g.methods[bucket].methods[idx].typ.firstParamType.skipTypes(skipPtrs)
        itemTable[obj.itemId][mIndex] = LazySym(sym: g.methods[bucket].methods[idx])
      g.addDispatchers genVTableDispatcher(g, g.methods[bucket].methods, mIndex)
    else: # if the base object doesn't have this method
      g.addDispatchers genIfDispatcher(g, g.methods[bucket].methods, relevantCols, g.idgen)

proc sortVTableDispatchers*(g: ModuleGraph) =
  var itemTable = initTable[ItemId, seq[LazySym]]()
  var rootTypeSeq = newSeq[ItemId]()
  var rootItemIdCount = initCountTable[ItemId]()
  for bucket in 0..<g.methods.len:
    var relevantCols = initIntSet()
    if relevantCol(g.methods[bucket].methods, 1): incl(relevantCols, 1)
    sortBucket(g.methods[bucket].methods, relevantCols)
    let base = g.methods[bucket].methods[^1]
    let baseType = base.typ.firstParamType.skipTypes(skipPtrs-{tyTypeDesc})
    if baseType.itemId in g.objectTree and not containGenerics(baseType, g.objectTree[baseType.itemId]):
      let methodIndexLen = g.bucketTable[baseType.itemId]
      if baseType.itemId notin itemTable: # once is enough
        rootTypeSeq.add baseType.itemId
        itemTable[baseType.itemId] = newSeq[LazySym](methodIndexLen)

        sort(g.objectTree[baseType.itemId], cmp = proc (x, y: tuple[depth: int, value: PType]): int =
          if x.depth >= y.depth: 1
          else: -1
          )

        for item in g.objectTree[baseType.itemId]:
          if item.value.itemId notin itemTable:
            itemTable[item.value.itemId] = newSeq[LazySym](methodIndexLen)

      var mIndex = 0 # here is the correpsonding index
      if baseType.itemId notin rootItemIdCount:
        rootItemIdCount[baseType.itemId] = 1
      else:
        mIndex = rootItemIdCount[baseType.itemId]
        rootItemIdCount.inc(baseType.itemId)
      for idx in 0..<g.methods[bucket].methods.len:
        let obj = g.methods[bucket].methods[idx].typ.firstParamType.skipTypes(skipPtrs)
        itemTable[obj.itemId][mIndex] = LazySym(sym: g.methods[bucket].methods[idx])

  for baseType in rootTypeSeq:
    g.setMethodsPerType(baseType, itemTable[baseType])
    for item in g.objectTree[baseType]:
      let typ = item.value.skipTypes(skipPtrs)
      let idx = typ.itemId
      for mIndex in 0..<itemTable[idx].len:
        if itemTable[idx][mIndex].sym == nil:
          let parentIndex = typ.baseClass.skipTypes(skipPtrs).itemId
          itemTable[idx][mIndex] = itemTable[parentIndex][mIndex]
      g.setMethodsPerType(idx, itemTable[idx])