ccgliterals.nim 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. var res = newBuilder("")
  33. res.addVarWithTypeAndInitializer(AlwaysConst, name = tmp):
  34. res.addSimpleStruct(m, name = "", baseType = ""):
  35. res.addField(name = "Sup", typ = "TGenericSeq")
  36. res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
  37. do:
  38. var strInit: StructInitializer
  39. res.addStructInitializer(strInit, kind = siOrderedStruct):
  40. res.addField(strInit, name = "Sup"):
  41. var seqInit: StructInitializer
  42. res.addStructInitializer(seqInit, kind = siOrderedStruct):
  43. res.addField(seqInit, name = "len"):
  44. res.addIntValue(s.len)
  45. res.addField(seqInit, name = "reserved"):
  46. res.add(cCast(NimInt, cOp(BitOr, NimUint, cCast(NimUint, cIntValue(s.len)), NimStrlitFlag)))
  47. res.addField(strInit, name = "data"):
  48. res.add(makeCString(s))
  49. m.s[cfsStrData].add(extract(res))
  50. proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
  51. if s.isNil:
  52. result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
  53. else:
  54. let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
  55. var name: string = ""
  56. if id == m.labels:
  57. # string literal not found in the cache:
  58. genStringLiteralDataOnlyV1(m, n.strVal, name)
  59. else:
  60. name = m.tmpBase & $id
  61. result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), cAddr(name)))
  62. # ------ Version 2: destructor based strings and seqs -----------------------
  63. proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
  64. var res = newBuilder("")
  65. res.addVarWithTypeAndInitializer(
  66. if isConst: AlwaysConst else: Global,
  67. name = result):
  68. res.addSimpleStruct(m, name = "", baseType = ""):
  69. res.addField(name = "cap", typ = NimInt)
  70. res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
  71. do:
  72. var structInit: StructInitializer
  73. res.addStructInitializer(structInit, kind = siOrderedStruct):
  74. res.addField(structInit, name = "cap"):
  75. res.add(cOp(BitOr, NimInt, cIntValue(s.len), NimStrlitFlag))
  76. res.addField(structInit, name = "data"):
  77. res.add(makeCString(s))
  78. m.s[cfsStrData].add(extract(res))
  79. proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
  80. let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
  81. var litName: string
  82. if id == m.labels:
  83. cgsym(m, "NimStrPayload")
  84. cgsym(m, "NimStringV2")
  85. # string literal not found in the cache:
  86. litName = getTempName(m)
  87. genStringLiteralDataOnlyV2(m, n.strVal, litName, isConst)
  88. else:
  89. litName = m.tmpBase & $id
  90. let tmp = getTempName(m)
  91. result.add tmp
  92. var res = newBuilder("")
  93. res.addVarWithInitializer(
  94. if isConst: AlwaysConst else: Global,
  95. name = tmp,
  96. typ = "NimStringV2"):
  97. var strInit: StructInitializer
  98. res.addStructInitializer(strInit, kind = siOrderedStruct):
  99. res.addField(strInit, name = "len"):
  100. res.addIntValue(n.strVal.len)
  101. res.addField(strInit, name = "p"):
  102. res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
  103. m.s[cfsStrData].add(extract(res))
  104. proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
  105. let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
  106. var pureLit: Rope
  107. if id == m.labels:
  108. pureLit = getTempName(m)
  109. cgsym(m, "NimStrPayload")
  110. cgsym(m, "NimStringV2")
  111. # string literal not found in the cache:
  112. genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
  113. else:
  114. pureLit = m.tmpBase & rope(id)
  115. var strInit: StructInitializer
  116. result.addStructInitializer(strInit, kind = siOrderedStruct):
  117. result.addField(strInit, name = "len"):
  118. result.addIntValue(n.strVal.len)
  119. result.addField(strInit, name = "p"):
  120. result.add(cCast(ptrType("NimStrPayload"), cAddr(pureLit)))
  121. # ------ Version selector ---------------------------------------------------
  122. proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
  123. isConst: bool; result: var Rope) =
  124. case detectStrVersion(m)
  125. of 0, 1: genStringLiteralDataOnlyV1(m, s, result)
  126. of 2:
  127. let tmp = getTempName(m)
  128. genStringLiteralDataOnlyV2(m, s, tmp, isConst)
  129. result.add tmp
  130. else:
  131. localError(m.config, info, "cannot determine how to produce code for string literal")
  132. proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
  133. result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
  134. proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
  135. case detectStrVersion(m)
  136. of 0, 1: genStringLiteralV1(m, n, result)
  137. of 2: genStringLiteralV2(m, n, isConst = true, result)
  138. else:
  139. localError(m.config, n.info, "cannot determine how to produce code for string literal")