Compare commits

..

53 Commits

Author SHA1 Message Date
narimiran
eeea72060c bump NimVersion to 1.2.16 2021-12-16 09:05:32 +01:00
Miran
0b1fee5d66 [backport:1.0] json: limit recursion depth (#19252)
* json: limit recursion depth

* do not run this check for JS backend

(cherry picked from commit c17baaefbc)
2021-12-14 18:23:42 +01:00
flywind
594831620b oids: switch from PRNG to random module (#16203)
* switch from PRNG to random module
* fix the regression
* comments + tests
* runnableExamples
* make oids better

(cherry picked from commit 89a21e4ec7)
2021-12-13 15:00:32 +01:00
Dominik Picheta
2eb0442a9a Update uri.nim (#19148) [backport:1.0]
(cherry picked from commit a3ef5df680)
2021-12-11 09:25:46 +01:00
Ștefan Talpalaru
002621b61d nimc.rst: fix table markup (#19239)
(cherry picked from commit 1a92edeb89)
2021-12-11 05:48:38 +01:00
Ștefan Talpalaru
8ea5475dd9 nimRawSetjmp: support Windows (#19197)
* nimRawSetjmp: support Windows

Using `_setjmp()` directly is required to avoid some rare (but very
annoying) exception-related stack corruption leading to segfaults on
Windows, with Mingw-w64 and SEH.
More details: https://github.com/status-im/nimbus-eth2/issues/3121

Also add "nimBuiltinSetjmp" - mostly for benchmarking.

* fix for Apple's Clang++

(cherry picked from commit 69aabdab80)
2021-12-11 05:48:35 +01:00
Andreas Rumpf
3e6d708175 implements https://github.com/nim-lang/RFCs/issues/260 (#15505)
* implements https://github.com/nim-lang/RFCs/issues/260

* added a test case

(cherry picked from commit 51e3e0c7c4)
2021-12-10 14:59:44 +01:00
narimiran
e3fb2c21d7 rename the file to prevent clashes in megatest 2021-12-08 14:58:18 +01:00
narimiran
c4ab020f0f correctly enable chronos 2021-12-08 08:26:01 +01:00
Tanguy
6e4fdbc4a9 fix #19193 (#19195) [backport:1.2]
(cherry picked from commit cd592ed85b)
2021-12-07 21:51:46 +01:00
Andreas Rumpf
497d061cd1 re-enable chronos testing once again [backport:1.2] (#19222)
(cherry picked from commit 93c8427fca)
2021-12-07 21:49:26 +01:00
Etan Kissling
4cb522fb8a allow HSlice bounded by constants of distinct types (#19219) [backport:1.2]
When creating heterogenous slices of distinct types, the compiler does
not initialize the internal type's `size` before accessing it.
This then leads to this crash message:
```
compiler/int128.nim(594, 11) `false` masking only implemented for 1, 2, 4 and 8 bytes [AssertionError]
```
This patch initializes the `size` properly, fixing the problem.

(cherry picked from commit 0213c7313b)
2021-12-07 21:48:08 +01:00
narimiran
84c1b1af0e we must use Ubuntu 18.04 2021-12-07 19:27:45 +01:00
narimiran
a683ca3fac bigints are not supposed to work on 1.2.x 2021-12-07 19:15:47 +01:00
narimiran
f7ea7b3c4f disable nimpy 2021-12-07 18:09:57 +01:00
Andreas Rumpf
a34845b66c fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db7ee)
2021-12-07 16:34:58 +01:00
Andreas Rumpf
79f95a2efc misc bugfixes [backport:1.2] (#19203)
(cherry picked from commit 23c117a950)
2021-12-06 12:53:37 +01:00
Andreas Rumpf
8a3f542532 fixes #14470 [backport:1.2] (#19115)
(cherry picked from commit 15157d06c3)
2021-12-06 12:51:56 +01:00
Andreas Rumpf
2009df72cb fixes a 'mixin' statement handling regression [backport:1.2] (#18968)
(cherry picked from commit 8eef557157)
2021-12-06 12:51:32 +01:00
narimiran
f4216f12b3 bump NimVersion to 1.2.15 2021-12-06 12:50:03 +01:00
narimiran
d327eaacbf bump NimVersion to 1.2.14 2021-11-07 09:51:32 +01:00
Etan Kissling
735e3eea78 allow converting static vars to openArray (#19049)
When assigning constant output to a seq, and then passing that static
seq to other functions that take `openArray`, the compiler may end up
producing errors, as it does not know how to convert `static[seq[T]]`
to `openArray[T]`. By ignoring the `static` wrapper on the type for
the purpose of determining data memory location and length, this gets
resolved cleanly. Unfortunately, it is relatively tricky to come up
with a minimal example, as there are followup problems from the failing
conversion, e.g., this may lead to `internal error: inconsistent
environment type`, instead of the relevant `openArrayLoc` error message.

(cherry picked from commit 490c4226a5)
2021-10-27 11:04:39 +02:00
flywind
d8cc349ac6 [tools] use the right parameter [backport:1.0] (#18957)
(cherry picked from commit b2873f0f63)
2021-10-06 13:41:27 +02:00
narimiran
e05daba73e try to fix the flaky test, similarly to the devel version 2021-08-25 08:22:51 +02:00
narimiran
2a72eeafdf it is IndexError, not IndexDefect, in 1.2 2021-08-24 15:05:17 +02:00
narimiran
2d06867388 disable testing packages which depend on newer Nim versions 2021-08-24 11:32:45 +02:00
narimiran
9b47614ba1 we can't use collect like that in 1.2 2021-08-24 11:32:28 +02:00
flywind
8d5065453f fix #18702(fix parseutils.parseFloat) (#18703) [backport:1.0]
* fix #18702
* Apply suggestions from code review

(cherry picked from commit 901c5ded52)
2021-08-24 07:20:47 +02:00
Andreas Rumpf
1802f94868 fixes #18643 [backport:1.0] (#18678)
(cherry picked from commit 018465a234)
2021-08-24 07:18:08 +02:00
Timothee Cour
5a42d393a4 link stable and devel docs in nim docs (#18272) [backport:1.2]
(cherry picked from commit d3b27eb63e)
2021-08-24 07:14:17 +02:00
Ștefan Talpalaru
76560576d2 asyncdispatch+stackTraceOverride: fix premature collection (#18039) [backport:1.2]
Copying StackTraceEntry instances when nimStackTraceOverride is defined
breaks the link between a cstring field that's supposed to point at
another string field in the same object.

Sometimes, the original object is garbage collected, that memory region
reused for storing other strings, so when the StackTraceEntry copy tries
to use its cstring pointer to construct a traceback message, it accesses
unrelated strings.

This only happens for async tracebacks and this patch prevents that by
making sure we only use the string fields when nimStackTraceOverride is
defined.

Async tracebacks also beautified slightly by getting rid of an extra line
that was supposed to be commented out, along with the corresponding debugging output.

There's also a micro-optimisation to avoid concatenating two strings just
to get their combined length.

(cherry picked from commit a1c82c39af)
2021-05-19 19:52:50 +02:00
narimiran
2684b04ab1 disable 'nimquery' package 2021-05-17 22:27:10 +02:00
Timothee Cour
6dde797752 fix #13166 tioselectors flaky test on freebsd+OSX (#14634)
(cherry picked from commit d149823019)
2021-05-17 22:26:45 +02:00
Andreas Rumpf
74f34c81e8 feature: the compiler can warn when you use the implicit 'result' variable (#17988) [backport:1.2]
* implements #17855

(cherry picked from commit 378ee7f888)
2021-05-17 19:04:34 +02:00
Andreas Rumpf
34563f86c2 fixes #15848 [backport:1.2] (#17959)
(cherry picked from commit 51f3ef6cb8)
2021-05-17 16:13:10 +02:00
shirleyquirk
7a9e5ba68f Fix buffer-overrun bug in net (#17728) [backport:1.0]
(cherry picked from commit fdd4391534)
2021-05-17 16:10:33 +02:00
narimiran
d2af421089 use csources_v1 in build_all scripts 2021-04-30 10:56:42 +02:00
Andreas Rumpf
ba02bf50b9 CIs: attempt to use csources_v1 (#16282)
* CIs: attempt to use csources_v1
* also updated the BSDs
* also updated azure pipelines
* std modules should not itself use the 'std/' import dir...
* compiler has to be careful with std/ for v1 booting

(cherry picked from commit a9b62de895)
2021-04-28 08:50:39 +02:00
narimiran
424a00db2b bump NimVersion to 1.2.13 2021-04-28 08:40:02 +02:00
zah
fb03c4b937 Remove the use of usrToCell in gcMark [backport:1.2] (#17709)
* Remove the use of usrToCell in gcMark [backport:1.2]

Recently, we've discovered a GC crash resulting from inlining of
the memory allocation procs that allowed the compiler to avoid
maintaining any references to the "user pointer" on the stack.
Instead, a "cell pointer" appeared there and all field accesses
were performed with adjusted offsets. This interfered with the
ability of the GC to mark the correct cell in the conservative
stack scans which lead to premature collection of objects.

More details here:
af69b3ceae

This commit closes another theoretical loophole that may lead to
the same problem. If a short proc is accessing both the object and
its reference count in a short sequence of instructions, the compiler
may be enticed to reduce the number of registers being used by storing
only a single pointer to the object and using offsets when reading
and writing fields. A perfectly good strategy would be to store only
the cell pointer, so the reference count updates can be performed
without applying offsets. Accessing the fields of the object requires
offsets anyway, but these can be adjusted at compile-time without any
loss. Following this strategy will lead to the same problem of marking
a wrong cell during the conservative stack scan, leading to premature
collection.

The problem is avoided by not using `usrToCell` in `gcMark`. Since
the cell discovery logic can already handle interior pointers, the
user pointers don't need to be adjusted for the GC to function correctly.

(cherry picked from commit 3b47a689cf)
2021-04-14 12:10:39 +02:00
narimiran
ba8f657635 bump NimVersion to 1.2.12 2021-04-13 21:52:25 +02:00
narimiran
6238f2ee1e Revert "fixes #11225; generic sandwich problems; [backport:1.2] (#17255)"
This reverts commit d85b7dde7b.
2021-04-13 09:59:53 +02:00
narimiran
7aff6ded84 [ci skip] minor: fix indentation in manual.rst
(cherry picked from commit d3529d0d5a)
2021-03-31 13:42:48 +02:00
Miran
fe8b84496f [backport:1.2] Avoid inlining of newObj and newObjRC1 calls (#17582)
This is taken from:
af69b3ceae

Full original comment:

This is to avoid heavy inlining happening when two allocation calls
would occur shortly after each other.

This inlining would sometimes be accompanied with an optimisation
as the compiler is able to see that cellToUsr ending the first
allocation call is shortly followed by an usrToCell call. The
pointer arithmetic is redundant and the compiler can eliminate it,
leaving only the cell address in a register (and later the stack)
instead of the actual pointer to the user data, as one would expect.

This combined with a GC collect cycle will cause the stack scan to
only notice the cell address, which is of no good due to a usrToCell
in the gcMark call which shifts that address to an adjacent cell.
This means that the actual cell of importance will not get marked
and thus cause a premature collection of that cell. BOOM.

(cherry picked from commit 40093b4a93)
2021-03-30 11:47:39 +02:00
Danil Yarantsev
7f834c69fb Free the certificate after checking in checkCertName (#17558) [backport:1.2]
* Fix small leak in checkCertName
* Size is not needed either
* Free the certificate after checking

(cherry picked from commit b36182b0a4)
2021-03-29 15:34:11 +02:00
Timothee Cour
9a58bddc55 fix #17454 (#17461)
(cherry picked from commit d78ebe4a0e)
2021-03-29 15:34:03 +02:00
narimiran
9ebf537341 bump NimVersion to 1.2.11 2021-03-26 09:02:54 +01:00
narimiran
5ea5d82507 Revert "fixes #15210 [backport:1.2] (#15237)"
This reverts commit ae688aa7f5.
2021-03-22 11:52:22 +01:00
Andreas Rumpf
d85b7dde7b fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db7ee)
2021-03-20 08:44:04 +01:00
Igor Ribeiro de Assis
1d301e354f Fix FutureStream memory usage (#17395) [backport:1.2]
(cherry picked from commit 9bb0e55749)
2021-03-18 17:46:59 +01:00
xioren
a7570ff0c2 Relocate 4xx/5xx exception in downloadFile (#17332) [backport:1.2]
Move 4xx/5xx exception to before disk i/o. As it stands an empty file is created on http error 4xx/5xx.

(cherry picked from commit 3d198fdcc2)
2021-03-18 17:30:15 +01:00
alaviss
86c8977726 compiler/installer.ini: package cacert.pem on Windows [backport:1.2] (#17172)
Follow up of 5dc544e1f5

After updating windeps.zip, it appears that Windows' build was
unchanged. As it turns out, cacert.pem is not set for packaging by the
compiler package manifest.

This commit add cacert.pem to the Windows package.

(cherry picked from commit d35f366d6f)
2021-03-18 17:25:41 +01:00
Andreas Rumpf
2ee078cdf8 fixes yet another SSL problem on Windows [backport:1.2] (#17167)
(cherry picked from commit b48a32053f)
2021-03-18 17:24:37 +01:00
83 changed files with 918 additions and 242 deletions

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 ..

View File

@@ -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 ..

View File

@@ -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%

View File

@@ -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:

View File

@@ -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 =

View File

@@ -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])

View File

@@ -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:

View File

@@ -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 =

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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,

View File

@@ -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) =

View File

@@ -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

View File

@@ -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)

View File

@@ -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])

View File

@@ -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)

View File

@@ -38,6 +38,7 @@ type
mappingExists*: bool
mapping*: TIdTable
caseContext*: seq[tuple[n: PNode, idx: int]]
localBindStmts*: seq[PNode]
TMatchedConcept* = object
candidateType*: PType

View File

@@ -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}))

View File

@@ -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)

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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">

View File

@@ -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

View File

@@ -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.

View File

@@ -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
-----------

View File

@@ -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
-------------------

View File

@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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)

View File

@@ -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.")

View File

@@ -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

View File

@@ -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>`_

View File

@@ -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])

View File

@@ -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):

View File

@@ -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:

View File

@@ -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

View File

@@ -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".}

View File

@@ -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")

View File

@@ -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.

View File

@@ -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:

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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!"

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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 ""

View 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
View 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()

View File

@@ -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"

View File

@@ -0,0 +1,4 @@
int cfunction(void) {
return NUMBER_HERE;
}

View File

@@ -0,0 +1,9 @@
discard """
output: '''34'''
"""
{.compile("cfunction.c", "-DNUMBER_HERE=34").}
proc cfunction(): cint {.importc.}
echo cfunction()

View File

@@ -0,0 +1,6 @@
proc libraryFunc*[T](x: T) =
mixin mixedIn, indirectlyMixedIn
echo mixedIn()
echo indirectlyMixedIn()

View File

@@ -0,0 +1,3 @@
proc indirectlyMixedIn*: int =
200

View 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
View File

@@ -0,0 +1,9 @@
discard """
output: '''100
200'''
"""
import
module_using_generic_library
makeUseOfLibrary "test"

View File

@@ -0,0 +1,2 @@
type Foo = distinct uint64
const slice = 0 ..< 42.Foo

4
tests/stdlib/tmacros.nim Normal file
View File

@@ -0,0 +1,4 @@
import macros
block: # bug #17454
proc f(v: NimNode): string {.raises: [].} = $v

6
tests/stdlib/toids.nim Normal file
View File

@@ -0,0 +1,6 @@
import std/oids
block: # genOid
let x = genOid()
doAssert ($x).len == 24

View 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

View 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")

View File

@@ -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: