liftlocals.nim 2.3 KB

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