ccgliterals.nim 3.9 KB

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