summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-08-23 10:13:37 +0200
committerAndreas Rumpf <rumpf_a@web.de>2016-08-23 10:13:37 +0200
commitf439a2f25f8e2aac2278322aa7ee351390d8161c (patch)
tree7da33cefe5da1e895ea9483087baed34a812da02
parent55e86184a5289ee61b6105ed4ddb2cc1ca4f76dc (diff)
downloadNim-f439a2f25f8e2aac2278322aa7ee351390d8161c.tar.gz
fixes #4579
-rw-r--r--compiler/pragmas.nim55
-rw-r--r--doc/manual/ffi.txt26
2 files changed, 48 insertions, 33 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 1f93f5317..db5f8e727 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -90,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
       else:
         invalidPragma(it)
 
-proc setExternName(s: PSym, extname: string) =
-  s.loc.r = rope(extname % s.name.s)
+proc setExternName(s: PSym, extname: string, info: TLineInfo) =
+  # special cases to improve performance:
+  if extname == "$1":
+    s.loc.r = rope(s.name.s)
+  elif '$' notin extname:
+    s.loc.r = rope(extname)
+  else:
+    try:
+      s.loc.r = rope(extname % s.name.s)
+    except ValueError:
+      localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
   if gCmd == cmdPretty and '$' notin extname:
     # note that '{.importc.}' is transformed into '{.importc: "$1".}'
     s.loc.flags.incl(lfFullExternalName)
 
-proc makeExternImport(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
 
-proc validateExternCName(s: PSym, info: TLineInfo) =
-  ## Validates that the symbol name in s.loc.r is a valid C identifier.
-  ##
-  ## Valid identifiers are those alphanumeric including the underscore not
-  ## starting with a number. If the check fails, a generic error will be
-  ## displayed to the user.
-  let target = $s.loc.r
-  if target.len < 1 or target[0] notin IdentStartChars or
-      not target.allCharsInSet(IdentChars):
-    localError(info, errGenerated, "invalid exported symbol")
-
 proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname)
-  # XXX to fix make it work with nimrtl.
-  #if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
-  #  validateExternCName(s, info)
+  setExternName(s, extname, info)
   incl(s.flags, sfExportc)
 
-proc processImportCompilerProc(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
   incl(s.loc.flags, lfImportCompilerProc)
 
-proc processImportCpp(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   incl(s.flags, sfInfixCall)
   excl(s.flags, sfForward)
@@ -134,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) =
   incl(m.flags, sfCompileToCpp)
   extccomp.gMixedMode = true
 
-proc processImportObjC(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   incl(s.flags, sfNamedParamCall)
   excl(s.flags, sfForward)
@@ -623,10 +618,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
       of wExportc:
         makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
         incl(sym.flags, sfUsed) # avoid wrong hints
-      of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
+      of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
       of wImportCompilerProc:
-        processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
-      of wExtern: setExternName(sym, expectStrLit(c, it))
+        processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
+      of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
       of wImmediate:
         if sym.kind in {skTemplate, skMacro}:
           incl(sym.flags, sfImmediate)
@@ -637,9 +632,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         if sym.kind == skTemplate: incl(sym.flags, sfDirty)
         else: invalidPragma(it)
       of wImportCpp:
-        processImportCpp(sym, getOptionalStr(c, it, "$1"))
+        processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
       of wImportObjC:
-        processImportObjC(sym, getOptionalStr(c, it, "$1"))
+        processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
       of wAlign:
         if sym.typ == nil: invalidPragma(it)
         var align = expectIntLit(c, it)
diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt
index 5055f18af..d7d9596d2 100644
--- a/doc/manual/ffi.txt
+++ b/doc/manual/ffi.txt
@@ -16,12 +16,20 @@ spelled*:
 .. code-block::
   proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
 
-Note that this pragma is somewhat of a misnomer: Other backends will provide
+Note that this pragma is somewhat of a misnomer: Other backends do provide
 the same feature under the same name. Also, if one is interfacing with C++
 the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
 interfacing with Objective-C the `ImportObjC pragma
 <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used.
 
+The string literal passed to ``importc`` can be a format string:
+
+.. code-block:: Nim
+  proc p(s: cstring) {.importc: "prefix$1".}
+
+In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
+is available and a literal dollar sign must be written as ``$$``.
+
 
 Exportc pragma
 --------------
@@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*:
 .. code-block:: Nim
   proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
 
-Note that this pragma is somewhat of a misnomer: Other backends will provide
+Note that this pragma is somewhat of a misnomer: Other backends do provide
 the same feature under the same name.
 
+The string literal passed to ``exportc`` can be a format string:
+
+.. code-block:: Nim
+  proc p(s: string) {.exportc: "prefix$1".} =
+    echo s
+
+In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
+is available and a literal dollar sign must be written as ``$$``.
+
+
 
 Extern pragma
 -------------
@@ -46,7 +64,9 @@ mangling. The string literal passed to ``extern`` can be a format string:
   proc p(s: string) {.extern: "prefix$1".} =
     echo s
 
-In the example the external name of ``p`` is set to ``prefixp``.
+In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
+is available and a literal dollar sign must be written as ``$$``.
+
 
 
 Bycopy pragma