diff --git a/compiler/cbuilderbase.nim b/compiler/cbuilderbase.nim
index 3cb42bbd95c39..046f9b8ed2bea 100644
--- a/compiler/cbuilderbase.nim
+++ b/compiler/cbuilderbase.nim
@@ -282,3 +282,48 @@ type
WaitingIf, WaitingElseIf, InBlock
IfBuilder* = object
state*: IfBuilderState
+
+when buildNifc:
+ import std/assertions
+
+ proc cSymbol*(s: string): Snippet =
+ result = newStringOfCap(s.len)
+ for c in s:
+ case c
+ of 'A'..'Z', 'a'..'z', '0'..'9', '_':
+ result.add(c)
+ else:
+ const HexChars = "0123456789ABCDEF"
+ result.add('\\')
+ result.add(HexChars[(c.byte shr 4) and 0xF])
+ result.add(HexChars[c.byte and 0xF])
+ result.add(".c")
+
+ proc getHexChar(c: char): byte =
+ case c
+ of '0'..'9': c.byte - '0'.byte
+ of 'A'..'Z': c.byte - 'A'.byte + 10
+ of 'a'..'z': c.byte - 'a'.byte + 10
+ else: raiseAssert "invalid hex char " & c
+
+ proc unescapeCSymbol*(s: string): Snippet =
+ assert s.len >= 2 and s[^2 .. ^1] == ".c"
+ let viewLen = s.len - 2
+ result = newStringOfCap(viewLen)
+ var i = 0
+ while i < viewLen:
+ case s[i]
+ of 'A'..'Z', 'a'..'z', '0'..'9', '_':
+ result.add(s[i])
+ of '\\':
+ assert i + 2 < viewLen
+ let b = (getHexChar(s[i + 1]) shl 4) or getHexChar(s[i + 2])
+ result.add(char(b))
+ inc i, 2
+ else:
+ raiseAssert "invalid char in escaped c symbol " & s[i]
+ inc i
+
+else:
+ template cSymbol*(x: string): Snippet = x
+ template unescapeCSymbol*(x: Snippet): string = x
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 1a9b4cf9583b0..16459147c42f1 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1425,7 +1425,7 @@ proc genEcho(p: BProc, n: PNode) =
p.module.includeHeader("")
p.module.includeHeader("")
var a: TLoc
- let logName = "Genode::log"
+ let logName = cSymbol("Genode::log")
var logCall: CallBuilder
p.s(cpsStmts).addStmt():
p.s(cpsStmts).addCall(logCall, logName):
@@ -1436,7 +1436,7 @@ proc genEcho(p: BProc, n: PNode) =
elif n.len != 0:
a = initLocExpr(p, it)
let ra = a.rdLoc
- let fnName = "Genode::Cstring"
+ let fnName = cSymbol("Genode::Cstring")
p.s(cpsStmts).addArgument(logCall):
case detectStrVersion(p.module)
of 2:
@@ -3019,8 +3019,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# - not sure, and it wouldn't work if the symbol behind the magic isn't
# somehow forward-declared from some other usage, but it is *possible*
if lfNoDecl notin opr.loc.flags:
- let prc = magicsys.getCompilerProc(p.module.g.graph, $opr.loc.snippet)
- assert prc != nil, $opr.loc.snippet
+ let prc = magicsys.getCompilerProc(p.module.g.graph, unescapeCSymbol(opr.loc.snippet))
+ assert prc != nil, unescapeCSymbol(opr.loc.snippet)
# HACK:
# Explicitly add this proc as declared here so the cgsym call doesn't
# add a forward declaration - without this we could end up with the same
@@ -3033,7 +3033,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
let wasDeclared = containsOrIncl(p.module.declaredProtos, prc.id)
# Make the function behind the magic get actually generated - this will
# not lead to a forward declaration! The genCall will lead to one.
- cgsym(p.module, $opr.loc.snippet)
+ cgsym(p.module, unescapeCSymbol(opr.loc.snippet))
# make sure we have pointer-initialising code for hot code reloading
if not wasDeclared and p.hcrOn:
let name = mangleDynLibProc(prc)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index e5fb1bfd18ecd..7cb62ced6adfd 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -1104,10 +1104,10 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
if not hasDefault:
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
p.s(cpsStmts).addSwitchElse():
- p.s(cpsStmts).addCallStmt("__builtin_unreachable")
+ p.s(cpsStmts).addCallStmt(cSymbol("__builtin_unreachable"))
elif hasAssume in CC[p.config.cCompiler].props:
p.s(cpsStmts).addSwitchElse():
- p.s(cpsStmts).addCallStmt("__assume", cIntValue(0))
+ p.s(cpsStmts).addCallStmt(cSymbol("__assume"), cIntValue(0))
if lend != "": fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) =
@@ -1618,20 +1618,20 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "pushSafePoint"), cAddr(safePoint))
if isDefined(p.config, "nimStdSetjmp"):
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context"))
+ p.s(cpsStmts).addCall(cSymbol("setjmp"), dotField(safePoint, "context"))
elif isDefined(p.config, "nimSigSetjmp"):
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("sigsetjmp", dotField(safePoint, "context"), cIntValue(0))
+ p.s(cpsStmts).addCall(cSymbol("sigsetjmp"), dotField(safePoint, "context"), cIntValue(0))
elif isDefined(p.config, "nimBuiltinSetjmp"):
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("__builtin_setjmp", dotField(safePoint, "context"))
+ p.s(cpsStmts).addCall(cSymbol("__builtin_setjmp"), dotField(safePoint, "context"))
elif isDefined(p.config, "nimRawSetjmp"):
if isDefined(p.config, "mswindows"):
if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"):
# For the vcc compiler, use `setjmp()` with one argument.
# See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context"))
+ p.s(cpsStmts).addCall(cSymbol("setjmp"), dotField(safePoint, "context"))
else:
# The Windows `_setjmp()` takes two arguments, with the second being an
# undocumented buffer used by the SEH mechanism for stack unwinding.
@@ -1640,13 +1640,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
# it to NULL.
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("_setjmp", dotField(safePoint, "context"), cIntValue(0))
+ p.s(cpsStmts).addCall(cSymbol("_setjmp"), dotField(safePoint, "context"), cIntValue(0))
else:
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("_setjmp", dotField(safePoint, "context"))
+ p.s(cpsStmts).addCall(cSymbol("_setjmp"), dotField(safePoint, "context"))
else:
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
- p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context"))
+ p.s(cpsStmts).addCall(cSymbol("setjmp"), dotField(safePoint, "context"))
nonQuirkyIf = initIfStmt(p.s(cpsStmts))
initElifBranch(p.s(cpsStmts), nonQuirkyIf, removeSinglePar(
cOp(Equal, dotField(safePoint, "status"), cIntValue(0))))
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 17bb6ef06635e..ce3a1042dc683 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1736,7 +1736,7 @@ proc genNimMainBody(m: BModule, preMainCode: Snippet) =
genNimMainProc(m, preMainCode)
proc genPosixCMain(m: BModule) =
- m.s[cfsProcs].addProcHeader("main", CInt, cProcParams(
+ m.s[cfsProcs].addProcHeader(cSymbol("main"), CInt, cProcParams(
(name: "argc", typ: CInt),
(name: "args", typ: ptrType(ptrType(CChar))),
(name: "env", typ: ptrType(ptrType(CChar)))))
@@ -1748,7 +1748,7 @@ proc genPosixCMain(m: BModule) =
m.s[cfsProcs].addNewline()
proc genStandaloneCMain(m: BModule) =
- m.s[cfsProcs].addProcHeader("main", CInt, cProcParams())
+ m.s[cfsProcs].addProcHeader(cSymbol("main"), CInt, cProcParams())
m.s[cfsProcs].finishProcHeaderWithBody():
genMainProcs(m)
m.s[cfsProcs].addReturn(cIntValue(0))
@@ -1758,10 +1758,10 @@ proc genWinNimMain(m: BModule, preMainCode: Snippet) =
genNimMainBody(m, preMainCode)
proc genWinCMain(m: BModule) =
- m.s[cfsProcs].addProcHeader(ccStdCall, "WinMain", CInt, cProcParams(
- (name: "hCurInstance", typ: "HINSTANCE"),
- (name: "hPrevInstance", typ: "HINSTANCE"),
- (name: "lpCmdLine", typ: "LPSTR"),
+ m.s[cfsProcs].addProcHeader(ccStdCall, cSymbol("WinMain"), CInt, cProcParams(
+ (name: "hCurInstance", typ: cSymbol("HINSTANCE")),
+ (name: "hPrevInstance", typ: cSymbol("HINSTANCE")),
+ (name: "lpCmdLine", typ: cSymbol("LPSTR")),
(name: "nCmdShow", typ: CInt)))
m.s[cfsProcs].finishProcHeaderWithBody():
genMainProcsWithResult(m)
@@ -1774,12 +1774,12 @@ proc genWinNimDllMain(m: BModule, preMainCode: Snippet) =
proc genWinCDllMain(m: BModule) =
# used to use WINAPI macro, now ccStdCall:
- m.s[cfsProcs].addProcHeader(ccStdCall, "DllMain", "BOOL", cProcParams(
- (name: "hinstDLL", typ: "HINSTANCE"),
- (name: "fwdreason", typ: "DWORD"),
- (name: "lpvReserved", typ: "LPVOID")))
+ m.s[cfsProcs].addProcHeader(ccStdCall, cSymbol("DllMain"), cSymbol("BOOL"), cProcParams(
+ (name: "hinstDLL", typ: cSymbol("HINSTANCE")),
+ (name: "fwdreason", typ: cSymbol("DWORD")),
+ (name: "lpvReserved", typ: cSymbol("LPVOID"))))
m.s[cfsProcs].finishProcHeaderWithBody():
- m.s[cfsProcs].addSingleIfStmt(removeSinglePar(cOp(Equal, "fwdreason", "DLL_PROCESS_ATTACH"))):
+ m.s[cfsProcs].addSingleIfStmt(removeSinglePar(cOp(Equal, "fwdreason", cSymbol("DLL_PROCESS_ATTACH")))):
genMainProcs(m)
m.s[cfsProcs].addReturn(cIntValue(1))
m.s[cfsProcs].addNewline()
@@ -1795,7 +1795,7 @@ proc genPosixCDllMain(m: BModule) =
m.s[cfsProcs].addNewline()
proc genGenodeNimMain(m: BModule, preMainCode: Snippet) =
- let typName = "Genode::Env"
+ let typName = cSymbol("Genode::Env")
m.s[cfsProcs].addDeclWithVisibility(Extern):
m.s[cfsProcs].addVar(name = "nim_runtime_env", typ = ptrType(typName))
m.s[cfsProcs].addDeclWithVisibility(ExternC):
@@ -1804,8 +1804,8 @@ proc genGenodeNimMain(m: BModule, preMainCode: Snippet) =
genNimMainBody(m, preMainCode)
proc genComponentConstruct(m: BModule) =
- let fnName = "Libc::Component::construct"
- let typName = "Libc::Env"
+ let fnName = cSymbol("Libc::Component::construct")
+ let typName = cSymbol("Libc::Env")
m.s[cfsProcs].addProcHeader(fnName, CVoid, cProcParams((name: "env", typ: cppRefType(typName))))
m.s[cfsProcs].finishProcHeaderWithBody():
m.s[cfsProcs].addLineComment("Set Env used during runtime initialization")
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c38fa2e62af6a..06e4f7f8f27d1 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -12,7 +12,8 @@
import
condsyms, ast, astalgo, idents, semdata, msgs, renderer,
wordrecg, ropes, options, extccomp, magicsys, trees,
- types, lookups, lineinfos, pathutils, linter, modulepaths
+ types, lookups, lineinfos, pathutils, linter, modulepaths,
+ cbuilderbase
from sigmatch import trySuggestPragmas
@@ -156,12 +157,12 @@ proc pragmaEnsures(c: PContext, n: PNode) =
proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
# special cases to improve performance:
if extname == "$1":
- s.loc.snippet = rope(s.name.s)
+ s.loc.snippet = cSymbol(s.name.s)
elif '$' notin extname:
- s.loc.snippet = rope(extname)
+ s.loc.snippet = cSymbol(extname)
else:
try:
- s.loc.snippet = rope(extname % s.name.s)
+ s.loc.snippet = cSymbol(extname % s.name.s)
except ValueError:
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
when hasFFI: