summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-02-03 09:49:36 +0100
committerAndreas Rumpf <rumpf_a@web.de>2017-02-03 09:49:36 +0100
commit848676cec6ba75e9bd0f8f590c6e47f6be7e696e (patch)
tree542fcc65dba46c46666ae9f2089da235958372d1 /compiler
parent04c4d3d77f86086efa2447c0c9b47ba84342d245 (diff)
downloadNim-848676cec6ba75e9bd0f8f590c6e47f6be7e696e.tar.gz
name mangling bugfixes; ndi file generation for debugger support
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/ccgtypes.nim73
-rw-r--r--compiler/ccgutils.nim12
-rw-r--r--compiler/cgen.nim6
-rw-r--r--compiler/cgendata.nim3
-rw-r--r--compiler/ndi.nim40
6 files changed, 71 insertions, 65 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 09b455ec0..45d675f64 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -64,7 +64,7 @@ proc genVarTuple(p: BProc, n: PNode) =
       field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
     else:
       if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
-      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
+      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
     putLocIntoDest(p, v.loc, field)
 
 proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index ba505facb..e30fe5598 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -22,12 +22,10 @@ proc isKeyword(w: PIdent): bool =
      ord(wInline): return true
   else: return false
 
-proc mangleField(name: PIdent): string =
+proc mangleField(m: BModule; name: PIdent): string =
   result = mangle(name.s)
-  if isKeyword(name):
-    result[0] = result[0].toUpperAscii
-    # Mangling makes everything lowercase,
-    # but some identifiers are C keywords
+  if isKeyword(name) or m.g.config.cppDefines.contains(result):
+    result.add "_0"
 
 when false:
   proc hashOwner(s: PSym): SigHash =
@@ -67,54 +65,10 @@ proc idOrSig(m: BModule; s: PSym): Rope =
 proc mangleName(m: BModule; s: PSym): Rope =
   result = s.loc.r
   if result == nil:
