liftlocals.nim 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. strutils, options, ast, msgs,
  12. idents, renderer, types, lowerings, lineinfos
  13. from pragmas import getPragmaVal
  14. from wordrecg import wLiftLocals
  15. type
  16. Ctx = object
  17. partialParam: PSym
  18. objType: PType
  19. cache: IdentCache
  20. proc interestingVar(s: PSym): bool {.inline.} =
  21. result = s.kind in {skVar, skLet, skTemp, skForVar, skResult} and
  22. sfGlobal notin s.flags
  23. proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
  24. let field = addUniqueField(c.objType, s, c.cache)
  25. var deref = newNodeI(nkHiddenDeref, info)
  26. deref.typ = c.objType
  27. deref.add(newSymNode(c.partialParam, info))
  28. result = newNodeI(nkDotExpr, info)
  29. result.add(deref)
  30. result.add(newSymNode(field))
  31. result.typ = field.typ
  32. proc liftLocals(n: PNode; i: int; c: var Ctx) =
  33. let it = n[i]
  34. case it.kind
  35. of nkSym:
  36. if interestingVar(it.sym):
  37. n[i] = lookupOrAdd(c, it.sym, it.info)
  38. of procDefs, nkTypeSection: discard
  39. else:
  40. for i in 0..<it.safeLen:
  41. liftLocals(it, i, c)
  42. proc lookupParam(params, dest: PNode): PSym =
  43. if dest.kind != nkIdent: return nil
  44. for i in 1..<params.len:
  45. if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
  46. return params[i].sym
  47. proc liftLocalsIfRequested*(prc: PSym; n: PNode; cache: IdentCache; conf: ConfigRef): PNode =
  48. let liftDest = getPragmaVal(prc.ast, wLiftLocals)
  49. if liftDest == nil: return n
  50. let partialParam = lookupParam(prc.typ.n, liftDest)
  51. if partialParam.isNil:
  52. localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" %
  53. [$liftDest, prc.name.s])
  54. return n
  55. let objType = partialParam.typ.skipTypes(abstractPtrs)
  56. if objType.kind != tyObject or tfPartial notin objType.flags:
  57. localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
  58. return n
  59. var c = Ctx(partialParam: partialParam, objType: objType, cache: cache)
  60. let w = newTree(nkStmtList, n)
  61. liftLocals(w, 0, c)
  62. result = w[0]