mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 19:33:42 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9084d9bc02 | ||
|
|
48c62ca48b | ||
|
|
70320482be | ||
|
|
e3a07f1997 | ||
|
|
bcf9448a75 | ||
|
|
a2f5e98baa | ||
|
|
a3b370fa87 | ||
|
|
b7a0c08b4f | ||
|
|
46275126b8 | ||
|
|
83c472c40d | ||
|
|
ac57c3193d | ||
|
|
7cf5e73fb7 | ||
|
|
c14008d77f | ||
|
|
168a8784f4 | ||
|
|
ee876aee28 | ||
|
|
8ed903d1d0 | ||
|
|
bfa8188dac | ||
|
|
56409c15c0 | ||
|
|
b614d97a2d | ||
|
|
2bb3a85a7c | ||
|
|
1247043c90 | ||
|
|
0ba76622a3 | ||
|
|
ab6770e77f | ||
|
|
c7920e9f87 | ||
|
|
167881bb83 | ||
|
|
73366c015f | ||
|
|
cfee71e779 | ||
|
|
1090b0c4af | ||
|
|
3f6de926f0 | ||
|
|
13343180b8 | ||
|
|
95dce90467 | ||
|
|
f85e09633d | ||
|
|
575450dfec | ||
|
|
6a2babac47 | ||
|
|
a6e192f020 | ||
|
|
233c6e9fb3 | ||
|
|
97286db546 | ||
|
|
1ac029c0f6 | ||
|
|
b18b636ea6 | ||
|
|
ac89e06c6e | ||
|
|
861b625a66 | ||
|
|
727c6378d2 |
43
changelog.md
43
changelog.md
@@ -4,6 +4,10 @@
|
|||||||
## Changes affecting backward compatibility
|
## Changes affecting backward compatibility
|
||||||
|
|
||||||
|
|
||||||
|
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
|
||||||
|
`experimental:flexibleOptionalParams`.
|
||||||
|
|
||||||
|
## Standard library additions and changes
|
||||||
|
|
||||||
## Standard library additions and changes
|
## Standard library additions and changes
|
||||||
|
|
||||||
@@ -12,6 +16,38 @@
|
|||||||
## Language changes
|
## Language changes
|
||||||
|
|
||||||
|
|
||||||
|
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
|
||||||
|
allowing multiple type definitions to be injected in place of the original type definition.
|
||||||
|
|
||||||
|
```nim
|
||||||
|
import macros
|
||||||
|
|
||||||
|
macro multiply(amount: static int, s: untyped): untyped =
|
||||||
|
let name = $s[0].basename
|
||||||
|
result = newNimNode(nnkTypeSection)
|
||||||
|
for i in 1 .. amount:
|
||||||
|
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo = object
|
||||||
|
Bar {.multiply: 3.} = object
|
||||||
|
x, y, z: int
|
||||||
|
Baz = object
|
||||||
|
|
||||||
|
# becomes
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo = object
|
||||||
|
Bar1 = object
|
||||||
|
x, y, z: int
|
||||||
|
Bar2 = object
|
||||||
|
x, y, z: int
|
||||||
|
Bar3 = object
|
||||||
|
x, y, z: int
|
||||||
|
Baz = object
|
||||||
|
```
|
||||||
|
- [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental,
|
||||||
|
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
|
||||||
|
|
||||||
## Compiler changes
|
## Compiler changes
|
||||||
|
|
||||||
@@ -21,5 +57,12 @@
|
|||||||
|
|
||||||
## Tool changes
|
## Tool changes
|
||||||
|
|
||||||
|
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||||
|
reality better. (Nim moved away from all techniques based on "tracing".)
|
||||||
|
|
||||||
|
- Nim now supports Nimble version 0.14 which added support for lock-files. This is done by
|
||||||
|
a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg`
|
||||||
|
replace `pkgs` by `pkgs2`.
|
||||||
|
|
||||||
|
- There is a new switch `--nimMainPrefix:prefix` to influence the `NimMain` that the
|
||||||
|
compiler produces. This is particularly useful for generating static libraries.
|
||||||
|
|||||||
31
changelogs/changelog.md
Normal file
31
changelogs/changelog.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# v1.xx.x - yyyy-mm-dd
|
||||||
|
|
||||||
|
## Changes affecting backward compatibility
|
||||||
|
|
||||||
|
## Standard library additions and changes
|
||||||
|
|
||||||
|
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
|
||||||
|
|
||||||
|
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||||
|
|
||||||
|
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||||
|
|
||||||
|
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||||
|
```sh
|
||||||
|
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||||
|
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||||
|
$ sh build.sh # per unix install instructions
|
||||||
|
$ bin/nim c koch # per unix install instructions
|
||||||
|
$ ./koch boot -d:release # per unix install instructions
|
||||||
|
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||||
|
```
|
||||||
|
|
||||||
|
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
|
||||||
|
|
||||||
|
## Language changes
|
||||||
|
|
||||||
|
|
||||||
|
## Compiler changes
|
||||||
|
|
||||||
|
|
||||||
|
## Tool changes
|
||||||
@@ -673,7 +673,7 @@ type
|
|||||||
mSwap, mIsNil, mArrToSeq,
|
mSwap, mIsNil, mArrToSeq,
|
||||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||||
mMove, mWasMoved, mDestroy, mTrace,
|
mMove, mWasMoved, mDestroy, mTrace,
|
||||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mReset,
|
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||||
mOrdinal, mIterableType,
|
mOrdinal, mIterableType,
|
||||||
@@ -2101,3 +2101,11 @@ proc skipAddr*(n: PNode): PNode {.inline.} =
|
|||||||
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
||||||
assert n.kind == nkTypeClassTy
|
assert n.kind == nkTypeClassTy
|
||||||
result = n[0].kind == nkEmpty
|
result = n[0].kind == nkEmpty
|
||||||
|
|
||||||
|
const
|
||||||
|
nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||||
|
nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
|
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||||
|
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||||
|
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
|||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
||||||
case skipTypes(a.t, abstractVar).kind
|
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
if reifiedOpenArray(n):
|
if reifiedOpenArray(n):
|
||||||
if a.t.kind in {tyVar, tyLent}:
|
if a.t.kind in {tyVar, tyLent}:
|
||||||
|
|||||||
@@ -1741,6 +1741,13 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
|
|||||||
# use the dynamic type stored at offset 0:
|
# use the dynamic type stored at offset 0:
|
||||||
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
|
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
|
||||||
|
|
||||||
|
proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) =
|
||||||
|
var a: TLoc
|
||||||
|
initLocExpr(p, e[1], a)
|
||||||
|
var nilCheck = Rope(nil)
|
||||||
|
# use the dynamic type stored at offset 0:
|
||||||
|
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
|
||||||
|
|
||||||
template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
|
template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n[1], a)
|
initLocExpr(p, n[1], a)
|
||||||
@@ -2449,6 +2456,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||||||
of mMove: genMove(p, e, d)
|
of mMove: genMove(p, e, d)
|
||||||
of mDestroy: genDestroy(p, e)
|
of mDestroy: genDestroy(p, e)
|
||||||
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
|
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
|
||||||
|
of mAccessTypeField: genAccessTypeField(p, e, d)
|
||||||
of mSlice: genSlice(p, e, d)
|
of mSlice: genSlice(p, e, d)
|
||||||
of mTrace: discard "no code to generate"
|
of mTrace: discard "no code to generate"
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1356,8 +1356,19 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
|||||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||||
elif isDefined(p.config, "nimSigSetjmp"):
|
elif isDefined(p.config, "nimSigSetjmp"):
|
||||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint])
|
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint])
|
||||||
|
elif isDefined(p.config, "nimBuiltinSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint])
|
||||||
elif isDefined(p.config, "nimRawSetjmp"):
|
elif isDefined(p.config, "nimRawSetjmp"):
|
||||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
if isDefined(p.config, "mswindows"):
|
||||||
|
# The Windows `_setjmp()` takes two arguments, with the second being an
|
||||||
|
# undocumented buffer used by the SEH mechanism for stack unwinding.
|
||||||
|
# Mingw-w64 has been trying to get it right for years, but it's still
|
||||||
|
# prone to stack corruption during unwinding, so we disable that by setting
|
||||||
|
# it to NULL.
|
||||||
|
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
|
||||||
|
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||||
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])
|
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ proc mangleName(m: BModule; s: PSym): Rope =
|
|||||||
result = s.loc.r
|
result = s.loc.r
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = s.name.s.mangle.rope
|
result = s.name.s.mangle.rope
|
||||||
result.add "_"
|
result.add "__"
|
||||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||||
result.add "_"
|
result.add "_"
|
||||||
result.add rope s.itemId.item
|
result.add rope s.itemId.item
|
||||||
@@ -220,7 +220,8 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
|||||||
# such a poor programming language.
|
# such a poor programming language.
|
||||||
# We exclude records with refs too. This enhances efficiency and
|
# We exclude records with refs too. This enhances efficiency and
|
||||||
# is necessary for proper code generation of assignments.
|
# is necessary for proper code generation of assignments.
|
||||||
if rettype == nil: result = true
|
if rettype == nil or getSize(conf, rettype) > conf.target.floatSize*3:
|
||||||
|
result = true
|
||||||
else:
|
else:
|
||||||
case mapType(conf, rettype, skResult)
|
case mapType(conf, rettype, skResult)
|
||||||
of ctArray:
|
of ctArray:
|
||||||
@@ -582,7 +583,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
|||||||
|
|
||||||
if typ.kind == tyObject:
|
if typ.kind == tyObject:
|
||||||
if typ[0] == nil:
|
if typ[0] == nil:
|
||||||
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
|
if lacksMTypeField(typ):
|
||||||
appcg(m, result, " {$n", [])
|
appcg(m, result, " {$n", [])
|
||||||
else:
|
else:
|
||||||
if optTinyRtti in m.config.globalOptions:
|
if optTinyRtti in m.config.globalOptions:
|
||||||
|
|||||||
@@ -154,6 +154,11 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
|||||||
inc(i)
|
inc(i)
|
||||||
result.add newCall(formatValue, resVar, args[num])
|
result.add newCall(formatValue, resVar, args[num])
|
||||||
inc(num)
|
inc(num)
|
||||||
|
of '^':
|
||||||
|
flushStrLit()
|
||||||
|
inc(i)
|
||||||
|
result.add newCall(formatValue, resVar, args[^1])
|
||||||
|
inc(num)
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
var j = 0
|
var j = 0
|
||||||
while true:
|
while true:
|
||||||
@@ -363,7 +368,8 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
|||||||
else:
|
else:
|
||||||
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
|
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
|
||||||
of frEmbedded:
|
of frEmbedded:
|
||||||
if optTinyRtti in p.config.globalOptions:
|
# inheritance in C++ does not allow struct initialization: bug #18410
|
||||||
|
if not p.module.compileToCpp and optTinyRtti in p.config.globalOptions:
|
||||||
var tmp: TLoc
|
var tmp: TLoc
|
||||||
if mode == constructRefObj:
|
if mode == constructRefObj:
|
||||||
let objType = t.skipTypes(abstractInst+{tyRef})
|
let objType = t.skipTypes(abstractInst+{tyRef})
|
||||||
@@ -442,8 +448,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
|||||||
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
|
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
|
||||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||||
elif not isComplexValueType(typ):
|
elif not isComplexValueType(typ):
|
||||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
if containsGarbageCollectedRef(loc.t):
|
||||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
var nilLoc: TLoc
|
||||||
|
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||||
|
nilLoc.r = rope("NIM_NIL")
|
||||||
|
genRefAssign(p, loc, nilLoc)
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||||
|
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||||
else:
|
else:
|
||||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||||
# don't use nimZeroMem for temporary values for performance if we can
|
# don't use nimZeroMem for temporary values for performance if we can
|
||||||
@@ -1359,7 +1371,7 @@ proc genMainProc(m: BModule) =
|
|||||||
"}$N$N"
|
"}$N$N"
|
||||||
|
|
||||||
MainProcs =
|
MainProcs =
|
||||||
"\tNimMain();$N"
|
"\t$^NimMain();$N"
|
||||||
|
|
||||||
MainProcsWithResult =
|
MainProcsWithResult =
|
||||||
MainProcs & ("\treturn $1nim_program_result;$N")
|
MainProcs & ("\treturn $1nim_program_result;$N")
|
||||||
@@ -1369,7 +1381,7 @@ proc genMainProc(m: BModule) =
|
|||||||
"}$N$N"
|
"}$N$N"
|
||||||
|
|
||||||
NimMainProc =
|
NimMainProc =
|
||||||
"N_CDECL(void, NimMain)(void) {$N" &
|
"N_CDECL(void, $5NimMain)(void) {$N" &
|
||||||
"\tvoid (*volatile inner)(void);$N" &
|
"\tvoid (*volatile inner)(void);$N" &
|
||||||
"$4" &
|
"$4" &
|
||||||
"\tinner = NimMainInner;$N" &
|
"\tinner = NimMainInner;$N" &
|
||||||
@@ -1449,28 +1461,27 @@ proc genMainProc(m: BModule) =
|
|||||||
if optGenGuiApp in m.config.globalOptions:
|
if optGenGuiApp in m.config.globalOptions:
|
||||||
const nimMain = WinNimMain
|
const nimMain = WinNimMain
|
||||||
appcg(m, m.s[cfsProcs], nimMain,
|
appcg(m, m.s[cfsProcs], nimMain,
|
||||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||||
else:
|
else:
|
||||||
const nimMain = WinNimDllMain
|
const nimMain = WinNimDllMain
|
||||||
appcg(m, m.s[cfsProcs], nimMain,
|
appcg(m, m.s[cfsProcs], nimMain,
|
||||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||||
elif m.config.target.targetOS == osGenode:
|
elif m.config.target.targetOS == osGenode:
|
||||||
const nimMain = GenodeNimMain
|
const nimMain = GenodeNimMain
|
||||||
appcg(m, m.s[cfsProcs], nimMain,
|
appcg(m, m.s[cfsProcs], nimMain,
|
||||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||||
elif optGenDynLib in m.config.globalOptions:
|
elif optGenDynLib in m.config.globalOptions:
|
||||||
const nimMain = PosixNimDllMain
|
const nimMain = PosixNimDllMain
|
||||||
appcg(m, m.s[cfsProcs], nimMain,
|
appcg(m, m.s[cfsProcs], nimMain,
|
||||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||||
elif m.config.target.targetOS == osStandalone:
|
elif m.config.target.targetOS == osStandalone:
|
||||||
const nimMain = NimMainBody
|
const nimMain = NimMainBody
|
||||||
appcg(m, m.s[cfsProcs], nimMain,
|
appcg(m, m.s[cfsProcs], nimMain,
|
||||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||||
else:
|
else:
|
||||||
const nimMain = NimMainBody
|
const nimMain = NimMainBody
|
||||||
appcg(m, m.s[cfsProcs], nimMain,
|
appcg(m, m.s[cfsProcs], nimMain,
|
||||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||||
|
|
||||||
|
|
||||||
if optNoMain notin m.config.globalOptions:
|
if optNoMain notin m.config.globalOptions:
|
||||||
if m.config.cppCustomNamespace.len > 0:
|
if m.config.cppCustomNamespace.len > 0:
|
||||||
@@ -1480,23 +1491,22 @@ proc genMainProc(m: BModule) =
|
|||||||
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||||
if optGenGuiApp in m.config.globalOptions:
|
if optGenGuiApp in m.config.globalOptions:
|
||||||
const otherMain = WinCMain
|
const otherMain = WinCMain
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""])
|
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
|
||||||
else:
|
else:
|
||||||
const otherMain = WinCDllMain
|
const otherMain = WinCDllMain
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||||
elif m.config.target.targetOS == osGenode:
|
elif m.config.target.targetOS == osGenode:
|
||||||
const otherMain = ComponentConstruct
|
const otherMain = ComponentConstruct
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||||
elif optGenDynLib in m.config.globalOptions:
|
elif optGenDynLib in m.config.globalOptions:
|
||||||
const otherMain = PosixCDllMain
|
const otherMain = PosixCDllMain
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||||
elif m.config.target.targetOS == osStandalone:
|
elif m.config.target.targetOS == osStandalone:
|
||||||
const otherMain = StandaloneCMain
|
const otherMain = StandaloneCMain
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||||
else:
|
else:
|
||||||
const otherMain = PosixCMain
|
const otherMain = PosixCMain
|
||||||
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""])
|
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
|
||||||
|
|
||||||
|
|
||||||
if m.config.cppCustomNamespace.len > 0:
|
if m.config.cppCustomNamespace.len > 0:
|
||||||
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
|
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
|
||||||
@@ -1878,7 +1888,7 @@ proc writeHeader(m: BModule) =
|
|||||||
|
|
||||||
if optGenDynLib in m.config.globalOptions:
|
if optGenDynLib in m.config.globalOptions:
|
||||||
result.add("N_LIB_IMPORT ")
|
result.add("N_LIB_IMPORT ")
|
||||||
result.addf("N_CDECL(void, NimMain)(void);$n", [])
|
result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix])
|
||||||
if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim()
|
if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim()
|
||||||
result.addf("#endif /* $1 */$n", [guard])
|
result.addf("#endif /* $1 */$n", [guard])
|
||||||
if not writeRope(result, m.filename):
|
if not writeRope(result, m.filename):
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ template deprecatedAlias(oldName, newName: string) =
|
|||||||
|
|
||||||
proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
|
proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
|
||||||
case switch.normalize
|
case switch.normalize
|
||||||
of "gc":
|
of "gc", "mm":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "boehm": result = conf.selectedGC == gcBoehm
|
of "boehm": result = conf.selectedGC == gcBoehm
|
||||||
of "refc": result = conf.selectedGC == gcRefc
|
of "refc": result = conf.selectedGC == gcRefc
|
||||||
@@ -596,7 +596,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
|||||||
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
|
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
|
||||||
of "project":
|
of "project":
|
||||||
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
|
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
|
||||||
of "gc":
|
of "gc", "mm":
|
||||||
if conf.backend == backendJs: return # for: bug #16033
|
if conf.backend == backendJs: return # for: bug #16033
|
||||||
expectArg(conf, switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}:
|
if pass in {passCmd2, passPP}:
|
||||||
@@ -1052,6 +1052,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
|||||||
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
|
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
|
||||||
handleStdinInput(conf)
|
handleStdinInput(conf)
|
||||||
of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
|
of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
|
||||||
|
of "nimmainprefix": conf.nimMainPrefix = arg
|
||||||
else:
|
else:
|
||||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||||
|
|||||||
@@ -138,3 +138,5 @@ proc initDefines*(symbols: StringTableRef) =
|
|||||||
defineSymbol("nimHasHintAll")
|
defineSymbol("nimHasHintAll")
|
||||||
defineSymbol("nimHasTrace")
|
defineSymbol("nimHasTrace")
|
||||||
defineSymbol("nimHasEffectsOf")
|
defineSymbol("nimHasEffectsOf")
|
||||||
|
|
||||||
|
defineSymbol("nimHasEnforceNoRaises")
|
||||||
|
|||||||
@@ -185,11 +185,13 @@ template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
|
|||||||
for it in mitems c.graph.ifaces[fromMod.position].converters:
|
for it in mitems c.graph.ifaces[fromMod.position].converters:
|
||||||
if filter:
|
if filter:
|
||||||
loadPackedSym(c.graph, it)
|
loadPackedSym(c.graph, it)
|
||||||
addConverter(c, it)
|
if sfExported in it.sym.flags:
|
||||||
|
addConverter(c, it)
|
||||||
for it in mitems c.graph.ifaces[fromMod.position].patterns:
|
for it in mitems c.graph.ifaces[fromMod.position].patterns:
|
||||||
if filter:
|
if filter:
|
||||||
loadPackedSym(c.graph, it)
|
loadPackedSym(c.graph, it)
|
||||||
addPattern(c, it)
|
if sfExported in it.sym.flags:
|
||||||
|
addPattern(c, it)
|
||||||
for it in mitems c.graph.ifaces[fromMod.position].pureEnums:
|
for it in mitems c.graph.ifaces[fromMod.position].pureEnums:
|
||||||
if filter:
|
if filter:
|
||||||
loadPackedSym(c.graph, it)
|
loadPackedSym(c.graph, it)
|
||||||
|
|||||||
@@ -77,6 +77,17 @@ proc canAlias*(arg, ret: PType): bool =
|
|||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
result = canAlias(arg, ret, marker)
|
result = canAlias(arg, ret, marker)
|
||||||
|
|
||||||
|
proc containsVariable(n: PNode): bool =
|
||||||
|
case n.kind
|
||||||
|
of nodesToIgnoreSet:
|
||||||
|
result = false
|
||||||
|
of nkSym:
|
||||||
|
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
|
||||||
|
else:
|
||||||
|
for ch in n:
|
||||||
|
if containsVariable(ch): return true
|
||||||
|
result = false
|
||||||
|
|
||||||
proc checkIsolate*(n: PNode): bool =
|
proc checkIsolate*(n: PNode): bool =
|
||||||
if types.containsTyRef(n.typ):
|
if types.containsTyRef(n.typ):
|
||||||
# XXX Maybe require that 'n.typ' is acyclic. This is not much
|
# XXX Maybe require that 'n.typ' is acyclic. This is not much
|
||||||
@@ -96,7 +107,11 @@ proc checkIsolate*(n: PNode): bool =
|
|||||||
else:
|
else:
|
||||||
let argType = n[i].typ
|
let argType = n[i].typ
|
||||||
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
|
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
|
||||||
if argType.canAlias(n.typ):
|
if argType.canAlias(n.typ) or containsVariable(n[i]):
|
||||||
|
# bug #19013: Alias information is not enough, we need to check for potential
|
||||||
|
# "overlaps". I claim the problem can only happen by reading again from a location
|
||||||
|
# that materialized which is only possible if a variable that contains a `ref`
|
||||||
|
# is involved.
|
||||||
return false
|
return false
|
||||||
result = true
|
result = true
|
||||||
of nkIfStmt, nkIfExpr:
|
of nkIfStmt, nkIfExpr:
|
||||||
|
|||||||
@@ -941,6 +941,12 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
|||||||
incl result.flags, sfFromGeneric
|
incl result.flags, sfFromGeneric
|
||||||
incl result.flags, sfGeneratedOp
|
incl result.flags, sfGeneratedOp
|
||||||
|
|
||||||
|
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
|
||||||
|
let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
|
||||||
|
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||||
|
yy.typ = xx.typ
|
||||||
|
body.add newAsgnStmt(xx, yy)
|
||||||
|
|
||||||
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||||
@@ -980,6 +986,10 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
|||||||
fillStrOp(a, typ, result.ast[bodyPos], d, src)
|
fillStrOp(a, typ, result.ast[bodyPos], d, src)
|
||||||
else:
|
else:
|
||||||
fillBody(a, typ, result.ast[bodyPos], d, src)
|
fillBody(a, typ, result.ast[bodyPos], d, src)
|
||||||
|
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
|
||||||
|
# bug #19205: Do not forget to also copy the hidden type field:
|
||||||
|
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
|
||||||
|
|
||||||
if not a.canRaise: incl result.flags, sfNeverRaises
|
if not a.canRaise: incl result.flags, sfNeverRaises
|
||||||
completePartialOp(g, idgen.module, typ, kind, result)
|
completePartialOp(g, idgen.module, typ, kind, result)
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,8 @@ type
|
|||||||
strictNotNil,
|
strictNotNil,
|
||||||
overloadableEnums,
|
overloadableEnums,
|
||||||
strictEffects,
|
strictEffects,
|
||||||
unicodeOperators
|
unicodeOperators,
|
||||||
|
flexibleOptionalParams
|
||||||
|
|
||||||
LegacyFeature* = enum
|
LegacyFeature* = enum
|
||||||
allowSemcheckedAstModification,
|
allowSemcheckedAstModification,
|
||||||
@@ -389,6 +390,7 @@ type
|
|||||||
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
|
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
|
||||||
severity: Severity) {.closure, gcsafe.}
|
severity: Severity) {.closure, gcsafe.}
|
||||||
cppCustomNamespace*: string
|
cppCustomNamespace*: string
|
||||||
|
nimMainPrefix*: string
|
||||||
vmProfileData*: ProfileData
|
vmProfileData*: ProfileData
|
||||||
|
|
||||||
proc parseNimVersion*(a: string): NimVer =
|
proc parseNimVersion*(a: string): NimVer =
|
||||||
|
|||||||
@@ -1877,7 +1877,7 @@ proc parseEnum(p: var Parser): PNode =
|
|||||||
|
|
||||||
var symPragma = a
|
var symPragma = a
|
||||||
var pragma: PNode
|
var pragma: PNode
|
||||||
if p.tok.tokType == tkCurlyDotLe:
|
if (p.tok.indent < 0 or p.tok.indent >= p.currInd) and p.tok.tokType == tkCurlyDotLe:
|
||||||
pragma = optPragmas(p)
|
pragma = optPragmas(p)
|
||||||
symPragma = newNodeP(nkPragmaExpr, p)
|
symPragma = newNodeP(nkPragmaExpr, p)
|
||||||
symPragma.add(a)
|
symPragma.add(a)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const
|
|||||||
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
|
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
|
||||||
wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wDelegator, wGcSafe,
|
wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wDelegator, wGcSafe,
|
||||||
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
|
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
|
||||||
wRequires, wEnsures}
|
wRequires, wEnsures, wEnforceNoRaises}
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||||
@@ -1237,6 +1237,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
|||||||
pragmaProposition(c, it)
|
pragmaProposition(c, it)
|
||||||
of wEnsures:
|
of wEnsures:
|
||||||
pragmaEnsures(c, it)
|
pragmaEnsures(c, it)
|
||||||
|
of wEnforceNoRaises:
|
||||||
|
sym.flags.incl sfNeverRaises
|
||||||
else: invalidPragma(c, it)
|
else: invalidPragma(c, it)
|
||||||
elif comesFromPush and whichKeyword(ident) != wInvalid:
|
elif comesFromPush and whichKeyword(ident) != wInvalid:
|
||||||
discard "ignore the .push pragma; it doesn't apply"
|
discard "ignore the .push pragma; it doesn't apply"
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
|
|||||||
of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g)
|
of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g)
|
||||||
of mBitnotI:
|
of mBitnotI:
|
||||||
if n.typ.isUnsigned:
|
if n.typ.isUnsigned:
|
||||||
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, idgen, g)
|
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(getSize(g.config, n.typ))), n, idgen, g)
|
||||||
else:
|
else:
|
||||||
result = newIntNodeT(bitnot(getInt(a)), n, idgen, g)
|
result = newIntNodeT(bitnot(getInt(a)), n, idgen, g)
|
||||||
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g)
|
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g)
|
||||||
@@ -248,23 +248,23 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
|
|||||||
of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g)
|
of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g)
|
||||||
of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
|
of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
|
||||||
of mAddU:
|
of mAddU:
|
||||||
let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
|
let val = maskBytes(getInt(a) + getInt(b), int(getSize(g.config, n.typ)))
|
||||||
result = newIntNodeT(val, n, idgen, g)
|
result = newIntNodeT(val, n, idgen, g)
|
||||||
of mSubU:
|
of mSubU:
|
||||||
let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size))
|
let val = maskBytes(getInt(a) - getInt(b), int(getSize(g.config, n.typ)))
|
||||||
result = newIntNodeT(val, n, idgen, g)
|
result = newIntNodeT(val, n, idgen, g)
|
||||||
# echo "subU: ", val, " n: ", n, " result: ", val
|
# echo "subU: ", val, " n: ", n, " result: ", val
|
||||||
of mMulU:
|
of mMulU:
|
||||||
let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size))
|
let val = maskBytes(getInt(a) * getInt(b), int(getSize(g.config, n.typ)))
|
||||||
result = newIntNodeT(val, n, idgen, g)
|
result = newIntNodeT(val, n, idgen, g)
|
||||||
of mModU:
|
of mModU:
|
||||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
|
||||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
|
||||||
if argB != Zero:
|
if argB != Zero:
|
||||||
result = newIntNodeT(argA mod argB, n, idgen, g)
|
result = newIntNodeT(argA mod argB, n, idgen, g)
|
||||||
of mDivU:
|
of mDivU:
|
||||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
|
||||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
|
||||||
if argB != Zero:
|
if argB != Zero:
|
||||||
result = newIntNodeT(argA div argB, n, idgen, g)
|
result = newIntNodeT(argA div argB, n, idgen, g)
|
||||||
of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g)
|
of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g)
|
||||||
|
|||||||
@@ -366,10 +366,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
|
|||||||
if objType.kind == tyObject:
|
if objType.kind == tyObject:
|
||||||
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
||||||
let initResult = semConstructTypeAux(c, constrCtx, {})
|
let initResult = semConstructTypeAux(c, constrCtx, {})
|
||||||
assert constrCtx.missingFields.len > 0
|
if constrCtx.missingFields.len > 0:
|
||||||
localError(c.config, info,
|
localError(c.config, info,
|
||||||
"The $1 type doesn't have a default value. The following fields must " &
|
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
||||||
"be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
|
||||||
elif objType.kind == tyDistinct:
|
elif objType.kind == tyDistinct:
|
||||||
localError(c.config, info,
|
localError(c.config, info,
|
||||||
"The $1 distinct type doesn't have a default value." % typeToString(t))
|
"The $1 distinct type doesn't have a default value." % typeToString(t))
|
||||||
|
|||||||
@@ -851,11 +851,15 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
|||||||
elif isIndirectCall(tracked, a):
|
elif isIndirectCall(tracked, a):
|
||||||
assumeTheWorst(tracked, n, op)
|
assumeTheWorst(tracked, n, op)
|
||||||
gcsafeAndSideeffectCheck()
|
gcsafeAndSideeffectCheck()
|
||||||
|
else:
|
||||||
|
if strictEffects in tracked.c.features and a.kind == nkSym and
|
||||||
|
a.sym.kind in routineKinds:
|
||||||
|
propagateEffects(tracked, n, a.sym)
|
||||||
else:
|
else:
|
||||||
mergeRaises(tracked, effectList[exceptionEffects], n)
|
mergeRaises(tracked, effectList[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList[tagEffects], n)
|
mergeTags(tracked, effectList[tagEffects], n)
|
||||||
gcsafeAndSideeffectCheck()
|
gcsafeAndSideeffectCheck()
|
||||||
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished}:
|
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}:
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
trackOperandForIndirectCall(tracked, n[i], op, i, a)
|
trackOperandForIndirectCall(tracked, n[i], op, i, a)
|
||||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||||
@@ -880,7 +884,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
|||||||
optStaticBoundsCheck in tracked.currOptions:
|
optStaticBoundsCheck in tracked.currOptions:
|
||||||
checkBounds(tracked, n[1], n[2])
|
checkBounds(tracked, n[1], n[2])
|
||||||
|
|
||||||
if a.kind != nkSym or a.sym.magic != mRunnableExamples:
|
if a.kind != nkSym or a.sym.magic notin {mRunnableExamples, mNBindSym, mExpandToAst, mQuoteAst}:
|
||||||
for i in 0..<n.safeLen:
|
for i in 0..<n.safeLen:
|
||||||
track(tracked, n[i])
|
track(tracked, n[i])
|
||||||
|
|
||||||
|
|||||||
@@ -2461,7 +2461,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
|||||||
if m.callee.n[f].kind != nkSym:
|
if m.callee.n[f].kind != nkSym:
|
||||||
internalError(c.config, n[a].info, "matches")
|
internalError(c.config, n[a].info, "matches")
|
||||||
noMatch()
|
noMatch()
|
||||||
if a >= firstArgBlock: f = max(f, m.callee.n.len - (n.len - a))
|
if flexibleOptionalParams in c.features and a >= firstArgBlock:
|
||||||
|
f = max(f, m.callee.n.len - (n.len - a))
|
||||||
formal = m.callee.n[f].sym
|
formal = m.callee.n[f].sym
|
||||||
m.firstMismatch.kind = kTypeMismatch
|
m.firstMismatch.kind = kTypeMismatch
|
||||||
if containsOrIncl(marker, formal.position) and container.isNil:
|
if containsOrIncl(marker, formal.position) and container.isNil:
|
||||||
|
|||||||
@@ -196,6 +196,11 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo
|
|||||||
accum.offset = szUnknownSize
|
accum.offset = szUnknownSize
|
||||||
|
|
||||||
proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||||
|
template setSize(typ, s) =
|
||||||
|
typ.size = s
|
||||||
|
typ.align = s
|
||||||
|
typ.paddingAtEnd = 0
|
||||||
|
|
||||||
## computes and sets ``size`` and ``align`` members of ``typ``
|
## computes and sets ``size`` and ``align`` members of ``typ``
|
||||||
assert typ != nil
|
assert typ != nil
|
||||||
let hasSize = typ.size != szUncomputedSize
|
let hasSize = typ.size != szUncomputedSize
|
||||||
@@ -258,14 +263,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
|||||||
|
|
||||||
of tyArray:
|
of tyArray:
|
||||||
computeSizeAlign(conf, typ[1])
|
computeSizeAlign(conf, typ[1])
|
||||||
let elemSize = typ[1].size
|
let elemSize = typ[1].size
|
||||||
let len = lengthOrd(conf, typ[0])
|
let len = lengthOrd(conf, typ[0])
|
||||||
if elemSize < 0:
|
if elemSize < 0:
|
||||||
typ.size = elemSize
|
typ.size = elemSize
|
||||||
typ.align = int16(elemSize)
|
typ.align = int16(elemSize)
|
||||||
elif len < 0:
|
elif len < 0:
|
||||||
typ.size = szUnknownSize
|
typ.size = szUnknownSize
|
||||||
typ.align = szUnknownSize
|
typ.align = szUnknownSize
|
||||||
else:
|
else:
|
||||||
typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize)
|
typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize)
|
||||||
typ.align = typ[1].align
|
typ.align = typ[1].align
|
||||||
@@ -445,6 +450,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
|||||||
typ.size = szUnknownSize
|
typ.size = szUnknownSize
|
||||||
typ.align = szUnknownSize
|
typ.align = szUnknownSize
|
||||||
typ.paddingAtEnd = szUnknownSize
|
typ.paddingAtEnd = szUnknownSize
|
||||||
|
of tyInt, tyUInt:
|
||||||
|
setSize typ, conf.target.intSize.int16
|
||||||
|
of tyBool, tyChar, tyUInt8, tyInt8:
|
||||||
|
setSize typ, 1
|
||||||
|
of tyInt16, tyUInt16:
|
||||||
|
setSize typ, 2
|
||||||
|
of tyInt32, tyUInt32:
|
||||||
|
setSize typ, 4
|
||||||
|
of tyInt64, tyUInt64:
|
||||||
|
setSize typ, 8
|
||||||
else:
|
else:
|
||||||
typ.size = szUnknownSize
|
typ.size = szUnknownSize
|
||||||
typ.align = szUnknownSize
|
typ.align = szUnknownSize
|
||||||
|
|||||||
@@ -1700,3 +1700,6 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
|
|||||||
result = allowPointerToChar
|
result = allowPointerToChar
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
proc lacksMTypeField*(typ: PType): bool {.inline.} =
|
||||||
|
(typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
|
|||||||
# calls do construct, what we construct must be destroyed,
|
# calls do construct, what we construct must be destroyed,
|
||||||
# so dest cannot be a cursor:
|
# so dest cannot be a cursor:
|
||||||
dest.flags.incl ownsData
|
dest.flags.incl ownsData
|
||||||
elif n.typ.kind in {tyLent, tyVar}:
|
elif n.typ.kind in {tyLent, tyVar} and n.len > 1:
|
||||||
# we know the result is derived from the first argument:
|
# we know the result is derived from the first argument:
|
||||||
var roots: seq[(PSym, int)]
|
var roots: seq[(PSym, int)]
|
||||||
allRoots(n[1], roots, RootEscapes)
|
allRoots(n[1], roots, RootEscapes)
|
||||||
@@ -647,13 +647,6 @@ proc deps(c: var Partitions; dest, src: PNode) =
|
|||||||
when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo
|
when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo
|
||||||
c.s[vid].flags.incl preventCursor
|
c.s[vid].flags.incl preventCursor
|
||||||
|
|
||||||
const
|
|
||||||
nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
|
|
||||||
nkTypeSection, nkProcDef, nkConverterDef,
|
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
|
||||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
|
||||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
|
|
||||||
|
|
||||||
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
|
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
|
||||||
if constParameters in c.goals and tfNoSideEffect in callee.flags:
|
if constParameters in c.goals and tfNoSideEffect in callee.flags:
|
||||||
|
|||||||
@@ -434,8 +434,10 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
|
|||||||
of tyFloat..tyFloat64:
|
of tyFloat..tyFloat64:
|
||||||
dest.intVal = int(src.floatVal)
|
dest.intVal = int(src.floatVal)
|
||||||
else:
|
else:
|
||||||
let srcDist = (sizeof(src.intVal) - styp.size) * 8
|
let srcSize = getSize(c.config, styp)
|
||||||
let destDist = (sizeof(dest.intVal) - desttyp.size) * 8
|
let destSize = getSize(c.config, desttyp)
|
||||||
|
let srcDist = (sizeof(src.intVal) - srcSize) * 8
|
||||||
|
let destDist = (sizeof(dest.intVal) - destSize) * 8
|
||||||
var value = cast[BiggestUInt](src.intVal)
|
var value = cast[BiggestUInt](src.intVal)
|
||||||
value = (value shl srcDist) shr srcDist
|
value = (value shl srcDist) shr srcDist
|
||||||
value = (value shl destDist) shr destDist
|
value = (value shl destDist) shr destDist
|
||||||
|
|||||||
@@ -749,18 +749,20 @@ proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
|
|||||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||||
# uint is uint64 in the VM, we we only need to mask the result for
|
# uint is uint64 in the VM, we we only need to mask the result for
|
||||||
# other unsigned types:
|
# other unsigned types:
|
||||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
let size = getSize(c.config, t)
|
||||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||||
c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
|
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
|
||||||
|
c.gABC(n, opcNarrowS, dest, TRegister(size*8))
|
||||||
|
|
||||||
proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
|
proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
|
||||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||||
# uint is uint64 in the VM, we we only need to mask the result for
|
# uint is uint64 in the VM, we we only need to mask the result for
|
||||||
# other unsigned types:
|
# other unsigned types:
|
||||||
|
let size = getSize(c.config, t)
|
||||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
|
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
|
||||||
(t.kind in {tyUInt, tyInt} and t.size < 8):
|
(t.kind in {tyUInt, tyInt} and size < 8):
|
||||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||||
|
|
||||||
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
genBinaryABC(c, n, dest, opc)
|
genBinaryABC(c, n, dest, opc)
|
||||||
@@ -1088,10 +1090,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
|||||||
genBinaryABC(c, n, dest, opcShlInt)
|
genBinaryABC(c, n, dest, opcShlInt)
|
||||||
# genNarrowU modified
|
# genNarrowU modified
|
||||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
let size = getSize(c.config, t)
|
||||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||||
c.gABC(n, opcSignExtend, dest, TRegister(t.size*8))
|
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
|
||||||
|
c.gABC(n, opcSignExtend, dest, TRegister(size*8))
|
||||||
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
|
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
|
||||||
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
||||||
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
|
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
|
||||||
@@ -1125,8 +1128,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
|||||||
genUnaryABC(c, n, dest, opcBitnotInt)
|
genUnaryABC(c, n, dest, opcBitnotInt)
|
||||||
#genNarrowU modified, do not narrow signed types
|
#genNarrowU modified, do not narrow signed types
|
||||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
let size = getSize(c.config, t)
|
||||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||||
|
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||||
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||||
genConv(c, n, n[1], dest)
|
genConv(c, n, n[1], dest)
|
||||||
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
|
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
|
|||||||
if a[i].kind == nkRange:
|
if a[i].kind == nkRange:
|
||||||
var x = copyNode(a[i][0])
|
var x = copyNode(a[i][0])
|
||||||
storeAny(s, t.lastSon, x, stored, conf)
|
storeAny(s, t.lastSon, x, stored, conf)
|
||||||
while x.intVal+1 <= a[i][1].intVal:
|
inc x.intVal
|
||||||
|
while x.intVal <= a[i][1].intVal:
|
||||||
s.add(", ")
|
s.add(", ")
|
||||||
storeAny(s, t.lastSon, x, stored, conf)
|
storeAny(s, t.lastSon, x, stored, conf)
|
||||||
inc x.intVal
|
inc x.intVal
|
||||||
@@ -231,7 +232,6 @@ proc loadAny(p: var JsonParser, t: PType,
|
|||||||
result = newNode(nkCurly)
|
result = newNode(nkCurly)
|
||||||
while p.kind != jsonArrayEnd and p.kind != jsonEof:
|
while p.kind != jsonArrayEnd and p.kind != jsonEof:
|
||||||
result.add loadAny(p, t.lastSon, tab, cache, conf, idgen)
|
result.add loadAny(p, t.lastSon, tab, cache, conf, idgen)
|
||||||
next(p)
|
|
||||||
if p.kind == jsonArrayEnd: next(p)
|
if p.kind == jsonArrayEnd: next(p)
|
||||||
else: raiseParseErr(p, "']' end of array expected")
|
else: raiseParseErr(p, "']' end of array expected")
|
||||||
of tyPtr, tyRef:
|
of tyPtr, tyRef:
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ type
|
|||||||
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",
|
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",
|
||||||
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
||||||
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
||||||
wLiftLocals = "liftlocals",
|
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
|
||||||
|
|
||||||
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
||||||
wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default",
|
wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default",
|
||||||
|
|||||||
@@ -44,10 +44,12 @@ path="$lib/core"
|
|||||||
path="$lib/pure"
|
path="$lib/pure"
|
||||||
|
|
||||||
@if not windows:
|
@if not windows:
|
||||||
|
nimblepath="/opt/nimble/pkgs2/"
|
||||||
nimblepath="/opt/nimble/pkgs/"
|
nimblepath="/opt/nimble/pkgs/"
|
||||||
@else:
|
@else:
|
||||||
# TODO:
|
# TODO:
|
||||||
@end
|
@end
|
||||||
|
nimblepath="$home/.nimble/pkgs2/"
|
||||||
nimblepath="$home/.nimble/pkgs/"
|
nimblepath="$home/.nimble/pkgs/"
|
||||||
|
|
||||||
# Syncronize with compiler/commands.specialDefine
|
# Syncronize with compiler/commands.specialDefine
|
||||||
@@ -154,9 +156,6 @@ nimblepath="$home/.nimble/pkgs/"
|
|||||||
# Configuration for the GNU C/C++ compiler:
|
# Configuration for the GNU C/C++ compiler:
|
||||||
@if windows:
|
@if windows:
|
||||||
#gcc.path = r"$nim\dist\mingw\bin"
|
#gcc.path = r"$nim\dist\mingw\bin"
|
||||||
@if gcc or tcc:
|
|
||||||
tlsEmulation:on
|
|
||||||
@end
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
gcc.maxerrorsimpl = "-fmax-errors=3"
|
gcc.maxerrorsimpl = "-fmax-errors=3"
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ doc.file = """
|
|||||||
%
|
%
|
||||||
% Compile it by: xelatex (up to 3 times to get labels generated)
|
% Compile it by: xelatex (up to 3 times to get labels generated)
|
||||||
% -------
|
% -------
|
||||||
|
% For example:
|
||||||
|
% xelatex file.tex
|
||||||
|
% xelatex file.tex
|
||||||
|
% makeindex file
|
||||||
|
% xelatex file.tex
|
||||||
%
|
%
|
||||||
\documentclass[a4paper,11pt]{article}
|
\documentclass[a4paper,11pt]{article}
|
||||||
\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry}
|
\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry}
|
||||||
@@ -97,7 +102,9 @@ doc.file = """
|
|||||||
\usepackage{parskip} % paragraphs delimited by vertical space, no indent
|
\usepackage{parskip} % paragraphs delimited by vertical space, no indent
|
||||||
\usepackage{graphicx}
|
\usepackage{graphicx}
|
||||||
|
|
||||||
\newcommand{\nimindexterm}[2]{#2\label{#1}}
|
\usepackage{makeidx}
|
||||||
|
\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}}
|
||||||
|
\makeindex
|
||||||
|
|
||||||
\usepackage{dingbat} % for \carriagereturn, etc
|
\usepackage{dingbat} % for \carriagereturn, etc
|
||||||
\usepackage{fvextra} % for code blocks (works better than original fancyvrb)
|
\usepackage{fvextra} % for code blocks (works better than original fancyvrb)
|
||||||
@@ -241,5 +248,8 @@ doc.file = """
|
|||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
$content
|
$content
|
||||||
|
|
||||||
|
\printindex
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -122,8 +122,9 @@ Advanced options:
|
|||||||
--skipUserCfg:on|off do not read the user's configuration file
|
--skipUserCfg:on|off do not read the user's configuration file
|
||||||
--skipParentCfg:on|off do not read the parent dirs' configuration files
|
--skipParentCfg:on|off do not read the parent dirs' configuration files
|
||||||
--skipProjCfg:on|off do not read the project's configuration file
|
--skipProjCfg:on|off do not read the project's configuration file
|
||||||
--gc:refc|arc|orc|markAndSweep|boehm|go|none|regions
|
--mm:orc|arc|refc|markAndSweep|boehm|go|none|regions
|
||||||
select the GC to use; default is 'refc'
|
select which memory management to use; default is 'refc'
|
||||||
|
recommended is 'orc'
|
||||||
--exceptions:setjmp|cpp|goto|quirky
|
--exceptions:setjmp|cpp|goto|quirky
|
||||||
select the exception handling implementation
|
select the exception handling implementation
|
||||||
--index:on|off turn index file generation on|off
|
--index:on|off turn index file generation on|off
|
||||||
@@ -134,6 +135,8 @@ Advanced options:
|
|||||||
--cppCompileToNamespace:namespace
|
--cppCompileToNamespace:namespace
|
||||||
use the provided namespace for the generated C++ code,
|
use the provided namespace for the generated C++ code,
|
||||||
if no namespace is provided "Nim" will be used
|
if no namespace is provided "Nim" will be used
|
||||||
|
--nimMainPrefix:prefix use `{prefix}NimMain` instead of `NimMain` in the produced
|
||||||
|
C/C++ code
|
||||||
--expandMacro:MACRO dump every generated AST from MACRO
|
--expandMacro:MACRO dump every generated AST from MACRO
|
||||||
--expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations
|
--expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations
|
||||||
before the final backend phase (mostly ARC/ORC specific)
|
before the final backend phase (mostly ARC/ORC specific)
|
||||||
@@ -163,4 +166,4 @@ Advanced options:
|
|||||||
--profileVM:on|off turn compile time VM profiler on|off
|
--profileVM:on|off turn compile time VM profiler on|off
|
||||||
--sinkInference:on|off turn sink parameter inference on|off (default: on)
|
--sinkInference:on|off turn sink parameter inference on|off (default: on)
|
||||||
--panics:on|off turn panics into process terminations (default: off)
|
--panics:on|off turn panics into process terminations (default: off)
|
||||||
--deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc``
|
--deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc``
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ The commands to compile to either C, C++ or Objective-C are:
|
|||||||
The most significant difference between these commands is that if you look
|
The most significant difference between these commands is that if you look
|
||||||
into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
|
into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
|
||||||
files, other than that all of them will produce a native binary for your
|
files, other than that all of them will produce a native binary for your
|
||||||
project. This allows you to take the generated code and place it directly
|
project. This allows you to take the generated code and place it directly
|
||||||
into a project using any of these languages. Here are some typical command-
|
into a project using any of these languages. Here are some typical command-
|
||||||
line invocations:
|
line invocations:
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ file. However, you can also run the code with `nodejs`:idx:
|
|||||||
If you experience errors saying that `globalThis` is not defined, be
|
If you experience errors saying that `globalThis` is not defined, be
|
||||||
sure to run a recent version of Node.js (at least 12.0).
|
sure to run a recent version of Node.js (at least 12.0).
|
||||||
|
|
||||||
|
|
||||||
Interfacing
|
Interfacing
|
||||||
===========
|
===========
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ Nim code can interface with the backend through the `Foreign function
|
|||||||
interface <manual.html#foreign-function-interface>`_ mainly through the
|
interface <manual.html#foreign-function-interface>`_ mainly through the
|
||||||
`importc pragma <manual.html#foreign-function-interface-importc-pragma>`_.
|
`importc pragma <manual.html#foreign-function-interface-importc-pragma>`_.
|
||||||
The `importc` pragma is the *generic* way of making backend symbols available
|
The `importc` pragma is the *generic* way of making backend symbols available
|
||||||
in Nim and is available in all the target backends (JavaScript too). The C++
|
in Nim and is available in all the target backends (JavaScript too). The C++
|
||||||
or Objective-C backends have their respective `ImportCpp
|
or Objective-C backends have their respective `ImportCpp
|
||||||
<manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
<manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||||
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
|
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
|
||||||
@@ -246,10 +246,8 @@ Also, C code requires you to specify a forward declaration for functions or
|
|||||||
the compiler will assume certain types for the return value and parameters
|
the compiler will assume certain types for the return value and parameters
|
||||||
which will likely make your program crash at runtime.
|
which will likely make your program crash at runtime.
|
||||||
|
|
||||||
The Nim compiler can generate a C interface header through the `--header`:option:
|
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||||
command-line switch. The generated header will contain all the exported
|
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||||
symbols and the `NimMain` proc which you need to call before any other
|
|
||||||
Nim code.
|
|
||||||
|
|
||||||
|
|
||||||
Nim invocation example from C
|
Nim invocation example from C
|
||||||
@@ -269,9 +267,10 @@ Create a ``maths.c`` file with the following content:
|
|||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
#include "fib.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int fib(int a);
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
NimMain();
|
NimMain();
|
||||||
@@ -286,13 +285,12 @@ program:
|
|||||||
|
|
||||||
.. code:: cmd
|
.. code:: cmd
|
||||||
|
|
||||||
nim c --noMain --noLinking --header:fib.h fib.nim
|
nim c --noMain --noLinking fib.nim
|
||||||
gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
|
gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
|
||||||
|
|
||||||
The first command runs the Nim compiler with three special options to avoid
|
The first command runs the Nim compiler with three special options to avoid
|
||||||
generating a `main()`:c: function in the generated files, avoid linking the
|
generating a `main()`:c: function in the generated files and to avoid linking the
|
||||||
object files into a final binary, and explicitly generate a header file for C
|
object files into a final binary. All the generated files are placed into the ``nimcache``
|
||||||
integration. All the generated files are placed into the ``nimcache``
|
|
||||||
directory. That's why the next command compiles the ``maths.c`` source plus
|
directory. That's why the next command compiles the ``maths.c`` source plus
|
||||||
all the ``.c`` files from ``nimcache``. In addition to this path, you also
|
all the ``.c`` files from ``nimcache``. In addition to this path, you also
|
||||||
have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
||||||
@@ -302,12 +300,12 @@ also ask the Nim compiler to generate a statically linked library:
|
|||||||
|
|
||||||
.. code:: cmd
|
.. code:: cmd
|
||||||
|
|
||||||
nim c --app:staticLib --noMain --header fib.nim
|
nim c --app:staticLib --noMain fib.nim
|
||||||
gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c
|
gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c
|
||||||
|
|
||||||
The Nim compiler will handle linking the source files generated in the
|
The Nim compiler will handle linking the source files generated in the
|
||||||
``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
|
``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
|
||||||
then link into your C program. Note that these commands are generic and will
|
then link into your C program. Note that these commands are generic and will
|
||||||
vary for each system. For instance, on Linux systems you will likely need to
|
vary for each system. For instance, on Linux systems you will likely need to
|
||||||
use `-ldl`:option: too to link in required dlopen functionality.
|
use `-ldl`:option: too to link in required dlopen functionality.
|
||||||
|
|
||||||
@@ -387,14 +385,8 @@ A similar thing happens with C code invoking Nim code which returns a
|
|||||||
proc gimme(): cstring {.exportc.} =
|
proc gimme(): cstring {.exportc.} =
|
||||||
result = "Hey there C code! " & $rand(100)
|
result = "Hey there C code! " & $rand(100)
|
||||||
|
|
||||||
Since Nim's garbage collector is not aware of the C code, once the
|
Since Nim's reference counting mechanism is not aware of the C code, once the
|
||||||
`gimme` proc has finished it can reclaim the memory of the `cstring`.
|
`gimme` proc has finished it can reclaim the memory of the `cstring`.
|
||||||
However, from a practical standpoint, the C code invoking the `gimme`
|
|
||||||
function directly will be able to use it since Nim's garbage collector has
|
|
||||||
not had a chance to run *yet*. This gives you enough time to make a copy for
|
|
||||||
the C side of the program, as calling any further Nim procs *might* trigger
|
|
||||||
garbage collection making the previously returned string garbage. Or maybe you
|
|
||||||
are `yourself triggering the collection <gc.html>`_.
|
|
||||||
|
|
||||||
|
|
||||||
Custom data types
|
Custom data types
|
||||||
@@ -414,31 +406,3 @@ you can clean it up. And of course, once cleaned you should avoid accessing it
|
|||||||
from Nim (or C for that matter). Typically C data structures have their own
|
from Nim (or C for that matter). Typically C data structures have their own
|
||||||
`malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping
|
`malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping
|
||||||
these for the Nim side should be enough.
|
these for the Nim side should be enough.
|
||||||
|
|
||||||
|
|
||||||
Thread coordination
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
When the `NimMain()` function is called Nim initializes the garbage
|
|
||||||
collector to the current thread, which is usually the main thread of your
|
|
||||||
application. If your C code later spawns a different thread and calls Nim
|
|
||||||
code, the garbage collector will fail to work properly and you will crash.
|
|
||||||
|
|
||||||
As long as you don't use the threadvar emulation Nim uses native thread
|
|
||||||
variables, of which you get a fresh version whenever you create a thread. You
|
|
||||||
can then attach a GC to this thread via
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
system.setupForeignThreadGc()
|
|
||||||
|
|
||||||
It is **not** safe to disable the garbage collector and enable it after the
|
|
||||||
call from your background thread even if the code you are calling is short
|
|
||||||
lived.
|
|
||||||
|
|
||||||
Before the thread exits, you should tear down the thread's GC to prevent memory
|
|
||||||
leaks by calling
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
system.tearDownForeignThreadGc()
|
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ Options:
|
|||||||
-a, --assertions:on|off turn assertions on|off
|
-a, --assertions:on|off turn assertions on|off
|
||||||
--opt:none|speed|size optimize not at all or for speed|size
|
--opt:none|speed|size optimize not at all or for speed|size
|
||||||
Note: use -d:release for a release build!
|
Note: use -d:release for a release build!
|
||||||
--debugger:native Use native debugger (gdb)
|
--debugger:native use native debugger (gdb)
|
||||||
--app:console|gui|lib|staticlib
|
--app:console|gui|lib|staticlib
|
||||||
generate a console app|GUI app|DLL|static library
|
generate a console app|GUI app|DLL|static library
|
||||||
-r, --run run the compiled program with given arguments
|
-r, --run run the compiled program with given arguments
|
||||||
--eval:cmd evaluates nim code directly; e.g.: `nim --eval:"echo 1"`
|
--eval:cmd evaluate nim code directly; e.g.: `nim --eval:"echo 1"`
|
||||||
defaults to `e` (nimscript) but customizable:
|
defaults to `e` (nimscript) but customizable:
|
||||||
`nim r --eval:'for a in stdin.lines: echo a'`
|
`nim r --eval:'for a in stdin.lines: echo a'`
|
||||||
--fullhelp show all command line switches
|
--fullhelp show all command line switches
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ written as:
|
|||||||
dealloc(x.data)
|
dealloc(x.data)
|
||||||
|
|
||||||
proc `=trace`[T](x: var myseq[T]; env: pointer) =
|
proc `=trace`[T](x: var myseq[T]; env: pointer) =
|
||||||
# `=trace` allows the cycle collector `--gc:orc`
|
# `=trace` allows the cycle collector `--mm:orc`
|
||||||
# to understand how to trace the object graph.
|
# to understand how to trace the object graph.
|
||||||
if x.data != nil:
|
if x.data != nil:
|
||||||
for i in 0..<x.len: `=trace`(x.data[i], env)
|
for i in 0..<x.len: `=trace`(x.data[i], env)
|
||||||
@@ -208,7 +208,7 @@ by the compiler. Notice that there is no `=` before the `{.error.}` pragma.
|
|||||||
`=trace` hook
|
`=trace` hook
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
A custom **container** type can support Nim's cycle collector `--gc:orc` via
|
A custom **container** type can support Nim's cycle collector `--mm:orc` via
|
||||||
the `=trace` hook. If the container does not implement `=trace`, cyclic data
|
the `=trace` hook. If the container does not implement `=trace`, cyclic data
|
||||||
structures which are constructed with the help of the container might leak
|
structures which are constructed with the help of the container might leak
|
||||||
memory or resources, but memory safety is not compromised.
|
memory or resources, but memory safety is not compromised.
|
||||||
@@ -224,7 +224,7 @@ to calls of the built-in `=trace` operation.
|
|||||||
|
|
||||||
Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates
|
Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates
|
||||||
manually allocated resources is also used, and then only when there is a chance of cyclic
|
manually allocated resources is also used, and then only when there is a chance of cyclic
|
||||||
references from items within the manually allocated resources when it is desired that `--gc:orc`
|
references from items within the manually allocated resources when it is desired that `--mm:orc`
|
||||||
is able to break and collect these cyclic referenced resources. Currently however, there is a
|
is able to break and collect these cyclic referenced resources. Currently however, there is a
|
||||||
mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically
|
mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically
|
||||||
create a version of the other which will then conflict with the creation of the second of the
|
create a version of the other which will then conflict with the creation of the second of the
|
||||||
@@ -256,7 +256,7 @@ The general pattern in using `=destroy` with `=trace` looks like:
|
|||||||
|
|
||||||
# following may be other custom "hooks" as required...
|
# following may be other custom "hooks" as required...
|
||||||
|
|
||||||
**Note**: The `=trace` hooks (which are only used by `--gc:orc`) are currently more experimental and less refined
|
**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
|
||||||
than the other hooks.
|
than the other hooks.
|
||||||
|
|
||||||
|
|
||||||
@@ -558,10 +558,10 @@ for expressions of type `lent T` or of type `var T`.
|
|||||||
The .cursor annotation
|
The .cursor annotation
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Under the `--gc:arc|orc`:option: modes Nim's `ref` type is implemented
|
Under the `--mm:arc|orc`:option: modes Nim's `ref` type is implemented
|
||||||
via the same runtime "hooks" and thus via reference counting.
|
via the same runtime "hooks" and thus via reference counting.
|
||||||
This means that cyclic structures cannot be freed
|
This means that cyclic structures cannot be freed
|
||||||
immediately (`--gc:orc`:option: ships with a cycle collector).
|
immediately (`--mm:orc`:option: ships with a cycle collector).
|
||||||
With the `.cursor` annotation one can break up cycles declaratively:
|
With the `.cursor` annotation one can break up cycles declaratively:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ The documentation consists of several documents:
|
|||||||
- | `Tools documentation <tools.html>`_
|
- | `Tools documentation <tools.html>`_
|
||||||
| Description of some tools that come with the standard distribution.
|
| Description of some tools that come with the standard distribution.
|
||||||
|
|
||||||
- | `GC <gc.html>`_
|
- | `Memory management <mm.html>`_
|
||||||
| Additional documentation about Nim's multi-paradigm memory management strategies
|
| Additional documentation about Nim's memory management strategies
|
||||||
| and how to operate them in a realtime setting.
|
| and how to operate them in a realtime setting.
|
||||||
|
|
||||||
- | `Source code filters <filters.html>`_
|
- | `Source code filters <filters.html>`_
|
||||||
|
|||||||
@@ -6699,11 +6699,11 @@ statement, as seen in stack backtraces:
|
|||||||
if not cond:
|
if not cond:
|
||||||
# change run-time line information of the 'raise' statement:
|
# change run-time line information of the 'raise' statement:
|
||||||
{.line: instantiationInfo().}:
|
{.line: instantiationInfo().}:
|
||||||
raise newException(EAssertionFailed, msg)
|
raise newException(AssertionDefect, msg)
|
||||||
|
|
||||||
If the `line` pragma is used with a parameter, the parameter needs be a
|
If the `line` pragma is used with a parameter, the parameter needs be a
|
||||||
`tuple[filename: string, line: int]`. If it is used without a parameter,
|
`tuple[filename: string, line: int]`. If it is used without a parameter,
|
||||||
`system.InstantiationInfo()` is used.
|
`system.instantiationInfo()` is used.
|
||||||
|
|
||||||
|
|
||||||
linearScanEnd pragma
|
linearScanEnd pragma
|
||||||
|
|||||||
95
doc/mm.rst
Normal file
95
doc/mm.rst
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
=======================
|
||||||
|
Nim's Memory Management
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. default-role:: code
|
||||||
|
.. include:: rstcommon.rst
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimversion|
|
||||||
|
|
||||||
|
..
|
||||||
|
|
||||||
|
|
||||||
|
"The road to hell is paved with good intentions."
|
||||||
|
|
||||||
|
|
||||||
|
Multi-paradigm Memory Management Strategies
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
.. default-role:: option
|
||||||
|
|
||||||
|
Nim offers multiple different memory management strategies.
|
||||||
|
To choose the memory management strategy use the `--mm:` switch.
|
||||||
|
|
||||||
|
**The recommended switch for newly written Nim code is `--mm:orc`.**
|
||||||
|
|
||||||
|
|
||||||
|
ARC/ORC
|
||||||
|
-------
|
||||||
|
|
||||||
|
`--mm:orc` is a memory management mode primarily based on reference counting. Cycles
|
||||||
|
in the object graph are handled by a "cycle collector" which is based on "trial deletion".
|
||||||
|
Since algorithms based on "tracing" are not used, the runtime behavior is oblivious to
|
||||||
|
the involved heap sizes.
|
||||||
|
|
||||||
|
The reference counting operations (= "RC ops") do not use atomic instructions and do not have to --
|
||||||
|
instead entire subgraphs are *moved* between threads. The Nim compiler also aggressively
|
||||||
|
optimizes away RC ops and exploits `move semantics <destructors.html#move-semantics>`_.
|
||||||
|
|
||||||
|
Nim performs a fair share of optimizations for ARC/ORC; you can inspect what it did
|
||||||
|
to your time critical function via `--expandArc:functionName`.
|
||||||
|
|
||||||
|
`--mm:arc` uses the same mechanism as `--mm:orc`, but it leaves out the cycle collector.
|
||||||
|
Both ARC and ORC offer deterministic performance for `hard realtime`:idx: systems, but
|
||||||
|
ARC can be easier to reason about for people coming from Ada/C++/C -- roughly speaking
|
||||||
|
the memory for a variable is freed when it goes "out of scope".
|
||||||
|
|
||||||
|
We generally advise you to use the `acyclic` annotation in order to optimize away the
|
||||||
|
cycle collector's overhead
|
||||||
|
but `--mm:orc` also produces more machine code than `--mm:arc`, so if you're on a target
|
||||||
|
where code size matters and you know that your code does not produce cycles, you can
|
||||||
|
use `--mm:arc`. Notice that the default `async`:idx: implementation produces cycles
|
||||||
|
and leaks memory with `--mm:arc`, in other words, for `async` you need to use `--mm:orc`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Other MM modes
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. note:: The default `refc` GC is incremental, thread-local and not "stop-the-world".
|
||||||
|
|
||||||
|
--mm:refc This is the default memory management strategy. It's a
|
||||||
|
deferred reference counting based garbage collector
|
||||||
|
with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local.
|
||||||
|
`This document <refc.html>`_ contains further information.
|
||||||
|
--mm:markAndSweep Simple Mark-And-Sweep based garbage collector.
|
||||||
|
Heaps are thread-local.
|
||||||
|
--mm:boehm Boehm based garbage collector, it offers a shared heap.
|
||||||
|
--mm:go Go's garbage collector, useful for interoperability with Go.
|
||||||
|
Offers a shared heap.
|
||||||
|
|
||||||
|
--mm:none No memory management strategy nor a garbage collector. Allocated memory is
|
||||||
|
simply never freed. You should use `--mm:arc` instead.
|
||||||
|
|
||||||
|
Here is a comparison of the different memory management modes:
|
||||||
|
|
||||||
|
================== ======== ================= ============== ===================
|
||||||
|
Memory Management Heap Reference Cycles Stop-The-World Command line switch
|
||||||
|
================== ======== ================= ============== ===================
|
||||||
|
ORC Shared Cycle Collector No `--mm:orc`
|
||||||
|
ARC Shared Leak No `--mm:arc`
|
||||||
|
RefC Local Cycle Collector No `--mm:refc`
|
||||||
|
Mark & Sweep Local Cycle Collector No `--mm:markAndSweep`
|
||||||
|
Boehm Shared Cycle Collector Yes `--mm:boehm`
|
||||||
|
Go Shared Cycle Collector Yes `--mm:go`
|
||||||
|
None Manual Manual Manual `--mm:none`
|
||||||
|
================== ======== ================= ============== ===================
|
||||||
|
|
||||||
|
.. default-role:: code
|
||||||
|
.. include:: rstcommon.rst
|
||||||
|
|
||||||
|
JavaScript's garbage collector is used for the `JavaScript and NodeJS
|
||||||
|
<backends.html#backends-the-javascript-target>`_ compilation targets.
|
||||||
|
The `NimScript <nims.html>`_ target uses the memory management strategy built into
|
||||||
|
the Nim compiler.
|
||||||
41
doc/nimc.rst
41
doc/nimc.rst
@@ -165,6 +165,22 @@ ignored too. `--define:FOO`:option: and `--define:foo`:option: are identical.
|
|||||||
Compile-time symbols starting with the `nim` prefix are reserved for the
|
Compile-time symbols starting with the `nim` prefix are reserved for the
|
||||||
implementation and should not be used elsewhere.
|
implementation and should not be used elsewhere.
|
||||||
|
|
||||||
|
========================== ============================================
|
||||||
|
Name Description
|
||||||
|
========================== ============================================
|
||||||
|
nimStdSetjmp Use the standard `setjmp()/longjmp()` library
|
||||||
|
functions for setjmp-based exceptions. This is
|
||||||
|
the default on most platforms.
|
||||||
|
nimSigSetjmp Use `sigsetjmp()/siglongjmp()` for setjmp-based exceptions.
|
||||||
|
nimRawSetjmp Use `_setjmp()/_longjmp()` on POSIX and `_setjmp()/longjmp()`
|
||||||
|
on Windows, for setjmp-based exceptions. It's the default on
|
||||||
|
BSDs and BSD-like platforms, where it's significantly faster
|
||||||
|
than the standard functions.
|
||||||
|
nimBuiltinSetjmp Use `__builtin_setjmp()/__builtin_longjmp()` for setjmp-based
|
||||||
|
exceptions. This will not work if an exception is being thrown
|
||||||
|
and caught inside the same procedure. Useful for benchmarking.
|
||||||
|
========================== ============================================
|
||||||
|
|
||||||
|
|
||||||
Configuration files
|
Configuration files
|
||||||
-------------------
|
-------------------
|
||||||
@@ -371,6 +387,10 @@ of your program.
|
|||||||
NimMain() # initialize garbage collector memory, types and stack
|
NimMain() # initialize garbage collector memory, types and stack
|
||||||
|
|
||||||
|
|
||||||
|
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||||
|
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||||
|
|
||||||
|
|
||||||
Cross-compilation for iOS
|
Cross-compilation for iOS
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
@@ -399,6 +419,9 @@ of your program.
|
|||||||
Note: XCode's "make clean" gets confused about the generated nim.c files,
|
Note: XCode's "make clean" gets confused about the generated nim.c files,
|
||||||
so you need to clean those files manually to do a clean build.
|
so you need to clean those files manually to do a clean build.
|
||||||
|
|
||||||
|
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||||
|
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||||
|
|
||||||
|
|
||||||
Cross-compilation for Nintendo Switch
|
Cross-compilation for Nintendo Switch
|
||||||
=====================================
|
=====================================
|
||||||
@@ -408,13 +431,13 @@ to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option:
|
|||||||
and `passL`:option: command line switches to something like:
|
and `passL`:option: command line switches to something like:
|
||||||
|
|
||||||
.. code-block:: cmd
|
.. code-block:: cmd
|
||||||
nim c ... --d:nimAllocPagesViaMalloc --gc:orc --passC="-I$DEVKITPRO/libnx/include" ...
|
nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ...
|
||||||
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
||||||
|
|
||||||
or setup a ``nim.cfg`` file like so::
|
or setup a ``nim.cfg`` file like so::
|
||||||
|
|
||||||
#nim.cfg
|
#nim.cfg
|
||||||
--gc:orc
|
--mm:orc
|
||||||
--d:nimAllocPagesViaMalloc
|
--d:nimAllocPagesViaMalloc
|
||||||
--passC="-I$DEVKITPRO/libnx/include"
|
--passC="-I$DEVKITPRO/libnx/include"
|
||||||
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
||||||
@@ -485,10 +508,10 @@ Define Effect
|
|||||||
`useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's
|
`useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's
|
||||||
own memory manager, albeit prefixing each allocation with
|
own memory manager, albeit prefixing each allocation with
|
||||||
its size to support clearing memory on reallocation.
|
its size to support clearing memory on reallocation.
|
||||||
This only works with `--gc:none`:option:,
|
This only works with `--mm:none`:option:,
|
||||||
`--gc:arc`:option: and `--gc:orc`:option:.
|
`--mm:arc`:option: and `--mm:orc`:option:.
|
||||||
`useRealtimeGC` Enables support of Nim's GC for *soft* realtime
|
`useRealtimeGC` Enables support of Nim's GC for *soft* realtime
|
||||||
systems. See the documentation of the `gc <gc.html>`_
|
systems. See the documentation of the `mm <mm.html>`_
|
||||||
for further information.
|
for further information.
|
||||||
`logGC` Enable GC logging to stdout.
|
`logGC` Enable GC logging to stdout.
|
||||||
`nodejs` The JS target is actually ``node.js``.
|
`nodejs` The JS target is actually ``node.js``.
|
||||||
@@ -614,9 +637,9 @@ A good start is to use the `any` operating target together with the
|
|||||||
|
|
||||||
.. code:: cmd
|
.. code:: cmd
|
||||||
|
|
||||||
nim c --os:any --gc:arc -d:useMalloc [...] x.nim
|
nim c --os:any --mm:arc -d:useMalloc [...] x.nim
|
||||||
|
|
||||||
- `--gc:arc`:option: will enable the reference counting memory management instead
|
- `--mm:arc`:option: will enable the reference counting memory management instead
|
||||||
of the default garbage collector. This enables Nim to use heap memory which
|
of the default garbage collector. This enables Nim to use heap memory which
|
||||||
is required for strings and seqs, for example.
|
is required for strings and seqs, for example.
|
||||||
|
|
||||||
@@ -654,13 +677,13 @@ devices. This allocator gets blocks/pages of memory via a currently undocumented
|
|||||||
`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap`
|
`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap`
|
||||||
is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc`
|
is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc`
|
||||||
define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently
|
define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently
|
||||||
only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6)
|
only supported with `--mm:arc` or `--mm:orc`. (Since version 1.6)
|
||||||
|
|
||||||
|
|
||||||
Nim for realtime systems
|
Nim for realtime systems
|
||||||
========================
|
========================
|
||||||
|
|
||||||
See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
|
See the `--mm:arc` or `--mm:orc` memory management settings in `MM <mm.html>`_ for further
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,81 +1,3 @@
|
|||||||
=======================
|
|
||||||
Nim's Memory Management
|
|
||||||
=======================
|
|
||||||
|
|
||||||
.. default-role:: code
|
|
||||||
.. include:: rstcommon.rst
|
|
||||||
|
|
||||||
:Author: Andreas Rumpf
|
|
||||||
:Version: |nimversion|
|
|
||||||
|
|
||||||
..
|
|
||||||
|
|
||||||
|
|
||||||
"The road to hell is paved with good intentions."
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
============
|
|
||||||
|
|
||||||
A memory-management algorithm optimal for every use-case cannot exist.
|
|
||||||
Nim provides multiple paradigms for needs ranging from large multi-threaded
|
|
||||||
applications, to games, hard-realtime systems and small microcontrollers.
|
|
||||||
|
|
||||||
This document describes how the management strategies work;
|
|
||||||
How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:,
|
|
||||||
and how the memory management strategies other than garbage collectors work.
|
|
||||||
|
|
||||||
.. note:: the default GC is incremental, thread-local and not "stop-the-world"
|
|
||||||
|
|
||||||
Multi-paradigm Memory Management Strategies
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
.. default-role:: option
|
|
||||||
|
|
||||||
To choose the memory management strategy use the `--gc:` switch.
|
|
||||||
|
|
||||||
--gc:refc This is the default GC. It's a
|
|
||||||
deferred reference counting based garbage collector
|
|
||||||
with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local.
|
|
||||||
--gc:markAndSweep Simple Mark-And-Sweep based garbage collector.
|
|
||||||
Heaps are thread-local.
|
|
||||||
--gc:boehm Boehm based garbage collector, it offers a shared heap.
|
|
||||||
--gc:go Go's garbage collector, useful for interoperability with Go.
|
|
||||||
Offers a shared heap.
|
|
||||||
--gc:arc Plain reference counting with
|
|
||||||
`move semantic optimizations <destructors.html#move-semantics>`_, offers a shared heap.
|
|
||||||
It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles
|
|
||||||
cause memory leaks, beware.
|
|
||||||
|
|
||||||
--gc:orc Same as `--gc:arc` but adds a cycle collector based on "trial deletion".
|
|
||||||
Unfortunately, that makes its performance profile hard to reason about so it is less
|
|
||||||
useful for hard real-time systems.
|
|
||||||
|
|
||||||
--gc:none No memory management strategy nor a garbage collector. Allocated memory is
|
|
||||||
simply never freed. You should use `--gc:arc` instead.
|
|
||||||
|
|
||||||
|
|
||||||
================== ======== ================= ============== ===================
|
|
||||||
Memory Management Heap Reference Cycles Stop-The-World Command line switch
|
|
||||||
================== ======== ================= ============== ===================
|
|
||||||
RefC Local Cycle Collector No `--gc:refc`
|
|
||||||
Mark & Sweep Local Cycle Collector No `--gc:markAndSweep`
|
|
||||||
ARC Shared Leak No `--gc:arc`
|
|
||||||
ORC Shared Cycle Collector No `--gc:orc`
|
|
||||||
Boehm Shared Cycle Collector Yes `--gc:boehm`
|
|
||||||
Go Shared Cycle Collector Yes `--gc:go`
|
|
||||||
None Manual Manual Manual `--gc:none`
|
|
||||||
================== ======== ================= ============== ===================
|
|
||||||
|
|
||||||
.. default-role:: code
|
|
||||||
.. include:: rstcommon.rst
|
|
||||||
|
|
||||||
JavaScript's garbage collector is used for the `JavaScript and NodeJS
|
|
||||||
<backends.html#backends-the-javascript-target>`_ compilation targets.
|
|
||||||
The `NimScript <nims.html>`_ target uses the memory management strategy built into
|
|
||||||
the Nim compiler.
|
|
||||||
|
|
||||||
|
|
||||||
Tweaking the refc GC
|
Tweaking the refc GC
|
||||||
====================
|
====================
|
||||||
|
|
||||||
@@ -164,6 +86,35 @@ that up to 100 objects are traversed and freed before it checks again. Thus
|
|||||||
highly specialized environments or for older hardware.
|
highly specialized environments or for older hardware.
|
||||||
|
|
||||||
|
|
||||||
|
Thread coordination
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
When the `NimMain()` function is called Nim initializes the garbage
|
||||||
|
collector to the current thread, which is usually the main thread of your
|
||||||
|
application. If your C code later spawns a different thread and calls Nim
|
||||||
|
code, the garbage collector will fail to work properly and you will crash.
|
||||||
|
|
||||||
|
As long as you don't use the threadvar emulation Nim uses native thread
|
||||||
|
variables, of which you get a fresh version whenever you create a thread. You
|
||||||
|
can then attach a GC to this thread via
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
system.setupForeignThreadGc()
|
||||||
|
|
||||||
|
It is **not** safe to disable the garbage collector and enable it after the
|
||||||
|
call from your background thread even if the code you are calling is short
|
||||||
|
lived.
|
||||||
|
|
||||||
|
Before the thread exits, you should tear down the thread's GC to prevent memory
|
||||||
|
leaks by calling
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
system.tearDownForeignThreadGc()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Keeping track of memory
|
Keeping track of memory
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
@@ -178,7 +129,7 @@ Other useful procs from `system <system.html>`_ you can use to keep track of mem
|
|||||||
* `GC_getStatistics()` Garbage collector statistics as a human-readable string.
|
* `GC_getStatistics()` Garbage collector statistics as a human-readable string.
|
||||||
|
|
||||||
These numbers are usually only for the running thread, not for the whole heap,
|
These numbers are usually only for the running thread, not for the whole heap,
|
||||||
with the exception of `--gc:boehm`:option: and `--gc:go`:option:.
|
with the exception of `--mm:boehm`:option: and `--mm:go`:option:.
|
||||||
|
|
||||||
In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually
|
In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually
|
||||||
allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`.
|
allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`.
|
||||||
2
koch.nim
2
koch.nim
@@ -604,7 +604,7 @@ proc runCI(cmd: string) =
|
|||||||
when not defined(bsd):
|
when not defined(bsd):
|
||||||
if not doUseCpp:
|
if not doUseCpp:
|
||||||
# the BSDs are overwhelmed already, so only run this test on the other machines:
|
# the BSDs are overwhelmed already, so only run this test on the other machines:
|
||||||
kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib")
|
kochExecFold("Boot Nim ORC", "boot -d:release --mm:orc --lib:lib")
|
||||||
|
|
||||||
proc testUnixInstall(cmdLineRest: string) =
|
proc testUnixInstall(cmdLineRest: string) =
|
||||||
csource("-d:danger" & cmdLineRest)
|
csource("-d:danger" & cmdLineRest)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
## can be done by simply searching for [footnoteName].
|
## can be done by simply searching for [footnoteName].
|
||||||
|
|
||||||
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
||||||
algorithm, parseutils, std/strbasics
|
algorithm, parseutils, std/strbasics, strscans
|
||||||
|
|
||||||
import ../../std/private/since
|
import ../../std/private/since
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
|||||||
var term = ""
|
var term = ""
|
||||||
renderAux(d, n, term)
|
renderAux(d, n, term)
|
||||||
setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection)
|
setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection)
|
||||||
dispA(d.target, result, "<span id=\"$1\">$2</span>", "\\nimindexterm{$2}{$1}",
|
dispA(d.target, result, "<span id=\"$1\">$2</span>", "\\nimindexterm{$1}{$2}",
|
||||||
[id, term])
|
[id, term])
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -823,6 +823,16 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
|||||||
rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName])
|
rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName])
|
||||||
|
|
||||||
|
|
||||||
|
proc safeProtocol(linkStr: var string) =
|
||||||
|
var protocol = ""
|
||||||
|
if scanf(linkStr, "$w:", protocol):
|
||||||
|
# if it has a protocol at all, ensure that it's not 'javascript:' or worse:
|
||||||
|
if cmpIgnoreCase(protocol, "http") == 0 or cmpIgnoreCase(protocol, "https") == 0 or
|
||||||
|
cmpIgnoreCase(protocol, "ftp") == 0:
|
||||||
|
discard "it's fine"
|
||||||
|
else:
|
||||||
|
linkStr = ""
|
||||||
|
|
||||||
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
||||||
dispA(d.target, result,
|
dispA(d.target, result,
|
||||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||||
@@ -887,6 +897,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
|||||||
|
|
||||||
# support for `:target:` links for images:
|
# support for `:target:` links for images:
|
||||||
var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl)
|
var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl)
|
||||||
|
safeProtocol(target)
|
||||||
|
|
||||||
if target.len > 0:
|
if target.len > 0:
|
||||||
# `htmlOut` needs to be of the following format for link to work for images:
|
# `htmlOut` needs to be of the following format for link to work for images:
|
||||||
# <a class="reference external" href="target"><img src=\"$1\"$2/></a>
|
# <a class="reference external" href="target"><img src=\"$1\"$2/></a>
|
||||||
@@ -1187,6 +1199,7 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external
|
|||||||
d.escMode = emUrl
|
d.escMode = emUrl
|
||||||
renderRstToOut(d, link, linkStr)
|
renderRstToOut(d, link, linkStr)
|
||||||
d.escMode = mode
|
d.escMode = mode
|
||||||
|
safeProtocol(linkStr)
|
||||||
var textStr = ""
|
var textStr = ""
|
||||||
renderRstToOut(d, text, textStr)
|
renderRstToOut(d, text, textStr)
|
||||||
if external:
|
if external:
|
||||||
|
|||||||
@@ -733,7 +733,7 @@ when defined(windows) or defined(nimdoc):
|
|||||||
|
|
||||||
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
|
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
|
||||||
inheritable = defined(nimInheritHandles)):
|
inheritable = defined(nimInheritHandles)):
|
||||||
owned(Future[tuple[address: string, client: AsyncFD]]) =
|
owned(Future[tuple[address: string, client: AsyncFD]]) {.gcsafe.} =
|
||||||
## Accepts a new connection. Returns a future containing the client socket
|
## Accepts a new connection. Returns a future containing the client socket
|
||||||
## corresponding to that connection and the remote address of the client.
|
## corresponding to that connection and the remote address of the client.
|
||||||
## The future will complete when the connection is successfully accepted.
|
## The future will complete when the connection is successfully accepted.
|
||||||
@@ -800,7 +800,7 @@ when defined(windows) or defined(nimdoc):
|
|||||||
|
|
||||||
var ol = newCustom()
|
var ol = newCustom()
|
||||||
ol.data = CompletionData(fd: socket, cb:
|
ol.data = CompletionData(fd: socket, cb:
|
||||||
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
|
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) {.gcsafe.} =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == OSErrorCode(-1):
|
if errcode == OSErrorCode(-1):
|
||||||
completeAccept()
|
completeAccept()
|
||||||
|
|||||||
@@ -87,20 +87,6 @@ proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] =
|
|||||||
## * `toDeque proc <#toDeque,openArray[T]>`_
|
## * `toDeque proc <#toDeque,openArray[T]>`_
|
||||||
result.initImpl(initialSize)
|
result.initImpl(initialSize)
|
||||||
|
|
||||||
proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} =
|
|
||||||
## Creates a new deque that contains the elements of `x` (in the same order).
|
|
||||||
##
|
|
||||||
## **See also:**
|
|
||||||
## * `initDeque proc <#initDeque,int>`_
|
|
||||||
runnableExamples:
|
|
||||||
let a = toDeque([7, 8, 9])
|
|
||||||
assert len(a) == 3
|
|
||||||
assert $a == "[7, 8, 9]"
|
|
||||||
|
|
||||||
result.initImpl(x.len)
|
|
||||||
for item in items(x):
|
|
||||||
result.addLast(item)
|
|
||||||
|
|
||||||
proc len*[T](deq: Deque[T]): int {.inline.} =
|
proc len*[T](deq: Deque[T]): int {.inline.} =
|
||||||
## Returns the number of elements of `deq`.
|
## Returns the number of elements of `deq`.
|
||||||
result = deq.count
|
result = deq.count
|
||||||
@@ -303,6 +289,20 @@ proc addLast*[T](deq: var Deque[T], item: sink T) =
|
|||||||
deq.data[deq.tail] = item
|
deq.data[deq.tail] = item
|
||||||
deq.tail = (deq.tail + 1) and deq.mask
|
deq.tail = (deq.tail + 1) and deq.mask
|
||||||
|
|
||||||
|
proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} =
|
||||||
|
## Creates a new deque that contains the elements of `x` (in the same order).
|
||||||
|
##
|
||||||
|
## **See also:**
|
||||||
|
## * `initDeque proc <#initDeque,int>`_
|
||||||
|
runnableExamples:
|
||||||
|
let a = toDeque([7, 8, 9])
|
||||||
|
assert len(a) == 3
|
||||||
|
assert $a == "[7, 8, 9]"
|
||||||
|
|
||||||
|
result.initImpl(x.len)
|
||||||
|
for item in items(x):
|
||||||
|
result.addLast(item)
|
||||||
|
|
||||||
proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} =
|
proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} =
|
||||||
## Returns the first element of `deq`, but does not remove it from the deque.
|
## Returns the first element of `deq`, but does not remove it from the deque.
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -353,8 +353,8 @@ const
|
|||||||
("lightcoral", colLightCoral),
|
("lightcoral", colLightCoral),
|
||||||
("lightcyan", colLightCyan),
|
("lightcyan", colLightCyan),
|
||||||
("lightgoldenrodyellow", colLightGoldenRodYellow),
|
("lightgoldenrodyellow", colLightGoldenRodYellow),
|
||||||
("lightgrey", colLightGrey),
|
|
||||||
("lightgreen", colLightGreen),
|
("lightgreen", colLightGreen),
|
||||||
|
("lightgrey", colLightGrey),
|
||||||
("lightpink", colLightPink),
|
("lightpink", colLightPink),
|
||||||
("lightsalmon", colLightSalmon),
|
("lightsalmon", colLightSalmon),
|
||||||
("lightseagreen", colLightSeaGreen),
|
("lightseagreen", colLightSeaGreen),
|
||||||
|
|||||||
@@ -202,6 +202,8 @@ type
|
|||||||
of JArray:
|
of JArray:
|
||||||
elems*: seq[JsonNode]
|
elems*: seq[JsonNode]
|
||||||
|
|
||||||
|
const DepthLimit = 1000
|
||||||
|
|
||||||
proc newJString*(s: string): JsonNode =
|
proc newJString*(s: string): JsonNode =
|
||||||
## Creates a new `JString JsonNode`.
|
## Creates a new `JString JsonNode`.
|
||||||
result = JsonNode(kind: JString, str: s)
|
result = JsonNode(kind: JString, str: s)
|
||||||
@@ -437,7 +439,7 @@ macro `%*`*(x: untyped): untyped =
|
|||||||
## `%` for every element.
|
## `%` for every element.
|
||||||
result = toJsonImpl(x)
|
result = toJsonImpl(x)
|
||||||
|
|
||||||
proc `==`*(a, b: JsonNode): bool =
|
proc `==`*(a, b: JsonNode): bool {.noSideEffect.} =
|
||||||
## Check two nodes for equality
|
## Check two nodes for equality
|
||||||
if a.isNil:
|
if a.isNil:
|
||||||
if b.isNil: return true
|
if b.isNil: return true
|
||||||
@@ -464,12 +466,16 @@ proc `==`*(a, b: JsonNode): bool =
|
|||||||
if a.fields.len != b.fields.len: return false
|
if a.fields.len != b.fields.len: return false
|
||||||
for key, val in a.fields:
|
for key, val in a.fields:
|
||||||
if not b.fields.hasKey(key): return false
|
if not b.fields.hasKey(key): return false
|
||||||
if b.fields[key] != val: return false
|
when defined(nimHasEffectsOf):
|
||||||
|
{.noSideEffect.}:
|
||||||
|
if b.fields[key] != val: return false
|
||||||
|
else:
|
||||||
|
if b.fields[key] != val: return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
||||||
|
|
||||||
proc hash*(n: JsonNode): Hash =
|
proc hash*(n: JsonNode): Hash {.noSideEffect.} =
|
||||||
## Compute the hash for a JSON node
|
## Compute the hash for a JSON node
|
||||||
case n.kind
|
case n.kind
|
||||||
of JArray:
|
of JArray:
|
||||||
@@ -845,7 +851,7 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
|
|||||||
for key, val in mpairs(node.fields):
|
for key, val in mpairs(node.fields):
|
||||||
yield (key, val)
|
yield (key, val)
|
||||||
|
|
||||||
proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool, depth = 0): JsonNode =
|
||||||
## Parses JSON from a JSON Parser `p`.
|
## Parses JSON from a JSON Parser `p`.
|
||||||
case p.tok
|
case p.tok
|
||||||
of tkString:
|
of tkString:
|
||||||
@@ -881,6 +887,8 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
|||||||
result = newJNull()
|
result = newJNull()
|
||||||
discard getTok(p)
|
discard getTok(p)
|
||||||
of tkCurlyLe:
|
of tkCurlyLe:
|
||||||
|
if depth > DepthLimit:
|
||||||
|
raiseParseErr(p, "}")
|
||||||
result = newJObject()
|
result = newJObject()
|
||||||
discard getTok(p)
|
discard getTok(p)
|
||||||
while p.tok != tkCurlyRi:
|
while p.tok != tkCurlyRi:
|
||||||
@@ -889,16 +897,18 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
|||||||
var key = p.a
|
var key = p.a
|
||||||
discard getTok(p)
|
discard getTok(p)
|
||||||
eat(p, tkColon)
|
eat(p, tkColon)
|
||||||
var val = parseJson(p, rawIntegers, rawFloats)
|
var val = parseJson(p, rawIntegers, rawFloats, depth+1)
|
||||||
result[key] = val
|
result[key] = val
|
||||||
if p.tok != tkComma: break
|
if p.tok != tkComma: break
|
||||||
discard getTok(p)
|
discard getTok(p)
|
||||||
eat(p, tkCurlyRi)
|
eat(p, tkCurlyRi)
|
||||||
of tkBracketLe:
|
of tkBracketLe:
|
||||||
|
if depth > DepthLimit:
|
||||||
|
raiseParseErr(p, "]")
|
||||||
result = newJArray()
|
result = newJArray()
|
||||||
discard getTok(p)
|
discard getTok(p)
|
||||||
while p.tok != tkBracketRi:
|
while p.tok != tkBracketRi:
|
||||||
result.add(parseJson(p, rawIntegers, rawFloats))
|
result.add(parseJson(p, rawIntegers, rawFloats, depth+1))
|
||||||
if p.tok != tkComma: break
|
if p.tok != tkComma: break
|
||||||
discard getTok(p)
|
discard getTok(p)
|
||||||
eat(p, tkBracketRi)
|
eat(p, tkBracketRi)
|
||||||
|
|||||||
@@ -3263,7 +3263,11 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
|
|||||||
## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows,
|
## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows,
|
||||||
## or a 'Stat' structure on posix
|
## or a 'Stat' structure on posix
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
template merge(a, b): untyped = a or (b shl 32)
|
template merge(a, b): untyped =
|
||||||
|
int64(
|
||||||
|
(uint64(cast[uint32](a))) or
|
||||||
|
(uint64(cast[uint32](b)) shl 32)
|
||||||
|
)
|
||||||
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
|
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
|
||||||
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
|
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
|
||||||
formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
|
formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ func parseAuthority(authority: string, result: var Uri) =
|
|||||||
result.isIpv6 = true
|
result.isIpv6 = true
|
||||||
of ']':
|
of ']':
|
||||||
inIPv6 = false
|
inIPv6 = false
|
||||||
|
of '\0':
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
if inPort:
|
if inPort:
|
||||||
result.port.add(authority[i])
|
result.port.add(authority[i])
|
||||||
|
|||||||
@@ -78,14 +78,17 @@ func addIntImpl(result: var string, x: uint64) {.inline.} =
|
|||||||
dec next
|
dec next
|
||||||
addChars(result, tmp, next, tmp.len - next)
|
addChars(result, tmp, next, tmp.len - next)
|
||||||
|
|
||||||
func addInt*(result: var string, x: uint64) =
|
when not defined(nimHasEnforceNoRaises):
|
||||||
|
{.pragma: enforceNoRaises.}
|
||||||
|
|
||||||
|
func addInt*(result: var string, x: uint64) {.enforceNoRaises.} =
|
||||||
when nimvm: addIntImpl(result, x)
|
when nimvm: addIntImpl(result, x)
|
||||||
else:
|
else:
|
||||||
when not defined(js): addIntImpl(result, x)
|
when not defined(js): addIntImpl(result, x)
|
||||||
else:
|
else:
|
||||||
addChars(result, numToString(x))
|
addChars(result, numToString(x))
|
||||||
|
|
||||||
proc addInt*(result: var string; x: int64) =
|
proc addInt*(result: var string; x: int64) {.enforceNoRaises.} =
|
||||||
## Converts integer to its string representation and appends it to `result`.
|
## Converts integer to its string representation and appends it to `result`.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var s = "foo"
|
var s = "foo"
|
||||||
@@ -110,5 +113,5 @@ proc addInt*(result: var string; x: int64) =
|
|||||||
addChars(result, numToString(x))
|
addChars(result, numToString(x))
|
||||||
else: impl()
|
else: impl()
|
||||||
|
|
||||||
proc addInt*(result: var string; x: int) {.inline.} =
|
proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} =
|
||||||
addInt(result, int64(x))
|
addInt(result, int64(x))
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
## .. _randomFillSync: https://nodejs.org/api/crypto.html#crypto_crypto_randomfillsync_buffer_offset_size
|
## .. _randomFillSync: https://nodejs.org/api/crypto.html#crypto_crypto_randomfillsync_buffer_offset_size
|
||||||
## .. _/dev/urandom: https://en.wikipedia.org/wiki//dev/random
|
## .. _/dev/urandom: https://en.wikipedia.org/wiki//dev/random
|
||||||
##
|
##
|
||||||
|
## On a Linux target, a call to the `getrandom` syscall can be avoided (e.g.
|
||||||
|
## for targets running kernel version < 3.17) by passing a compile flag of
|
||||||
|
## `-d:nimNoGetRandom`. If this flag is passed, sysrand will use `/dev/urandom`
|
||||||
|
## as with any other POSIX compliant OS.
|
||||||
|
##
|
||||||
|
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert urandom(0).len == 0
|
doAssert urandom(0).len == 0
|
||||||
@@ -159,7 +164,7 @@ elif defined(windows):
|
|||||||
|
|
||||||
result = randomBytes(addr dest[0], size)
|
result = randomBytes(addr dest[0], size)
|
||||||
|
|
||||||
elif defined(linux):
|
elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten):
|
||||||
# TODO using let, pending bootstrap >= 1.4.0
|
# TODO using let, pending bootstrap >= 1.4.0
|
||||||
var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
|
var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
|
||||||
const syscallHeader = """#include <unistd.h>
|
const syscallHeader = """#include <unistd.h>
|
||||||
|
|||||||
@@ -2121,11 +2121,11 @@ const
|
|||||||
## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard
|
## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard
|
||||||
# see also std/private/since
|
# see also std/private/since
|
||||||
|
|
||||||
NimMinor* {.intdefine.}: int = 5
|
NimMinor* {.intdefine.}: int = 6
|
||||||
## is the minor number of Nim's version.
|
## is the minor number of Nim's version.
|
||||||
## Odd for devel, even for releases.
|
## Odd for devel, even for releases.
|
||||||
|
|
||||||
NimPatch* {.intdefine.}: int = 1
|
NimPatch* {.intdefine.}: int = 2
|
||||||
## is the patch number of Nim's version.
|
## is the patch number of Nim's version.
|
||||||
## Odd for devel, even for releases.
|
## Odd for devel, even for releases.
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ proc c_abort*() {.
|
|||||||
importc: "abort", header: "<stdlib.h>", noSideEffect, noreturn.}
|
importc: "abort", header: "<stdlib.h>", noSideEffect, noreturn.}
|
||||||
|
|
||||||
|
|
||||||
when defined(linux) and defined(amd64):
|
when defined(nimBuiltinSetjmp):
|
||||||
|
type
|
||||||
|
C_JmpBuf* = array[5, pointer]
|
||||||
|
elif defined(linux) and defined(amd64):
|
||||||
type
|
type
|
||||||
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>", bycopy.} = object
|
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>", bycopy.} = object
|
||||||
abi: array[200 div sizeof(clong), clong]
|
abi: array[200 div sizeof(clong), clong]
|
||||||
@@ -92,18 +95,47 @@ when defined(macosx):
|
|||||||
elif defined(haiku):
|
elif defined(haiku):
|
||||||
const SIGBUS* = cint(30)
|
const SIGBUS* = cint(30)
|
||||||
|
|
||||||
when defined(nimSigSetjmp) and not defined(nimStdSetjmp):
|
# "nimRawSetjmp" is defined by default for certain platforms, so we need the
|
||||||
|
# "nimStdSetjmp" escape hatch with it.
|
||||||
|
when defined(nimSigSetjmp):
|
||||||
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
header: "<setjmp.h>", importc: "siglongjmp".}
|
header: "<setjmp.h>", importc: "siglongjmp".}
|
||||||
template c_setjmp*(jmpb: C_JmpBuf): cint =
|
proc c_setjmp*(jmpb: C_JmpBuf): cint =
|
||||||
proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {.
|
proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {.
|
||||||
header: "<setjmp.h>", importc: "sigsetjmp".}
|
header: "<setjmp.h>", importc: "sigsetjmp".}
|
||||||
c_sigsetjmp(jmpb, 0)
|
c_sigsetjmp(jmpb, 0)
|
||||||
|
elif defined(nimBuiltinSetjmp):
|
||||||
|
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) =
|
||||||
|
# Apple's Clang++ has trouble converting array names to pointers, so we need
|
||||||
|
# to be very explicit here.
|
||||||
|
proc c_builtin_longjmp(jmpb: ptr pointer, retval: cint) {.
|
||||||
|
importc: "__builtin_longjmp", nodecl.}
|
||||||
|
# The second parameter needs to be 1 and sometimes the C/C++ compiler checks it.
|
||||||
|
c_builtin_longjmp(unsafeAddr jmpb[0], 1)
|
||||||
|
proc c_setjmp*(jmpb: C_JmpBuf): cint =
|
||||||
|
proc c_builtin_setjmp(jmpb: ptr pointer): cint {.
|
||||||
|
importc: "__builtin_setjmp", nodecl.}
|
||||||
|
c_builtin_setjmp(unsafeAddr jmpb[0])
|
||||||
elif defined(nimRawSetjmp) and not defined(nimStdSetjmp):
|
elif defined(nimRawSetjmp) and not defined(nimStdSetjmp):
|
||||||
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
when defined(windows):
|
||||||
header: "<setjmp.h>", importc: "_longjmp".}
|
# No `_longjmp()` on Windows.
|
||||||
proc c_setjmp*(jmpb: C_JmpBuf): cint {.
|
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
header: "<setjmp.h>", importc: "_setjmp".}
|
header: "<setjmp.h>", importc: "longjmp".}
|
||||||
|
# The Windows `_setjmp()` takes two arguments, with the second being an
|
||||||
|
# undocumented buffer used by the SEH mechanism for stack unwinding.
|
||||||
|
# Mingw-w64 has been trying to get it right for years, but it's still
|
||||||
|
# prone to stack corruption during unwinding, so we disable that by setting
|
||||||
|
# it to NULL.
|
||||||
|
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
|
||||||
|
proc c_setjmp*(jmpb: C_JmpBuf): cint =
|
||||||
|
proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {.
|
||||||
|
header: "<setjmp.h>", importc: "_setjmp".}
|
||||||
|
c_setjmp_win(jmpb, nil)
|
||||||
|
else:
|
||||||
|
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
|
header: "<setjmp.h>", importc: "_longjmp".}
|
||||||
|
proc c_setjmp*(jmpb: C_JmpBuf): cint {.
|
||||||
|
header: "<setjmp.h>", importc: "_setjmp".}
|
||||||
else:
|
else:
|
||||||
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
header: "<setjmp.h>", importc: "longjmp".}
|
header: "<setjmp.h>", importc: "longjmp".}
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ var onUnhandledException*: (proc (errorMsg: string) {.
|
|||||||
## The default is to write a stacktrace to `stderr` and then call `quit(1)`.
|
## The default is to write a stacktrace to `stderr` and then call `quit(1)`.
|
||||||
## Unstable API.
|
## Unstable API.
|
||||||
|
|
||||||
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
|
||||||
when hasSomeStackTrace:
|
when hasSomeStackTrace:
|
||||||
var buf = newStringOfCap(2000)
|
var buf = newStringOfCap(2000)
|
||||||
if e.trace.len == 0:
|
if e.trace.len == 0:
|
||||||
@@ -362,7 +362,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
|||||||
else:
|
else:
|
||||||
var trace = $e.trace
|
var trace = $e.trace
|
||||||
add(buf, trace)
|
add(buf, trace)
|
||||||
`=destroy`(trace)
|
{.gcsafe.}:
|
||||||
|
`=destroy`(trace)
|
||||||
add(buf, "Error: unhandled exception: ")
|
add(buf, "Error: unhandled exception: ")
|
||||||
add(buf, e.msg)
|
add(buf, e.msg)
|
||||||
add(buf, " [")
|
add(buf, " [")
|
||||||
@@ -373,7 +374,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
|||||||
onUnhandledException(buf)
|
onUnhandledException(buf)
|
||||||
else:
|
else:
|
||||||
showErrorMessage2(buf)
|
showErrorMessage2(buf)
|
||||||
`=destroy`(buf)
|
{.gcsafe.}:
|
||||||
|
`=destroy`(buf)
|
||||||
else:
|
else:
|
||||||
# ugly, but avoids heap allocations :-)
|
# ugly, but avoids heap allocations :-)
|
||||||
template xadd(buf, s, slen) =
|
template xadd(buf, s, slen) =
|
||||||
@@ -387,7 +389,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
|||||||
if e.trace.len != 0:
|
if e.trace.len != 0:
|
||||||
var trace = $e.trace
|
var trace = $e.trace
|
||||||
add(buf, trace)
|
add(buf, trace)
|
||||||
`=destroy`(trace)
|
{.gcsafe.}:
|
||||||
|
`=destroy`(trace)
|
||||||
add(buf, "Error: unhandled exception: ")
|
add(buf, "Error: unhandled exception: ")
|
||||||
add(buf, e.msg)
|
add(buf, e.msg)
|
||||||
add(buf, " [")
|
add(buf, " [")
|
||||||
@@ -398,7 +401,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
|||||||
else:
|
else:
|
||||||
showErrorMessage(buf.addr, L)
|
showErrorMessage(buf.addr, L)
|
||||||
|
|
||||||
proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
|
proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} =
|
||||||
if unhandledExceptionHook != nil:
|
if unhandledExceptionHook != nil:
|
||||||
unhandledExceptionHook(e)
|
unhandledExceptionHook(e)
|
||||||
when hostOS != "any":
|
when hostOS != "any":
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
|
|||||||
q.cap = newCap
|
q.cap = newCap
|
||||||
result = q
|
result = q
|
||||||
|
|
||||||
proc shrink*[T](x: var seq[T]; newLen: Natural) =
|
proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} =
|
||||||
when nimvm:
|
when nimvm:
|
||||||
setLen(x, newLen)
|
setLen(x, newLen)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ pkg "cascade"
|
|||||||
pkg "cello"
|
pkg "cello"
|
||||||
pkg "chroma"
|
pkg "chroma"
|
||||||
pkg "chronicles", "nim c -o:chr -r chronicles.nim"
|
pkg "chronicles", "nim c -o:chr -r chronicles.nim"
|
||||||
pkg "chronos", "nim c -r -d:release tests/testall", allowFailure = true # pending https://github.com/nim-lang/Nim/issues/17130
|
pkg "chronos", "nim c -r -d:release tests/testall"
|
||||||
pkg "cligen", "nim c --path:. -r cligen.nim"
|
pkg "cligen", "nim c --path:. -r cligen.nim"
|
||||||
pkg "combparser", "nimble test --gc:orc"
|
pkg "combparser", "nimble test --gc:orc"
|
||||||
pkg "compactdict"
|
pkg "compactdict"
|
||||||
|
|||||||
10
tests/arc/t18971.nim
Normal file
10
tests/arc/t18971.nim
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
discard """
|
||||||
|
cmd: "nim c --gc:arc $file"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type MyObj = ref object
|
||||||
|
|
||||||
|
var o = MyObj()
|
||||||
|
proc x: var MyObj = o
|
||||||
|
|
||||||
|
var o2 = x()
|
||||||
@@ -30,6 +30,7 @@ ok
|
|||||||
true
|
true
|
||||||
copying
|
copying
|
||||||
123
|
123
|
||||||
|
42
|
||||||
closed
|
closed
|
||||||
destroying variable: 20
|
destroying variable: 20
|
||||||
destroying variable: 10
|
destroying variable: 10
|
||||||
@@ -482,3 +483,17 @@ method testMethod(self: BrokenObject) {.base.} =
|
|||||||
|
|
||||||
let mikasa = BrokenObject()
|
let mikasa = BrokenObject()
|
||||||
mikasa.testMethod()
|
mikasa.testMethod()
|
||||||
|
|
||||||
|
# bug #19205
|
||||||
|
type
|
||||||
|
InputSectionBase* = object of RootObj
|
||||||
|
relocations*: seq[int] # traced reference. string has a similar SIGSEGV.
|
||||||
|
InputSection* = object of InputSectionBase
|
||||||
|
|
||||||
|
proc fooz(sec: var InputSectionBase) =
|
||||||
|
if sec of InputSection: # this line SIGSEGV.
|
||||||
|
echo 42
|
||||||
|
|
||||||
|
var sec = create(InputSection)
|
||||||
|
sec[] = InputSection(relocations: newSeq[int]())
|
||||||
|
fooz sec[]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
discard """
|
discard """
|
||||||
output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]'''
|
output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]'''
|
||||||
cmd: "nim c --gc:arc $file"
|
matrix: "--gc:arc"
|
||||||
|
targets: "c cpp"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #13240
|
# bug #13240
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
discard """
|
discard """
|
||||||
cmd: "nim c -d:release $file"
|
cmd: "nim c -d:release $file"
|
||||||
output: 1
|
output: '''1
|
||||||
|
-1'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc bug() : void =
|
proc bug() : void =
|
||||||
@@ -12,3 +13,9 @@ proc bug() : void =
|
|||||||
echo x
|
echo x
|
||||||
|
|
||||||
bug()
|
bug()
|
||||||
|
|
||||||
|
# bug #19051
|
||||||
|
type GInt[T] = int
|
||||||
|
|
||||||
|
var a = 1
|
||||||
|
echo -a
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ discard """
|
|||||||
|
|
||||||
import marshal
|
import marshal
|
||||||
|
|
||||||
let orig: set[char] = {'A'..'Z'}
|
template main() =
|
||||||
let m = $$orig
|
let orig: set[char] = {'A'..'Z'}
|
||||||
let old = to[set[char]](m)
|
let m = $$orig
|
||||||
doAssert orig - old == {}
|
let old = to[set[char]](m)
|
||||||
|
doAssert orig - old == {}
|
||||||
|
|
||||||
|
static: main()
|
||||||
|
main()
|
||||||
|
|||||||
3
tests/converter/mdontleak.nim
Normal file
3
tests/converter/mdontleak.nim
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
converter toBool(x: uint32): bool = x != 0
|
||||||
|
# Note: This convertes is not exported!
|
||||||
10
tests/converter/tdontleak.nim
Normal file
10
tests/converter/tdontleak.nim
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
discard """
|
||||||
|
output: '''5'''
|
||||||
|
joinable: false
|
||||||
|
"""
|
||||||
|
|
||||||
|
import mdontleak
|
||||||
|
# bug #19213
|
||||||
|
|
||||||
|
let a = 5'u32
|
||||||
|
echo a
|
||||||
15
tests/cpp/torc.nim
Normal file
15
tests/cpp/torc.nim
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
discard """
|
||||||
|
targets: "cpp"
|
||||||
|
matrix: "--gc:orc"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import std/options
|
||||||
|
|
||||||
|
# bug #18410
|
||||||
|
type
|
||||||
|
O = object of RootObj
|
||||||
|
val: pointer
|
||||||
|
|
||||||
|
proc p(): Option[O] = none(O)
|
||||||
|
|
||||||
|
doAssert $p() == "none(O)"
|
||||||
63
tests/effects/tnestedprocs.nim
Normal file
63
tests/effects/tnestedprocs.nim
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
discard """
|
||||||
|
cmd: "nim check --hints:off $file"
|
||||||
|
nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects
|
||||||
|
> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2'
|
||||||
|
>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner'
|
||||||
|
|
||||||
|
tnestedprocs.nim(45, 8) Error: 'inner' can have side effects
|
||||||
|
> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6'
|
||||||
|
>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner'
|
||||||
|
|
||||||
|
tnestedprocs.nim(58, 41) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
|
||||||
|
Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
|
||||||
|
'''
|
||||||
|
errormsg: "type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'"
|
||||||
|
"""
|
||||||
|
{.experimental: "strictEffects".}
|
||||||
|
proc outer {.noSideEffect.} =
|
||||||
|
proc inner(p: int) =
|
||||||
|
if p == 0:
|
||||||
|
outer()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer()
|
||||||
|
|
||||||
|
proc outer2 =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
outer2()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer2()
|
||||||
|
|
||||||
|
proc outer3(p: int) {.noSideEffect.} =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
p.outer3()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer3(5)
|
||||||
|
|
||||||
|
proc outer6 =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
outer6()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
echo "bad"
|
||||||
|
|
||||||
|
outer6()
|
||||||
|
|
||||||
|
|
||||||
|
proc outer4 =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
let x: proc () {.noSideEffect.} = outer4
|
||||||
|
x()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer4()
|
||||||
@@ -15,3 +15,15 @@ proc fn(a: int, p1, p2: proc()) {.effectsOf: p1.} =
|
|||||||
proc main() {.raises: [ValueError].} =
|
proc main() {.raises: [ValueError].} =
|
||||||
fn(1, proc()=discard, proc() = raise newException(IOError, "foo"))
|
fn(1, proc()=discard, proc() = raise newException(IOError, "foo"))
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
# bug #19159
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
func mkEnter() =
|
||||||
|
template helper =
|
||||||
|
discard
|
||||||
|
when defined pass:
|
||||||
|
helper()
|
||||||
|
else:
|
||||||
|
let ast = getAst(helper())
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
discard """
|
discard """
|
||||||
|
disabled: "windows" # no sigsetjmp() there
|
||||||
|
matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
|
||||||
output: '''
|
output: '''
|
||||||
|
|
||||||
BEFORE
|
BEFORE
|
||||||
@@ -17,7 +19,7 @@ FINALLY
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
proc no_expcetion =
|
proc no_exception =
|
||||||
try:
|
try:
|
||||||
echo "BEFORE"
|
echo "BEFORE"
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ proc no_expcetion =
|
|||||||
finally:
|
finally:
|
||||||
echo "FINALLY"
|
echo "FINALLY"
|
||||||
|
|
||||||
try: no_expcetion()
|
try: no_exception()
|
||||||
except: echo "RECOVER"
|
except: echo "RECOVER"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
130
tests/exception/texceptions2.nim
Normal file
130
tests/exception/texceptions2.nim
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
discard """
|
||||||
|
disabled: "posix" # already covered by texceptions.nim
|
||||||
|
matrix: "-d:nimStdSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
|
||||||
|
output: '''
|
||||||
|
|
||||||
|
BEFORE
|
||||||
|
FINALLY
|
||||||
|
|
||||||
|
BEFORE
|
||||||
|
EXCEPT
|
||||||
|
FINALLY
|
||||||
|
RECOVER
|
||||||
|
|
||||||
|
BEFORE
|
||||||
|
EXCEPT: IOError: hi
|
||||||
|
FINALLY
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
proc no_exception =
|
||||||
|
try:
|
||||||
|
echo "BEFORE"
|
||||||
|
|
||||||
|
except:
|
||||||
|
echo "EXCEPT"
|
||||||
|
raise
|
||||||
|
|
||||||
|
finally:
|
||||||
|
echo "FINALLY"
|
||||||
|
|
||||||
|
try: no_exception()
|
||||||
|
except: echo "RECOVER"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
proc reraise_in_except =
|
||||||
|
try:
|
||||||
|
echo "BEFORE"
|
||||||
|
raise newException(IOError, "")
|
||||||
|
|
||||||
|
except IOError:
|
||||||
|
echo "EXCEPT"
|
||||||
|
raise
|
||||||
|
|
||||||
|
finally:
|
||||||
|
echo "FINALLY"
|
||||||
|
|
||||||
|
try: reraise_in_except()
|
||||||
|
except: echo "RECOVER"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
proc return_in_except =
|
||||||
|
try:
|
||||||
|
echo "BEFORE"
|
||||||
|
raise newException(IOError, "hi")
|
||||||
|
|
||||||
|
except:
|
||||||
|
echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg()
|
||||||
|
return
|
||||||
|
|
||||||
|
finally:
|
||||||
|
echo "FINALLY"
|
||||||
|
|
||||||
|
try: return_in_except()
|
||||||
|
except: echo "RECOVER"
|
||||||
|
|
||||||
|
block: #10417
|
||||||
|
proc moo() {.noreturn.} = discard
|
||||||
|
|
||||||
|
let bar =
|
||||||
|
try:
|
||||||
|
1
|
||||||
|
except:
|
||||||
|
moo()
|
||||||
|
|
||||||
|
doAssert(bar == 1)
|
||||||
|
|
||||||
|
# Make sure the VM handles the exceptions correctly
|
||||||
|
block:
|
||||||
|
proc fun1(): seq[int] =
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise newException(ValueError, "xx")
|
||||||
|
except:
|
||||||
|
doAssert("xx" == getCurrentExceptionMsg())
|
||||||
|
raise newException(KeyError, "yy")
|
||||||
|
except:
|
||||||
|
doAssert("yy" == getCurrentExceptionMsg())
|
||||||
|
result.add(1212)
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise newException(AssertionDefect, "a")
|
||||||
|
finally:
|
||||||
|
result.add(42)
|
||||||
|
except AssertionDefect:
|
||||||
|
result.add(99)
|
||||||
|
finally:
|
||||||
|
result.add(10)
|
||||||
|
result.add(4)
|
||||||
|
result.add(0)
|
||||||
|
try:
|
||||||
|
result.add(1)
|
||||||
|
except KeyError:
|
||||||
|
result.add(-1)
|
||||||
|
except ValueError:
|
||||||
|
result.add(-1)
|
||||||
|
except IndexDefect:
|
||||||
|
result.add(2)
|
||||||
|
except:
|
||||||
|
result.add(3)
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
result.add(1)
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
result.add(-1)
|
||||||
|
finally:
|
||||||
|
result.add(2)
|
||||||
|
except KeyError:
|
||||||
|
doAssert(false)
|
||||||
|
finally:
|
||||||
|
result.add(3)
|
||||||
|
|
||||||
|
let x1 = fun1()
|
||||||
|
const x2 = fun1()
|
||||||
|
doAssert(x1 == x2)
|
||||||
22
tests/isolate/tisolate2.nim
Normal file
22
tests/isolate/tisolate2.nim
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
discard """
|
||||||
|
errormsg: "expression cannot be isolated: a_to_b(a)"
|
||||||
|
line: 22
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #19013
|
||||||
|
import std/isolation
|
||||||
|
|
||||||
|
type Z = ref object
|
||||||
|
i: int
|
||||||
|
|
||||||
|
type A = object
|
||||||
|
z: Z
|
||||||
|
|
||||||
|
type B = object
|
||||||
|
z: Z
|
||||||
|
|
||||||
|
func a_to_b(a: A): B =
|
||||||
|
result = B(z: a.z)
|
||||||
|
|
||||||
|
let a = A(z: Z(i: 3))
|
||||||
|
let b = isolate(a_to_b(a))
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
|
||||||
|
{.experimental: "flexibleOptionalParams".}
|
||||||
|
|
||||||
# https://github.com/nim-lang/RFCs/issues/405
|
# https://github.com/nim-lang/RFCs/issues/405
|
||||||
|
|
||||||
template main =
|
template main =
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
discard """
|
discard """
|
||||||
output: '''34'''
|
output: '''34'''
|
||||||
|
joinable: false
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.compile("cfunction.c", "-DNUMBER_HERE=34").}
|
{.compile("cfunction.c", "-DNUMBER_HERE=34").}
|
||||||
|
|||||||
2
tests/slice/tdistinct.nim
Normal file
2
tests/slice/tdistinct.nim
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
type Foo = distinct uint64
|
||||||
|
const slice = 0 ..< 42.Foo
|
||||||
@@ -345,3 +345,35 @@ block:
|
|||||||
doAssert c == "18446744073709552000"
|
doAssert c == "18446744073709552000"
|
||||||
else:
|
else:
|
||||||
doAssert c == "18446744073709551615"
|
doAssert c == "18446744073709551615"
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = """
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||||
|
"""
|
||||||
|
|
||||||
|
when not defined(js):
|
||||||
|
try:
|
||||||
|
discard parseJson(a)
|
||||||
|
except JsonParsingError:
|
||||||
|
doAssert getCurrentExceptionMsg().contains("] expected")
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ Some chapter
|
|||||||
|
|
||||||
Level2
|
Level2
|
||||||
------
|
------
|
||||||
|
|
||||||
Level3
|
Level3
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@ Some chapter
|
|||||||
|
|
||||||
More
|
More
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Another
|
Another
|
||||||
-------
|
-------
|
||||||
|
|
||||||
@@ -683,7 +683,7 @@ Test1
|
|||||||
test "RST line blocks":
|
test "RST line blocks":
|
||||||
let input2 = dedent"""
|
let input2 = dedent"""
|
||||||
Paragraph1
|
Paragraph1
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Paragraph2"""
|
Paragraph2"""
|
||||||
@@ -704,7 +704,7 @@ Test1
|
|||||||
# check that '| ' with a few spaces is still parsed as new line
|
# check that '| ' with a few spaces is still parsed as new line
|
||||||
let input4 = dedent"""
|
let input4 = dedent"""
|
||||||
| xxx
|
| xxx
|
||||||
|
|
|
|
||||||
| zzz"""
|
| zzz"""
|
||||||
|
|
||||||
let output4 = input4.toHtml
|
let output4 = input4.toHtml
|
||||||
@@ -1548,3 +1548,30 @@ suite "RST/Code highlight":
|
|||||||
|
|
||||||
check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
|
check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
|
||||||
strip(expected)
|
strip(expected)
|
||||||
|
|
||||||
|
|
||||||
|
suite "invalid targets":
|
||||||
|
test "invalid image target":
|
||||||
|
let input1 = dedent """.. image:: /images/myimage.jpg
|
||||||
|
:target: https://bar.com
|
||||||
|
:alt: Alt text for the image"""
|
||||||
|
let output1 = input1.toHtml
|
||||||
|
check output1 == """<a class="reference external" href="https://bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
|
||||||
|
|
||||||
|
let input2 = dedent """.. image:: /images/myimage.jpg
|
||||||
|
:target: javascript://bar.com
|
||||||
|
:alt: Alt text for the image"""
|
||||||
|
let output2 = input2.toHtml
|
||||||
|
check output2 == """<img src="/images/myimage.jpg" alt="Alt text for the image"/>"""
|
||||||
|
|
||||||
|
let input3 = dedent """.. image:: /images/myimage.jpg
|
||||||
|
:target: bar.com
|
||||||
|
:alt: Alt text for the image"""
|
||||||
|
let output3 = input3.toHtml
|
||||||
|
check output3 == """<a class="reference external" href="bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
|
||||||
|
|
||||||
|
test "invalid links":
|
||||||
|
check("(([Nim](https://nim-lang.org/)))".toHtml ==
|
||||||
|
"""((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
|
||||||
|
check("(([Nim](javascript://nim-lang.org/)))".toHtml ==
|
||||||
|
"""((<a class="reference external" href="">Nim</a>))""")
|
||||||
|
|||||||
@@ -290,10 +290,10 @@ block: # bug #10815
|
|||||||
|
|
||||||
const a = P()
|
const a = P()
|
||||||
doAssert $a == ""
|
doAssert $a == ""
|
||||||
|
|
||||||
when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734
|
when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734
|
||||||
block:
|
block:
|
||||||
type CharSet {.union.} = object
|
type CharSet {.union.} = object
|
||||||
cs: set[char]
|
cs: set[char]
|
||||||
vs: array[4, uint64]
|
vs: array[4, uint64]
|
||||||
const a = Charset(cs: {'a'..'z'})
|
const a = Charset(cs: {'a'..'z'})
|
||||||
@@ -553,3 +553,22 @@ block: # bug #8015
|
|||||||
doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)"
|
doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)"
|
||||||
doAssert viaProc.table[1].handler() == 100
|
doAssert viaProc.table[1].handler() == 100
|
||||||
doAssert viaProc.table[2].handler() == 200
|
doAssert viaProc.table[2].handler() == 200
|
||||||
|
|
||||||
|
|
||||||
|
# bug #19198
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
Foo[n: static int] = int
|
||||||
|
|
||||||
|
block:
|
||||||
|
static:
|
||||||
|
let x = int 1
|
||||||
|
echo x.type # Foo
|
||||||
|
|
||||||
|
block:
|
||||||
|
static:
|
||||||
|
let x = int 1
|
||||||
|
let y = x + 1
|
||||||
|
# Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect]
|
||||||
|
echo y
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ tut2.rst
|
|||||||
tut3.rst
|
tut3.rst
|
||||||
nimc.rst
|
nimc.rst
|
||||||
niminst.rst
|
niminst.rst
|
||||||
gc.rst
|
mm.rst
|
||||||
""".splitWhitespace().mapIt("doc" / it)
|
""".splitWhitespace().mapIt("doc" / it)
|
||||||
|
|
||||||
doc0 = """
|
doc0 = """
|
||||||
@@ -298,6 +298,12 @@ proc nim2pdf(src: string, dst: string, nimArgs: string) =
|
|||||||
# `>` should work on windows, if not, we can use `execCmdEx`
|
# `>` should work on windows, if not, we can use `execCmdEx`
|
||||||
let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell]
|
let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell]
|
||||||
exec(cmd) # on error, user can inspect `xelatexLog`
|
exec(cmd) # on error, user can inspect `xelatexLog`
|
||||||
|
if i == 1: # build .ind file
|
||||||
|
var texFileBase = texFile
|
||||||
|
texFileBase.removeSuffix(".tex")
|
||||||
|
let cmd = "makeindex $# > $#" % [
|
||||||
|
texFileBase.quoteShell, xelatexLog.quoteShell]
|
||||||
|
exec(cmd)
|
||||||
moveFile(texFile.changeFileExt("pdf"), dst)
|
moveFile(texFile.changeFileExt("pdf"), dst)
|
||||||
|
|
||||||
proc buildPdfDoc*(nimArgs, destPath: string) =
|
proc buildPdfDoc*(nimArgs, destPath: string) =
|
||||||
|
|||||||
Reference in New Issue
Block a user