mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeea72060c | ||
|
|
0b1fee5d66 | ||
|
|
594831620b | ||
|
|
2eb0442a9a | ||
|
|
002621b61d | ||
|
|
8ea5475dd9 | ||
|
|
3e6d708175 | ||
|
|
e3fb2c21d7 | ||
|
|
c4ab020f0f | ||
|
|
6e4fdbc4a9 | ||
|
|
497d061cd1 | ||
|
|
4cb522fb8a | ||
|
|
84c1b1af0e | ||
|
|
a683ca3fac | ||
|
|
f7ea7b3c4f | ||
|
|
a34845b66c | ||
|
|
79f95a2efc | ||
|
|
8a3f542532 | ||
|
|
2009df72cb | ||
|
|
f4216f12b3 | ||
|
|
d327eaacbf | ||
|
|
735e3eea78 | ||
|
|
d8cc349ac6 | ||
|
|
e05daba73e | ||
|
|
2a72eeafdf | ||
|
|
2d06867388 | ||
|
|
9b47614ba1 | ||
|
|
8d5065453f | ||
|
|
1802f94868 | ||
|
|
5a42d393a4 | ||
|
|
76560576d2 | ||
|
|
2684b04ab1 | ||
|
|
6dde797752 | ||
|
|
74f34c81e8 | ||
|
|
34563f86c2 | ||
|
|
7a9e5ba68f | ||
|
|
d2af421089 | ||
|
|
ba02bf50b9 | ||
|
|
424a00db2b | ||
|
|
fb03c4b937 | ||
|
|
ba8f657635 | ||
|
|
6238f2ee1e | ||
|
|
7aff6ded84 | ||
|
|
fe8b84496f | ||
|
|
7f834c69fb | ||
|
|
9a58bddc55 | ||
|
|
9ebf537341 | ||
|
|
5ea5d82507 | ||
|
|
d85b7dde7b | ||
|
|
1d301e354f | ||
|
|
a7570ff0c2 | ||
|
|
86c8977726 | ||
|
|
2ee078cdf8 |
@@ -15,7 +15,7 @@ environment:
|
||||
tasks:
|
||||
- setup: |
|
||||
cd Nim
|
||||
git clone --depth 1 -q https://github.com/nim-lang/csources.git
|
||||
git clone --depth 1 -q https://github.com/nim-lang/csources_v1.git csources
|
||||
gmake -C csources -j $(sysctl -n hw.ncpu)
|
||||
bin/nim c --skipUserCfg --skipParentCfg koch
|
||||
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
|
||||
|
||||
4
.github/workflows/ci_docs.yml
vendored
4
.github/workflows/ci_docs.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
id: csources-version
|
||||
shell: bash
|
||||
run: |
|
||||
sha=$(git ls-remote https://github.com/nim-lang/csources master | cut -f 1)
|
||||
sha=$(git ls-remote https://github.com/nim-lang/csources_v1 master | cut -f 1)
|
||||
echo "::set-output name=sha::$sha"
|
||||
|
||||
- name: 'Get prebuilt csources from cache'
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
if: steps.csources-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: nim-lang/csources
|
||||
repository: nim-lang/csources_v1
|
||||
path: csources
|
||||
|
||||
- name: 'Build 1-stage compiler from csources'
|
||||
|
||||
@@ -15,10 +15,10 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
vmImage: 'ubuntu-18.04'
|
||||
CPU: amd64
|
||||
Linux_i386:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
vmImage: 'ubuntu-18.04'
|
||||
CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-10.15'
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
Linux_amd64_pkg:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
vmImage: 'ubuntu-18.04'
|
||||
CPU: amd64
|
||||
NIM_TEST_PACKAGES: true
|
||||
OSX_amd64_pkg:
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources_v1 csources
|
||||
displayName: 'Checkout Nim csources'
|
||||
|
||||
- task: NodeTool@0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@echo off
|
||||
rem build development version of the compiler; can be rerun safely
|
||||
if not exist csources (
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources
|
||||
)
|
||||
if not exist bin\nim.exe (
|
||||
cd csources
|
||||
|
||||
@@ -11,7 +11,7 @@ echo_run(){
|
||||
"$@"
|
||||
}
|
||||
|
||||
[ -d csources ] || echo_run git clone -q --depth 1 https://github.com/nim-lang/csources.git
|
||||
[ -d csources ] || echo_run git clone -q --depth 1 https://github.com/nim-lang/csources_v1.git csources
|
||||
|
||||
nim_csources=bin/nim_csources
|
||||
|
||||
|
||||
167
changelog.md
167
changelog.md
@@ -3,6 +3,13 @@
|
||||
|
||||
|
||||
## Standard library additions and changes
|
||||
- Added support for parenthesized expressions in `strformat`
|
||||
|
||||
- Fixed buffer overflow bugs in `net`
|
||||
|
||||
- Added `sections` iterator in `parsecfg`.
|
||||
|
||||
- Make custom op in macros.quote work for all statements.
|
||||
|
||||
For `net` and `nativesockets`, an `inheritable` flag has been added to all
|
||||
`proc`s that create sockets, allowing the user to control whether the
|
||||
@@ -140,6 +147,161 @@
|
||||
- Added `asyncdispatch.maxDescriptors` that returns the maximum number of
|
||||
active async event handles/file descriptors.
|
||||
|
||||
- Added `getPort` to `asynchttpserver`.
|
||||
|
||||
- `--gc:orc` is now 10% faster than previously for common workloads. If
|
||||
you have trouble with its changed behavior, compile with `-d:nimOldOrc`.
|
||||
|
||||
|
||||
- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`,
|
||||
determining preferred I/O block size for this file object.
|
||||
|
||||
- Added a simpler to use `io.readChars` overload.
|
||||
|
||||
- Added `**` to jsffi.
|
||||
|
||||
- `writeStackTrace` is available in JS backend now.
|
||||
|
||||
- Added `decodeQuery` to `std/uri`.
|
||||
|
||||
- `strscans.scanf` now supports parsing single characters.
|
||||
|
||||
- `strscans.scanTuple` added which uses `strscans.scanf` internally,
|
||||
returning a tuple which can be unpacked for easier usage of `scanf`.
|
||||
|
||||
- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`,
|
||||
if the iterable yields a built-in settable type.
|
||||
|
||||
- Added `setutils.fullSet` which returns a full built-in `set` for a valid type.
|
||||
|
||||
- Added `setutils.complement` which returns the complement of a built-in `set`.
|
||||
|
||||
- Added `setutils.[]=`.
|
||||
|
||||
- Added `math.isNaN`.
|
||||
|
||||
- Added `jsbigints` module, arbitrary precision integers for JavaScript target.
|
||||
|
||||
- Added `math.copySign`.
|
||||
|
||||
- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList`
|
||||
and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements
|
||||
shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes
|
||||
its argument, `addMoved`, is also supplied.
|
||||
|
||||
- Added `euclDiv` and `euclMod` to `math`.
|
||||
|
||||
- Added `httpcore.is1xx` and missing HTTP codes.
|
||||
|
||||
- Added `jsconsole.jsAssert` for JavaScript target.
|
||||
|
||||
- Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs.
|
||||
https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||
|
||||
- Added `socketstream` module that wraps sockets in the stream interface
|
||||
|
||||
- Added `sugar.dumpToString` which improves on `sugar.dump`.
|
||||
|
||||
- Added `math.signbit`.
|
||||
|
||||
- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably)
|
||||
|
||||
- In `lists`: renamed `append` to `add` and retained `append` as an alias;
|
||||
added `prepend` and `prependMoved` analogously to `add` and `addMoved`;
|
||||
added `remove` for `SinglyLinkedList`s.
|
||||
|
||||
- Deprecated `any`. See https://github.com/nim-lang/RFCs/issues/281
|
||||
|
||||
- Added optional `options` argument to `copyFile`, `copyFileToDir`, and
|
||||
`copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are
|
||||
followed (copy files symlinks point to); on Windows, `options` argument is
|
||||
ignored and symlinks are skipped.
|
||||
|
||||
- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as
|
||||
symlinks (instead of skipping them as it was before); on Windows symlinks are
|
||||
skipped.
|
||||
|
||||
- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks
|
||||
(instead of skipping them sometimes as it was before).
|
||||
|
||||
- Added optional `followSymlinks` argument to `setFilePermissions`.
|
||||
|
||||
- Added `os.isAdmin` to tell whether the caller's process is a member of the
|
||||
Administrators local group (on Windows) or a root (on POSIX).
|
||||
|
||||
- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C).
|
||||
|
||||
- Added `compilesettings.SingleValueSetting.libPath`.
|
||||
|
||||
- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding
|
||||
issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages)
|
||||
for modules importing `std/wrapnils`.
|
||||
Added `??.` macro which returns an `Option`.
|
||||
|
||||
- Added `math.frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead.
|
||||
|
||||
- `parseopt.initOptParser` has been made available and `parseopt` has been
|
||||
added back to `prelude` for all backends. Previously `initOptParser` was
|
||||
unavailable if the `os` module did not have `paramCount` or `paramStr`,
|
||||
but the use of these in `initOptParser` were conditionally to the runtime
|
||||
arguments passed to it, so `initOptParser` has been changed to raise
|
||||
`ValueError` when the real command line is not available. `parseopt` was
|
||||
previously excluded from `prelude` for JS, as it could not be imported.
|
||||
|
||||
- Added `system.prepareStrMutation` for better support of low
|
||||
level `moveMem`, `copyMem` operations for Orc's copy-on-write string
|
||||
implementation.
|
||||
|
||||
- Added `std/strbasics` for high performance string operations.
|
||||
Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`.
|
||||
|
||||
|
||||
- Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`.
|
||||
|
||||
- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"`
|
||||
and `$none(int)` to `"none(int)"` instead of `"None[int]"`.
|
||||
|
||||
- Added `algorithm.merge`.
|
||||
|
||||
|
||||
- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target.
|
||||
|
||||
- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) wrapper for JavaScript target.
|
||||
|
||||
- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) wrapper for JavaScript target.
|
||||
|
||||
- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible
|
||||
with most other languages.
|
||||
|
||||
- Removed support for named procs in `sugar.=>`.
|
||||
|
||||
- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger).
|
||||
|
||||
- Added `std/channels`.
|
||||
|
||||
- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals).
|
||||
|
||||
- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time
|
||||
zone offsets without colons, e.g. `UTC+7 -> +0700`.
|
||||
|
||||
- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`.
|
||||
|
||||
- Added dollar `$` and `len` for `jsre.RegExp`.
|
||||
|
||||
- Added `std/tasks`.
|
||||
|
||||
- Added `hasDataBuffered` to `asyncnet`.
|
||||
|
||||
- Added `hasClosure` to `std/typetraits`.
|
||||
|
||||
- Added `std/tempfiles`.
|
||||
|
||||
- Added `genasts.genAst` that avoids the problems inherent with `quote do` and can
|
||||
be used as a replacement.
|
||||
|
||||
- Added `copyWithin` [for `seq` and `array` for JavaScript targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin).
|
||||
|
||||
- Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place.
|
||||
|
||||
## Language changes
|
||||
- In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this:
|
||||
@@ -187,5 +349,10 @@
|
||||
## Compiler changes
|
||||
|
||||
|
||||
- The style checking of the compiler now supports a `--styleCheck:usages` switch. This switch
|
||||
enforces that every symbol is written as it was declared, not enforcing
|
||||
the official Nim style guide. To be enabled, this has to be combined either
|
||||
with `--styleCheck:error` or `--styleCheck:hint`.
|
||||
|
||||
## Tool changes
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ REM Some debug info
|
||||
echo "Running on %CI_RUNNER_ID% (%CI_RUNNER_DESCRIPTION%) with tags %CI_RUNNER_TAGS%."
|
||||
gcc -v
|
||||
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources
|
||||
cd csources
|
||||
call build64.bat
|
||||
cd ..
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
sh ci/deps.sh
|
||||
|
||||
# Build from C sources.
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources
|
||||
cd csources
|
||||
sh build.sh
|
||||
cd ..
|
||||
|
||||
@@ -25,7 +25,7 @@ Rem Build csources
|
||||
koch csources -d:release || exit /b
|
||||
|
||||
rem Grab C sources and nimsuggest
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources
|
||||
|
||||
set PATH=%CD%\bin;%PATH%
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
else:
|
||||
initLocExpr(p, n, a)
|
||||
case skipTypes(a.t, abstractVar).kind
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = "$1, $1Len_0" % [rdLoc(a)]
|
||||
of tyString, tySequence:
|
||||
|
||||
@@ -868,7 +868,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
if optBoundsCheck in p.options and ty.kind != tyUncheckedArray:
|
||||
if not isConstExpr(y):
|
||||
# semantic pass has already checked for const index expressions
|
||||
if firstOrd(p.config, ty) == 0:
|
||||
if firstOrd(p.config, ty) == 0 and lastOrd(p.config, ty) >= 0:
|
||||
if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)):
|
||||
linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)){ #raiseIndexError2($1, $2); $3}$n",
|
||||
[rdCharLoc(b), intLiteral(lastOrd(p.config, ty)), raiseInstr(p)])
|
||||
@@ -1982,30 +1982,25 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
discard "no need to generate a check because it was disabled"
|
||||
else:
|
||||
let raiser =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
discard cgsym(p.module, raiser)
|
||||
# This seems to be bug-compatible with Nim version 1 but what we
|
||||
# should really do here is to check if uint64Value < high(int)
|
||||
let n0t = n[0].typ
|
||||
|
||||
let boundaryCast =
|
||||
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
|
||||
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
|
||||
"(NI64)"
|
||||
else:
|
||||
""
|
||||
# emit range check:
|
||||
if n0t.kind in {tyUInt, tyUInt64}:
|
||||
linefmt(p, cpsStmts, "if ($1 > ($6)($3)){ #raiseRangeErrorNoArgs(); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), getTypeDesc(p.module, n0t)])
|
||||
else:
|
||||
let raiser =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
discard cgsym(p.module, raiser)
|
||||
|
||||
let boundaryCast =
|
||||
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
|
||||
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
|
||||
"(NI64)"
|
||||
else:
|
||||
""
|
||||
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), boundaryCast])
|
||||
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), boundaryCast])
|
||||
putIntoDest(p, d, n, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
|
||||
|
||||
@@ -2671,7 +2666,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
expr(p, n[1][0], d)
|
||||
of nkObjDownConv: downConv(p, n, d)
|
||||
of nkObjUpConv: upConv(p, n, d)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
|
||||
of nkChckRangeF: genRangeChck(p, n, d)
|
||||
of nkChckRange64: genRangeChck(p, n, d)
|
||||
of nkChckRange: genRangeChck(p, n, d)
|
||||
of nkStringToCString: convStrToCStr(p, n, d)
|
||||
of nkCStringToString: convCStrToStr(p, n, d)
|
||||
of nkLambdaKinds:
|
||||
@@ -2744,6 +2741,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
inc p.splitDecls
|
||||
genGotoState(p, n)
|
||||
of nkBreakState: genBreakState(p, n, d)
|
||||
of nkMixinStmt, nkBindStmt: discard
|
||||
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
||||
|
||||
proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
|
||||
|
||||
@@ -1330,8 +1330,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])
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
|
||||
@@ -220,7 +220,8 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
||||
# 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
|
||||
if rettype == nil or getSize(conf, rettype) > conf.target.floatSize*3:
|
||||
result = true
|
||||
else:
|
||||
case mapType(conf, rettype)
|
||||
of ctArray:
|
||||
|
||||
@@ -432,8 +432,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)])
|
||||
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)])
|
||||
else:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use nimZeroMem for temporary values for performance if we can
|
||||
@@ -838,7 +844,8 @@ proc containsResult(n: PNode): bool =
|
||||
for i in 0..<n.safeLen:
|
||||
if containsResult(n[i]): return true
|
||||
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef, nkMacroDef} +
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt} +
|
||||
declarativeDefs
|
||||
|
||||
proc easyResultAsgn(n: PNode): PNode =
|
||||
|
||||
@@ -156,7 +156,7 @@ type
|
||||
|
||||
const
|
||||
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
|
||||
nkCommentStmt} + procDefs
|
||||
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
|
||||
|
||||
proc newStateAccess(ctx: var Ctx): PNode =
|
||||
if ctx.stateVarSym.isNil:
|
||||
|
||||
@@ -851,6 +851,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
|
||||
of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError}
|
||||
of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
|
||||
of "usages": conf.globalOptions.incl optStyleUsages
|
||||
else: localError(conf, info, errOffHintsError % arg)
|
||||
of "showallmismatches":
|
||||
processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
|
||||
|
||||
@@ -651,6 +651,10 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||
if useCpp(conf, cfile.cname):
|
||||
options.add(' ' & CC[c].cppXsupport)
|
||||
|
||||
if cfile.customArgs != "":
|
||||
options.add ' '
|
||||
options.add cfile.customArgs
|
||||
|
||||
var compilePattern: string
|
||||
# compute include paths:
|
||||
var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
|
||||
|
||||
@@ -945,7 +945,8 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState:
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkMixinStmt, nkBindStmt:
|
||||
result = n
|
||||
of nkBreakStmt:
|
||||
inc c.hasUnstructuredCf
|
||||
|
||||
@@ -111,6 +111,7 @@ Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/downlo
|
||||
Files: "bin/makelink.exe"
|
||||
Files: "bin/7zG.exe"
|
||||
Files: "bin/*.dll"
|
||||
Files: "bin/cacert.pem"
|
||||
|
||||
[UnixBin]
|
||||
Files: "bin/nim"
|
||||
|
||||
@@ -2479,7 +2479,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkRaiseStmt: genRaiseStmt(p, n)
|
||||
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
|
||||
nkMixinStmt, nkBindStmt: discard
|
||||
of nkPragma: genPragma(p, n)
|
||||
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
|
||||
var s = n[namePos].sym
|
||||
|
||||
@@ -493,7 +493,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
w = up
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
|
||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr:
|
||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
discard
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil:
|
||||
@@ -747,7 +748,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
result = accessViaEnvVar(n, owner, d, c)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
|
||||
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef,
|
||||
nkMacroDef, nkFuncDef:
|
||||
nkMacroDef, nkFuncDef, nkMixinStmt, nkBindStmt:
|
||||
discard
|
||||
of nkClosure:
|
||||
if n[1].kind == nkNilLit:
|
||||
|
||||
@@ -42,7 +42,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
|
||||
of nkSym:
|
||||
if interestingVar(it.sym):
|
||||
n[i] = lookupOrAdd(c, it.sym, it.info)
|
||||
of procDefs, nkTypeSection: discard
|
||||
of procDefs, nkTypeSection, nkMixinStmt, nkBindStmt: discard
|
||||
else:
|
||||
for i in 0..<it.safeLen:
|
||||
liftLocals(it, i, c)
|
||||
|
||||
@@ -44,6 +44,7 @@ type
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated,
|
||||
warnObservableStores,
|
||||
warnResultUsed,
|
||||
warnUser,
|
||||
hintSuccess, hintSuccessX, hintCC,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed,
|
||||
@@ -110,6 +111,7 @@ const
|
||||
warnCaseTransition: "Potential object case transition, instantiate new object instead",
|
||||
warnCycleCreated: "$1",
|
||||
warnObservableStores: "observable stores to '$1'",
|
||||
warnResultUsed: "used 'result' variable",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
# keep in sync with `testament.isSuccess`
|
||||
@@ -160,7 +162,7 @@ const
|
||||
"IndexCheck", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
|
||||
"Spacing", "CaseTransition", "CycleCreated",
|
||||
"ObservableStores", "User"]
|
||||
"ObservableStores", "ResultUsed", "User"]
|
||||
|
||||
HintsToStr* = [
|
||||
"Success", "SuccessX", "CC", "LineTooLong",
|
||||
@@ -191,7 +193,7 @@ type
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnResultUsed}
|
||||
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
|
||||
@@ -101,7 +101,7 @@ proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
lintReport(conf, info, beau, s.name.s)
|
||||
|
||||
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {} and optStyleUsages notin conf.globalOptions:
|
||||
nep1CheckDefImpl(conf, info, s, k)
|
||||
|
||||
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
|
||||
@@ -59,6 +59,7 @@ type # please make sure we have under 32 options
|
||||
optRun, # run the compiled project
|
||||
optStyleHint, # check that the names adhere to NEP-1
|
||||
optStyleError, # enforce that the names adhere to NEP-1
|
||||
optStyleUsages, # only enforce consistent **usages** of the symbol
|
||||
optSkipSystemConfigFile, # skip the system's cfg/nims config file
|
||||
optSkipProjConfigFile, # skip the project's cfg/nims config file
|
||||
optSkipUserConfigFile, # skip the users's cfg/nims config file
|
||||
@@ -180,6 +181,7 @@ type
|
||||
nimname*: string
|
||||
cname*, obj*: AbsoluteFile
|
||||
flags*: set[CfileFlag]
|
||||
customArgs*: string
|
||||
CfileList* = seq[Cfile]
|
||||
|
||||
Suggest* = ref object
|
||||
@@ -309,7 +311,7 @@ proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) =
|
||||
proc hasHint*(conf: ConfigRef, note: TNoteKind): bool =
|
||||
optHints in conf.options and note in conf.notes
|
||||
|
||||
proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool =
|
||||
proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool {.inline.} =
|
||||
optWarns in conf.options and note in conf.notes
|
||||
|
||||
proc hcrOn*(conf: ConfigRef): bool = return optHotCodeReloading in conf.globalOptions
|
||||
|
||||
@@ -92,11 +92,10 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
|
||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
|
||||
isStatement: bool = false)
|
||||
|
||||
proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") =
|
||||
proc recordPragma(c: PContext; n: PNode; args: varargs[string]) =
|
||||
var recorded = newNodeI(nkCommentStmt, n.info)
|
||||
recorded.add newStrNode(key, n.info)
|
||||
recorded.add newStrNode(val, n.info)
|
||||
if val2.len > 0: recorded.add newStrNode(val2, n.info)
|
||||
for i in 0..args.high:
|
||||
recorded.add newStrNode(args[i], n.info)
|
||||
c.graph.recordStmt(c.graph, c.module, recorded)
|
||||
|
||||
const
|
||||
@@ -496,11 +495,12 @@ proc relativeFile(c: PContext; n: PNode; ext=""): AbsoluteFile =
|
||||
if result.isEmpty: result = AbsoluteFile s
|
||||
|
||||
proc processCompile(c: PContext, n: PNode) =
|
||||
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile) =
|
||||
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile; customArgs: string) =
|
||||
var cf = Cfile(nimname: splitFile(src).name,
|
||||
cname: src, obj: dest, flags: {CfileFlag.External})
|
||||
cname: src, obj: dest, flags: {CfileFlag.External},
|
||||
customArgs: customArgs)
|
||||
extccomp.addExternalFileToCompile(c.config, cf)
|
||||
recordPragma(c, it, "compile", src.string, dest.string)
|
||||
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
|
||||
|
||||
proc getStrLit(c: PContext, n: PNode; i: int): string =
|
||||
n[i] = c.semConstExpr(c, n[i])
|
||||
@@ -518,9 +518,19 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
var found = parentDir(toFullPath(c.config, n.info)) / s
|
||||
for f in os.walkFiles(found):
|
||||
let obj = completeCfilePath(c.config, AbsoluteFile(dest % extractFilename(f)))
|
||||
docompile(c, it, AbsoluteFile f, obj)
|
||||
docompile(c, it, AbsoluteFile f, obj, "")
|
||||
else:
|
||||
let s = expectStrLit(c, n)
|
||||
var s = ""
|
||||
var customArgs = ""
|
||||
if n.kind in nkCallKinds:
|
||||
s = getStrLit(c, n, 1)
|
||||
if n.len <= 3:
|
||||
customArgs = getStrLit(c, n, 2)
|
||||
else:
|
||||
localError(c.config, n.info, "'.compile' pragma takes up 2 arguments")
|
||||
else:
|
||||
s = expectStrLit(c, n)
|
||||
|
||||
var found = AbsoluteFile(parentDir(toFullPath(c.config, n.info)) / s)
|
||||
if not fileExists(found):
|
||||
if isAbsolute(s): found = AbsoluteFile s
|
||||
@@ -528,7 +538,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
found = findFile(c.config, s)
|
||||
if found.isEmpty: found = AbsoluteFile s
|
||||
let obj = toObjFile(c.config, completeCfilePath(c.config, found, false))
|
||||
docompile(c, it, found, obj)
|
||||
docompile(c, it, found, obj, customArgs)
|
||||
|
||||
proc processLink(c: PContext, n: PNode) =
|
||||
let found = relativeFile(c, n, CC[c.config.cCompiler].objExt)
|
||||
|
||||
@@ -106,6 +106,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
|
||||
decl(a[1])
|
||||
else:
|
||||
for i in 0..<n.safeLen: deps(n[i])
|
||||
of nkMixinStmt, nkBindStmt: discard
|
||||
else:
|
||||
for i in 0..<n.safeLen: deps(n[i])
|
||||
|
||||
|
||||
@@ -838,11 +838,12 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
|
||||
of "warning": message(g.config, n.info, warnUser, n[1].strVal)
|
||||
of "error": localError(g.config, n.info, errUser, n[1].strVal)
|
||||
of "compile":
|
||||
internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit
|
||||
internalAssert g.config, n.len == 4 and n[2].kind == nkStrLit
|
||||
let cname = AbsoluteFile n[1].strVal
|
||||
var cf = Cfile(nimname: splitFile(cname).name, cname: cname,
|
||||
obj: AbsoluteFile n[2].strVal,
|
||||
flags: {CfileFlag.External})
|
||||
flags: {CfileFlag.External},
|
||||
customArgs: n[3].strVal)
|
||||
extccomp.addExternalFileToCompile(g.config, cf)
|
||||
of "link":
|
||||
extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal)
|
||||
|
||||
@@ -38,6 +38,7 @@ type
|
||||
mappingExists*: bool
|
||||
mapping*: TIdTable
|
||||
caseContext*: seq[tuple[n: PNode, idx: int]]
|
||||
localBindStmts*: seq[PNode]
|
||||
|
||||
TMatchedConcept* = object
|
||||
candidateType*: PType
|
||||
|
||||
@@ -1207,6 +1207,9 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
# not sure the symbol really ends up being used:
|
||||
# var len = 0 # but won't be called
|
||||
# genericThatUsesLen(x) # marked as taking a closure?
|
||||
if hasWarn(c.config, warnResultUsed):
|
||||
message(c.config, n.info, warnResultUsed)
|
||||
|
||||
of skGenericParam:
|
||||
onUse(n.info, s)
|
||||
if s.typ.kind == tyStatic:
|
||||
@@ -2830,6 +2833,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
for i in 0..<n.len:
|
||||
n[i] = semExpr(c, n[i])
|
||||
of nkComesFrom: discard "ignore the comes from information for now"
|
||||
of nkMixinStmt: discard
|
||||
of nkBindStmt:
|
||||
if c.p != nil:
|
||||
c.p.localBindStmts.add n
|
||||
else:
|
||||
localError(c.config, n.info, "invalid context for 'bind' statement: " &
|
||||
renderTree(n, {renderNoComments}))
|
||||
else:
|
||||
localError(c.config, n.info, "invalid expression: " &
|
||||
renderTree(n, {renderNoComments}))
|
||||
|
||||
@@ -164,7 +164,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, g)
|
||||
of mBitnotI:
|
||||
if n.typ.isUnsigned:
|
||||
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, g)
|
||||
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(getSize(g.config, n.typ))), n, g)
|
||||
else:
|
||||
result = newIntNodeT(bitnot(getInt(a)), n, g)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
|
||||
@@ -276,23 +276,23 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g)
|
||||
of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, 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, 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, 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, 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, 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, g)
|
||||
of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, g)
|
||||
|
||||
@@ -319,6 +319,14 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
prc.typ = result
|
||||
popInfoContext(c.config)
|
||||
|
||||
proc fillMixinScope(c: PContext) =
|
||||
var p = c.p
|
||||
while p != nil:
|
||||
for bnd in p.localBindStmts:
|
||||
for n in bnd:
|
||||
addSym(c.currentScope, n.sym)
|
||||
p = p.next
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
## Generates a new instance of a generic procedure.
|
||||
@@ -345,6 +353,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
result.ast = n
|
||||
pushOwner(c, result)
|
||||
|
||||
# mixin scope:
|
||||
openScope(c)
|
||||
fillMixinScope(c)
|
||||
|
||||
openScope(c)
|
||||
let gp = n[genericParamsPos]
|
||||
internalAssert c.config, gp.kind != nkEmpty
|
||||
@@ -395,6 +407,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
popProcCon(c)
|
||||
popInfoContext(c.config)
|
||||
closeScope(c) # close scope for parameters
|
||||
closeScope(c) # close scope for 'mixin' declarations
|
||||
popOwner(c)
|
||||
c.currentScope = oldScope
|
||||
discard c.friendModules.pop()
|
||||
|
||||
@@ -359,12 +359,17 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
|
||||
while objType.kind != tyObject:
|
||||
objType = objType.lastSon
|
||||
assert objType != nil
|
||||
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 objType.kind == tyObject:
|
||||
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
||||
let initResult = semConstructTypeAux(c, constrCtx, {})
|
||||
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))
|
||||
else:
|
||||
assert false, "Must not enter here."
|
||||
|
||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var t = semTypeNode(c, n[0], nil)
|
||||
|
||||
@@ -391,7 +391,8 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
||||
addFactNeg(c.guards, canon(n[0], c.guards.o))
|
||||
dec c.inLoop
|
||||
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
||||
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
|
||||
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef,
|
||||
nkMixinStmt, nkBindStmt, nkExportStmt:
|
||||
discard
|
||||
else:
|
||||
analyseSons(c, n)
|
||||
|
||||
@@ -1828,8 +1828,8 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
|
||||
let t = tt[col]
|
||||
if t != nil and t.kind == tyGenericInvocation:
|
||||
var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
|
||||
tyGenericInvocation, tyGenericBody,
|
||||
tyAlias, tySink, tyOwned})
|
||||
tyGenericInvocation, tyGenericBody,
|
||||
tyAlias, tySink, tyOwned})
|
||||
if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
|
||||
foundObj = true
|
||||
x.methods.add((col,s))
|
||||
|
||||
@@ -86,6 +86,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
|
||||
a = nextOverloadIter(o, c, n)
|
||||
|
||||
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||
result = copyNode(n)
|
||||
for i in 0..<n.len:
|
||||
var a = n[i]
|
||||
# If 'a' is an overloaded symbol, we used to use the first symbol
|
||||
@@ -99,16 +100,24 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||
let sc = symChoice(c, n, s, scClosed)
|
||||
if sc.kind == nkSym:
|
||||
toBind.incl(sc.sym.id)
|
||||
result.add sc
|
||||
else:
|
||||
for x in items(sc): toBind.incl(x.sym.id)
|
||||
for x in items(sc):
|
||||
toBind.incl(x.sym.id)
|
||||
result.add x
|
||||
else:
|
||||
illFormedAst(a, c.config)
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
||||
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
|
||||
result = copyNode(n)
|
||||
var count = 0
|
||||
for i in 0..<n.len:
|
||||
toMixin.incl(considerQuotedIdent(c, n[i]).id)
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
let x = symChoice(c, n[i], nil, scForceOpen)
|
||||
inc count, x.len
|
||||
result.add x
|
||||
if count == 0:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
||||
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
|
||||
case n.kind
|
||||
|
||||
@@ -993,7 +993,7 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||
of nkConstSection:
|
||||
# do not replace ``const c = 3`` with ``const 3 = 3``
|
||||
return transformConstSection(c, n)
|
||||
of nkTypeSection, nkTypeOfExpr:
|
||||
of nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
# no need to transform type sections:
|
||||
return n
|
||||
of nkVarSection, nkLetSection:
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# types that use the 'node' field; the reason is that slots are
|
||||
# re-used in a register based VM. Example:
|
||||
#
|
||||
#..code-block:: nim
|
||||
#.. code-block:: nim
|
||||
# let s = a & b # no matter what, create fresh node
|
||||
# s = a & b # no matter what, keep the node
|
||||
#
|
||||
@@ -2106,7 +2106,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
else:
|
||||
dest = tmp0
|
||||
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
|
||||
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt:
|
||||
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
|
||||
nkMixinStmt, nkBindStmt:
|
||||
unused(c, n, dest)
|
||||
of nkStringToCString, nkCStringToString:
|
||||
gen(c, n[0], dest)
|
||||
|
||||
@@ -136,15 +136,10 @@ doc.body_toc_group = """
|
||||
</div>
|
||||
<div id="global-links">
|
||||
<ul class="simple-boot">
|
||||
<li>
|
||||
<a href="manual.html">Manual</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="lib.html">Standard library</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="theindex.html">Index</a>
|
||||
</li>
|
||||
<li><a href="manual.html">Manual</a></li>
|
||||
<li><a href="lib.html">Standard library</a></li>
|
||||
<li><a href="theindex.html">Index</a></li>
|
||||
<li><a href="https://nim-lang.github.io/Nim/">devel</a>, <a href="https://nim-lang.org/documentation.html">stable</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="searchInputDiv">
|
||||
|
||||
@@ -42,6 +42,8 @@ Advanced options:
|
||||
produce hints or errors for Nim identifiers that
|
||||
do not adhere to Nim's official style guide
|
||||
https://nim-lang.org/docs/nep1.html
|
||||
--styleCheck:usages only enforce consistent spellings of identifiers,
|
||||
do not enforce the style on declarations
|
||||
--showAllMismatches:on|off
|
||||
show all mismatching candidates in overloading
|
||||
resolution
|
||||
|
||||
@@ -47,9 +47,11 @@ 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
|
||||
into a project using any of these languages. Here are some typical command
|
||||
line invocations::
|
||||
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:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
$ nim c hallo.nim
|
||||
$ nim cpp hallo.nim
|
||||
@@ -108,8 +110,8 @@ Nim code calling the backend
|
||||
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++
|
||||
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++
|
||||
or Objective-C backends have their respective `ImportCpp
|
||||
<manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
|
||||
@@ -230,11 +232,6 @@ 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``
|
||||
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.
|
||||
|
||||
|
||||
Nim invocation example from C
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -253,9 +250,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();
|
||||
@@ -268,13 +266,14 @@ Now you can run the following Unix like commands to first generate C sources
|
||||
form the Nim code, then link them into a static binary along your main C
|
||||
program::
|
||||
|
||||
$ nim c --noMain --noLinking --header:fib.h fib.nim
|
||||
$ gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
|
||||
.. code:: cmd
|
||||
|
||||
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()`` 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 form ``nimcache``. In addition to this path, you also
|
||||
have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
||||
@@ -282,12 +281,12 @@ have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
||||
Instead of depending on the generation of the individual ``.c`` files you can
|
||||
also ask the Nim compiler to generate a statically linked library::
|
||||
|
||||
$ nim c --app:staticLib --noMain --header fib.nim
|
||||
$ gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c
|
||||
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`` too to link in required dlopen functionality.
|
||||
|
||||
|
||||
@@ -4789,6 +4789,50 @@ scope is the default.
|
||||
``bind`` statements only make sense in templates and generics.
|
||||
|
||||
|
||||
Delegating bind statements
|
||||
--------------------------
|
||||
|
||||
The following example outlines a problem that can arise when generic
|
||||
instantiations cross multiple different modules:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
# module A
|
||||
proc genericA*[T](x: T) =
|
||||
mixin init
|
||||
init(x)
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
import C
|
||||
|
||||
# module B
|
||||
proc genericB*[T](x: T) =
|
||||
# Without the `bind init` statement C's init proc is
|
||||
# not available when `genericB` is instantiated:
|
||||
bind init
|
||||
genericA(x)
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
# module C
|
||||
type O = object
|
||||
proc init*(x: var O) = discard
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
# module main
|
||||
import B, C
|
||||
|
||||
genericB O()
|
||||
|
||||
In module B has an `init` proc from module C in its scope that is not
|
||||
taken into account when `genericB` is instantiated which leads to the
|
||||
instantiation of `genericA`. The solution is to `forward`:idx these
|
||||
symbols by a `bind` statement inside `genericB`.
|
||||
|
||||
|
||||
Templates
|
||||
=========
|
||||
|
||||
@@ -5715,12 +5759,12 @@ avoid ambiguity when there are multiple modules with the same path.
|
||||
There are two pseudo directories:
|
||||
|
||||
1. ``std``: The ``std`` pseudo directory is the abstract location of Nim's standard
|
||||
library. For example, the syntax ``import std / strutils`` is used to unambiguously
|
||||
refer to the standard library's ``strutils`` module.
|
||||
library. For example, the syntax ``import std / strutils`` is used to unambiguously
|
||||
refer to the standard library's ``strutils`` module.
|
||||
2. ``pkg``: The ``pkg`` pseudo directory is used to unambiguously refer to a Nimble
|
||||
package. However, for technical details that lie outside of the scope of this document
|
||||
its semantics are: *Use the search path to look for module name but ignore the standard
|
||||
library locations*. In other words, it is the opposite of ``std``.
|
||||
package. However, for technical details that lie outside of the scope of this document
|
||||
its semantics are: *Use the search path to look for module name but ignore the standard
|
||||
library locations*. In other words, it is the opposite of ``std``.
|
||||
|
||||
|
||||
From import statement
|
||||
@@ -6608,6 +6652,14 @@ with the project:
|
||||
has changed. One can use the ``-f`` command line option to force recompilation
|
||||
of the file.
|
||||
|
||||
Since 1.4 the `compile` pragma is also available with this syntax:
|
||||
|
||||
.. code-block:: Nim
|
||||
{.compile("myfile.cpp", "--custom flags here").}
|
||||
|
||||
As can be seen in the example, this new variant allows for custom flags
|
||||
that are passed to the C compiler when the file is recompiled.
|
||||
|
||||
|
||||
Link pragma
|
||||
-----------
|
||||
|
||||
16
doc/nimc.rst
16
doc/nimc.rst
@@ -149,6 +149,22 @@ ignored too. ``--define:FOO`` and ``--define:foo`` 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
|
||||
-------------------
|
||||
|
||||
@@ -1262,7 +1262,15 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
|
||||
else:
|
||||
badNodeKind someProc, "body="
|
||||
|
||||
proc basename*(a: NimNode): NimNode {.compileTime, benign.}
|
||||
proc basename*(a: NimNode): NimNode {.raises: [].} =
|
||||
## Pull an identifier from prefix/postfix expressions.
|
||||
case a.kind
|
||||
of nnkIdent: result = a
|
||||
of nnkPostfix, nnkPrefix: result = a[1]
|
||||
of nnkPragmaExpr: result = basename(a[0])
|
||||
else:
|
||||
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
|
||||
repr(a), a)
|
||||
|
||||
proc `$`*(node: NimNode): string {.compileTime.} =
|
||||
## Get the string of an identifier node.
|
||||
@@ -1325,16 +1333,6 @@ proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
|
||||
a[i + 1] = a[i]
|
||||
a[pos] = b
|
||||
|
||||
proc basename*(a: NimNode): NimNode =
|
||||
## Pull an identifier from prefix/postfix expressions.
|
||||
case a.kind
|
||||
of nnkIdent: result = a
|
||||
of nnkPostfix, nnkPrefix: result = a[1]
|
||||
of nnkPragmaExpr: result = basename(a[0])
|
||||
else:
|
||||
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
|
||||
repr(a), a)
|
||||
|
||||
proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
|
||||
case a.kind
|
||||
of nnkIdent:
|
||||
|
||||
@@ -298,19 +298,33 @@ proc `callback=`*[T](future: Future[T],
|
||||
## If future has already completed then ``cb`` will be called immediately.
|
||||
future.callback = proc () = cb(future)
|
||||
|
||||
template getFilenameProcname(entry: StackTraceEntry): (string, string) =
|
||||
when compiles(entry.filenameStr) and compiles(entry.procnameStr):
|
||||
# We can't rely on "entry.filename" and "entry.procname" still being valid
|
||||
# cstring pointers, because the "string.data" buffers they pointed to might
|
||||
# be already garbage collected (this entry being a non-shallow copy,
|
||||
# "entry.filename" no longer points to "entry.filenameStr.data", but to the
|
||||
# buffer of the original object).
|
||||
(entry.filenameStr, entry.procnameStr)
|
||||
else:
|
||||
($entry.filename, $entry.procname)
|
||||
|
||||
proc getHint(entry: StackTraceEntry): string =
|
||||
## We try to provide some hints about stack trace entries that the user
|
||||
## may not be familiar with, in particular calls inside the stdlib.
|
||||
|
||||
let (filename, procname) = getFilenameProcname(entry)
|
||||
|
||||
result = ""
|
||||
if entry.procname == cstring"processPendingCallbacks":
|
||||
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
||||
if procname == "processPendingCallbacks":
|
||||
if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0:
|
||||
return "Executes pending callbacks"
|
||||
elif entry.procname == cstring"poll":
|
||||
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
||||
elif procname == "poll":
|
||||
if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0:
|
||||
return "Processes asynchronous completion events"
|
||||
|
||||
if entry.procname.endsWith(NimAsyncContinueSuffix):
|
||||
if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0:
|
||||
if procname.endsWith(NimAsyncContinueSuffix):
|
||||
if cmpIgnoreStyle(filename, "asyncmacro.nim") == 0:
|
||||
return "Resumes an async procedure"
|
||||
|
||||
proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string =
|
||||
@@ -323,16 +337,20 @@ proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string =
|
||||
# Find longest filename & line number combo for alignment purposes.
|
||||
var longestLeft = 0
|
||||
for entry in entries:
|
||||
if entry.procname.isNil: continue
|
||||
let (filename, procname) = getFilenameProcname(entry)
|
||||
|
||||
let left = $entry.filename & $entry.line
|
||||
if left.len > longestLeft:
|
||||
longestLeft = left.len
|
||||
if procname == "": continue
|
||||
|
||||
let leftLen = filename.len + len($entry.line)
|
||||
if leftLen > longestLeft:
|
||||
longestLeft = leftLen
|
||||
|
||||
var indent = 2
|
||||
# Format the entries.
|
||||
for entry in entries:
|
||||
if entry.procname.isNil:
|
||||
let (filename, procname) = getFilenameProcname(entry)
|
||||
|
||||
if procname == "":
|
||||
if entry.line == reraisedFromBegin:
|
||||
result.add(spaces(indent) & "#[\n")
|
||||
indent.inc(2)
|
||||
@@ -341,11 +359,11 @@ proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string =
|
||||
result.add(spaces(indent) & "]#\n")
|
||||
continue
|
||||
|
||||
let left = "$#($#)" % [$entry.filename, $entry.line]
|
||||
let left = "$#($#)" % [filename, $entry.line]
|
||||
result.add((spaces(indent) & "$#$# $#\n") % [
|
||||
left,
|
||||
spaces(longestLeft - left.len + 2),
|
||||
$entry.procname
|
||||
procname
|
||||
])
|
||||
let hint = getHint(entry)
|
||||
if hint.len > 0:
|
||||
@@ -369,9 +387,9 @@ proc injectStacktrace[T](future: Future[T]) =
|
||||
newMsg.add($entries)
|
||||
|
||||
newMsg.add("Exception message: " & exceptionMsg & "\n")
|
||||
newMsg.add("Exception type:")
|
||||
|
||||
# # For debugging purposes
|
||||
# newMsg.add("Exception type:")
|
||||
# for entry in getStackTraceEntries(future.error):
|
||||
# newMsg.add "\n" & $entry
|
||||
future.error.msg = newMsg
|
||||
|
||||
@@ -110,7 +110,11 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) =
|
||||
resFut.complete(res)
|
||||
|
||||
# If the saved callback isn't nil then let's call it.
|
||||
if not savedCb.isNil: savedCb()
|
||||
if not savedCb.isNil:
|
||||
if fs.queue.len > 0:
|
||||
savedCb()
|
||||
else:
|
||||
future.cb = savedCb
|
||||
|
||||
if future.queue.len > 0 or future.finished:
|
||||
newCb(future)
|
||||
|
||||
@@ -1140,15 +1140,15 @@ proc downloadFile*(client: HttpClient, url: string, filename: string) =
|
||||
client.getBody = true
|
||||
let resp = client.get(url)
|
||||
|
||||
if resp.code.is4xx or resp.code.is5xx:
|
||||
raise newException(HttpRequestError, resp.status)
|
||||
|
||||
client.bodyStream = newFileStream(filename, fmWrite)
|
||||
if client.bodyStream.isNil:
|
||||
fileError("Unable to open file")
|
||||
parseBody(client, resp.headers, resp.version)
|
||||
client.bodyStream.close()
|
||||
|
||||
if resp.code.is4xx or resp.code.is5xx:
|
||||
raise newException(HttpRequestError, resp.status)
|
||||
|
||||
proc downloadFile*(client: AsyncHttpClient, url: string,
|
||||
filename: string): Future[void] =
|
||||
proc downloadFileEx(client: AsyncHttpClient,
|
||||
|
||||
@@ -181,6 +181,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)
|
||||
@@ -771,7 +773,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): JsonNode =
|
||||
proc parseJson(p: var JsonParser, depth=0): JsonNode =
|
||||
## Parses JSON from a JSON Parser `p`.
|
||||
case p.tok
|
||||
of tkString:
|
||||
@@ -795,6 +797,8 @@ proc parseJson(p: var JsonParser): JsonNode =
|
||||
result = newJNull()
|
||||
discard getTok(p)
|
||||
of tkCurlyLe:
|
||||
if depth > DepthLimit:
|
||||
raiseParseErr(p, "}")
|
||||
result = newJObject()
|
||||
discard getTok(p)
|
||||
while p.tok != tkCurlyRi:
|
||||
@@ -803,16 +807,18 @@ proc parseJson(p: var JsonParser): JsonNode =
|
||||
var key = p.a
|
||||
discard getTok(p)
|
||||
eat(p, tkColon)
|
||||
var val = parseJson(p)
|
||||
var val = parseJson(p, 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))
|
||||
result.add(parseJson(p, depth+1))
|
||||
if p.tok != tkComma: break
|
||||
discard getTok(p)
|
||||
eat(p, tkBracketRi)
|
||||
|
||||
@@ -583,7 +583,7 @@ when defineSsl:
|
||||
if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1:
|
||||
raiseSSLError()
|
||||
|
||||
when defined(nimDisableCertificateValidation) or defined(windows):
|
||||
when defined(nimDisableCertificateValidation):
|
||||
newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
|
||||
else:
|
||||
case verifyMode
|
||||
@@ -650,12 +650,11 @@ when defineSsl:
|
||||
let ctx = SslContext(context: ssl.SSL_get_SSL_CTX)
|
||||
let hintString = if hint == nil: "" else: $hint
|
||||
let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
|
||||
if psk.len.cuint > max_psk_len:
|
||||
if pskString.len.cuint > max_psk_len:
|
||||
return 0
|
||||
if identityString.len.cuint >= max_identity_len:
|
||||
return 0
|
||||
|
||||
copyMem(identity, identityString.cstring, pskString.len + 1) # with the last zero byte
|
||||
copyMem(identity, identityString.cstring, identityString.len + 1) # with the last zero byte
|
||||
copyMem(psk, pskString.cstring, pskString.len)
|
||||
|
||||
return pskString.len.cuint
|
||||
@@ -676,7 +675,7 @@ when defineSsl:
|
||||
max_psk_len: cint): cuint {.cdecl.} =
|
||||
let ctx = SslContext(context: ssl.SSL_get_SSL_CTX)
|
||||
let pskString = (ctx.serverGetPskFunc)($identity)
|
||||
if psk.len.cint > max_psk_len:
|
||||
if pskString.len.cint > max_psk_len:
|
||||
return 0
|
||||
copyMem(psk, pskString.cstring, pskString.len)
|
||||
|
||||
@@ -729,10 +728,11 @@ when defineSsl:
|
||||
raiseSSLError("No SSL certificate found.")
|
||||
|
||||
const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint
|
||||
const size = 1024
|
||||
var peername: string = newString(size)
|
||||
# https://www.openssl.org/docs/man1.1.1/man3/X509_check_host.html
|
||||
let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint,
|
||||
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, peername)
|
||||
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, nil)
|
||||
# https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_certificate.html
|
||||
X509_free(certificate)
|
||||
if match != 1:
|
||||
raiseSSLError("SSL Certificate check failed.")
|
||||
|
||||
|
||||
@@ -12,24 +12,24 @@
|
||||
## produce a globally distributed unique ID. This implementation was extracted
|
||||
## from the Mongodb interface and it thus binary compatible with a Mongo OID.
|
||||
##
|
||||
## This implementation calls ``math.randomize()`` for the first call of
|
||||
## This implementation calls `initRand()` for the first call of
|
||||
## ``genOid``.
|
||||
|
||||
import hashes, times, endians
|
||||
import hashes, times, endians, random
|
||||
|
||||
type
|
||||
Oid* = object ## an OID
|
||||
Oid* = object ## An OID.
|
||||
time: int32 ##
|
||||
fuzz: int32 ##
|
||||
count: int32 ##
|
||||
|
||||
proc `==`*(oid1: Oid, oid2: Oid): bool =
|
||||
## Compare two Mongo Object IDs for equality
|
||||
## Compares two Mongo Object IDs for equality.
|
||||
return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and
|
||||
(oid1.count == oid2.count)
|
||||
|
||||
proc hash*(oid: Oid): Hash =
|
||||
## Generate hash of Oid for use in hashtables
|
||||
## Generates hash of Oid for use in hashtables.
|
||||
var h: Hash = 0
|
||||
h = h !& hash(oid.time)
|
||||
h = h !& hash(oid.fuzz)
|
||||
@@ -44,7 +44,7 @@ proc hexbyte*(hex: char): int =
|
||||
else: discard
|
||||
|
||||
proc parseOid*(str: cstring): Oid =
|
||||
## parses an OID.
|
||||
## Parses an OID.
|
||||
var bytes = cast[cstring](addr(result.time))
|
||||
var i = 0
|
||||
while i < 12:
|
||||
@@ -52,6 +52,7 @@ proc parseOid*(str: cstring): Oid =
|
||||
inc(i)
|
||||
|
||||
proc oidToString*(oid: Oid, str: cstring) =
|
||||
## Converts an oid to `str` which must have space allocated for 25 elements.
|
||||
const hex = "0123456789abcdef"
|
||||
# work around a compiler bug:
|
||||
var str = str
|
||||
@@ -66,35 +67,33 @@ proc oidToString*(oid: Oid, str: cstring) =
|
||||
str[24] = '\0'
|
||||
|
||||
proc `$`*(oid: Oid): string =
|
||||
## Converts an oid to string.
|
||||
result = newString(24)
|
||||
oidToString(oid, result)
|
||||
|
||||
proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
|
||||
proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>", nodecl.}
|
||||
|
||||
var t = getTime().toUnix.int32
|
||||
srand(t)
|
||||
|
||||
var
|
||||
incr: int = rand()
|
||||
fuzz: int32 = rand()
|
||||
t = getTime().toUnix.int32
|
||||
seed = initRand(t)
|
||||
incr: int = seed.rand(int.high)
|
||||
|
||||
let fuzz = cast[int32](seed.rand(high(int)))
|
||||
|
||||
proc genOid*(): Oid =
|
||||
## generates a new OID.
|
||||
## Generates a new OID.
|
||||
runnableExamples:
|
||||
doAssert ($genOid()).len == 24
|
||||
if false: doAssert $genOid() == "5fc7f546ddbbc84800006aaf"
|
||||
t = getTime().toUnix.int32
|
||||
var i = int32(atomicInc(incr))
|
||||
var i = cast[int32](atomicInc(incr))
|
||||
|
||||
bigEndian32(addr result.time, addr(t))
|
||||
result.fuzz = fuzz
|
||||
bigEndian32(addr result.count, addr(i))
|
||||
|
||||
proc generatedTime*(oid: Oid): Time =
|
||||
## returns the generated timestamp of the OID.
|
||||
## Returns the generated timestamp of the OID.
|
||||
var tmp: int32
|
||||
var dummy = oid.time
|
||||
bigEndian32(addr(tmp), addr(dummy))
|
||||
result = fromUnix(tmp)
|
||||
|
||||
when not defined(testing) and isMainModule:
|
||||
let xo = genOid()
|
||||
echo xo.generatedTime
|
||||
|
||||
@@ -943,6 +943,8 @@ proc expandTilde*(path: string): string {.
|
||||
## Windows: this is still supported despite Windows platform not having this
|
||||
## convention; also, both ``~/`` and ``~\`` are handled.
|
||||
##
|
||||
## **Warning**: `~bob` and `~bob/` are not yet handled correctly.
|
||||
##
|
||||
## See also:
|
||||
## * `getHomeDir proc <#getHomeDir>`_
|
||||
## * `getConfigDir proc <#getConfigDir>`_
|
||||
|
||||
@@ -163,6 +163,8 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||
inIPv6 = true
|
||||
of ']':
|
||||
inIPv6 = false
|
||||
of '\0':
|
||||
break
|
||||
else:
|
||||
if inPort:
|
||||
result.port.add(authority[i])
|
||||
|
||||
@@ -74,7 +74,7 @@ when defined(js):
|
||||
system.`+`(a, b)
|
||||
{.pop.}
|
||||
|
||||
elif defined(posix):
|
||||
elif defined(posix) and not defined(osx):
|
||||
import posix
|
||||
|
||||
elif defined(windows):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## This module allows chains of field-access and indexing where the LHS can be nil.
|
||||
## This simplifies code by reducing need for if-else branches around intermediate values
|
||||
## that maybe be nil.
|
||||
## that may be nil.
|
||||
##
|
||||
## Note: experimental module and relies on {.experimental: "dotOperators".}
|
||||
## Unstable API.
|
||||
@@ -82,7 +82,7 @@ template `[]`*(a: Wrapnil): untyped =
|
||||
else:
|
||||
default(T)
|
||||
|
||||
import std/macros
|
||||
import macros
|
||||
|
||||
proc replace(n: NimNode): NimNode =
|
||||
if n.kind == nnkPar:
|
||||
|
||||
@@ -2058,7 +2058,7 @@ const
|
||||
NimMinor* {.intdefine.}: int = 2
|
||||
## is the minor number of Nim's version.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 10
|
||||
NimPatch* {.intdefine.}: int = 16
|
||||
## is the patch number of Nim's version.
|
||||
|
||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
|
||||
@@ -33,7 +33,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]
|
||||
@@ -89,18 +92,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".}
|
||||
|
||||
@@ -38,9 +38,6 @@ proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} =
|
||||
# todo: better error reporting
|
||||
sysFatal(RangeError, "value out of range")
|
||||
|
||||
proc raiseRangeErrorNoArgs() {.compilerproc, noinline.} =
|
||||
sysFatal(RangeError, "value out of range")
|
||||
|
||||
proc raiseObjectConversionError() {.compilerproc, noinline.} =
|
||||
sysFatal(ObjectConversionError, "invalid object conversion")
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ type
|
||||
programCounter*: uint ## Program counter - will be used to get the rest of the info,
|
||||
## when `$` is called on this type. We can't use
|
||||
## "cuintptr_t" in here.
|
||||
procnameStr*, filenameStr*: string ## GC-ed objects holding the cstrings in "procname" and "filename"
|
||||
procnameStr*, filenameStr*: string ## GC-ed alternatives to "procname" and "filename"
|
||||
|
||||
Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \
|
||||
## Base exception class.
|
||||
|
||||
@@ -436,7 +436,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
@@ -451,7 +451,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
{.pop.}
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
# generates a new object and sets its reference counter to 1
|
||||
incTypeSize typ, size
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||
@@ -662,16 +662,16 @@ proc collectCycles(gch: var GcHeap) =
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
sysAssert(allocInv(gch.region), "gcMark begin")
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[ByteAddress](cell)
|
||||
var c = cast[ByteAddress](p)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
|
||||
if objStart != nil:
|
||||
# mark the cell:
|
||||
incRef(objStart)
|
||||
add(gch.decStack, objStart)
|
||||
when false:
|
||||
let cell = usrToCell(p)
|
||||
if isAllocatedPtr(gch.region, cell):
|
||||
sysAssert false, "allocated pointer but not interior?"
|
||||
# mark the cell:
|
||||
|
||||
@@ -454,11 +454,10 @@ proc markGlobals(gch: var GcHeap) =
|
||||
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[ByteAddress](cell)
|
||||
var c = cast[ByteAddress](p)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
|
||||
if objStart != nil:
|
||||
mark(gch, objStart)
|
||||
|
||||
|
||||
@@ -248,15 +248,16 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||
var ti = 0
|
||||
let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
||||
|
||||
result = i - start
|
||||
let endPos = i
|
||||
result = endPos - start
|
||||
i = start
|
||||
# re-parse without error checking, any error should be handled by the code above.
|
||||
if i < s.len and s[i] == '.': i.inc
|
||||
while i < s.len and s[i] in {'0'..'9','+','-'}:
|
||||
if i < endPos and s[i] == '.': i.inc
|
||||
while i < endPos and s[i] in {'0'..'9','+','-'}:
|
||||
if ti < maxlen:
|
||||
t[ti] = s[i]; inc(ti)
|
||||
inc(i)
|
||||
while i < s.len and s[i] in {'.', '_'}: # skip underscore and decimal point
|
||||
while i < endPos and s[i] in {'.', '_'}: # skip underscore and decimal point
|
||||
inc(i)
|
||||
|
||||
# insert exponent
|
||||
|
||||
@@ -719,6 +719,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows):
|
||||
|
||||
proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
# Certificates store
|
||||
|
||||
type PX509_STORE* = SslPtr
|
||||
|
||||
@@ -9,7 +9,6 @@ pkg "argparse"
|
||||
pkg "arraymancer", true, "nim c tests/tests_cpu.nim"
|
||||
pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim"
|
||||
pkg "asyncmysql", true
|
||||
pkg "bigints", url = "https://github.com/Araq/nim-bigints"
|
||||
pkg "binaryheap", false, "nim c -r binaryheap.nim"
|
||||
# pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39
|
||||
pkg "bncurve", true
|
||||
@@ -17,8 +16,7 @@ pkg "c2nim", false, "nim c testsuite/tester.nim"
|
||||
pkg "cascade"
|
||||
pkg "chroma"
|
||||
pkg "chronicles", true, "nim c -o:chr -r chronicles.nim"
|
||||
# disable until my chronos fix was merged
|
||||
#pkg "chronos", true
|
||||
pkg "chronos", true, "nim c -r -d:release tests/testall"
|
||||
pkg "cligen", false, "nim c -o:cligenn -r cligen.nim"
|
||||
pkg "coco", true
|
||||
pkg "combparser"
|
||||
@@ -31,7 +29,7 @@ pkg "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmo
|
||||
pkg "elvis"
|
||||
pkg "fragments", false, "nim c -r fragments/dsl.nim"
|
||||
pkg "gara"
|
||||
pkg "ggplotnim", true, "nimble testCI"
|
||||
# pkg "ggplotnim", true, "nimble testCI"
|
||||
pkg "glob"
|
||||
pkg "gnuplot"
|
||||
pkg "hts", false, "nim c -o:htss src/hts.nim"
|
||||
@@ -52,13 +50,13 @@ pkg "nimcrypto", false, "nim c -r tests/testall.nim"
|
||||
pkg "NimData", true, "nim c -o:nimdataa src/nimdata.nim"
|
||||
pkg "nimes", true, "nim c src/nimes.nim"
|
||||
pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim"
|
||||
pkg "nimgame2", true, "nim c nimgame2/nimgame.nim"
|
||||
pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim"
|
||||
# pkg "nimgame2", true, "nim c nimgame2/nimgame.nim"
|
||||
# pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim"
|
||||
# pkg "nimlsp", true
|
||||
# pkg "nimly", true
|
||||
# pkg "nimongo", true, "nimble test_ci"
|
||||
pkg "nimpy", false, "nim c -r tests/nimfrompy.nim"
|
||||
pkg "nimquery"
|
||||
# pkg "nimpy", false, "nim c -r tests/nimfrompy.nim"
|
||||
# pkg "nimquery"
|
||||
pkg "nimsl", true
|
||||
pkg "nimsvg"
|
||||
# pkg "nimterop", true
|
||||
|
||||
@@ -590,3 +590,14 @@ block t12466:
|
||||
a[0'u16 + i] = i
|
||||
for i in 0'u16 ..< 8'u16:
|
||||
a[0'u16 + i] = i
|
||||
|
||||
block t18643:
|
||||
# https://github.com/nim-lang/Nim/issues/18643
|
||||
let a: array[0, int] = []
|
||||
var caught = false
|
||||
let b = 9999999
|
||||
try:
|
||||
echo a[b]
|
||||
except IndexError:
|
||||
caught = true
|
||||
doAssert caught, "IndexError not caught!"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import asyncdispatch
|
||||
|
||||
proc task() {.async.} =
|
||||
await sleepAsync(40)
|
||||
const tSleep = 40
|
||||
await sleepAsync(tSleep)
|
||||
|
||||
proc main() =
|
||||
var counter = 0
|
||||
@@ -10,6 +11,10 @@ proc main() =
|
||||
inc(counter)
|
||||
poll(10)
|
||||
|
||||
doAssert counter <= 4
|
||||
const slack = 1
|
||||
# because there is overhead in `async` + `sleepAsync`
|
||||
# as can be seen by increasing `tSleep` from 40 to 49, which increases the number
|
||||
# of failures.
|
||||
doAssert counter <= 4 + slack
|
||||
|
||||
for i in 0 .. 4: main()
|
||||
|
||||
@@ -86,7 +86,7 @@ Async traceback:
|
||||
asyncfutures\.nim\(\d+?\)\s+?read
|
||||
\]#
|
||||
Exception message: b failure
|
||||
Exception type:
|
||||
|
||||
|
||||
bar failure
|
||||
Async traceback:
|
||||
@@ -114,7 +114,7 @@ Async traceback:
|
||||
asyncfutures\.nim\(\d+?\)\s+?read
|
||||
\]#
|
||||
Exception message: bar failure
|
||||
Exception type:
|
||||
|
||||
"""
|
||||
|
||||
let resLines = splitLines(result.strip)
|
||||
|
||||
@@ -10,9 +10,7 @@ template processTest(t, x: untyped) =
|
||||
#stdout.flushFile()
|
||||
if not x: echo(t & " FAILED\r\n")
|
||||
|
||||
when defined(macosx):
|
||||
echo "All tests passed!"
|
||||
elif not defined(windows):
|
||||
when not defined(windows):
|
||||
import os, posix, nativesockets
|
||||
|
||||
when ioselSupportedPlatform:
|
||||
@@ -147,15 +145,16 @@ elif not defined(windows):
|
||||
proc timer_notification_test(): bool =
|
||||
var selector = newSelector[int]()
|
||||
var timer = selector.registerTimer(100, false, 0)
|
||||
var rc1 = selector.select(140)
|
||||
var rc2 = selector.select(140)
|
||||
assert(len(rc1) == 1 and len(rc2) == 1)
|
||||
var rc1 = selector.select(10000)
|
||||
var rc2 = selector.select(10000)
|
||||
# if this flakes, see tests/m14634.nim
|
||||
assert len(rc1) == 1 and len(rc2) == 1, $(len(rc1), len(rc2))
|
||||
selector.unregister(timer)
|
||||
discard selector.select(0)
|
||||
selector.registerTimer(100, true, 0)
|
||||
var rc4 = selector.select(120)
|
||||
var rc5 = selector.select(120)
|
||||
assert(len(rc4) == 1 and len(rc5) == 0)
|
||||
var rc4 = selector.select(10000)
|
||||
var rc5 = selector.select(1000) # this will be an actual wait, keep it small
|
||||
assert len(rc4) == 1 and len(rc5) == 0, $(len(rc4), len(rc5))
|
||||
assert(selector.isEmpty())
|
||||
selector.close()
|
||||
result = true
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
discard """
|
||||
disabled: "windows" # no sigsetjmp() there
|
||||
matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
|
||||
output: '''
|
||||
BEFORE
|
||||
FINALLY
|
||||
@@ -16,7 +18,7 @@ FINALLY
|
||||
|
||||
echo ""
|
||||
|
||||
proc no_expcetion =
|
||||
proc no_exception =
|
||||
try:
|
||||
echo "BEFORE"
|
||||
|
||||
@@ -27,7 +29,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)
|
||||
48
tests/m14634.nim
Normal file
48
tests/m14634.nim
Normal file
@@ -0,0 +1,48 @@
|
||||
#[
|
||||
Tool to investigate underlying reasons for https://github.com/nim-lang/Nim/pull/14634
|
||||
nim r --threads:on -d:threadsafe tests/m14634.nim
|
||||
]#
|
||||
|
||||
when not defined(windows):
|
||||
import std/selectors
|
||||
|
||||
type TestData = object
|
||||
s1, s2, s3: int
|
||||
|
||||
proc timerNotificationTestImpl(data: var TestData) =
|
||||
var selector = newSelector[int]()
|
||||
let t0 = 5
|
||||
var timer = selector.registerTimer(t0, false, 0)
|
||||
let t = 2000
|
||||
# values too close to `t0` cause the test to be flaky in CI on OSX+freebsd
|
||||
# When running locally, t0=100, t=98 will succeed some of the time which indicates
|
||||
# there is some lag involved. Note that the higher `t-t0` is, the less times
|
||||
# the test fails.
|
||||
var rc1 = selector.select(t)
|
||||
var rc2 = selector.select(t)
|
||||
assert len(rc1) <= 1 and len(rc2) <= 1
|
||||
data.s1 += ord(len(rc1) == 1)
|
||||
data.s2 += ord(len(rc2) == 1)
|
||||
selector.unregister(timer)
|
||||
discard selector.select(0)
|
||||
selector.registerTimer(t0, true, 0)
|
||||
# same comment as above
|
||||
var rc4 = selector.select(t)
|
||||
let t2 = 100
|
||||
# this can't be too large as it'll actually wait that long:
|
||||
# timer_notification_test.n * t2
|
||||
var rc5 = selector.select(t2)
|
||||
assert len(rc4) + len(rc5) <= 1
|
||||
data.s3 += ord(len(rc4) + len(rc5) == 1)
|
||||
assert(selector.isEmpty())
|
||||
selector.close()
|
||||
|
||||
proc timerNotificationTest() =
|
||||
var data: TestData
|
||||
let n = 10
|
||||
for i in 0..<n:
|
||||
timerNotificationTestImpl(data)
|
||||
doAssert data.s1 == n and data.s2 == n and data.s3 == n, $data
|
||||
|
||||
when isMainModule:
|
||||
timerNotificationTest()
|
||||
@@ -75,14 +75,3 @@ let rangeVar = 0'u64 ..< limit
|
||||
doAssert repr(rangeVar) == """[a = 0,
|
||||
b = 0]
|
||||
"""
|
||||
|
||||
# bug #15210
|
||||
|
||||
let a3 = not 0'u64
|
||||
var success = false
|
||||
try:
|
||||
discard a3.int64
|
||||
except RangeError:
|
||||
success = true
|
||||
|
||||
doAssert success, "conversion should fail at runtime"
|
||||
|
||||
4
tests/pragmas/cfunction.c
Normal file
4
tests/pragmas/cfunction.c
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
int cfunction(void) {
|
||||
return NUMBER_HERE;
|
||||
}
|
||||
9
tests/pragmas/tcompile_pragma.nim
Normal file
9
tests/pragmas/tcompile_pragma.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
discard """
|
||||
output: '''34'''
|
||||
"""
|
||||
|
||||
{.compile("cfunction.c", "-DNUMBER_HERE=34").}
|
||||
|
||||
proc cfunction(): cint {.importc.}
|
||||
|
||||
echo cfunction()
|
||||
6
tests/sandwich/generic_library.nim
Normal file
6
tests/sandwich/generic_library.nim
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
proc libraryFunc*[T](x: T) =
|
||||
mixin mixedIn, indirectlyMixedIn
|
||||
echo mixedIn()
|
||||
echo indirectlyMixedIn()
|
||||
|
||||
3
tests/sandwich/helper_module.nim
Normal file
3
tests/sandwich/helper_module.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
proc indirectlyMixedIn*: int =
|
||||
200
|
||||
12
tests/sandwich/module_using_generic_library.nim
Normal file
12
tests/sandwich/module_using_generic_library.nim
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
import
|
||||
generic_library, helper_module
|
||||
|
||||
proc mixedIn: int = 100
|
||||
|
||||
proc makeUseOfLibrary*[T](x: T) =
|
||||
bind mixedIn, indirectlyMixedIn
|
||||
libraryFunc(x)
|
||||
|
||||
when isMainModule:
|
||||
makeUseOfLibrary "test"
|
||||
9
tests/sandwich/tmain.nim
Normal file
9
tests/sandwich/tmain.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
discard """
|
||||
output: '''100
|
||||
200'''
|
||||
"""
|
||||
|
||||
import
|
||||
module_using_generic_library
|
||||
|
||||
makeUseOfLibrary "test"
|
||||
2
tests/slice/tdistinctslice.nim
Normal file
2
tests/slice/tdistinctslice.nim
Normal file
@@ -0,0 +1,2 @@
|
||||
type Foo = distinct uint64
|
||||
const slice = 0 ..< 42.Foo
|
||||
4
tests/stdlib/tmacros.nim
Normal file
4
tests/stdlib/tmacros.nim
Normal file
@@ -0,0 +1,4 @@
|
||||
import macros
|
||||
|
||||
block: # bug #17454
|
||||
proc f(v: NimNode): string {.raises: [].} = $v
|
||||
6
tests/stdlib/toids.nim
Normal file
6
tests/stdlib/toids.nim
Normal file
@@ -0,0 +1,6 @@
|
||||
import std/oids
|
||||
|
||||
|
||||
block: # genOid
|
||||
let x = genOid()
|
||||
doAssert ($x).len == 24
|
||||
43
tests/stdlib/tparseutils.nim
Normal file
43
tests/stdlib/tparseutils.nim
Normal file
@@ -0,0 +1,43 @@
|
||||
import parseutils, sequtils
|
||||
|
||||
|
||||
let input = "$test{} $this is ${an{ example}} "
|
||||
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
||||
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
||||
doAssert toSeq(interpolatedFragments(input)) == expected
|
||||
|
||||
var value = 0
|
||||
discard parseHex("0x38", value)
|
||||
doAssert value == 56
|
||||
|
||||
value = -1
|
||||
doAssert(parseSaturatedNatural("848", value) == 3)
|
||||
doAssert value == 848
|
||||
|
||||
value = -1
|
||||
discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
|
||||
doAssert value == high(int)
|
||||
|
||||
value = -1
|
||||
discard parseSaturatedNatural("9223372036854775808", value)
|
||||
doAssert value == high(int)
|
||||
|
||||
value = -1
|
||||
discard parseSaturatedNatural("9223372036854775807", value)
|
||||
doAssert value == high(int)
|
||||
|
||||
value = -1
|
||||
discard parseSaturatedNatural("18446744073709551616", value)
|
||||
doAssert value == high(int)
|
||||
|
||||
value = -1
|
||||
discard parseSaturatedNatural("18446744073709551615", value)
|
||||
doAssert value == high(int)
|
||||
|
||||
value = -1
|
||||
doAssert(parseSaturatedNatural("1_000_000", value) == 9)
|
||||
doAssert value == 1_000_000
|
||||
|
||||
var i64Value: int64
|
||||
discard parseBiggestInt("9223372036854775807", i64Value)
|
||||
doAssert i64Value == 9223372036854775807
|
||||
23
tests/stylecheck/tusages.nim
Normal file
23
tests/stylecheck/tusages.nim
Normal file
@@ -0,0 +1,23 @@
|
||||
discard """
|
||||
cmd: "nim c --styleCheck:error --styleCheck:usages $file"
|
||||
errormsg: "'BAD_STYLE' should be: 'BADSTYLE'"
|
||||
line: 20
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
||||
proc BADSTYLE(c: char) = discard
|
||||
|
||||
proc toSnakeCase(s: string): string =
|
||||
result = newStringOfCap(s.len + 3)
|
||||
for i in 0..<s.len:
|
||||
if s[i] in {'A'..'Z'}:
|
||||
if i > 0 and s[i-1] in {'a'..'z'}:
|
||||
result.add '_'
|
||||
result.add toLowerAscii(s[i])
|
||||
else:
|
||||
result.add s[i]
|
||||
BAD_STYLE(s[i])
|
||||
|
||||
echo toSnakeCase("fooBarBaz Yes")
|
||||
|
||||
@@ -41,7 +41,7 @@ proc downloadMingw(): DownloadResult =
|
||||
let curl = findExe"curl"
|
||||
var cmd: string
|
||||
if curl.len > 0:
|
||||
cmd = quoteShell(curl) & " --out " & "dist" / mingw & " " & url
|
||||
cmd = quoteShell(curl) & " --output " & "dist" / mingw & " " & url
|
||||
elif fileExists"bin/nimgrab.exe":
|
||||
cmd = r"bin\nimgrab.exe " & url & " dist" / mingw
|
||||
if cmd.len > 0:
|
||||
|
||||
Reference in New Issue
Block a user