summary refs log tree commit diff stats
path: root/compiler/ccgliterals.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ccgliterals.nim')
-rw-r--r--compiler/ccgliterals.nim118
1 files changed, 118 insertions, 0 deletions
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
new file mode 100644
index 000000000..cbef6771f
--- /dev/null
+++ b/compiler/ccgliterals.nim
@@ -0,0 +1,118 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# included from cgen.nim
+
+## This include file contains the logic to produce constant string
+## and seq literals. The code here is responsible that
+## ``const x = ["a", "b"]`` works without hidden runtime creation code.
+## The price is that seqs and strings are not purely a library
+## implementation.
+
+template detectVersion(field, corename) =
+  if m.g.field == 0:
+    let core = getCompilerProc(m.g.graph, corename)
+    if core == nil or core.kind != skConst:
+      m.g.field = 1
+    else:
+      m.g.field = toInt(ast.getInt(core.astdef))
+  result = m.g.field
+
+proc detectStrVersion(m: BModule): int =
+  detectVersion(strVersion, "nimStrVersion")
+
+proc detectSeqVersion(m: BModule): int =
+  detectVersion(seqVersion, "nimSeqVersion")
+
+# ----- Version 1: GC'ed strings and seqs --------------------------------
+
+proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
+  cgsym(m, "TGenericSeq")
+  let tmp = getTempName(m)
+  result.add tmp
+  m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n",
+       [tmp, makeCString(s), rope(s.len)])
+
+proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
+  if s.isNil:
+    appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
+  else:
+    let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
+    if id == m.labels:
+      # string literal not found in the cache:
+      appcg(m, result, "((#NimStringDesc*) &", [])
+      genStringLiteralDataOnlyV1(m, n.strVal, result)
+      result.add ")"
+    else:
+      appcg(m, result, "((#NimStringDesc*) &$1$2)",
+                      [m.tmpBase, id])
+
+# ------ Version 2: destructor based strings and seqs -----------------------
+
+proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
+  m.s[cfsStrData].addf("static $4 struct {$n" &
+       "  NI cap; NIM_CHAR data[$2+1];$n" &
+       "} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n",
+       [result, rope(s.len), makeCString(s),
+       rope(if isConst: "const" else: "")])
+
+proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
+  let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
+  if id == m.labels:
+    let pureLit = getTempName(m)
+    genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
+    let tmp = getTempName(m)
+    result.add tmp
+    cgsym(m, "NimStrPayload")
+    cgsym(m, "NimStringV2")
+    # string literal not found in the cache:
+    m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
+          [tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
+  else:
+    let tmp = getTempName(m)
+    result.add tmp
+    m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
+          [tmp, rope(n.strVal.len), m.tmpBase & rope(id),
+          rope(if isConst: "const" else: "")])
+
+proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
+  let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
+  var pureLit: Rope
+  if id == m.labels:
+    pureLit = getTempName(m)
+    cgsym(m, "NimStrPayload")
+    cgsym(m, "NimStringV2")
+    # string literal not found in the cache:
+    genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
+  else:
+    pureLit = m.tmpBase & rope(id)
+  result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
+
+# ------ Version selector ---------------------------------------------------
+
+proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
+                              isConst: bool; result: var Rope) =
+  case detectStrVersion(m)
+  of 0, 1: genStringLiteralDataOnlyV1(m, s, result)
+  of 2:
+    let tmp = getTempName(m)
+    genStringLiteralDataOnlyV2(m, s, tmp, isConst)
+    result.add tmp
+  else:
+    localError(m.config, info, "cannot determine how to produce code for string literal")
+
+proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
+  appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
+
+proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
+  case detectStrVersion(m)
+  of 0, 1: genStringLiteralV1(m, n, result)
+  of 2: genStringLiteralV2(m, n, isConst = true, result)
+  else:
+    localError(m.config, n.info, "cannot determine how to produce code for string literal")