-    let keepOrigName = s.kind in skLocalVars - {skForVar} and
-      {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
-      not isKeyword(s.name)
-    # Even with all these inefficient checks, the bootstrap
-    # time is actually improved. This is probably because so many
-    # rope concatenations are now eliminated.
-    #
-    # sfFromGeneric is needed in order to avoid multiple
-    # definitions of certain variables generated in transf with
-    # names such as:
-    # `r`, `res`
-    # I need to study where these come from.
-    #
-    # about sfShadowed:
-    # consider the following Nim code:
-    #   var x = 10
-    #   block:
-    #     var x = something(x)
-    # The generated C code will be:
-    #   NI x;
-    #   x = 10;
-    #   {
-    #     NI x;
-    #     x = something(x); // Oops, x is already shadowed here
-    #   }
-    # Right now, we work-around by not keeping the original name
-    # of the shadowed variable, but we can do better - we can
-    # create an alternative reference to it in the outer scope and
-    # use that in the inner scope.
-    #
-    # about isCKeyword:
-    # Nim variable names can be C keywords.
-    # We need to avoid such names in the generated code.
-    #
-    # about sfGlobal:
-    # This seems to be harder - a top level extern variable from
-    # another modules can have the same name as a local one.
-    # Maybe we should just implement sfShadowed for them too.
-    #
-    # about skForVar:
-    # These are not properly scoped now - we need to add blocks
-    # around for loops in transf
     result = s.name.s.mangle.rope
-    if keepOrigName:
-      result.add "0"
-    else:
-      add(result, m.idOrSig(s))
+    add(result, m.idOrSig(s))
     s.loc.r = result
+    writeMangledName(m.ndi, s)
 
 proc mangleParamName(m: BModule; s: PSym): Rope =
   ## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
@@ -122,10 +76,12 @@ proc mangleParamName(m: BModule; s: PSym): Rope =
   ## cause any trouble.
   result = s.loc.r
   if result == nil:
-    result = s.name.s.mangle.rope
-    if isKeyword(s.name) or m.g.config.cppDefines.contains(s.name.s):
-      result.add "0"
+    var res = s.name.s.mangle
+    if isKeyword(s.name) or m.g.config.cppDefines.contains(res):
+      res.add "_0"
+    result = res.rope
     s.loc.r = result
+    writeMangledName(m.ndi, s)
 
 proc mangleLocalName(p: BProc; s: PSym): Rope =
   assert s.kind in skLocalVars+{skTemp}
@@ -139,10 +95,11 @@ proc mangleLocalName(p: BProc; s: PSym): Rope =
     if s.kind == skTemp:
       # speed up conflict search for temps (these are quite common):
       if counter != 0: result.add "_" & rope(counter+1)
-    elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(s.name.s):
+    elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
       result.add "_" & rope(counter+1)
     p.sigConflicts.inc(key)
     s.loc.r = result
+    if s.kind != skTemp: writeMangledName(p.module.ndi, s)
 
 proc scopeMangledParam(p: BProc; param: PSym) =
   ## parameter generation only takes BModule, not a BProc, so we have to
@@ -472,12 +429,12 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
   else: add(params, ")")
   params = "(" & params
 
-proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
+proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
   if (rectype.sym != nil) and
       ({sfImportc, sfExportc} * rectype.sym.flags != {}):
     result = field.loc.r
   else:
-    result = rope(mangleField(field.name))
+    result = rope(mangleField(m, field.name))
   if result == nil: internalError(field.info, "mangleRecFieldName")
 
 proc genRecordFieldsAux(m: BModule, n: PNode,
@@ -516,7 +473,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     let field = n.sym
     if field.typ.kind == tyVoid: return
     #assert(field.ast == nil)
-    let sname = mangleRecFieldName(field, rectype)
+    let sname = mangleRecFieldName(m, field, rectype)
     let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
              else: sname
     fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 0985759b9..d42f0438f 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -164,9 +164,6 @@ proc makeSingleLineCString*(s: string): string =
   result.add('\"')
 
 proc mangle*(name: string): string =
-  ## Lowercases the given name and manges any non-alphanumeric characters
-  ## so they are represented as `HEX____`. If the name starts with a number,
-  ## `N` is prepended
   result = newStringOfCap(name.len)
   var start = 0
   if name[0] in Digits:
@@ -179,8 +176,15 @@ proc mangle*(name: string): string =
   for i in start..(name.len-1):
     let c = name[i]
     case c
-    of 'a'..'z', '0'..'9', 'A'..'Z', '_':
+    of 'a'..'z', '0'..'9', 'A'..'Z':
       add(result, c)
+    of '_':
+      # we generate names like 'foo_9' for scope disambiguations and so
+      # disallow this here:
+      if i < name.len-1 and name[i] in Digits:
+        discard
+      else:
+        add(result, c)
     of '$': special "dollar"
     of '%': special "percent"
     of '&': special "amp"
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ae735d30b..62ed9ad6e 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -14,7 +14,7 @@ import
   nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
   ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
   condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
-  lowerings, semparallel, tables, sets
+  lowerings, semparallel, tables, sets, ndi
 
 import strutils except `%` # collides with ropes.`%`
 
@@ -1152,6 +1152,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
     incl result.flags, preventStackTrace
     excl(result.preInitProc.options, optStackTrace)
     excl(result.postInitProc.options, optStackTrace)
+  let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
+                else: ""
+  open(result.ndi, ndiName)
 
 proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
@@ -1343,6 +1346,7 @@ proc writeModule(m: BModule, pending: bool) =
     var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
     if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
     addFileToCompile(cf)
+  close(m.ndi)
 
 proc updateCachedModule(m: BModule) =
   let cfile = getCFile(m)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index a91858b86..565399ead 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -11,7 +11,7 @@
 
 import
   ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes,
-  tables
+  tables, ndi
 
 from msgs import TLineInfo
 
@@ -146,6 +146,7 @@ type
     injectStmt*: Rope
     sigConflicts*: CountTable[SigHash]
     g*: BModuleList
+    ndi*: NdiFile
 
 proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
   # section in the current block
diff --git a/compiler/ndi.nim b/compiler/ndi.nim
new file mode 100644
index 000000000..a7ca02193
--- /dev/null
+++ b/compiler/ndi.nim
@@ -0,0 +1,40 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2017 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the generation of ``.ndi`` files for better debugging
+## support of Nim code. "ndi" stands for "Nim debug info".
+
+import ast, msgs, ropes
+
+type
+  NdiFile* = object
+    enabled: bool
+    f: File
+    buf: string
+
+proc doWrite(f: var NdiFile; s: PSym) =
+  f.buf.setLen 0
+  f.buf.add s.info.line.int
+  f.buf.add "\t"
+  f.buf.add s.info.col.int
+  f.f.write(s.name.s, "\t")
+  f.f.writeRope(s.loc.r)
+  f.f.writeLine("\t", s.info.toFullPath, "\t", f.buf)
+
+template writeMangledName*(f: NdiFile; s: PSym) =
+  if f.enabled: doWrite(f, s)
+
+proc open*(f: var NdiFile; filename: string) =
+  f.enabled = filename.len > 0
+  if f.enabled:
+    f.f = open(filename, fmWrite, 8000)
+    f.buf = newStringOfCap(20)
+
+proc close*(f: var NdiFile) =
+  if f.enabled: close(f.f)