liftlocals.nim 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements the '.liftLocals' pragma.
  10. import
  11. options, ast, msgs,
  12. idents, renderer, types, lowerings, lineinfos
  13. import std/strutils
  14. from pragmas import getPragmaVal
  15. from wordrecg import wLiftLocals
  16. type
  17. Ctx = object
  18. partialParam: PSym
  19. objType: PType
  20. cache: IdentCache
  21. idgen: IdGenerator
  22. proc interestingVar(s: PSym): bool {.inline.} =
  23. result = s.kind in {skVar, skLet, skTemp, skForVar, skResult} and
  24. sfGlobal notin s.flags
  25. proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
  26. let field = addUniqueField(c.objType, s, c.cache, c.idgen)
  27. var deref = newNodeI(nkHiddenDeref, info)
  28. deref.typ() = c.objType
  29. deref.add(newSymNode(c.partialParam, info))
  30. result = newNodeI(nkDotExpr, info)
  31. result.add(deref)
  32. result.add(newSymNode(field))
  33. result.typ() = field.typ
  34. proc liftLocals(n: PNode; i: int; c: var Ctx) =
  35. let it = n[i]
  36. case it.kind
  37. of nkSym:
  38. if interestingVar(it.sym):
  39. n[i] = lookupOrAdd(c, it.sym, it.info)
  40. of procDefs, nkTypeSection, nkMixinStmt, nkBindStmt: discard
  41. else:
  42. for i in 0..<it.safeLen:
  43. liftLocals(it, i, c)
  44. proc lookupParam(params, dest: PNode): PSym =
  45. result = nil
  46. if dest.kind != nkIdent: return nil
  47. for i in 1..<params.len:
  48. if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
  49. return params[i].sym
  50. proc liftLocalsIfRequested*(prc: PSym; n: PNode; cache: IdentCache; conf: ConfigRef;
  51. idgen: IdGenerator): PNode =
  52. let liftDest = getPragmaVal(prc.ast, wLiftLocals)
  53. if liftDest == nil: return n
  54. let partialParam = lookupParam(prc.typ.n, liftDest)
  55. if partialParam.isNil:
  56. localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" %
  57. [$liftDest, prc.name.s])
  58. return n
  59. let objType = partialParam.typ.skipTypes(abstractPtrs)
  60. if objType.kind != tyObject or tfPartial notin objType.flags:
  61. localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
  62. return n
  63. var c = Ctx(partialParam: partialParam, objType: objType, cache: cache, idgen: idgen)
  64. let w = newTree(nkStmtList, n)
  65. liftLocals(w, 0, c)
  66. result = w[0]