mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 02:43:41 +00:00
Compare commits
75 Commits
pr_distinc
...
v1.6.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7994556f38 | ||
|
|
8c9e88f520 | ||
|
|
7e52a57121 | ||
|
|
35c812fda1 | ||
|
|
47888c18f7 | ||
|
|
a8e040ec30 | ||
|
|
2fb1c80f42 | ||
|
|
e1f3c74bdc | ||
|
|
52d2ff601b | ||
|
|
41b71487af | ||
|
|
3d3b34473b | ||
|
|
fc0aec6f1b | ||
|
|
7cafd22377 | ||
|
|
9aff19f51a | ||
|
|
bc823b6487 | ||
|
|
3d3d790c63 | ||
|
|
a90cabbe40 | ||
|
|
2539d7a862 | ||
|
|
30737b3e7f | ||
|
|
984691bb67 | ||
|
|
5f70b1ab53 | ||
|
|
afa4bc34b4 | ||
|
|
0648cde117 | ||
|
|
980ec713da | ||
|
|
26ed4e5413 | ||
|
|
161736ceb3 | ||
|
|
ce6fa79858 | ||
|
|
f2e7e5d899 | ||
|
|
d4de5d32bc | ||
|
|
efdb180f62 | ||
|
|
095202e218 | ||
|
|
f4e41e6c4f | ||
|
|
8aec198abc | ||
|
|
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 |
47
changelog.md
47
changelog.md
@@ -4,14 +4,54 @@
|
||||
## 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
|
||||
|
||||
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
|
||||
filename argument for more informative errors.
|
||||
- Module `colors` expanded with missing colors from the CSS color standard.
|
||||
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
@@ -21,5 +61,12 @@
|
||||
|
||||
## 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
|
||||
@@ -501,7 +501,7 @@ type
|
||||
nfHasComment # node has a comment
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43)
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
@@ -673,7 +673,7 @@ type
|
||||
mSwap, mIsNil, mArrToSeq,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mMove, mWasMoved, mDestroy, mTrace,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mReset,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
mOrdinal, mIterableType,
|
||||
@@ -2101,3 +2101,11 @@ proc skipAddr*(n: PNode): PNode {.inline.} =
|
||||
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
||||
assert n.kind == nkTypeClassTy
|
||||
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}
|
||||
|
||||
@@ -76,7 +76,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
if typ[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ[0]):
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if params != nil: pl.add(~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
||||
@@ -214,7 +214,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
else:
|
||||
var a: TLoc
|
||||
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:
|
||||
if reifiedOpenArray(n):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
@@ -376,8 +376,8 @@ proc genParams(p: BProc, ri: PNode, typ: PType): Rope =
|
||||
if not needTmp[i - 1]:
|
||||
needTmp[i - 1] = potentialAlias(n, potentialWrites)
|
||||
getPotentialWrites(ri[i], false, potentialWrites)
|
||||
if ri[i].kind == nkHiddenAddr:
|
||||
# Optimization: don't use a temp, if we would only take the adress anyway
|
||||
if ri[i].kind in {nkHiddenAddr, nkAddr}:
|
||||
# Optimization: don't use a temp, if we would only take the address anyway
|
||||
needTmp[i - 1] = false
|
||||
|
||||
for i in 1..<ri.len:
|
||||
@@ -439,7 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
let rawProc = getClosureType(p.module, typ, clHalf)
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
if typ[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ[0]):
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if ri.len > 1: pl.add(~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
||||
@@ -737,7 +737,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
pl.add(~": ")
|
||||
pl.add(genArg(p, ri[i], param, ri))
|
||||
if typ[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ[0]):
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if ri.len > 1: pl.add(~" ")
|
||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||
if d.k in {locTemp, locNone}:
|
||||
|
||||
@@ -1741,6 +1741,13 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
|
||||
# use the dynamic type stored at offset 0:
|
||||
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) =
|
||||
var a: TLoc
|
||||
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 mDestroy: genDestroy(p, e)
|
||||
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
|
||||
of mAccessTypeField: genAccessTypeField(p, e, d)
|
||||
of mSlice: genSlice(p, e, d)
|
||||
of mTrace: discard "no code to generate"
|
||||
else:
|
||||
|
||||
@@ -32,13 +32,20 @@ proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
|
||||
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
||||
|
||||
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
if n.kind == nkEmpty: return false
|
||||
if isInvalidReturnType(conf, n.typ):
|
||||
# var v = f()
|
||||
# is transformed into: var v; f(addr v)
|
||||
# where 'f' **does not** initialize the result!
|
||||
return false
|
||||
result = true
|
||||
if n.kind == nkEmpty:
|
||||
result = false
|
||||
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
|
||||
if isInvalidReturnType(conf, n[0].typ, true):
|
||||
# var v = f()
|
||||
# is transformed into: var v; f(addr v)
|
||||
# where 'f' **does not** initialize the result!
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
elif isInvalidReturnType(conf, n.typ, false):
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc inExceptBlockLen(p: BProc): int =
|
||||
for x in p.nestedTryStmts:
|
||||
@@ -1356,8 +1363,19 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
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"):
|
||||
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:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$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
|
||||
if result == nil:
|
||||
result = s.name.s.mangle.rope
|
||||
result.add "_"
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_"
|
||||
result.add rope s.itemId.item
|
||||
@@ -215,12 +215,19 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||
(typ[0] == nil) or isPureObject(typ))
|
||||
|
||||
proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
||||
proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
|
||||
# Arrays and sets cannot be returned by a C procedure, because C is
|
||||
# such a poor programming language.
|
||||
# We exclude records with refs too. This enhances efficiency and
|
||||
# is necessary for proper code generation of assignments.
|
||||
if rettype == nil: result = true
|
||||
var rettype = typ
|
||||
var isAllowedCall = true
|
||||
if isProc:
|
||||
rettype = rettype[0]
|
||||
isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall}
|
||||
if rettype == nil or (isAllowedCall and
|
||||
getSize(conf, rettype) > conf.target.floatSize*3):
|
||||
result = true
|
||||
else:
|
||||
case mapType(conf, rettype, skResult)
|
||||
of ctArray:
|
||||
@@ -256,11 +263,11 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
|
||||
# see `testCodegenABICheck` for example error message it generates
|
||||
|
||||
|
||||
proc fillResult(conf: ConfigRef; param: PNode) =
|
||||
proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
|
||||
fillLoc(param.sym.loc, locParam, param, ~"Result",
|
||||
OnStack)
|
||||
let t = param.sym.typ
|
||||
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
|
||||
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype):
|
||||
incl(param.sym.loc.flags, lfIndirect)
|
||||
param.sym.loc.storage = OnUnknown
|
||||
|
||||
@@ -425,7 +432,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false) =
|
||||
params = nil
|
||||
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
|
||||
if t[0] == nil or isInvalidReturnType(m.config, t):
|
||||
rettype = ~"void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t[0], check, skResult)
|
||||
@@ -460,7 +467,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
|
||||
inc(j)
|
||||
arr = arr[0].skipTypes({tySink})
|
||||
if t[0] != nil and isInvalidReturnType(m.config, t[0]):
|
||||
if t[0] != nil and isInvalidReturnType(m.config, t):
|
||||
var arr = t[0]
|
||||
if params != nil: params.add(", ")
|
||||
if mapReturnType(m.config, t[0]) != ctArray:
|
||||
@@ -582,7 +589,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||
|
||||
if typ.kind == tyObject:
|
||||
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", [])
|
||||
else:
|
||||
if optTinyRtti in m.config.globalOptions:
|
||||
|
||||
@@ -48,8 +48,13 @@ proc addForwardedProc(m: BModule, prc: PSym) =
|
||||
m.g.forwardedProcs.add(prc)
|
||||
|
||||
proc findPendingModule(m: BModule, s: PSym): BModule =
|
||||
let ms = s.itemId.module #getModule(s)
|
||||
result = m.g.modules[ms]
|
||||
# TODO fixme
|
||||
if m.config.symbolFiles == v2Sf:
|
||||
let ms = s.itemId.module #getModule(s)
|
||||
result = m.g.modules[ms]
|
||||
else:
|
||||
var ms = getModule(s)
|
||||
result = m.g.modules[ms.position]
|
||||
|
||||
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
|
||||
result.k = k
|
||||
@@ -154,6 +159,11 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
||||
inc(i)
|
||||
result.add newCall(formatValue, resVar, args[num])
|
||||
inc(num)
|
||||
of '^':
|
||||
flushStrLit()
|
||||
inc(i)
|
||||
result.add newCall(formatValue, resVar, args[^1])
|
||||
inc(num)
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
@@ -363,7 +373,8 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||
else:
|
||||
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
|
||||
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
|
||||
if mode == constructRefObj:
|
||||
let objType = t.skipTypes(abstractInst+{tyRef})
|
||||
@@ -442,8 +453,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}:
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
if containsGarbageCollectedRef(loc.t):
|
||||
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:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use nimZeroMem for temporary values for performance if we can
|
||||
@@ -1022,7 +1039,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
let resNode = prc.ast[resultPos]
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(m.config, prc.typ[0]):
|
||||
if not isInvalidReturnType(m.config, prc.typ):
|
||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
@@ -1036,7 +1053,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
else:
|
||||
fillResult(p.config, resNode)
|
||||
fillResult(p.config, resNode, prc.typ)
|
||||
assignParam(p, res, prc.typ[0])
|
||||
# We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
|
||||
# to 'unsureAsgn(result, x)'
|
||||
@@ -1359,7 +1376,7 @@ proc genMainProc(m: BModule) =
|
||||
"}$N$N"
|
||||
|
||||
MainProcs =
|
||||
"\tNimMain();$N"
|
||||
"\t$^NimMain();$N"
|
||||
|
||||
MainProcsWithResult =
|
||||
MainProcs & ("\treturn $1nim_program_result;$N")
|
||||
@@ -1369,7 +1386,7 @@ proc genMainProc(m: BModule) =
|
||||
"}$N$N"
|
||||
|
||||
NimMainProc =
|
||||
"N_CDECL(void, NimMain)(void) {$N" &
|
||||
"N_CDECL(void, $5NimMain)(void) {$N" &
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"$4" &
|
||||
"\tinner = NimMainInner;$N" &
|
||||
@@ -1449,28 +1466,27 @@ proc genMainProc(m: BModule) =
|
||||
if optGenGuiApp in m.config.globalOptions:
|
||||
const nimMain = WinNimMain
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
else:
|
||||
const nimMain = WinNimDllMain
|
||||
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:
|
||||
const nimMain = GenodeNimMain
|
||||
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:
|
||||
const nimMain = PosixNimDllMain
|
||||
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:
|
||||
const nimMain = NimMainBody
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
|
||||
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
|
||||
else:
|
||||
const nimMain = NimMainBody
|
||||
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 m.config.cppCustomNamespace.len > 0:
|
||||
@@ -1480,23 +1496,22 @@ proc genMainProc(m: BModule) =
|
||||
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in m.config.globalOptions:
|
||||
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:
|
||||
const otherMain = WinCDllMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
elif m.config.target.targetOS == osGenode:
|
||||
const otherMain = ComponentConstruct
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
elif optGenDynLib in m.config.globalOptions:
|
||||
const otherMain = PosixCDllMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
elif m.config.target.targetOS == osStandalone:
|
||||
const otherMain = StandaloneCMain
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
||||
else:
|
||||
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:
|
||||
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
|
||||
@@ -1878,7 +1893,7 @@ proc writeHeader(m: BModule) =
|
||||
|
||||
if optGenDynLib in m.config.globalOptions:
|
||||
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()
|
||||
result.addf("#endif /* $1 */$n", [guard])
|
||||
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 =
|
||||
case switch.normalize
|
||||
of "gc":
|
||||
of "gc", "mm":
|
||||
case arg.normalize
|
||||
of "boehm": result = conf.selectedGC == gcBoehm
|
||||
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)
|
||||
of "project":
|
||||
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
|
||||
of "gc":
|
||||
of "gc", "mm":
|
||||
if conf.backend == backendJs: return # for: bug #16033
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
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 -)
|
||||
handleStdinInput(conf)
|
||||
of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
|
||||
of "nimmainprefix": conf.nimMainPrefix = arg
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
|
||||
@@ -138,3 +138,5 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasHintAll")
|
||||
defineSymbol("nimHasTrace")
|
||||
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:
|
||||
if filter:
|
||||
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:
|
||||
if filter:
|
||||
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:
|
||||
if filter:
|
||||
loadPackedSym(c.graph, it)
|
||||
|
||||
@@ -77,6 +77,17 @@ proc canAlias*(arg, ret: PType): bool =
|
||||
var marker = initIntSet()
|
||||
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 =
|
||||
if types.containsTyRef(n.typ):
|
||||
# XXX Maybe require that 'n.typ' is acyclic. This is not much
|
||||
@@ -96,7 +107,11 @@ proc checkIsolate*(n: PNode): bool =
|
||||
else:
|
||||
let argType = n[i].typ
|
||||
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
|
||||
result = true
|
||||
of nkIfStmt, nkIfExpr:
|
||||
|
||||
@@ -178,7 +178,7 @@ const
|
||||
proc mapType(typ: PType): TJSTypeKind =
|
||||
let t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
of tyVar, tyRef, tyPtr, tyLent:
|
||||
of tyVar, tyRef, tyPtr:
|
||||
if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
|
||||
result = etyObject
|
||||
else:
|
||||
@@ -186,7 +186,8 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||
of tyPointer:
|
||||
# treat a tyPointer like a typed pointer to an array of bytes
|
||||
result = etyBaseIndex
|
||||
of tyRange, tyDistinct, tyOrdinal, tyProxy:
|
||||
of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
|
||||
# tyLent is no-op as JS has pass-by-reference semantics
|
||||
result = mapType(t[0])
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
|
||||
of tyBool: result = etyBool
|
||||
@@ -1060,14 +1061,14 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
xtyp = etySeq
|
||||
case xtyp
|
||||
of etySeq:
|
||||
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyObject:
|
||||
if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
@@ -1092,10 +1093,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
|
||||
lineF(p, "$1 = $2;$n", [a.address, b.res])
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
elif a.typ == etyBaseIndex:
|
||||
# array indexing may not map to var type
|
||||
if b.address != nil:
|
||||
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||
else:
|
||||
lineF(p, "$1 = $2;$n", [a.address, b.res])
|
||||
else:
|
||||
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
|
||||
else:
|
||||
elif b.address != nil:
|
||||
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||
else:
|
||||
lineF(p, "$1 = $2;$n", [a.address, b.res])
|
||||
else:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
|
||||
@@ -1442,13 +1451,17 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
if s.loc.r == nil:
|
||||
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
|
||||
r.res = s.loc.r
|
||||
if mapType(p, s.typ) == etyBaseIndex:
|
||||
r.address = s.loc.r
|
||||
r.res = s.loc.r & "_Idx"
|
||||
else:
|
||||
r.res = s.loc.r
|
||||
r.kind = resVal
|
||||
|
||||
proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let it = n[0]
|
||||
let t = mapType(p, it.typ)
|
||||
if t == etyObject:
|
||||
if t == etyObject or it.typ.kind == tyLent:
|
||||
gen(p, it, r)
|
||||
else:
|
||||
var a: TCompRes
|
||||
@@ -1689,7 +1702,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
result = putToSeq("0", indirect)
|
||||
of tyFloat..tyFloat128:
|
||||
result = putToSeq("0.0", indirect)
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned:
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
|
||||
result = createVar(p, lastSon(typ), indirect)
|
||||
of tySet:
|
||||
result = putToSeq("{}", indirect)
|
||||
@@ -1731,7 +1744,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
createObjInitList(p, t, initIntSet(), initList)
|
||||
result = ("({$1})") % [initList]
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyVar, tyPtr, tyLent, tyRef, tyPointer:
|
||||
of tyVar, tyPtr, tyRef, tyPointer:
|
||||
if mapType(p, t) == etyBaseIndex:
|
||||
result = putToSeq("[null, 0]", indirect)
|
||||
else:
|
||||
@@ -2380,16 +2393,17 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
if prc.typ[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast[resultPos].sym
|
||||
let mname = mangleName(p.module, resultSym)
|
||||
if not isIndirect(resultSym) and
|
||||
let returnAddress = not isIndirect(resultSym) and
|
||||
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
|
||||
mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
mapType(p, resultSym.typ) == etyBaseIndex
|
||||
if returnAddress:
|
||||
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
|
||||
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||
else:
|
||||
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||
resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
|
||||
gen(p, prc.ast[resultPos], a)
|
||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
if returnAddress:
|
||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
@@ -2565,8 +2579,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkObjConstr: genObjConstr(p, n, r)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
genAddr(p, n, r)
|
||||
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
|
||||
if n.typ.kind in {tyLent}:
|
||||
gen(p, n[0], r)
|
||||
else:
|
||||
genAddr(p, n, r)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
if n.typ.kind in {tyLent}:
|
||||
gen(p, n[0], r)
|
||||
else:
|
||||
genDeref(p, n, r)
|
||||
of nkBracketExpr: genArrayAccess(p, n, r)
|
||||
of nkDotExpr: genFieldAccess(p, n, r)
|
||||
of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r)
|
||||
|
||||
@@ -941,6 +941,12 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
incl result.flags, sfFromGeneric
|
||||
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;
|
||||
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)
|
||||
else:
|
||||
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
|
||||
completePartialOp(g, idgen.module, typ, kind, result)
|
||||
|
||||
|
||||
@@ -207,7 +207,8 @@ type
|
||||
strictNotNil,
|
||||
overloadableEnums,
|
||||
strictEffects,
|
||||
unicodeOperators
|
||||
unicodeOperators,
|
||||
flexibleOptionalParams
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
@@ -389,6 +390,7 @@ type
|
||||
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
|
||||
severity: Severity) {.closure, gcsafe.}
|
||||
cppCustomNamespace*: string
|
||||
nimMainPrefix*: string
|
||||
vmProfileData*: ProfileData
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
|
||||
@@ -582,10 +582,10 @@ proc parsePar(p: var Parser): PNode =
|
||||
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
#| | 'when' | 'var' | 'mixin'
|
||||
#| par = '(' optInd
|
||||
#| ( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
#| | ';' (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
#| ( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
#| | ';' (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
#| | pragmaStmt
|
||||
#| | simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
|
||||
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
#| optPar ')'
|
||||
#
|
||||
@@ -1877,7 +1877,7 @@ proc parseEnum(p: var Parser): PNode =
|
||||
|
||||
var symPragma = a
|
||||
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)
|
||||
symPragma = newNodeP(nkPragmaExpr, p)
|
||||
symPragma.add(a)
|
||||
|
||||
@@ -31,7 +31,7 @@ const
|
||||
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wDelegator, wGcSafe,
|
||||
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
|
||||
wRequires, wEnsures}
|
||||
wRequires, wEnsures, wEnforceNoRaises}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
@@ -1237,6 +1237,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
pragmaProposition(c, it)
|
||||
of wEnsures:
|
||||
pragmaEnsures(c, it)
|
||||
of wEnforceNoRaises:
|
||||
sym.flags.incl sfNeverRaises
|
||||
else: invalidPragma(c, it)
|
||||
elif comesFromPush and whichKeyword(ident) != wInvalid:
|
||||
discard "ignore the .push pragma; it doesn't apply"
|
||||
|
||||
@@ -1414,7 +1414,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||
ty = ty.lastSon
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink})
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink, tyStatic})
|
||||
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
|
||||
@@ -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 mBitnotI:
|
||||
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:
|
||||
result = newIntNodeT(bitnot(getInt(a)), 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 mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
|
||||
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)
|
||||
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)
|
||||
# echo "subU: ", val, " n: ", n, " result: ", val
|
||||
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)
|
||||
of mModU:
|
||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
||||
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
|
||||
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
|
||||
if argB != Zero:
|
||||
result = newIntNodeT(argA mod argB, n, idgen, g)
|
||||
of mDivU:
|
||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
||||
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
|
||||
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
|
||||
if argB != Zero:
|
||||
result = newIntNodeT(argA div argB, 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:
|
||||
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
||||
let initResult = semConstructTypeAux(c, constrCtx, {})
|
||||
assert constrCtx.missingFields.len > 0
|
||||
localError(c.config, info,
|
||||
"The $1 type doesn't have a default value. The following fields must " &
|
||||
"be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
||||
if constrCtx.missingFields.len > 0:
|
||||
localError(c.config, info,
|
||||
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
||||
elif objType.kind == tyDistinct:
|
||||
localError(c.config, info,
|
||||
"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):
|
||||
assumeTheWorst(tracked, n, op)
|
||||
gcsafeAndSideeffectCheck()
|
||||
else:
|
||||
if strictEffects in tracked.c.features and a.kind == nkSym and
|
||||
a.sym.kind in routineKinds:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
else:
|
||||
mergeRaises(tracked, effectList[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList[tagEffects], n)
|
||||
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:
|
||||
trackOperandForIndirectCall(tracked, n[i], op, i, a)
|
||||
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:
|
||||
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:
|
||||
track(tracked, n[i])
|
||||
|
||||
|
||||
@@ -2075,6 +2075,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
incl(s.flags, sfWasForwarded)
|
||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||
sideEffectsCheck(c, s)
|
||||
|
||||
closeScope(c) # close scope for parameters
|
||||
# c.currentScope = oldScope
|
||||
popOwner(c)
|
||||
|
||||
@@ -2461,7 +2461,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
if m.callee.n[f].kind != nkSym:
|
||||
internalError(c.config, n[a].info, "matches")
|
||||
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
|
||||
m.firstMismatch.kind = kTypeMismatch
|
||||
if containsOrIncl(marker, formal.position) and container.isNil:
|
||||
|
||||
@@ -196,6 +196,11 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo
|
||||
accum.offset = szUnknownSize
|
||||
|
||||
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``
|
||||
assert typ != nil
|
||||
let hasSize = typ.size != szUncomputedSize
|
||||
@@ -258,14 +263,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
|
||||
of tyArray:
|
||||
computeSizeAlign(conf, typ[1])
|
||||
let elemSize = typ[1].size
|
||||
let elemSize = typ[1].size
|
||||
let len = lengthOrd(conf, typ[0])
|
||||
if elemSize < 0:
|
||||
typ.size = elemSize
|
||||
typ.align = int16(elemSize)
|
||||
elif len < 0:
|
||||
typ.size = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
else:
|
||||
typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize)
|
||||
typ.align = typ[1].align
|
||||
@@ -445,6 +450,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
typ.size = szUnknownSize
|
||||
typ.align = 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:
|
||||
typ.size = szUnknownSize
|
||||
typ.align = szUnknownSize
|
||||
|
||||
@@ -57,6 +57,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
of tyVar, tyLent:
|
||||
if kind in {skProc, skFunc, skConst} and (views notin c.features):
|
||||
result = t
|
||||
elif taIsOpenArray in flags:
|
||||
result = t
|
||||
elif t.kind == tyLent and ((kind != skResult and views notin c.features) or
|
||||
kind == skParam): # lent can't be used as parameters.
|
||||
result = t
|
||||
@@ -231,7 +233,7 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind =
|
||||
case t.kind
|
||||
of tyVar:
|
||||
result = mutableView
|
||||
of tyLent, tyOpenArray:
|
||||
of tyLent, tyOpenArray, tyVarargs:
|
||||
result = immutableView
|
||||
of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned,
|
||||
tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic:
|
||||
|
||||
@@ -1700,3 +1700,6 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
|
||||
result = allowPointerToChar
|
||||
else:
|
||||
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,
|
||||
# so dest cannot be a cursor:
|
||||
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:
|
||||
var roots: seq[(PSym, int)]
|
||||
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
|
||||
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) =
|
||||
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:
|
||||
dest.intVal = int(src.floatVal)
|
||||
else:
|
||||
let srcDist = (sizeof(src.intVal) - styp.size) * 8
|
||||
let destDist = (sizeof(dest.intVal) - desttyp.size) * 8
|
||||
let srcSize = getSize(c.config, styp)
|
||||
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)
|
||||
value = (value shl srcDist) shr srcDist
|
||||
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})
|
||||
# uint is uint64 in the VM, we we only need to mask the result for
|
||||
# other unsigned types:
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(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) =
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
# uint is uint64 in the VM, we we only need to mask the result for
|
||||
# other unsigned types:
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
|
||||
(t.kind in {tyUInt, tyInt} and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
(t.kind in {tyUInt, tyInt} and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
|
||||
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
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)
|
||||
# genNarrowU modified
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
||||
c.gABC(n, opcSignExtend, dest, TRegister(t.size*8))
|
||||
let size = getSize(c.config, t)
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(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 mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
||||
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)
|
||||
#genNarrowU modified, do not narrow signed types
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
let size = getSize(c.config, t)
|
||||
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:
|
||||
genConv(c, n, n[1], dest)
|
||||
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:
|
||||
var x = copyNode(a[i][0])
|
||||
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(", ")
|
||||
storeAny(s, t.lastSon, x, stored, conf)
|
||||
inc x.intVal
|
||||
@@ -231,7 +232,6 @@ proc loadAny(p: var JsonParser, t: PType,
|
||||
result = newNode(nkCurly)
|
||||
while p.kind != jsonArrayEnd and p.kind != jsonEof:
|
||||
result.add loadAny(p, t.lastSon, tab, cache, conf, idgen)
|
||||
next(p)
|
||||
if p.kind == jsonArrayEnd: next(p)
|
||||
else: raiseParseErr(p, "']' end of array expected")
|
||||
of tyPtr, tyRef:
|
||||
|
||||
@@ -86,7 +86,7 @@ type
|
||||
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",
|
||||
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
|
||||
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
|
||||
wLiftLocals = "liftlocals",
|
||||
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
|
||||
|
||||
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
|
||||
wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default",
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
cppDefine "errno"
|
||||
cppDefine "unix"
|
||||
|
||||
# mangle the macro names in nimbase.h
|
||||
cppDefine "NAN_INFINITY"
|
||||
cppDefine "INF"
|
||||
cppDefine "NAN"
|
||||
|
||||
when defined(nimStrictMode):
|
||||
# xxx add more flags here, and use `-d:nimStrictMode` in more contexts in CI.
|
||||
|
||||
|
||||
@@ -44,10 +44,12 @@ path="$lib/core"
|
||||
path="$lib/pure"
|
||||
|
||||
@if not windows:
|
||||
nimblepath="/opt/nimble/pkgs2/"
|
||||
nimblepath="/opt/nimble/pkgs/"
|
||||
@else:
|
||||
# TODO:
|
||||
@end
|
||||
nimblepath="$home/.nimble/pkgs2/"
|
||||
nimblepath="$home/.nimble/pkgs/"
|
||||
|
||||
# Syncronize with compiler/commands.specialDefine
|
||||
@@ -154,9 +156,6 @@ nimblepath="$home/.nimble/pkgs/"
|
||||
# Configuration for the GNU C/C++ compiler:
|
||||
@if windows:
|
||||
#gcc.path = r"$nim\dist\mingw\bin"
|
||||
@if gcc or tcc:
|
||||
tlsEmulation:on
|
||||
@end
|
||||
@end
|
||||
|
||||
gcc.maxerrorsimpl = "-fmax-errors=3"
|
||||
|
||||
@@ -55,6 +55,11 @@ doc.file = """
|
||||
%
|
||||
% 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}
|
||||
\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{graphicx}
|
||||
|
||||
\newcommand{\nimindexterm}[2]{#2\label{#1}}
|
||||
\usepackage{makeidx}
|
||||
\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}}
|
||||
\makeindex
|
||||
|
||||
\usepackage{dingbat} % for \carriagereturn, etc
|
||||
\usepackage{fvextra} % for code blocks (works better than original fancyvrb)
|
||||
@@ -241,5 +248,8 @@ doc.file = """
|
||||
\maketitle
|
||||
|
||||
$content
|
||||
|
||||
\printindex
|
||||
|
||||
\end{document}
|
||||
"""
|
||||
|
||||
@@ -122,8 +122,9 @@ Advanced options:
|
||||
--skipUserCfg:on|off do not read the user's configuration file
|
||||
--skipParentCfg:on|off do not read the parent dirs' configuration files
|
||||
--skipProjCfg:on|off do not read the project's configuration file
|
||||
--gc:refc|arc|orc|markAndSweep|boehm|go|none|regions
|
||||
select the GC to use; default is 'refc'
|
||||
--mm:orc|arc|refc|markAndSweep|boehm|go|none|regions
|
||||
select which memory management to use; default is 'refc'
|
||||
recommended is 'orc'
|
||||
--exceptions:setjmp|cpp|goto|quirky
|
||||
select the exception handling implementation
|
||||
--index:on|off turn index file generation on|off
|
||||
@@ -134,6 +135,8 @@ Advanced options:
|
||||
--cppCompileToNamespace:namespace
|
||||
use the provided namespace for the generated C++ code,
|
||||
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
|
||||
--expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations
|
||||
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
|
||||
--sinkInference:on|off turn sink parameter inference on|off (default: on)
|
||||
--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
|
||||
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
|
||||
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-
|
||||
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
|
||||
sure to run a recent version of Node.js (at least 12.0).
|
||||
|
||||
|
||||
|
||||
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
|
||||
`importc pragma <manual.html#foreign-function-interface-importc-pragma>`_.
|
||||
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
|
||||
<manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||
`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
|
||||
which will likely make your program crash at runtime.
|
||||
|
||||
The Nim compiler can generate a C interface header through the `--header`:option:
|
||||
command-line switch. The generated header will contain all the exported
|
||||
symbols and the `NimMain` proc which you need to call before any other
|
||||
Nim code.
|
||||
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
|
||||
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||
|
||||
|
||||
Nim invocation example from C
|
||||
@@ -269,9 +267,10 @@ Create a ``maths.c`` file with the following content:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "fib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern int fib(int a);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
NimMain();
|
||||
@@ -286,13 +285,12 @@ program:
|
||||
|
||||
.. 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
|
||||
|
||||
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
|
||||
object files into a final binary, and explicitly generate a header file for C
|
||||
integration. All the generated files are placed into the ``nimcache``
|
||||
generating a `main()`:c: function in the generated files and to avoid linking the
|
||||
object files into a final binary. All the generated files are placed into the ``nimcache``
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
The Nim compiler will handle linking the source files generated in the
|
||||
``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
|
||||
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.} =
|
||||
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`.
|
||||
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
|
||||
@@ -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
|
||||
`malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping
|
||||
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
|
||||
--opt:none|speed|size optimize not at all or for speed|size
|
||||
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
|
||||
generate a console app|GUI app|DLL|static library
|
||||
-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:
|
||||
`nim r --eval:'for a in stdin.lines: echo a'`
|
||||
--fullhelp show all command line switches
|
||||
|
||||
@@ -43,7 +43,7 @@ written as:
|
||||
dealloc(x.data)
|
||||
|
||||
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.
|
||||
if x.data != nil:
|
||||
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
|
||||
-------------
|
||||
|
||||
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
|
||||
structures which are constructed with the help of the container might leak
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -256,7 +256,7 @@ The general pattern in using `=destroy` with `=trace` looks like:
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
@@ -558,10 +558,10 @@ for expressions of type `lent T` or of type `var T`.
|
||||
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.
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
@@ -22,8 +22,8 @@ The documentation consists of several documents:
|
||||
- | `Tools documentation <tools.html>`_
|
||||
| Description of some tools that come with the standard distribution.
|
||||
|
||||
- | `GC <gc.html>`_
|
||||
| Additional documentation about Nim's multi-paradigm memory management strategies
|
||||
- | `Memory management <mm.html>`_
|
||||
| Additional documentation about Nim's memory management strategies
|
||||
| and how to operate them in a realtime setting.
|
||||
|
||||
- | `Source code filters <filters.html>`_
|
||||
|
||||
@@ -37,10 +37,10 @@ parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
|
||||
| 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
| 'when' | 'var' | 'mixin'
|
||||
par = '(' optInd
|
||||
( &parKeyw (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
| ';' (ifExpr \ complexOrSimpleStmt) ^+ ';'
|
||||
( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
| ';' (ifExpr / complexOrSimpleStmt) ^+ ';'
|
||||
| pragmaStmt
|
||||
| simpleExpr ( ('=' expr (';' (ifExpr \ complexOrSimpleStmt) ^+ ';' )? )
|
||||
| simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
|
||||
| (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
optPar ')'
|
||||
literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
|
||||
@@ -1899,7 +1899,7 @@ A small example:
|
||||
cast uncheckedAssign
|
||||
--------------------
|
||||
|
||||
Some restrictions for case objects can be disabled via a `{.cast(unsafeAssign).}` section:
|
||||
Some restrictions for case objects can be disabled via a `{.cast(uncheckedAssign).}` section:
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
@@ -5002,7 +5002,7 @@ be used:
|
||||
|
||||
See also:
|
||||
|
||||
- `Shared heap memory management <gc.html>`_.
|
||||
- `Shared heap memory management <mm.html>`_.
|
||||
|
||||
|
||||
|
||||
@@ -6699,11 +6699,11 @@ statement, as seen in stack backtraces:
|
||||
if not cond:
|
||||
# change run-time line information of the 'raise' statement:
|
||||
{.line: instantiationInfo().}:
|
||||
raise newException(EAssertionFailed, msg)
|
||||
raise newException(AssertionDefect, msg)
|
||||
|
||||
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,
|
||||
`system.InstantiationInfo()` is used.
|
||||
`system.instantiationInfo()` is used.
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
-------------------
|
||||
@@ -371,6 +387,10 @@ of your program.
|
||||
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
|
||||
=========================
|
||||
|
||||
@@ -399,6 +419,9 @@ of your program.
|
||||
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.
|
||||
|
||||
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
|
||||
=====================================
|
||||
@@ -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:
|
||||
|
||||
.. 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"
|
||||
|
||||
or setup a ``nim.cfg`` file like so::
|
||||
|
||||
#nim.cfg
|
||||
--gc:orc
|
||||
--mm:orc
|
||||
--d:nimAllocPagesViaMalloc
|
||||
--passC="-I$DEVKITPRO/libnx/include"
|
||||
--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
|
||||
own memory manager, albeit prefixing each allocation with
|
||||
its size to support clearing memory on reallocation.
|
||||
This only works with `--gc:none`:option:,
|
||||
`--gc:arc`:option: and `--gc:orc`:option:.
|
||||
This only works with `--mm:none`:option:,
|
||||
`--mm:arc`:option: and `--mm:orc`:option:.
|
||||
`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.
|
||||
`logGC` Enable GC logging to stdout.
|
||||
`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
|
||||
|
||||
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
|
||||
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`
|
||||
is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc`
|
||||
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
|
||||
========================
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
====================
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
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
|
||||
=======================
|
||||
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`.
|
||||
5
koch.nim
5
koch.nim
@@ -559,7 +559,8 @@ proc runCI(cmd: string) =
|
||||
|
||||
let batchParam = "--batch:$1" % "NIM_TESTAMENT_BATCH".getEnv("_")
|
||||
if getEnv("NIM_TEST_PACKAGES", "0") == "1":
|
||||
execFold("Test selected Nimble packages", "nim r testament/testament $# pcat nimble-packages" % batchParam)
|
||||
nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release")
|
||||
execFold("Test selected Nimble packages", "testament $# pcat nimble-packages" % batchParam)
|
||||
else:
|
||||
buildTools()
|
||||
|
||||
@@ -604,7 +605,7 @@ proc runCI(cmd: string) =
|
||||
when not defined(bsd):
|
||||
if not doUseCpp:
|
||||
# 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) =
|
||||
csource("-d:danger" & cmdLineRest)
|
||||
|
||||
@@ -1718,8 +1718,8 @@ proc extractDocCommentsAndRunnables*(n: NimNode): NimNode =
|
||||
case ni.kind
|
||||
of nnkCommentStmt:
|
||||
result.add ni
|
||||
of nnkCall:
|
||||
if ni[0].kind == nnkIdent and ni[0].strVal == "runnableExamples":
|
||||
of nnkCall, nnkCommand:
|
||||
if ni[0].kind == nnkIdent and ni[0].eqIdent "runnableExamples":
|
||||
result.add ni
|
||||
else: break
|
||||
else: break
|
||||
|
||||
@@ -522,19 +522,22 @@ iterator split*(s: string, sep: Regex; maxsplit = -1): string =
|
||||
@["", "this", "is", "an", "example", ""]
|
||||
var last = 0
|
||||
var splits = maxsplit
|
||||
var x: int
|
||||
var x = -1
|
||||
if len(s) == 0:
|
||||
last = 1
|
||||
if matchLen(s, sep, 0) == 0:
|
||||
x = 0
|
||||
while last <= len(s):
|
||||
var first = last
|
||||
var sepLen = 1
|
||||
if x == 0:
|
||||
inc(last)
|
||||
while last < len(s):
|
||||
x = matchLen(s, sep, last)
|
||||
if x >= 0:
|
||||
sepLen = x
|
||||
break
|
||||
inc(last)
|
||||
if x == 0:
|
||||
if last >= len(s): break
|
||||
inc last
|
||||
if splits == 0: last = len(s)
|
||||
yield substr(s, first, last-1)
|
||||
if splits == 0: break
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
## can be done by simply searching for [footnoteName].
|
||||
|
||||
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
||||
algorithm, parseutils, std/strbasics
|
||||
algorithm, parseutils, std/strbasics, strscans
|
||||
|
||||
import ../../std/private/since
|
||||
|
||||
@@ -406,7 +406,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||
var term = ""
|
||||
renderAux(d, n, term)
|
||||
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])
|
||||
|
||||
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])
|
||||
|
||||
|
||||
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) =
|
||||
dispA(d.target, result,
|
||||
"<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:
|
||||
var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl)
|
||||
safeProtocol(target)
|
||||
|
||||
if target.len > 0:
|
||||
# `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>
|
||||
@@ -915,7 +927,8 @@ proc getField1Int(d: PDoc, n: PRstNode, fieldName: string): int =
|
||||
let nChars = parseInt(value, number)
|
||||
if nChars == 0:
|
||||
if value.len == 0:
|
||||
err("field $1 requires an argument" % [fieldName])
|
||||
# use a good default value:
|
||||
result = 1
|
||||
else:
|
||||
err("field $1 requires an integer, but '$2' was given" %
|
||||
[fieldName, value])
|
||||
@@ -1187,6 +1200,7 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external
|
||||
d.escMode = emUrl
|
||||
renderRstToOut(d, link, linkStr)
|
||||
d.escMode = mode
|
||||
safeProtocol(linkStr)
|
||||
var textStr = ""
|
||||
renderRstToOut(d, text, textStr)
|
||||
if external:
|
||||
|
||||
@@ -733,7 +733,7 @@ when defined(windows) or defined(nimdoc):
|
||||
|
||||
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
|
||||
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
|
||||
## corresponding to that connection and the remote address of the client.
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
@@ -800,7 +800,7 @@ when defined(windows) or defined(nimdoc):
|
||||
|
||||
var ol = newCustom()
|
||||
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 errcode == OSErrorCode(-1):
|
||||
completeAccept()
|
||||
|
||||
@@ -87,20 +87,6 @@ proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] =
|
||||
## * `toDeque proc <#toDeque,openArray[T]>`_
|
||||
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.} =
|
||||
## Returns the number of elements of `deq`.
|
||||
result = deq.count
|
||||
@@ -303,6 +289,20 @@ proc addLast*[T](deq: var Deque[T], item: sink T) =
|
||||
deq.data[deq.tail] = item
|
||||
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.} =
|
||||
## Returns the first element of `deq`, but does not remove it from the deque.
|
||||
##
|
||||
|
||||
@@ -531,11 +531,12 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} =
|
||||
ci
|
||||
assert s == [0, 1, 0, 1, 0, 1]
|
||||
|
||||
if a.tail != nil:
|
||||
a.tail.next = b.head
|
||||
a.tail = b.tail
|
||||
if a.head == nil:
|
||||
a.head = b.head
|
||||
if b.head != nil:
|
||||
if a.head == nil:
|
||||
a.head = b.head
|
||||
else:
|
||||
a.tail.next = b.head
|
||||
a.tail = b.tail
|
||||
if a.addr != b.addr:
|
||||
b.head = nil
|
||||
b.tail = nil
|
||||
@@ -675,12 +676,12 @@ proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} =
|
||||
assert s == [0, 1, 0, 1, 0, 1]
|
||||
|
||||
if b.head != nil:
|
||||
b.head.prev = a.tail
|
||||
if a.tail != nil:
|
||||
a.tail.next = b.head
|
||||
a.tail = b.tail
|
||||
if a.head == nil:
|
||||
a.head = b.head
|
||||
if a.head == nil:
|
||||
a.head = b.head
|
||||
else:
|
||||
b.head.prev = a.tail
|
||||
a.tail.next = b.head
|
||||
a.tail = b.tail
|
||||
if a.addr != b.addr:
|
||||
b.head = nil
|
||||
b.tail = nil
|
||||
@@ -739,6 +740,8 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.disc
|
||||
if prev.next == nil:
|
||||
return false
|
||||
prev.next = n.next
|
||||
if L.tail == n:
|
||||
L.tail = prev # update tail if we removed the last node
|
||||
true
|
||||
|
||||
proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
||||
|
||||
@@ -353,8 +353,8 @@ const
|
||||
("lightcoral", colLightCoral),
|
||||
("lightcyan", colLightCyan),
|
||||
("lightgoldenrodyellow", colLightGoldenRodYellow),
|
||||
("lightgrey", colLightGrey),
|
||||
("lightgreen", colLightGreen),
|
||||
("lightgrey", colLightGrey),
|
||||
("lightpink", colLightPink),
|
||||
("lightsalmon", colLightSalmon),
|
||||
("lightseagreen", colLightSeaGreen),
|
||||
|
||||
@@ -293,19 +293,16 @@ else:
|
||||
AtomicInt32 {.importc: "_Atomic NI32".} = int32
|
||||
AtomicInt64 {.importc: "_Atomic NI64".} = int64
|
||||
|
||||
template atomicType*(T: typedesc[Trivial]): untyped =
|
||||
# Maps the size of a trivial type to it's internal atomic type
|
||||
when sizeof(T) == 1: AtomicInt8
|
||||
elif sizeof(T) == 2: AtomicInt16
|
||||
elif sizeof(T) == 4: AtomicInt32
|
||||
elif sizeof(T) == 8: AtomicInt64
|
||||
|
||||
type
|
||||
AtomicFlag* {.importc: "atomic_flag", size: 1.} = object
|
||||
|
||||
Atomic*[T] = object
|
||||
when T is Trivial:
|
||||
value: T.atomicType
|
||||
# Maps the size of a trivial type to it's internal atomic type
|
||||
when sizeof(T) == 1: value: AtomicInt8
|
||||
elif sizeof(T) == 2: value: AtomicInt16
|
||||
elif sizeof(T) == 4: value: AtomicInt32
|
||||
elif sizeof(T) == 8: value: AtomicInt64
|
||||
else:
|
||||
nonAtomicValue: T
|
||||
guard: AtomicFlag
|
||||
@@ -364,11 +361,11 @@ else:
|
||||
cast[T](atomic_fetch_xor_explicit(addr(location.value), cast[nonAtomicType(T)](value), order))
|
||||
|
||||
template withLock[T: not Trivial](location: var Atomic[T]; order: MemoryOrder; body: untyped): untyped =
|
||||
while location.guard.testAndSet(moAcquire): discard
|
||||
while testAndSet(location.guard, moAcquire): discard
|
||||
try:
|
||||
body
|
||||
finally:
|
||||
location.guard.clear(moRelease)
|
||||
clear(location.guard, moRelease)
|
||||
|
||||
proc load*[T: not Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} =
|
||||
withLock(location, order):
|
||||
|
||||
@@ -523,7 +523,7 @@ proc generateHeaders(requestUrl: Uri, httpMethod: HttpMethod, headers: HttpHeade
|
||||
# Proxy auth header.
|
||||
if not proxy.isNil and proxy.auth != "":
|
||||
let auth = base64.encode(proxy.auth)
|
||||
add(result, "Proxy-Authorization: basic " & auth & httpNewLine)
|
||||
add(result, "Proxy-Authorization: Basic " & auth & httpNewLine)
|
||||
|
||||
for key, val in headers:
|
||||
add(result, key & ": " & val & httpNewLine)
|
||||
@@ -673,7 +673,7 @@ proc reportProgress(client: HttpClient | AsyncHttpClient,
|
||||
progress: BiggestInt) {.multisync.} =
|
||||
client.contentProgress += progress
|
||||
client.oneSecondProgress += progress
|
||||
if (getMonoTime() - client.lastProgressReport).inSeconds > 1:
|
||||
if (getMonoTime() - client.lastProgressReport).inSeconds >= 1:
|
||||
if not client.onProgressChanged.isNil:
|
||||
await client.onProgressChanged(client.contentTotal,
|
||||
client.contentProgress,
|
||||
|
||||
@@ -202,6 +202,8 @@ type
|
||||
of JArray:
|
||||
elems*: seq[JsonNode]
|
||||
|
||||
const DepthLimit = 1000
|
||||
|
||||
proc newJString*(s: string): JsonNode =
|
||||
## Creates a new `JString JsonNode`.
|
||||
result = JsonNode(kind: JString, str: s)
|
||||
@@ -437,7 +439,7 @@ macro `%*`*(x: untyped): untyped =
|
||||
## `%` for every element.
|
||||
result = toJsonImpl(x)
|
||||
|
||||
proc `==`*(a, b: JsonNode): bool =
|
||||
proc `==`*(a, b: JsonNode): bool {.noSideEffect.} =
|
||||
## Check two nodes for equality
|
||||
if a.isNil:
|
||||
if b.isNil: return true
|
||||
@@ -464,12 +466,16 @@ proc `==`*(a, b: JsonNode): bool =
|
||||
if a.fields.len != b.fields.len: return false
|
||||
for key, val in a.fields:
|
||||
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
|
||||
|
||||
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
|
||||
case n.kind
|
||||
of JArray:
|
||||
@@ -845,7 +851,7 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
|
||||
for key, val in mpairs(node.fields):
|
||||
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`.
|
||||
case p.tok
|
||||
of tkString:
|
||||
@@ -881,6 +887,8 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
||||
result = newJNull()
|
||||
discard getTok(p)
|
||||
of tkCurlyLe:
|
||||
if depth > DepthLimit:
|
||||
raiseParseErr(p, "}")
|
||||
result = newJObject()
|
||||
discard getTok(p)
|
||||
while p.tok != tkCurlyRi:
|
||||
@@ -889,16 +897,18 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
||||
var key = p.a
|
||||
discard getTok(p)
|
||||
eat(p, tkColon)
|
||||
var val = parseJson(p, rawIntegers, rawFloats)
|
||||
var val = parseJson(p, rawIntegers, rawFloats, depth+1)
|
||||
result[key] = val
|
||||
if p.tok != tkComma: break
|
||||
discard getTok(p)
|
||||
eat(p, tkCurlyRi)
|
||||
of tkBracketLe:
|
||||
if depth > DepthLimit:
|
||||
raiseParseErr(p, "]")
|
||||
result = newJArray()
|
||||
discard getTok(p)
|
||||
while p.tok != tkBracketRi:
|
||||
result.add(parseJson(p, rawIntegers, rawFloats))
|
||||
result.add(parseJson(p, rawIntegers, rawFloats, depth+1))
|
||||
if p.tok != tkComma: break
|
||||
discard getTok(p)
|
||||
eat(p, tkBracketRi)
|
||||
|
||||
@@ -1618,7 +1618,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
|
||||
## used. Therefore if `socket` contains something in its buffer this
|
||||
## function will make no effort to return it.
|
||||
template adaptRecvFromToDomain(domain: Domain) =
|
||||
var addrLen = sizeof(sockAddress).SockLen
|
||||
var addrLen = SockLen(sizeof(sockAddress))
|
||||
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
|
||||
cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
|
||||
|
||||
|
||||
@@ -3263,7 +3263,11 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
|
||||
## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows,
|
||||
## or a 'Stat' structure on posix
|
||||
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.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
|
||||
formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
|
||||
|
||||
@@ -574,6 +574,9 @@ template formatValue(result: var string; value: cstring; specifier: string) =
|
||||
result.add value
|
||||
|
||||
proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
template missingCloseChar =
|
||||
error("invalid format string: missing closing character '" & closeChar & "'")
|
||||
|
||||
if openChar == ':' or closeChar == ':':
|
||||
error "openChar and closeChar must not be ':'"
|
||||
var i = 0
|
||||
@@ -618,6 +621,8 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
let start = i
|
||||
inc i
|
||||
i += f.skipWhitespace(i)
|
||||
if i == f.len:
|
||||
missingCloseChar
|
||||
if f[i] == closeChar or f[i] == ':':
|
||||
result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i]))
|
||||
else:
|
||||
@@ -627,6 +632,9 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
subexpr.add f[i]
|
||||
inc i
|
||||
|
||||
if i == f.len:
|
||||
missingCloseChar
|
||||
|
||||
var x: NimNode
|
||||
try:
|
||||
x = parseExpr(subexpr)
|
||||
@@ -639,10 +647,10 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
while i < f.len and f[i] != closeChar:
|
||||
options.add f[i]
|
||||
inc i
|
||||
if i == f.len:
|
||||
missingCloseChar
|
||||
if f[i] == closeChar:
|
||||
inc i
|
||||
else:
|
||||
doAssert false, "invalid format string: missing '}'"
|
||||
result.add newCall(formatSym, res, x, newLit(options))
|
||||
elif f[i] == closeChar:
|
||||
if i<f.len-1 and f[i+1] == closeChar:
|
||||
|
||||
@@ -1859,7 +1859,7 @@ func find*(s: string, sub: char, start: Natural = 0, last = 0): int {.rtl,
|
||||
## Use `s[start..last].rfind` for a `start`-origin index.
|
||||
##
|
||||
## See also:
|
||||
## * `rfind func<#rfind,string,char,Natural>`_
|
||||
## * `rfind func<#rfind,string,char,Natural,int>`_
|
||||
## * `replace func<#replace,string,char,char>`_
|
||||
let last = if last == 0: s.high else: last
|
||||
when nimvm:
|
||||
@@ -1887,7 +1887,7 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = 0): int {.
|
||||
## Use `s[start..last].find` for a `start`-origin index.
|
||||
##
|
||||
## See also:
|
||||
## * `rfind func<#rfind,string,set[char],Natural>`_
|
||||
## * `rfind func<#rfind,string,set[char],Natural,int>`_
|
||||
## * `multiReplace func<#multiReplace,string,varargs[]>`_
|
||||
let last = if last == 0: s.high else: last
|
||||
for i in int(start)..last:
|
||||
@@ -1904,7 +1904,7 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl,
|
||||
## Use `s[start..last].find` for a `start`-origin index.
|
||||
##
|
||||
## See also:
|
||||
## * `rfind func<#rfind,string,string,Natural>`_
|
||||
## * `rfind func<#rfind,string,string,Natural,int>`_
|
||||
## * `replace func<#replace,string,string,string>`_
|
||||
if sub.len > s.len - start: return -1
|
||||
if sub.len == 1: return find(s, sub[0], start, last)
|
||||
|
||||
@@ -78,14 +78,17 @@ func addIntImpl(result: var string, x: uint64) {.inline.} =
|
||||
dec 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)
|
||||
else:
|
||||
when not defined(js): addIntImpl(result, x)
|
||||
else:
|
||||
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`.
|
||||
runnableExamples:
|
||||
var s = "foo"
|
||||
@@ -110,5 +113,5 @@ proc addInt*(result: var string; x: int64) =
|
||||
addChars(result, numToString(x))
|
||||
else: impl()
|
||||
|
||||
proc addInt*(result: var string; x: int) {.inline.} =
|
||||
proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} =
|
||||
addInt(result, int64(x))
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
## .. _randomFillSync: https://nodejs.org/api/crypto.html#crypto_crypto_randomfillsync_buffer_offset_size
|
||||
## .. _/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:
|
||||
doAssert urandom(0).len == 0
|
||||
@@ -159,7 +164,7 @@ elif defined(windows):
|
||||
|
||||
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
|
||||
var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
|
||||
const syscallHeader = """#include <unistd.h>
|
||||
|
||||
@@ -1189,8 +1189,8 @@ proc align(address, alignment: int): int =
|
||||
else:
|
||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||
|
||||
when defined(nimdoc):
|
||||
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}
|
||||
when defined(nimNoQuit):
|
||||
proc quit*(errorcode: int = QuitSuccess) = discard "ignoring quit"
|
||||
## Stops the program immediately with an exit code.
|
||||
##
|
||||
## Before stopping the program the "exit procedures" are called in the
|
||||
@@ -1214,6 +1214,9 @@ when defined(nimdoc):
|
||||
## It does *not* call the garbage collector to free all the memory,
|
||||
## unless an `addExitProc` proc calls `GC_fullCollect <#GC_fullCollect>`_.
|
||||
|
||||
elif defined(nimdoc):
|
||||
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}
|
||||
|
||||
elif defined(genode):
|
||||
include genode/env
|
||||
|
||||
@@ -2121,11 +2124,11 @@ const
|
||||
## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard
|
||||
# see also std/private/since
|
||||
|
||||
NimMinor* {.intdefine.}: int = 5
|
||||
NimMinor* {.intdefine.}: int = 6
|
||||
## is the minor number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 1
|
||||
NimPatch* {.intdefine.}: int = 4
|
||||
## is the patch number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@ proc c_abort*() {.
|
||||
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
|
||||
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>", bycopy.} = object
|
||||
abi: array[200 div sizeof(clong), clong]
|
||||
@@ -92,18 +95,47 @@ when defined(macosx):
|
||||
elif defined(haiku):
|
||||
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) {.
|
||||
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 {.
|
||||
header: "<setjmp.h>", importc: "sigsetjmp".}
|
||||
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):
|
||||
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".}
|
||||
when defined(windows):
|
||||
# No `_longjmp()` on Windows.
|
||||
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
||||
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:
|
||||
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
|
||||
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)`.
|
||||
## Unstable API.
|
||||
|
||||
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
|
||||
when hasSomeStackTrace:
|
||||
var buf = newStringOfCap(2000)
|
||||
if e.trace.len == 0:
|
||||
@@ -362,7 +362,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||
else:
|
||||
var trace = $e.trace
|
||||
add(buf, trace)
|
||||
`=destroy`(trace)
|
||||
{.gcsafe.}:
|
||||
`=destroy`(trace)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
@@ -373,7 +374,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||
onUnhandledException(buf)
|
||||
else:
|
||||
showErrorMessage2(buf)
|
||||
`=destroy`(buf)
|
||||
{.gcsafe.}:
|
||||
`=destroy`(buf)
|
||||
else:
|
||||
# ugly, but avoids heap allocations :-)
|
||||
template xadd(buf, s, slen) =
|
||||
@@ -387,7 +389,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||
if e.trace.len != 0:
|
||||
var trace = $e.trace
|
||||
add(buf, trace)
|
||||
`=destroy`(trace)
|
||||
{.gcsafe.}:
|
||||
`=destroy`(trace)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
@@ -398,7 +401,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||
else:
|
||||
showErrorMessage(buf.addr, L)
|
||||
|
||||
proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
|
||||
proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} =
|
||||
if unhandledExceptionHook != nil:
|
||||
unhandledExceptionHook(e)
|
||||
when hostOS != "any":
|
||||
|
||||
@@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
|
||||
q.cap = newCap
|
||||
result = q
|
||||
|
||||
proc shrink*[T](x: var seq[T]; newLen: Natural) =
|
||||
proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} =
|
||||
when nimvm:
|
||||
setLen(x, newLen)
|
||||
else:
|
||||
|
||||
@@ -35,7 +35,7 @@ proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true, allowFailu
|
||||
|
||||
pkg "alea", allowFailure = true
|
||||
pkg "argparse"
|
||||
pkg "arraymancer", "nim c tests/tests_cpu.nim", allowFailure = true
|
||||
pkg "arraymancer", "nim c tests/tests_cpu.nim"
|
||||
pkg "ast_pattern_matching", "nim c -r --oldgensym:on tests/test1.nim", allowFailure = true
|
||||
pkg "asyncthreadpool"
|
||||
pkg "awk"
|
||||
@@ -51,11 +51,11 @@ pkg "cascade"
|
||||
pkg "cello"
|
||||
pkg "chroma"
|
||||
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 "combparser", "nimble test --gc:orc"
|
||||
pkg "compactdict"
|
||||
pkg "comprehension", "nimble test", "https://github.com/alehander42/comprehension"
|
||||
pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension"
|
||||
pkg "criterion", allowFailure = true # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed)
|
||||
pkg "datamancer"
|
||||
pkg "dashing", "nim c tests/functional.nim"
|
||||
@@ -63,8 +63,8 @@ pkg "delaunay"
|
||||
pkg "docopt"
|
||||
pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
|
||||
pkg "elvis"
|
||||
pkg "fidget", allowFailure = true
|
||||
pkg "fragments", "nim c -r fragments/dsl.nim"
|
||||
pkg "fidget"
|
||||
pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115
|
||||
pkg "fusion"
|
||||
pkg "gara"
|
||||
pkg "glob"
|
||||
@@ -91,7 +91,7 @@ pkg "memo"
|
||||
pkg "msgpack4nim", "nim c -r tests/test_spec.nim"
|
||||
pkg "nake", "nim c nakefile.nim"
|
||||
pkg "neo", "nim c -d:blas=openblas tests/all.nim"
|
||||
pkg "nesm", "nimble tests", allowFailure = true # notice plural 'tests'
|
||||
pkg "nesm", "nimble tests" # notice plural 'tests'
|
||||
pkg "netty"
|
||||
pkg "nico", allowFailure = true
|
||||
pkg "nicy", "nim c -r src/nicy.nim"
|
||||
@@ -103,7 +103,7 @@ pkg "nimfp", "nim c -o:nfp -r src/fp.nim"
|
||||
pkg "nimgame2", "nim c -d:nimLegacyConvEnumEnum nimgame2/nimgame.nim"
|
||||
# XXX Doesn't work with deprecated 'randomize', will create a PR.
|
||||
pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim"
|
||||
pkg "nimlsp"
|
||||
pkg "nimlsp", allowFailure = true
|
||||
pkg "nimly", "nim c -r tests/test_readme_example.nim"
|
||||
pkg "nimongo", "nimble test_ci", allowFailure = true
|
||||
pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true
|
||||
@@ -115,9 +115,9 @@ pkg "nimterop", "nimble minitest"
|
||||
pkg "nimwc", "nim c nimwc.nim"
|
||||
pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true
|
||||
pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
||||
pkg "norm", "nim c -r tests/sqlite/trows.nim"
|
||||
pkg "norm", "testament r tests/sqlite/trows.nim"
|
||||
pkg "npeg", "nimble testarc"
|
||||
pkg "numericalnim", "nim c -r tests/test_integrate.nim"
|
||||
pkg "numericalnim", "nimble nimCI"
|
||||
pkg "optionsutils"
|
||||
pkg "ormin", "nim c -o:orminn ormin.nim"
|
||||
pkg "parsetoml"
|
||||
@@ -157,7 +157,7 @@ pkg "tiny_sqlite"
|
||||
pkg "unicodedb", "nim c -d:release -r tests/tests.nim"
|
||||
pkg "unicodeplus", "nim c -d:release -r tests/tests.nim"
|
||||
pkg "unpack"
|
||||
pkg "weave", "nimble test_gc_arc", allowFailure = true
|
||||
pkg "weave", "nimble test_gc_arc"
|
||||
pkg "websocket", "nim c websocket.nim"
|
||||
pkg "winim", "nim c winim.nim"
|
||||
pkg "with"
|
||||
|
||||
@@ -103,7 +103,7 @@ type
|
||||
|
||||
proc getCmd*(s: TSpec): string =
|
||||
if s.cmd.len == 0:
|
||||
result = compilerPrefix & " $target --hints:on -d:testing --clearNimblePath --nimblePath:build/deps/pkgs $options $file"
|
||||
result = compilerPrefix & " $target --hints:on -d:testing --nimblePath:build/deps/pkgs $options $file"
|
||||
else:
|
||||
result = s.cmd
|
||||
|
||||
|
||||
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()
|
||||
22
tests/arc/tarc_orc.nim
Normal file
22
tests/arc/tarc_orc.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
discard """
|
||||
matrix: "--mm:arc; --mm:orc"
|
||||
"""
|
||||
|
||||
block:
|
||||
type
|
||||
PublicKey = array[32, uint8]
|
||||
PrivateKey = array[64, uint8]
|
||||
|
||||
proc ed25519_create_keypair(publicKey: ptr PublicKey; privateKey: ptr PrivateKey) =
|
||||
publicKey[][0] = uint8(88)
|
||||
|
||||
type
|
||||
KeyPair = object
|
||||
public: PublicKey
|
||||
private: PrivateKey
|
||||
|
||||
proc initKeyPair(): KeyPair =
|
||||
ed25519_create_keypair(result.public.addr, result.private.addr)
|
||||
|
||||
let keys = initKeyPair()
|
||||
doAssert keys.public[0] == 88
|
||||
@@ -30,6 +30,7 @@ ok
|
||||
true
|
||||
copying
|
||||
123
|
||||
42
|
||||
closed
|
||||
destroying variable: 20
|
||||
destroying variable: 10
|
||||
@@ -482,3 +483,17 @@ method testMethod(self: BrokenObject) {.base.} =
|
||||
|
||||
let mikasa = BrokenObject()
|
||||
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 """
|
||||
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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
discard """
|
||||
cmd: "nim c -d:release $file"
|
||||
output: 1
|
||||
output: '''1
|
||||
-1'''
|
||||
"""
|
||||
|
||||
proc bug() : void =
|
||||
@@ -12,3 +13,9 @@ proc bug() : void =
|
||||
echo x
|
||||
|
||||
bug()
|
||||
|
||||
# bug #19051
|
||||
type GInt[T] = int
|
||||
|
||||
var a = 1
|
||||
echo -a
|
||||
|
||||
@@ -4,7 +4,11 @@ discard """
|
||||
|
||||
import marshal
|
||||
|
||||
let orig: set[char] = {'A'..'Z'}
|
||||
let m = $$orig
|
||||
let old = to[set[char]](m)
|
||||
doAssert orig - old == {}
|
||||
template main() =
|
||||
let orig: set[char] = {'A'..'Z'}
|
||||
let m = $$orig
|
||||
let old = to[set[char]](m)
|
||||
doAssert orig - old == {}
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
16
tests/ccgbugs/tmangle.nim
Normal file
16
tests/ccgbugs/tmangle.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
block:
|
||||
proc hello() =
|
||||
let NAN_INFINITY = 12
|
||||
doAssert NAN_INFINITY == 12
|
||||
let INF = "2.0"
|
||||
doAssert INF == "2.0"
|
||||
let NAN = 2.3
|
||||
doAssert NAN == 2.3
|
||||
|
||||
hello()
|
||||
|
||||
block:
|
||||
proc hello(NAN: float) =
|
||||
doAssert NAN == 2.0
|
||||
|
||||
hello(2.0)
|
||||
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].} =
|
||||
fn(1, proc()=discard, proc() = raise newException(IOError, "foo"))
|
||||
main()
|
||||
|
||||
# bug #19159
|
||||
|
||||
import macros
|
||||
|
||||
func mkEnter() =
|
||||
template helper =
|
||||
discard
|
||||
when defined pass:
|
||||
helper()
|
||||
else:
|
||||
let ast = getAst(helper())
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
discard """
|
||||
disabled: "windows" # no sigsetjmp() there
|
||||
matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
|
||||
output: '''
|
||||
|
||||
BEFORE
|
||||
@@ -17,7 +19,7 @@ FINALLY
|
||||
|
||||
echo ""
|
||||
|
||||
proc no_expcetion =
|
||||
proc no_exception =
|
||||
try:
|
||||
echo "BEFORE"
|
||||
|
||||
@@ -28,7 +30,7 @@ proc no_expcetion =
|
||||
finally:
|
||||
echo "FINALLY"
|
||||
|
||||
try: no_expcetion()
|
||||
try: no_exception()
|
||||
except: echo "RECOVER"
|
||||
|
||||
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))
|
||||
33
tests/js/tlent.nim
Normal file
33
tests/js/tlent.nim
Normal file
@@ -0,0 +1,33 @@
|
||||
discard """
|
||||
output: '''
|
||||
hmm
|
||||
100
|
||||
hmm
|
||||
100
|
||||
'''
|
||||
"""
|
||||
|
||||
# #16800
|
||||
|
||||
type A = object
|
||||
b: int
|
||||
var t = A(b: 100)
|
||||
block:
|
||||
proc getValues: lent int =
|
||||
echo "hmm"
|
||||
result = t.b
|
||||
echo getValues()
|
||||
block:
|
||||
proc getValues: lent int =
|
||||
echo "hmm"
|
||||
t.b
|
||||
echo getValues()
|
||||
|
||||
when false: # still an issue, #16908
|
||||
template main =
|
||||
iterator fn[T](a:T): lent T = yield a
|
||||
let a = @[10]
|
||||
for b in fn(a): echo b
|
||||
|
||||
static: main()
|
||||
main()
|
||||
@@ -17,22 +17,26 @@ proc main =
|
||||
main()
|
||||
|
||||
template main2 = # bug #15958
|
||||
when defined(js):
|
||||
proc sameAddress[T](a, b: T): bool {.importjs: "(# === #)".}
|
||||
else:
|
||||
template sameAddress(a, b): bool = a.unsafeAddr == b.unsafeAddr
|
||||
proc byLent[T](a: T): lent T = a
|
||||
let a = [11,12]
|
||||
let b = @[21,23]
|
||||
let ss = {1, 2, 3, 5}
|
||||
doAssert byLent(a) == [11,12]
|
||||
doAssert byLent(a).unsafeAddr == a.unsafeAddr
|
||||
doAssert sameAddress(byLent(a), a)
|
||||
doAssert byLent(b) == @[21,23]
|
||||
when not defined(js): # pending bug #16073
|
||||
doAssert byLent(b).unsafeAddr == b.unsafeAddr
|
||||
# bug #16073
|
||||
doAssert sameAddress(byLent(b), b)
|
||||
doAssert byLent(ss) == {1, 2, 3, 5}
|
||||
doAssert byLent(ss).unsafeAddr == ss.unsafeAddr
|
||||
doAssert sameAddress(byLent(ss), ss)
|
||||
|
||||
let r = new(float)
|
||||
r[] = 10.0
|
||||
when not defined(js): # pending bug #16073
|
||||
doAssert byLent(r)[] == 10.0
|
||||
# bug #16073
|
||||
doAssert byLent(r)[] == 10.0
|
||||
|
||||
when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372
|
||||
let p = create(float)
|
||||
@@ -41,9 +45,9 @@ template main2 = # bug #15958
|
||||
|
||||
proc byLent2[T](a: openarray[T]): lent T = a[0]
|
||||
doAssert byLent2(a) == 11
|
||||
doAssert byLent2(a).unsafeAddr == a[0].unsafeAddr
|
||||
doAssert sameAddress(byLent2(a), a[0])
|
||||
doAssert byLent2(b) == 21
|
||||
doAssert byLent2(b).unsafeAddr == b[0].unsafeAddr
|
||||
doAssert sameAddress(byLent2(b), b[0])
|
||||
|
||||
proc byLent3[T](a: varargs[T]): lent T = a[1]
|
||||
let
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
|
||||
{.experimental: "flexibleOptionalParams".}
|
||||
|
||||
# https://github.com/nim-lang/RFCs/issues/405
|
||||
|
||||
template main =
|
||||
|
||||
12
tests/objects/m19342.c
Normal file
12
tests/objects/m19342.c
Normal file
@@ -0,0 +1,12 @@
|
||||
struct Node
|
||||
{
|
||||
int data[25];
|
||||
};
|
||||
|
||||
|
||||
struct Node hello(int name) {
|
||||
struct Node x = {999, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,
|
||||
1, 2, 3, 4, 5};
|
||||
return x;
|
||||
}
|
||||
18
tests/objects/t19342.nim
Normal file
18
tests/objects/t19342.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
targets: "c cpp"
|
||||
"""
|
||||
|
||||
{.compile: "m19342.c".}
|
||||
|
||||
# bug #19342
|
||||
type
|
||||
Node* {.bycopy.} = object
|
||||
data: array[25, cint]
|
||||
|
||||
proc myproc(name: cint): Node {.importc: "hello", cdecl.}
|
||||
|
||||
proc parse =
|
||||
let node = myproc(10)
|
||||
doAssert node.data[0] == 999
|
||||
|
||||
parse()
|
||||
18
tests/objects/t19342_2.nim
Normal file
18
tests/objects/t19342_2.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
targets: "c cpp"
|
||||
"""
|
||||
|
||||
{.compile: "m19342.c".}
|
||||
|
||||
# bug #19342
|
||||
type
|
||||
Node* {.byRef.} = object
|
||||
data: array[25, cint]
|
||||
|
||||
proc myproc(name: cint): Node {.importc: "hello", cdecl.}
|
||||
|
||||
proc parse =
|
||||
let node = myproc(10)
|
||||
doAssert node.data[0] == 999
|
||||
|
||||
parse()
|
||||
@@ -1,5 +1,6 @@
|
||||
discard """
|
||||
output: '''34'''
|
||||
joinable: false
|
||||
"""
|
||||
|
||||
{.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
|
||||
9
tests/stdlib/concurrency/atomicSample.nim
Normal file
9
tests/stdlib/concurrency/atomicSample.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
import atomics
|
||||
|
||||
type
|
||||
AtomicWithGeneric*[T] = object
|
||||
value: Atomic[T]
|
||||
|
||||
proc initAtomicWithGeneric*[T](value: T): AtomicWithGeneric[T] =
|
||||
result.value.store(value)
|
||||
|
||||
11
tests/stdlib/concurrency/tatomic_import.nim
Normal file
11
tests/stdlib/concurrency/tatomic_import.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
import atomicSample
|
||||
|
||||
block crossFileObjectContainingAGenericWithAComplexObject:
|
||||
discard initAtomicWithGeneric[string]("foo")
|
||||
|
||||
block crossFileObjectContainingAGenericWithAnInteger:
|
||||
discard initAtomicWithGeneric[int](1)
|
||||
discard initAtomicWithGeneric[int8](1)
|
||||
discard initAtomicWithGeneric[int16](1)
|
||||
discard initAtomicWithGeneric[int32](1)
|
||||
discard initAtomicWithGeneric[int64](1)
|
||||
@@ -345,3 +345,35 @@ block:
|
||||
doAssert c == "18446744073709552000"
|
||||
else:
|
||||
doAssert c == "18446744073709551615"
|
||||
|
||||
block:
|
||||
let a = """
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
|
||||
"""
|
||||
|
||||
when not defined(js):
|
||||
try:
|
||||
discard parseJson(a)
|
||||
except JsonParsingError:
|
||||
doAssert getCurrentExceptionMsg().contains("] expected")
|
||||
|
||||
@@ -233,6 +233,43 @@ template main =
|
||||
doAssert l.toSeq == [1]
|
||||
doAssert l.remove(l.head) == true
|
||||
doAssert l.toSeq == []
|
||||
|
||||
block issue19297: # add (appends a shallow copy)
|
||||
var a: SinglyLinkedList[int]
|
||||
var b: SinglyLinkedList[int]
|
||||
|
||||
doAssert a.toSeq == @[]
|
||||
a.add(1)
|
||||
doAssert a.toSeq == @[1]
|
||||
a.add(b)
|
||||
doAssert a.toSeq == @[1]
|
||||
a.add(2)
|
||||
doAssert a.toSeq == @[1, 2]
|
||||
|
||||
block issue19314: # add (appends a shallow copy)
|
||||
var a: DoublyLinkedList[int]
|
||||
var b: DoublyLinkedList[int]
|
||||
|
||||
doAssert a.toSeq == @[]
|
||||
a.add(1)
|
||||
doAssert a.toSeq == @[1]
|
||||
a.add(b)
|
||||
doAssert a.toSeq == @[1]
|
||||
a.add(2)
|
||||
doAssert a.toSeq == @[1, 2]
|
||||
|
||||
block RemoveLastNodeFromSinglyLinkedList:
|
||||
var list = initSinglyLinkedList[string]()
|
||||
let n1 = newSinglyLinkedNode("sonic")
|
||||
let n2 = newSinglyLinkedNode("the")
|
||||
let n3 = newSinglyLinkedNode("tiger")
|
||||
let n4 = newSinglyLinkedNode("hedgehog")
|
||||
list.add(n1)
|
||||
list.add(n2)
|
||||
list.add(n3)
|
||||
list.remove(n3)
|
||||
list.add(n4)
|
||||
doAssert list.toSeq == @["sonic", "the", "hedgehog"]
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
@@ -66,3 +66,23 @@ block: # unpackVarargs
|
||||
doAssert call1(toString) == ""
|
||||
doAssert call1(toString, 10) == "10"
|
||||
doAssert call1(toString, 10, 11) == "1011"
|
||||
|
||||
block: # extractDocCommentsAndRunnables
|
||||
macro checkRunnables(prc: untyped) =
|
||||
let runnables = prc.body.extractDocCommentsAndRunnables()
|
||||
doAssert runnables[0][0].eqIdent("runnableExamples")
|
||||
|
||||
macro checkComments(comment: static[string], prc: untyped) =
|
||||
let comments = prc.body.extractDocCommentsAndRunnables()
|
||||
doAssert comments[0].strVal == comment
|
||||
|
||||
proc a() {.checkRunnables.} =
|
||||
runnableExamples: discard
|
||||
discard
|
||||
|
||||
proc b() {.checkRunnables.} =
|
||||
runnableExamples "-d:ssl": discard
|
||||
discard
|
||||
|
||||
proc c() {.checkComments("Hello world").} =
|
||||
## Hello world
|
||||
|
||||
@@ -108,4 +108,10 @@ proc testAll() =
|
||||
doAssert replace("foo", re"", "-") == "-f-o-o-"
|
||||
doAssert replace("ooo", re"o", "-") == "---"
|
||||
|
||||
block: # bug #14468
|
||||
accum = @[]
|
||||
for word in split("this is an example", re"\b"):
|
||||
accum.add(word)
|
||||
doAssert(accum == @["this", " ", "is", " ", "an", " ", "example"])
|
||||
|
||||
testAll()
|
||||
|
||||
@@ -398,7 +398,7 @@ Some chapter
|
||||
|
||||
Level2
|
||||
------
|
||||
|
||||
|
||||
Level3
|
||||
~~~~~~
|
||||
|
||||
@@ -407,7 +407,7 @@ Some chapter
|
||||
|
||||
More
|
||||
~~~~
|
||||
|
||||
|
||||
Another
|
||||
-------
|
||||
|
||||
@@ -683,7 +683,7 @@ Test1
|
||||
test "RST line blocks":
|
||||
let input2 = dedent"""
|
||||
Paragraph1
|
||||
|
||||
|
||||
|
|
||||
|
||||
Paragraph2"""
|
||||
@@ -704,7 +704,7 @@ Test1
|
||||
# check that '| ' with a few spaces is still parsed as new line
|
||||
let input4 = dedent"""
|
||||
| xxx
|
||||
|
|
||||
|
|
||||
| zzz"""
|
||||
|
||||
let output4 = input4.toHtml
|
||||
@@ -1548,3 +1548,30 @@ suite "RST/Code highlight":
|
||||
|
||||
check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
|
||||
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>))""")
|
||||
|
||||
@@ -44,6 +44,14 @@ template main() =
|
||||
proc parseInt(f: static[bool]): int {.used.} = discard
|
||||
|
||||
doAssert "123".parseInt == 123
|
||||
block:
|
||||
type
|
||||
MyType = object
|
||||
field: float32
|
||||
AType[T: static MyType] = distinct range[0f32 .. T.field]
|
||||
var a: AType[MyType(field: 5f32)]
|
||||
proc n(S: static Slice[int]): range[S.a..S.b] = discard
|
||||
assert typeof(n 1..2) is range[1..2]
|
||||
|
||||
|
||||
static: main()
|
||||
|
||||
@@ -290,10 +290,10 @@ block: # bug #10815
|
||||
|
||||
const a = P()
|
||||
doAssert $a == ""
|
||||
|
||||
|
||||
when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734
|
||||
block:
|
||||
type CharSet {.union.} = object
|
||||
type CharSet {.union.} = object
|
||||
cs: set[char]
|
||||
vs: array[4, uint64]
|
||||
const a = Charset(cs: {'a'..'z'})
|
||||
@@ -553,3 +553,22 @@ block: # bug #8015
|
||||
doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)"
|
||||
doAssert viaProc.table[1].handler() == 100
|
||||
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
|
||||
nimc.rst
|
||||
niminst.rst
|
||||
gc.rst
|
||||
mm.rst
|
||||
""".splitWhitespace().mapIt("doc" / it)
|
||||
|
||||
doc0 = """
|
||||
@@ -298,6 +298,12 @@ proc nim2pdf(src: string, dst: string, nimArgs: string) =
|
||||
# `>` should work on windows, if not, we can use `execCmdEx`
|
||||
let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell]
|
||||
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)
|
||||
|
||||
proc buildPdfDoc*(nimArgs, destPath: string) =
|
||||
|
||||
Reference in New Issue
Block a user