ccgliterals.nim 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2018 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # included from cgen.nim
  10. ## This include file contains the logic to produce constant string
  11. ## and seq literals. The code here is responsible that
  12. ## ``const x = ["a", "b"]`` works without hidden runtime creation code.
  13. ## The price is that seqs and strings are not purely a library
  14. ## implementation.
  15. template detectVersion(field, corename) =
  16. if m.g.field == 0:
  17. let core = getCompilerProc(m.g.graph, corename)
  18. if core == nil or core.kind != skConst:
  19. m.g.field = 1
  20. else:
  21. m.g.field = toInt(ast.getInt(core.astdef))
  22. result = m.g.field
  23. proc detectStrVersion(m: BModule): int =
  24. detectVersion(strVersion, "nimStrVersion")
  25. proc detectSeqVersion(m: BModule): int =
  26. detectVersion(seqVersion, "nimSeqVersion")
  27. # ----- Version 1: GC'ed strings and seqs --------------------------------
  28. proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
  29. cgsym(m, "TGenericSeq")
  30. let tmp = getTempName(m)
  31. result.add tmp
  32. m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n",
  33. [tmp, makeCString(s), rope(s.len)])
  34. proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
  35. if s.isNil:
  36. appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
  37. else:
  38. let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
  39. if id == m.labels:
  40. # string literal not found in the cache:
  41. appcg(m, result, "((#NimStringDesc*) &", [])
  42. genStringLiteralDataOnlyV1(m, n.strVal, result)
  43. result.add ")"
  44. else:
  45. appcg(m, result, "((#NimStringDesc*) &$1$2)",
  46. [m.tmpBase, id])
  47. # ------ Version 2: destructor based strings and seqs -----------------------
  48. proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
  49. m.s[cfsStrData].addf("static $4 struct {$n" &
  50. " NI cap; NIM_CHAR data[$2+1];$n" &
  51. "} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n",
  52. [result, rope(s.len), makeCString(s),
  53. rope(if isConst: "const" else: "")])
  54. proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
  55. let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
  56. if id == m.labels:
  57. let pureLit = getTempName(m)
  58. genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
  59. let tmp = getTempName(m)
  60. result.add tmp
  61. cgsym(m, "NimStrPayload")
  62. cgsym(m, "NimStringV2")
  63. # string literal not found in the cache:
  64. m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
  65. [tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
  66. else:
  67. let tmp = getTempName(m)
  68. result.add tmp
  69. m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
  70. [tmp, rope(n.strVal.len), m.tmpBase & rope(id),
  71. rope(if isConst: "const" else: "")])
  72. proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
  73. let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
  74. var pureLit: Rope
  75. if id == m.labels:
  76. pureLit = getTempName(m)
  77. cgsym(m, "NimStrPayload")
  78. cgsym(m, "NimStringV2")
  79. # string literal not found in the cache:
  80. genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
  81. else:
  82. pureLit = m.tmpBase & rope(id)
  83. result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
  84. # ------ Version selector ---------------------------------------------------
  85. proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
  86. isConst: bool; result: var Rope) =
  87. case detectStrVersion(m)
  88. of 0, 1: genStringLiteralDataOnlyV1(m, s, result)
  89. of 2:
  90. let tmp = getTempName(m)
  91. genStringLiteralDataOnlyV2(m, s, tmp, isConst)
  92. result.add tmp
  93. else:
  94. localError(m.config, info, "cannot determine how to produce code for string literal")
  95. proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
  96. appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
  97. proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
  98. case detectStrVersion(m)
  99. of 0, 1: genStringLiteralV1(m, n, result)
  100. of 2: genStringLiteralV2(m, n, isConst = true, result)
  101. else:
  102. localError(m.config, n.info, "cannot determine how to produce code for string literal")