mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
121 Commits
v1.4.2
...
version-1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce295d7243 | ||
|
|
c6e0983b47 | ||
|
|
c5cd23a776 | ||
|
|
30ba13d22a | ||
|
|
315f4ecff1 | ||
|
|
49379e85ec | ||
|
|
6ab3c1b365 | ||
|
|
0dae9115c8 | ||
|
|
32882fa024 | ||
|
|
dc1e948f15 | ||
|
|
65db3013a8 | ||
|
|
7f0e662032 | ||
|
|
547973c3e9 | ||
|
|
4d5c5893ae | ||
|
|
8c356fd971 | ||
|
|
17522d6ae1 | ||
|
|
f8047c3e3c | ||
|
|
cfb6ebc07a | ||
|
|
8f20400466 | ||
|
|
6d3b706f6e | ||
|
|
0df0510722 | ||
|
|
68df3c9afd | ||
|
|
a8aaf5a27d | ||
|
|
80c8107c56 | ||
|
|
5bed375b52 | ||
|
|
1228c5b3fc | ||
|
|
0a8e9318d3 | ||
|
|
22650a61e7 | ||
|
|
8b80039cac | ||
|
|
b18c6fd09b | ||
|
|
88340aab6d | ||
|
|
8a3e64f00e | ||
|
|
6c5585fc0b | ||
|
|
ca1b7feb0f | ||
|
|
44e653a931 | ||
|
|
0250c4710d | ||
|
|
8001c7be98 | ||
|
|
94f80f5bcb | ||
|
|
1281d8dfb8 | ||
|
|
7a8817e87f | ||
|
|
a63d434180 | ||
|
|
9fc0955587 | ||
|
|
cb22a99584 | ||
|
|
ad5c784d22 | ||
|
|
a6d84179fc | ||
|
|
e4d5139de0 | ||
|
|
9d23c14dd2 | ||
|
|
daad1cd9d9 | ||
|
|
61ac87a2b8 | ||
|
|
f825c8f691 | ||
|
|
4b4ef2b4b3 | ||
|
|
431eb05708 | ||
|
|
3e154e7740 | ||
|
|
e70044fb28 | ||
|
|
5618a34d61 | ||
|
|
f48daa29f6 | ||
|
|
2640dc2637 | ||
|
|
2b6b080323 | ||
|
|
ab1ae92587 | ||
|
|
5dd88ca1a4 | ||
|
|
598d9f8402 | ||
|
|
f7f7a02915 | ||
|
|
28b301cbaa | ||
|
|
69c2c05463 | ||
|
|
cc6bc8960d | ||
|
|
05991805fb | ||
|
|
82561f31eb | ||
|
|
e5027dc3da | ||
|
|
f97d840f96 | ||
|
|
560800246e | ||
|
|
cf1ecee794 | ||
|
|
6b00463074 | ||
|
|
e996d98a8a | ||
|
|
5c88067953 | ||
|
|
061d106671 | ||
|
|
c2e2f50d35 | ||
|
|
2ff517462b | ||
|
|
29a064e275 | ||
|
|
bfc0d64825 | ||
|
|
540d16540b | ||
|
|
7705948d52 | ||
|
|
a154acda85 | ||
|
|
8f9ea358b6 | ||
|
|
8d7e1c4649 | ||
|
|
87dc838370 | ||
|
|
c04214f8cb | ||
|
|
132a694c6e | ||
|
|
c55506006f | ||
|
|
a263e9aae0 | ||
|
|
94560a9faa | ||
|
|
5f46474555 | ||
|
|
21e1fa6217 | ||
|
|
bf06fb7053 | ||
|
|
ccbdb95539 | ||
|
|
de98648caa | ||
|
|
3f1f26a7e2 | ||
|
|
8f38f3e34d | ||
|
|
c7d090c418 | ||
|
|
9b31b12ca5 | ||
|
|
3c74ec0a0f | ||
|
|
4da6577c97 | ||
|
|
93ee832d3c | ||
|
|
5e49d3b68a | ||
|
|
5e5803f28f | ||
|
|
d9e14414a4 | ||
|
|
c346c0b91b | ||
|
|
822c7acd3c | ||
|
|
71bbbdbf96 | ||
|
|
1d8b7aa07c | ||
|
|
db5ce7ed48 | ||
|
|
939702a001 | ||
|
|
753aed9d63 | ||
|
|
c9d7c67acb | ||
|
|
265499ee57 | ||
|
|
2f13f5bb56 | ||
|
|
9a86afc8fd | ||
|
|
553c2e5cff | ||
|
|
bf0ad3acab | ||
|
|
4c918515fd | ||
|
|
6e45429ab1 | ||
|
|
8a528979e8 |
@@ -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
|
||||
|
||||
@@ -18,7 +18,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.ncpuonline)
|
||||
bin/nim c koch
|
||||
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
|
||||
|
||||
@@ -18,7 +18,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.ncpuonline)
|
||||
bin/nim c koch
|
||||
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
|
||||
|
||||
@@ -18,7 +18,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.ncpuonline)
|
||||
bin/nim c koch
|
||||
echo 'export PATH=$HOME/Nim/bin:$PATH' >> $HOME/.buildenv
|
||||
|
||||
6
.github/workflows/ci_docs.yml
vendored
6
.github/workflows/ci_docs.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
- target: windows
|
||||
os: windows-2019
|
||||
- target: osx
|
||||
os: macos-10.15
|
||||
os: macos-11
|
||||
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -74,7 +74,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'
|
||||
@@ -88,7 +88,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'
|
||||
|
||||
2
.github/workflows/ci_packages.yml
vendored
2
.github/workflows/ci_packages.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-18.04, macos-10.15]
|
||||
os: [ubuntu-20.04, macos-11]
|
||||
cpu: [amd64]
|
||||
pkg: [1, 2]
|
||||
name: '${{ matrix.os }} (pkg: ${{ matrix.pkg }})'
|
||||
|
||||
@@ -22,7 +22,7 @@ addons:
|
||||
- valgrind
|
||||
|
||||
before_script:
|
||||
- git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
- git clone --depth 1 https://github.com/nim-lang/csources_v1.git csources
|
||||
- export PATH="$PWD/bin${PATH:+:$PATH}"
|
||||
- make -C csources -j 2 LD=$CC ucpu=$CPU
|
||||
|
||||
|
||||
@@ -15,16 +15,16 @@ 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'
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
vmImage: 'macOS-10.15'
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
NIM_COMPILE_TO_CPP: true
|
||||
Windows_amd64_batch0_3:
|
||||
@@ -55,7 +55,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
|
||||
|
||||
|
||||
47
changelog.md
47
changelog.md
@@ -2,7 +2,33 @@
|
||||
|
||||
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected.
|
||||
The downside is that these defines now have custom logic that doesn't apply for
|
||||
other defines.
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
- On Windows the SSL library now checks for valid certificates.
|
||||
It uses the `cacert.pem` file for this purpose which was extracted
|
||||
from `https://curl.se/ca/cacert.pem`. Besides
|
||||
the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
|
||||
now also need to ship `cacert.pem` with your `.exe` file.
|
||||
|
||||
|
||||
- Make `{.requiresInit.}` pragma to work for `distinct` types.
|
||||
|
||||
- Added a macros `enumLen` for returning the number of items in an enum to the
|
||||
`typetraits.nim` module.
|
||||
|
||||
- `prelude` now works with the JavaScript target.
|
||||
|
||||
@@ -19,6 +45,7 @@
|
||||
- Added `asyncdispatch.activeDescriptors` that returns the number of currently
|
||||
active async event handles/file descriptors
|
||||
|
||||
- Fixed premature garbage collection in asyncdispatch, when a stack trace override is in place.
|
||||
|
||||
## Language changes
|
||||
|
||||
@@ -32,5 +59,25 @@
|
||||
|
||||
|
||||
|
||||
- Added `unsafeIsolate` and `extract` to `std/isolation`.
|
||||
|
||||
- `--hint:CC` now goes to stderr (like all other hints) instead of stdout.
|
||||
|
||||
- json build instructions are now generated in `$nimcache/outFileBasename.json`
|
||||
instead of `$nimcache/projectName.json`. This allows avoiding recompiling a given project
|
||||
compiled with different options if the output file differs.
|
||||
|
||||
- `--usenimcache` (implied by `nim r main`) now generates an output file that includes a hash of
|
||||
some of the compilation options, which allows caching generated binaries:
|
||||
nim r main # recompiles
|
||||
nim r -d:foo main # recompiles
|
||||
nim r main # uses cached binary
|
||||
nim r main arg1 arg2 # ditto (runtime arguments are irrelevant)
|
||||
|
||||
- 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%
|
||||
|
||||
|
||||
@@ -807,7 +807,7 @@ type
|
||||
|
||||
PInstantiation* = ref TInstantiation
|
||||
|
||||
TScope* = object
|
||||
TScope* {.acyclic.} = object
|
||||
depthLevel*: int
|
||||
symbols*: TStrTable
|
||||
parent*: PScope
|
||||
|
||||
@@ -16,7 +16,7 @@ const
|
||||
Mhalf = M div 2
|
||||
|
||||
type
|
||||
Node[Key, Val] = ref object
|
||||
Node[Key, Val] {.acyclic.} = ref object
|
||||
entries: int
|
||||
keys: array[M, Key]
|
||||
case isInternal: bool
|
||||
|
||||
@@ -214,7 +214,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
||||
case skipTypes(a.t, abstractVar).kind
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(n):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
|
||||
@@ -916,7 +916,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)])
|
||||
@@ -2307,7 +2307,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
|
||||
of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
|
||||
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
|
||||
of mStrToStr, mUnown, mIsolate: expr(p, e[1], d)
|
||||
of mStrToStr, mUnown: expr(p, e[1], d)
|
||||
of mIsolate: genCall(p, e, d)
|
||||
of mEnumToStr:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
genEnumToStr(p, e, d)
|
||||
@@ -2323,7 +2324,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
gcUsage(p.config, e)
|
||||
else:
|
||||
genNewFinalize(p, e)
|
||||
of mNewSeq: genNewSeq(p, e)
|
||||
of mNewSeq:
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
e[1] = makeAddr(e[1])
|
||||
genCall(p, e, d)
|
||||
else:
|
||||
genNewSeq(p, e)
|
||||
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
|
||||
of mSizeOf:
|
||||
let t = e[1].typ.skipTypes({tyTypeDesc})
|
||||
@@ -2851,6 +2857,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 =
|
||||
|
||||
@@ -25,10 +25,10 @@ proc getTraverseProc(p: BProc, v: PSym): Rope =
|
||||
|
||||
proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
|
||||
if sfThread in v.flags:
|
||||
appcg(p.module, p.module.initProc.procSec(cpsInit),
|
||||
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
|
||||
"$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc])
|
||||
else:
|
||||
appcg(p.module, p.module.initProc.procSec(cpsInit),
|
||||
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
|
||||
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
||||
|
||||
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
@@ -1349,8 +1349,19 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimBuiltinSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint])
|
||||
elif isDefined(p.config, "nimRawSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||
if isDefined(p.config, "mswindows"):
|
||||
# The Windows `_setjmp()` takes two arguments, with the second being an
|
||||
# undocumented buffer used by the SEH mechanism for stack unwinding.
|
||||
# Mingw-w64 has been trying to get it right for years, but it's still
|
||||
# prone to stack corruption during unwinding, so we disable that by setting
|
||||
# it to NULL.
|
||||
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])
|
||||
|
||||
@@ -223,7 +223,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 (tfByCopy notin rettype.flags and getSize(conf, rettype) > conf.target.floatSize*3):
|
||||
result = true
|
||||
else:
|
||||
case mapType(conf, rettype, skResult)
|
||||
of ctArray:
|
||||
@@ -1327,6 +1328,10 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
|
||||
|
||||
genProc(m, theProc)
|
||||
result = theProc.loc.r
|
||||
|
||||
when false:
|
||||
if not canFormAcycle(t) and op == attachedTrace:
|
||||
echo "ayclic but has this =trace ", t, " ", theProc.ast
|
||||
else:
|
||||
when false:
|
||||
if op == attachedTrace and m.config.selectedGC == gcOrc and
|
||||
@@ -1352,9 +1357,12 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn
|
||||
let traceImpl = genHook(m, t, info, attachedTrace)
|
||||
let disposeImpl = genHook(m, t, info, attachedDispose)
|
||||
|
||||
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6;", [
|
||||
var flags = 0
|
||||
if not canFormAcycle(t): flags = flags or 1
|
||||
|
||||
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6; $1.flags = $7;", [
|
||||
name, destroyImpl, getTypeDesc(m, t), typeName,
|
||||
traceImpl, disposeImpl])
|
||||
traceImpl, disposeImpl, rope(flags)])
|
||||
|
||||
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
|
||||
discard genTypeInfoV1(m, t, info)
|
||||
|
||||
@@ -439,8 +439,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
||||
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
if containsGarbageCollectedRef(loc.t):
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
else:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use nimZeroMem for temporary values for performance if we can
|
||||
@@ -855,7 +861,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 =
|
||||
@@ -1686,7 +1693,7 @@ proc genInitCode(m: BModule) =
|
||||
writeSection(preInitProc, cpsLocals)
|
||||
writeSection(preInitProc, cpsInit, m.hcrOn)
|
||||
writeSection(preInitProc, cpsStmts)
|
||||
prc.addf("}$N", [])
|
||||
prc.addf("}/* preInitProc end */$N", [])
|
||||
when false:
|
||||
m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals)
|
||||
m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit)
|
||||
@@ -2052,7 +2059,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil:
|
||||
discard cgsym(m, "nimTestErrorFlag")
|
||||
|
||||
if {optGenStaticLib, optGenDynLib} * m.config.globalOptions == {}:
|
||||
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
|
||||
for i in countdown(high(graph.globalDestructors), 0):
|
||||
n.add graph.globalDestructors[i]
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
|
||||
@@ -121,7 +121,10 @@
|
||||
# yield 2
|
||||
# if :unrollFinally: # This node is created by `newEndFinallyNode`
|
||||
# if :curExc.isNil:
|
||||
# return :tmpResult
|
||||
# if nearestFinally == 0:
|
||||
# return :tmpResult
|
||||
# else:
|
||||
# :state = nearestFinally # bubble up
|
||||
# else:
|
||||
# closureIterSetupExc(nil)
|
||||
# raise
|
||||
@@ -156,7 +159,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:
|
||||
@@ -604,6 +607,12 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
|
||||
result.add(n)
|
||||
result.add(ctx.newEnvVarAccess(tmp))
|
||||
elif n[0].kind == nkStmtListExpr:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
let (st, ex) = exprToStmtList(n[0])
|
||||
result.add(st)
|
||||
n[0] = ex
|
||||
result.add(n)
|
||||
|
||||
of nkCallKinds, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
var ns = false
|
||||
@@ -794,7 +803,10 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
||||
# Generate the following code:
|
||||
# if :unrollFinally:
|
||||
# if :curExc.isNil:
|
||||
# return :tmpResult
|
||||
# if nearestFinally == 0:
|
||||
# return :tmpResult
|
||||
# else:
|
||||
# :state = nearestFinally # bubble up
|
||||
# else:
|
||||
# raise
|
||||
let curExc = ctx.newCurExcAccess()
|
||||
@@ -803,11 +815,17 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
||||
let cmp = newTree(nkCall, newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info), curExc, nilnode)
|
||||
cmp.typ = ctx.g.getSysType(info, tyBool)
|
||||
|
||||
let asgn = newTree(nkFastAsgn,
|
||||
newSymNode(getClosureIterResult(ctx.g, ctx.fn), info),
|
||||
ctx.newTmpResultAccess())
|
||||
let retStmt =
|
||||
if ctx.nearestFinally == 0:
|
||||
# last finally, we can return
|
||||
let asgn = newTree(nkFastAsgn,
|
||||
newSymNode(getClosureIterResult(ctx.g, ctx.fn), info),
|
||||
ctx.newTmpResultAccess())
|
||||
newTree(nkReturnStmt, asgn)
|
||||
else:
|
||||
# bubble up to next finally
|
||||
newTree(nkGotoState, ctx.g.newIntLit(info, ctx.nearestFinally))
|
||||
|
||||
let retStmt = newTree(nkReturnStmt, asgn)
|
||||
let branch = newTree(nkElifBranch, cmp, retStmt)
|
||||
|
||||
let nullifyExc = newTree(nkCall, newSymNode(ctx.g.getCompilerProc("closureIterSetupExc")), nilnode)
|
||||
@@ -851,6 +869,13 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
|
||||
of nkSkip:
|
||||
discard
|
||||
of nkTryStmt:
|
||||
if n.hasYields:
|
||||
# the inner try will handle these transformations
|
||||
discard
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
n[i] = ctx.transformReturnsInTry(n[i])
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
n[i] = ctx.transformReturnsInTry(n[i])
|
||||
|
||||
@@ -145,7 +145,7 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC
|
||||
proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
case arg.normalize
|
||||
of "","on": conf.options.incl op
|
||||
of "", "on": conf.options.incl op
|
||||
of "off": conf.options.excl op
|
||||
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||
|
||||
@@ -391,6 +391,19 @@ proc handleStdinInput*(conf: ConfigRef) =
|
||||
if conf.outDir.isEmpty:
|
||||
conf.outDir = getNimcacheDir(conf)
|
||||
|
||||
proc specialDefine(conf: ConfigRef, key: string) =
|
||||
# Keep this syncronized with the default config/nim.cfg!
|
||||
if cmpIgnoreStyle(key, "nimQuirky") == 0:
|
||||
conf.exc = excQuirky
|
||||
elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0:
|
||||
conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize}
|
||||
conf.globalOptions.excl {optExcessiveStackTrace, optCDebug}
|
||||
conf.options.incl optOptimizeSpeed
|
||||
if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0:
|
||||
conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
|
||||
optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir}
|
||||
conf.globalOptions.excl {optCDebug}
|
||||
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf: ConfigRef) =
|
||||
var
|
||||
@@ -450,12 +463,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if {':', '='} in arg:
|
||||
splitSwitch(conf, arg, key, val, pass, info)
|
||||
if cmpIgnoreStyle(key, "nimQuirky") == 0:
|
||||
conf.exc = excQuirky
|
||||
specialDefine(conf, key)
|
||||
defineSymbol(conf.symbols, key, val)
|
||||
else:
|
||||
if cmpIgnoreStyle(arg, "nimQuirky") == 0:
|
||||
conf.exc = excQuirky
|
||||
specialDefine(conf, arg)
|
||||
defineSymbol(conf.symbols, arg)
|
||||
of "undef", "u":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
@@ -854,6 +865,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)
|
||||
|
||||
@@ -123,3 +123,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasStacktracesModule")
|
||||
defineSymbol("nimHasEffectTraitsModule")
|
||||
defineSymbol("nimHasCastPragmaBlocks")
|
||||
defineSymbol("nimHasJsBigIntBackend")
|
||||
|
||||
@@ -843,7 +843,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
result = n
|
||||
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
|
||||
|
||||
@@ -6,8 +6,8 @@ Name: "Nim"
|
||||
Version: "$version"
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
|
||||
macosx: i386;amd64;powerpc64
|
||||
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64
|
||||
macosx: i386;amd64;powerpc64;arm64
|
||||
solaris: i386;amd64;sparc;sparc64
|
||||
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
|
||||
netbsd: i386;amd64
|
||||
@@ -110,6 +110,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"
|
||||
|
||||
@@ -14,27 +14,28 @@ The JS code generator contains only 2 tricks:
|
||||
|
||||
Trick 1
|
||||
-------
|
||||
Some locations (for example 'var int') require "fat pointers" (``etyBaseIndex``)
|
||||
Some locations (for example 'var int') require "fat pointers" (`etyBaseIndex`)
|
||||
which are pairs (array, index). The derefence operation is then 'array[index]'.
|
||||
Check ``mapType`` for the details.
|
||||
Check `mapType` for the details.
|
||||
|
||||
Trick 2
|
||||
-------
|
||||
It is preferable to generate '||' and '&&' if possible since that is more
|
||||
idiomatic and hence should be friendlier for the JS JIT implementation. However
|
||||
code like ``foo and (let bar = baz())`` cannot be translated this way. Instead
|
||||
the expressions need to be transformed into statements. ``isSimpleExpr``
|
||||
code like `foo and (let bar = baz())` cannot be translated this way. Instead
|
||||
the expressions need to be transformed into statements. `isSimpleExpr`
|
||||
implements the required case distinction.
|
||||
"""
|
||||
|
||||
|
||||
import
|
||||
ast, strutils, trees, magicsys, options,
|
||||
nversion, msgs, idents, types, tables,
|
||||
ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
transf, injectdestructors, sourcemap, json, sets
|
||||
ast, trees, magicsys, options,
|
||||
nversion, msgs, idents, types,
|
||||
ropes, passes, ccgutils, wordrecg, renderer,
|
||||
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
transf, injectdestructors, sourcemap
|
||||
|
||||
import json, sets, math, tables, intsets, strutils
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -1345,7 +1346,15 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkStmtListExpr:
|
||||
if n.len == 1: gen(p, n[0], r)
|
||||
else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
|
||||
else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
||||
of nkCallKinds:
|
||||
if n[0].typ.kind == tyOpenArray:
|
||||
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
||||
# namely toOpenArray(a, 1, 3)
|
||||
gen(p, n[0], r)
|
||||
else:
|
||||
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
||||
else:
|
||||
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
||||
|
||||
proc attachProc(p: PProc; content: Rope; s: PSym) =
|
||||
p.g.code.add(content)
|
||||
@@ -1418,7 +1427,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
s.name.s)
|
||||
discard mangleName(p.module, s)
|
||||
r.res = s.loc.r
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
||||
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or
|
||||
{sfImportc, sfInfixCall} * s.flags != {}:
|
||||
discard
|
||||
elif s.kind == skMethod and s.getBody.kind == nkEmpty:
|
||||
@@ -1672,7 +1681,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
var t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
|
||||
result = putToSeq("0", indirect)
|
||||
if $t.sym.loc.r == "bigint":
|
||||
result = putToSeq("0n", indirect)
|
||||
else:
|
||||
result = putToSeq("0", indirect)
|
||||
of tyFloat..tyFloat128:
|
||||
result = putToSeq("0.0", indirect)
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned:
|
||||
@@ -1994,7 +2006,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n[2], rhs)
|
||||
|
||||
if skipTypes(n[1].typ, abstractVarRange).kind == tyCString:
|
||||
r.res = "$1 += $2;" % [lhs.rdLoc, rhs.rdLoc]
|
||||
let (b, tmp) = maybeMakeTemp(p, n[2], rhs)
|
||||
r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" %
|
||||
[b, lhs.rdLoc, tmp]
|
||||
else:
|
||||
let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
|
||||
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
|
||||
@@ -2045,9 +2059,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mDestroy: discard "ignore calls to the default destructor"
|
||||
of mOrd: genOrd(p, n, r)
|
||||
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||
unaryExpr(p, n, r, "", "($1).length")
|
||||
var x: TCompRes
|
||||
gen(p, n[1], x)
|
||||
if skipTypes(n[1].typ, abstractInst).kind == tyCString:
|
||||
let (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
r.res = "(($1) == null ? 0 : ($2).length)" % [a, tmp]
|
||||
else:
|
||||
r.res = "($1).length" % [x.rdLoc]
|
||||
r.kind = resExpr
|
||||
of mHigh:
|
||||
unaryExpr(p, n, r, "", "(($1).length-1)")
|
||||
var x: TCompRes
|
||||
gen(p, n[1], x)
|
||||
if skipTypes(n[1].typ, abstractInst).kind == tyCString:
|
||||
let (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
r.res = "(($1) == null ? -1 : ($2).length - 1)" % [a, tmp]
|
||||
else:
|
||||
r.res = "($1).length - 1" % [x.rdLoc]
|
||||
r.kind = resExpr
|
||||
of mInc:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
|
||||
binaryUintExpr(p, n, r, "+", true)
|
||||
@@ -2523,7 +2551,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let s = n[namePos].sym
|
||||
discard mangleName(p.module, s)
|
||||
r.res = s.loc.r
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
|
||||
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard
|
||||
elif not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
p.locals.add(genProc(p, s))
|
||||
of nkType: r.res = genTypeInfo(p, n.typ)
|
||||
@@ -2560,7 +2588,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkRaiseStmt: genRaiseStmt(p, n)
|
||||
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
|
||||
nkMixinStmt, nkBindStmt: discard
|
||||
of nkIteratorDef:
|
||||
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
|
||||
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
|
||||
|
||||
@@ -238,10 +238,11 @@ proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
|
||||
result = conf.backend == backendJs and not isCompileTime
|
||||
|
||||
proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; owner: PSym) =
|
||||
createTypeBoundOps(g, nil, refType.lastSon, info)
|
||||
createTypeBoundOps(g, nil, refType, info)
|
||||
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
|
||||
owner.flags.incl sfInjectDestructors
|
||||
if owner.kind != skMacro:
|
||||
createTypeBoundOps(g, nil, refType.lastSon, info)
|
||||
createTypeBoundOps(g, nil, refType, info)
|
||||
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
|
||||
owner.flags.incl sfInjectDestructors
|
||||
|
||||
proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
@@ -494,7 +495,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:
|
||||
@@ -611,7 +613,8 @@ proc rawClosureCreation(owner: PSym;
|
||||
let fieldAccess = indirectAccess(env, local, env.info)
|
||||
# add ``env.param = param``
|
||||
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
|
||||
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info)
|
||||
if owner.kind != skMacro:
|
||||
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info)
|
||||
if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions:
|
||||
owner.flags.incl sfInjectDestructors
|
||||
|
||||
@@ -748,7 +751,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:
|
||||
|
||||
@@ -435,13 +435,17 @@ proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
|
||||
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
|
||||
|
||||
proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let counterIdx = body.len
|
||||
let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
|
||||
let whileLoop = genWhileLoop(c, i, x)
|
||||
let elemType = t.lastSon
|
||||
let b = if c.kind == attachedTrace: y else: y.at(i, elemType)
|
||||
fillBody(c, elemType, whileLoop[1], x.at(i, elemType), b)
|
||||
addIncStmt(c, whileLoop[1], i)
|
||||
body.add whileLoop
|
||||
if whileLoop[1].len > 0:
|
||||
addIncStmt(c, whileLoop[1], i)
|
||||
body.add whileLoop
|
||||
else:
|
||||
body.sons.setLen counterIdx
|
||||
|
||||
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
@@ -464,8 +468,9 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add genBuiltin(c.g, mDestroy, "destroy", x)
|
||||
of attachedTrace:
|
||||
# follow all elements:
|
||||
forallElements(c, t, body, x, y)
|
||||
if canFormAcycle(t.elemType):
|
||||
# follow all elements:
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedDispose:
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add genBuiltin(c.g, mDestroy, "destroy", x)
|
||||
@@ -598,16 +603,20 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genIf(c, cond, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace:
|
||||
if isFinal(elemType):
|
||||
let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
|
||||
typInfo.typ = getSysType(c.g, c.info, tyPointer)
|
||||
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
|
||||
else:
|
||||
# If the ref is polymorphic we have to account for this
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x), y)
|
||||
if isCyclic:
|
||||
if isFinal(elemType):
|
||||
let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
|
||||
typInfo.typ = getSysType(c.g, c.info, tyPointer)
|
||||
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
|
||||
else:
|
||||
# If the ref is polymorphic we have to account for this
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x), y)
|
||||
#echo "can follow ", elemType, " static ", isFinal(elemType)
|
||||
of attachedDispose:
|
||||
# this is crucial! dispose is like =destroy but we don't follow refs
|
||||
# as that is dealt within the cycle collector.
|
||||
if not isCyclic:
|
||||
body.add genIf(c, cond, actions)
|
||||
when false:
|
||||
let cond = copyTree(x)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -55,6 +55,7 @@ type
|
||||
warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed",
|
||||
warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition",
|
||||
warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores",
|
||||
warnResultUsed = "ResultUsed",
|
||||
warnUser = "User",
|
||||
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC",
|
||||
@@ -125,6 +126,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`
|
||||
@@ -176,7 +178,7 @@ type
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores}
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed}
|
||||
result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
|
||||
@@ -93,7 +93,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) =
|
||||
|
||||
@@ -31,7 +31,7 @@ import ast, intsets, tables, options, lineinfos, hashes, idents,
|
||||
type
|
||||
SigHash* = distinct MD5Digest
|
||||
|
||||
ModuleGraph* = ref object
|
||||
ModuleGraph* {.acyclic.} = ref object
|
||||
modules*: seq[PSym] ## indexed by int32 fileIdx
|
||||
packageSyms*: TStrTable
|
||||
deps*: IntSet # the dependency graph or potentially its transitive closure.
|
||||
|
||||
@@ -24,7 +24,7 @@ import
|
||||
idents, lineinfos, cmdlinehelper,
|
||||
pathutils, modulegraphs
|
||||
|
||||
from std/browsers import openDefaultBrowser
|
||||
from browsers import openDefaultBrowser
|
||||
from nodejs import findNodeJs
|
||||
|
||||
when hasTinyCBackend:
|
||||
|
||||
@@ -16,7 +16,7 @@ interpolation variables:
|
||||
Unstable API
|
||||
]##
|
||||
|
||||
import std/[os,strutils]
|
||||
import os, strutils
|
||||
|
||||
const
|
||||
docCss* = "$nimr/doc/nimdoc.css"
|
||||
|
||||
@@ -150,7 +150,8 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
|
||||
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
discard "do not follow the construct"
|
||||
|
||||
of nkAsgn, nkFastAsgn:
|
||||
@@ -249,7 +250,8 @@ proc opt(c: Con; n, parent: PNode; parentPos: int) =
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr,
|
||||
nkMixinStmt, nkBindStmt:
|
||||
parent[parentPos] = n
|
||||
|
||||
else:
|
||||
|
||||
@@ -19,7 +19,7 @@ const
|
||||
useEffectSystem* = true
|
||||
useWriteTracking* = false
|
||||
hasFFI* = defined(nimHasLibFFI)
|
||||
copyrightYear* = "2020"
|
||||
copyrightYear* = "2021"
|
||||
|
||||
type # please make sure we have under 32 options
|
||||
# (improves code efficiency a lot!)
|
||||
@@ -59,6 +59,7 @@ type # please make sure we have under 32 options
|
||||
optUseNimcache, # save artifacts (including binary) in $nimcache
|
||||
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
|
||||
@@ -229,7 +230,7 @@ type
|
||||
ProfileData* = ref object
|
||||
data*: TableRef[TLineInfo, ProfileInfo]
|
||||
|
||||
ConfigRef* = ref object ## every global configuration
|
||||
ConfigRef* {.acyclic.} = ref object ## every global configuration
|
||||
## fields marked with '*' are subject to
|
||||
## the incremental compilation mechanisms
|
||||
## (+) means "part of the dependency"
|
||||
@@ -355,7 +356,7 @@ proc hasHint*(conf: ConfigRef, note: TNoteKind): bool =
|
||||
note in conf.mainPackageNotes
|
||||
else: 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
|
||||
|
||||
@@ -1310,6 +1310,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
#| | IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' exprList ':' stmt
|
||||
#| | IND{=} 'finally' ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
result = x
|
||||
if p.tok.indent >= 0: return
|
||||
@@ -1364,6 +1365,9 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
of tkExcept:
|
||||
nextBlock = newNodeP(nkExceptBranch, p)
|
||||
exprList(p, tkColon, nextBlock)
|
||||
of tkFinally:
|
||||
nextBlock = newNodeP(nkFinally, p)
|
||||
getTok(p)
|
||||
of tkElse:
|
||||
nextBlock = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
@@ -1374,7 +1378,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
nextBlock.flags.incl nfBlockArg
|
||||
result.add nextBlock
|
||||
|
||||
if nextBlock.kind == nkElse: break
|
||||
if nextBlock.kind in {nkElse, nkFinally}: break
|
||||
else:
|
||||
if openingParams.kind != nkEmpty:
|
||||
parMessage(p, "expected ':'")
|
||||
|
||||
@@ -193,7 +193,7 @@ type
|
||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||
cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips,
|
||||
cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430,
|
||||
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuEsp, cpuWasm32
|
||||
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32
|
||||
|
||||
type
|
||||
TEndian* = enum
|
||||
@@ -226,6 +226,7 @@ const
|
||||
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)]
|
||||
|
||||
@@ -20,7 +20,7 @@ const
|
||||
|
||||
const
|
||||
declPragmas = {wImportc, wImportObjC, wImportCpp, wImportJs, wExportc, wExportCpp,
|
||||
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed, wAlign}
|
||||
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed}
|
||||
## common pragmas for declarations, to a good approximation
|
||||
procPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
wMagic, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
|
||||
@@ -54,22 +54,23 @@ const
|
||||
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
|
||||
wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert}
|
||||
lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv,
|
||||
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
|
||||
wThread, wAsmNoStackFrame,
|
||||
wRaises, wLocks, wTags, wRequires, wEnsures,
|
||||
wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these?
|
||||
wGcSafe, wCodegenDecl, wNoInit}
|
||||
typePragmas* = declPragmas + {wMagic, wAcyclic,
|
||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
||||
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
|
||||
fieldPragmas* = declPragmas + {
|
||||
wGuard, wBitsize, wCursor, wRequiresInit, wNoalias} - {wExportNims, wNodecl} # why exclude these?
|
||||
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
|
||||
wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these?
|
||||
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
|
||||
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
|
||||
wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wNoalias}
|
||||
wGensym, wInject, wCodegenDecl,
|
||||
wGuard, wGoto, wCursor, wNoalias, wAlign}
|
||||
constPragmas* = declPragmas + {wHeader, wMagic,
|
||||
wGensym, wInject,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
|
||||
|
||||
@@ -105,6 +105,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])
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ type
|
||||
|
||||
POptionEntry* = ref TOptionEntry
|
||||
PProcCon* = ref TProcCon
|
||||
TProcCon* = object # procedure context; also used for top-level
|
||||
# statements
|
||||
TProcCon* {.acyclic.} = object # procedure context; also used for top-level
|
||||
# statements
|
||||
owner*: PSym # the symbol this context belongs to
|
||||
resultSym*: PSym # the result symbol (if we are in a proc)
|
||||
selfSym*: PSym # the 'self' symbol (if available)
|
||||
@@ -38,6 +38,7 @@ type
|
||||
mappingExists*: bool
|
||||
mapping*: TIdTable
|
||||
caseContext*: seq[tuple[n: PNode, idx: int]]
|
||||
localBindStmts*: seq[PNode]
|
||||
|
||||
TMatchedConcept* = object
|
||||
candidateType*: PType
|
||||
|
||||
@@ -1216,6 +1216,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:
|
||||
@@ -2901,6 +2904,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 {.nosinks.} =
|
||||
## 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()
|
||||
|
||||
@@ -358,12 +358,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)
|
||||
|
||||
@@ -1822,8 +1822,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
|
||||
|
||||
@@ -841,7 +841,7 @@ proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
addInheritedFields(c, check, pos, obj[0].skipGenericInvocation)
|
||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||
|
||||
proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PType =
|
||||
proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType =
|
||||
if n.len == 0:
|
||||
return newConstraint(c, tyObject)
|
||||
var check = initIntSet()
|
||||
@@ -877,8 +877,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PTy
|
||||
if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode")
|
||||
result = newOrPrevType(tyObject, prev, c)
|
||||
rawAddSon(result, realBase)
|
||||
if realBase == nil and isInheritable:
|
||||
if realBase == nil and tfInheritable in flags:
|
||||
result.flags.incl tfInheritable
|
||||
if tfAcyclic in flags: result.flags.incl tfAcyclic
|
||||
if result.n.isNil:
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
else:
|
||||
@@ -903,8 +904,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
let body = n.lastSon
|
||||
var t = if prev != nil and body.kind == nkObjectTy and tfInheritable in prev.flags:
|
||||
semObjectNode(c, body, nil, isInheritable=true)
|
||||
var t = if prev != nil and body.kind == nkObjectTy:
|
||||
semObjectNode(c, body, nil, prev.flags)
|
||||
else:
|
||||
semTypeNode(c, body, nil)
|
||||
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
|
||||
@@ -1916,7 +1917,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
localError(c.config, n.info, "type expected, but got symbol '$1' of kind '$2'" %
|
||||
[s.name.s, substr($s.kind, 2)])
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
of nkObjectTy: result = semObjectNode(c, n, prev, isInheritable=false)
|
||||
of nkObjectTy: result = semObjectNode(c, n, prev, {})
|
||||
of nkTupleTy: result = semTuple(c, n, prev)
|
||||
of nkTupleClassTy: result = newConstraint(c, tyTuple)
|
||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||
|
||||
@@ -67,7 +67,7 @@ proc cacheTypeInst*(inst: PType) =
|
||||
gt.sym.typeInstCache.add(inst)
|
||||
|
||||
type
|
||||
LayeredIdTable* = ref object
|
||||
LayeredIdTable* {.acyclic.} = ref object
|
||||
topLayer*: TIdTable
|
||||
nextLayer*: LayeredIdTable
|
||||
|
||||
|
||||
@@ -614,8 +614,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
# if f is metatype.
|
||||
result = typeRel(c, f, a)
|
||||
|
||||
# v--- is this correct?
|
||||
if result <= isIntConv or inconsistentVarTypes(f, a):
|
||||
if result <= isSubrange or inconsistentVarTypes(f, a):
|
||||
result = isNone
|
||||
|
||||
#if result == isEqual:
|
||||
|
||||
@@ -966,7 +966,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:
|
||||
|
||||
@@ -73,7 +73,7 @@ const
|
||||
tyInferred, tySink, tyLent, tyOwned}
|
||||
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
|
||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||
typedescInst* = abstractInst + {tyTypeDesc, tyOwned}
|
||||
typedescInst* = abstractInst + {tyTypeDesc, tyOwned, tyUserTypeClass}
|
||||
|
||||
proc invalidGenericInst*(f: PType): bool =
|
||||
result = f.kind == tyGenericInst and lastSon(f) == nil
|
||||
@@ -365,13 +365,13 @@ proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
|
||||
if tfAcyclic in t.flags: return
|
||||
case t.kind
|
||||
of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs:
|
||||
if not containsOrIncl(marker, t.id):
|
||||
if t.id == startId:
|
||||
result = true
|
||||
elif not containsOrIncl(marker, t.id):
|
||||
for i in 0..<t.len:
|
||||
result = canFormAcycleAux(marker, t[i], startId)
|
||||
if result: return
|
||||
if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
|
||||
else:
|
||||
result = t.id == startId
|
||||
# Inheritance can introduce cyclic types, however this is not relevant
|
||||
# as the type that is passed to 'new' is statically known!
|
||||
# er but we use it also for the write barrier ...
|
||||
@@ -387,7 +387,8 @@ proc isFinal*(t: PType): bool =
|
||||
|
||||
proc canFormAcycle*(typ: PType): bool =
|
||||
var marker = initIntSet()
|
||||
result = canFormAcycleAux(marker, typ, typ.id)
|
||||
let t = skipTypes(typ, abstractInst+{tyOwned}-{tyTypeDesc})
|
||||
result = canFormAcycleAux(marker, t, t.id)
|
||||
|
||||
proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
|
||||
closure: RootRef): PType
|
||||
|
||||
@@ -57,6 +57,7 @@ type
|
||||
ownsData,
|
||||
preventCursor,
|
||||
isReassigned,
|
||||
isConditionallyReassigned,
|
||||
viewDoesMutate,
|
||||
viewBorrowsFromConst
|
||||
|
||||
@@ -98,6 +99,7 @@ type
|
||||
goals: set[Goal]
|
||||
unanalysableMutation: bool
|
||||
inAsgnSource, inConstructor, inNoSideEffectSection: int
|
||||
inConditional, inLoop: int
|
||||
owner: PSym
|
||||
config: ConfigRef
|
||||
|
||||
@@ -629,7 +631,8 @@ const
|
||||
nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr}
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
|
||||
|
||||
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
|
||||
if constParameters in c.goals and tfNoSideEffect in callee.flags:
|
||||
@@ -748,6 +751,13 @@ proc traverse(c: var Partitions; n: PNode) =
|
||||
else:
|
||||
for child in n: traverse(c, child)
|
||||
|
||||
proc markAsReassigned(c: var Partitions; vid: int) {.inline.} =
|
||||
c.s[vid].flags.incl isReassigned
|
||||
if c.inConditional > 0 and c.inLoop > 0:
|
||||
# bug #17033: live ranges with loops and conditionals are too
|
||||
# complex for our current analysis, so we prevent the cursorfication.
|
||||
c.s[vid].flags.incl isConditionallyReassigned
|
||||
|
||||
proc computeLiveRanges(c: var Partitions; n: PNode) =
|
||||
# first pass: Compute live ranges for locals.
|
||||
# **Watch out!** We must traverse the tree like 'traverse' does
|
||||
@@ -777,7 +787,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) =
|
||||
if n[1].kind == nkSym and (c.s[vid].reassignedTo == 0 or c.s[vid].reassignedTo == n[1].sym.id):
|
||||
c.s[vid].reassignedTo = n[1].sym.id
|
||||
else:
|
||||
c.s[vid].flags.incl isReassigned
|
||||
markAsReassigned(c, vid)
|
||||
|
||||
of nkSym:
|
||||
dec c.abstractTime
|
||||
@@ -804,7 +814,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) =
|
||||
if not paramType.isCompileTimeOnly and paramType.kind == tyVar:
|
||||
let vid = variableId(c, it.sym)
|
||||
if vid >= 0:
|
||||
c.s[vid].flags.incl isReassigned
|
||||
markAsReassigned(c, vid)
|
||||
|
||||
of nkAddr, nkHiddenAddr:
|
||||
computeLiveRanges(c, n[0])
|
||||
@@ -822,7 +832,13 @@ proc computeLiveRanges(c: var Partitions; n: PNode) =
|
||||
# while cond:
|
||||
# mutate(graph)
|
||||
# connect(graph, cursorVar)
|
||||
inc c.inLoop
|
||||
for child in n: computeLiveRanges(c, child)
|
||||
inc c.inLoop
|
||||
of nkElifBranch, nkElifExpr, nkElse, nkOfBranch:
|
||||
inc c.inConditional
|
||||
for child in n: computeLiveRanges(c, child)
|
||||
dec c.inConditional
|
||||
else:
|
||||
for child in n: computeLiveRanges(c, child)
|
||||
|
||||
@@ -896,7 +912,8 @@ proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) =
|
||||
var par = computeGraphPartitions(s, n, config, {cursorInference})
|
||||
for i in 0 ..< par.s.len:
|
||||
let v = addr(par.s[i])
|
||||
if v.flags * {ownsData, preventCursor} == {} and v.sym.kind notin {skParam, skResult} and
|
||||
if v.flags * {ownsData, preventCursor, isConditionallyReassigned} == {} and
|
||||
v.sym.kind notin {skParam, skResult} and
|
||||
v.sym.flags * {sfThread, sfGlobal} == {} and hasDestructor(v.sym.typ) and
|
||||
v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned:
|
||||
let rid = root(par, i)
|
||||
|
||||
@@ -995,7 +995,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let nc = regs[rc].node
|
||||
if nb.kind != nc.kind: discard
|
||||
elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional
|
||||
elif sameConstant(nb, nc): ret = true
|
||||
elif (nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ.kind == tyProc) and sameConstant(nb, nc):
|
||||
ret = true
|
||||
# this also takes care of procvar's, represented as nkTupleConstr, e.g. (nil, nil)
|
||||
elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit
|
||||
let tb = nb.getTyp
|
||||
|
||||
@@ -265,7 +265,7 @@ type
|
||||
templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst
|
||||
|
||||
PStackFrame* = ref TStackFrame
|
||||
TStackFrame* = object
|
||||
TStackFrame* {.acyclic.} = object
|
||||
prc*: PSym # current prc; proc that is evaluated
|
||||
slots*: seq[TFullReg] # parameters passed to the proc + locals;
|
||||
# parameters come first
|
||||
|
||||
@@ -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
|
||||
#
|
||||
@@ -1003,7 +1003,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.genNarrow(n[1], d)
|
||||
c.genAsgnPatch(n[1], d)
|
||||
c.freeTemp(d)
|
||||
of mOrd, mChr, mArrToSeq, mUnown, mIsolate: c.gen(n[1], dest)
|
||||
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
|
||||
of mIsolate:
|
||||
genCall(c, n, dest)
|
||||
of mNew, mNewFinalize:
|
||||
unused(c, n, dest)
|
||||
c.genNew(n)
|
||||
@@ -1952,14 +1954,6 @@ proc genProc*(c: PCtx; s: PSym): int
|
||||
|
||||
proc matches(s: PSym; x: string): bool =
|
||||
let y = x.split('.')
|
||||
var s = s
|
||||
for i in 1..y.len:
|
||||
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
|
||||
return false
|
||||
s = s.owner
|
||||
result = true
|
||||
|
||||
proc matches(s: PSym; y: varargs[string]): bool =
|
||||
var s = s
|
||||
for i in 1..y.len:
|
||||
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
|
||||
@@ -2022,11 +2016,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
elif s.kind == skMethod:
|
||||
localError(c.config, n.info, "cannot call method " & s.name.s &
|
||||
" at compile time")
|
||||
elif matches(s, "stdlib", "marshal", "to"):
|
||||
elif matches(s, "stdlib.marshal.to"):
|
||||
# XXX marshal load&store should not be opcodes, but use the
|
||||
# general callback mechanisms.
|
||||
genMarshalLoad(c, n, dest)
|
||||
elif matches(s, "stdlib", "marshal", "$$"):
|
||||
elif matches(s, "stdlib.marshal.$$"):
|
||||
genMarshalStore(c, n, dest)
|
||||
else:
|
||||
genCall(c, n, dest)
|
||||
@@ -2109,7 +2103,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)
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#import vmdeps, vm
|
||||
from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
|
||||
arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
|
||||
floor, ceil, `mod`
|
||||
floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma,
|
||||
lgamma
|
||||
|
||||
from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename
|
||||
from md5 import getMD5
|
||||
@@ -147,6 +148,7 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
setResult a, c.config.projectPath.string
|
||||
|
||||
wrap1f_math(sqrt)
|
||||
wrap1f_math(cbrt)
|
||||
wrap1f_math(ln)
|
||||
wrap1f_math(log10)
|
||||
wrap1f_math(log2)
|
||||
@@ -155,6 +157,9 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
wrap1f_math(arccos)
|
||||
wrap1f_math(arcsin)
|
||||
wrap1f_math(arctan)
|
||||
wrap1f_math(arcsinh)
|
||||
wrap1f_math(arccosh)
|
||||
wrap1f_math(arctanh)
|
||||
wrap2f_math(arctan2)
|
||||
wrap1f_math(cos)
|
||||
wrap1f_math(cosh)
|
||||
@@ -167,6 +172,10 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
wrap1f_math(trunc)
|
||||
wrap1f_math(floor)
|
||||
wrap1f_math(ceil)
|
||||
wrap1f_math(erf)
|
||||
wrap1f_math(erfc)
|
||||
wrap1f_math(gamma)
|
||||
wrap1f_math(lgamma)
|
||||
|
||||
wrap1s(getMD5, md5op)
|
||||
|
||||
|
||||
@@ -3,3 +3,9 @@
|
||||
when defined(nimHasCppDefine):
|
||||
cppDefine "errno"
|
||||
cppDefine "unix"
|
||||
|
||||
# mangle the macro names in nimbase.h
|
||||
cppDefine "NAN_INFINITY"
|
||||
cppDefine "INF"
|
||||
cppDefine "NAN"
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ path="$lib/pure"
|
||||
nimblepath="$home/.nimble/pkgs/"
|
||||
@end
|
||||
|
||||
# Syncronize with compiler/commands.specialDefine
|
||||
@if danger or quick:
|
||||
obj_checks:off
|
||||
field_checks:off
|
||||
@@ -69,6 +70,7 @@ path="$lib/pure"
|
||||
@end
|
||||
@end
|
||||
|
||||
# Syncronize with compiler/commands.specialDefine
|
||||
@if release or danger:
|
||||
stacktrace:off
|
||||
excessiveStackTrace:off
|
||||
|
||||
@@ -122,21 +122,12 @@ 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="$theindexhref">Index</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="compiler/$theindexhref">Compiler docs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://nim-lang.github.io/fusion/theindex.html">Fusion docs</a>
|
||||
</li>
|
||||
<li><a href="manual.html">Manual</a></li>
|
||||
<li><a href="lib.html">Standard library</a></li>
|
||||
<li> <a href="$theindexhref">Index</a></li>
|
||||
<li><a href="compiler/$theindexhref">Compiler docs</a></li>
|
||||
<li><a href="https://nim-lang.github.io/fusion/theindex.html">Fusion docs</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">
|
||||
|
||||
@@ -46,6 +46,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,7 +47,7 @@ The commands to compile to either C, C++ or Objective-C are:
|
||||
The most significant difference between these commands is that if you look
|
||||
into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
|
||||
files, other than that all of them will produce a native binary for your
|
||||
project. This allows you to take the generated code and place it directly
|
||||
project. This allows you to take the generated code and place it directly
|
||||
into a project using any of these languages. Here are some typical command-
|
||||
line invocations::
|
||||
|
||||
@@ -110,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>`_
|
||||
@@ -232,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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -255,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();
|
||||
@@ -270,13 +266,14 @@ Now you can run the following Unix like commands to first generate C sources
|
||||
from 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 from ``nimcache``. In addition to this path, you also
|
||||
have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
||||
@@ -284,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.
|
||||
|
||||
|
||||
@@ -2487,13 +2487,13 @@ matches) is preferred:
|
||||
gen(ri) # "ref T"
|
||||
|
||||
|
||||
Overloading based on 'var T' / 'out T'
|
||||
Overloading based on 'var T'
|
||||
--------------------------------------
|
||||
|
||||
If the formal parameter ``f`` is of type ``var T`` (or ``out T``)
|
||||
in addition to the ordinary
|
||||
type checking, the argument is checked to be an `l-value`:idx:.
|
||||
``var T`` (or ``out T``) matches better than just ``T`` then.
|
||||
If the formal parameter ``f`` is of type ``var T``
|
||||
in addition to the ordinary type checking,
|
||||
the argument is checked to be an `l-value`:idx:.
|
||||
``var T`` matches better than just ``T`` then.
|
||||
|
||||
.. code-block:: nim
|
||||
proc sayHi(x: int): string =
|
||||
@@ -2512,17 +2512,6 @@ type checking, the argument is checked to be an `l-value`:idx:.
|
||||
# 13
|
||||
|
||||
|
||||
An l-value matches ``var T`` and ``out T`` equally well, hence
|
||||
the following is ambiguous:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
proc p(x: out string) = x = ""
|
||||
proc p(x: var string) = x = ""
|
||||
var v: string
|
||||
p(v) # ambiguous
|
||||
|
||||
|
||||
Lazy type resolution for untyped
|
||||
--------------------------------
|
||||
|
||||
@@ -4933,7 +4922,7 @@ of "typedesc"-ness is stripped off:
|
||||
Generic inference restrictions
|
||||
------------------------------
|
||||
|
||||
The types ``var T``, ``out T`` and ``typedesc[T]`` cannot be inferred in a generic
|
||||
The types ``var T`` and ``typedesc[T]`` cannot be inferred in a generic
|
||||
instantiation. The following is not allowed:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -5040,6 +5029,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
|
||||
=========
|
||||
|
||||
@@ -5951,12 +5984,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
|
||||
@@ -6113,10 +6146,10 @@ noSideEffect pragma
|
||||
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
||||
effects. This means that the proc/iterator only changes locations that are
|
||||
reachable from its parameters and the return value only depends on the
|
||||
arguments. If none of its parameters have the type ``var T`` or ``out T``
|
||||
or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||
verify this.
|
||||
arguments. If none of its parameters have the type ``var T`` or ``ref T``
|
||||
or ``ptr T`` this means no locations are modified. It is a static error to
|
||||
mark a proc/iterator to have no side effect if the compiler cannot verify
|
||||
this.
|
||||
|
||||
As a special semantic rule, the built-in `debugEcho
|
||||
<system.html#debugEcho,varargs[typed,]>`_ pretends to be free of side effects,
|
||||
|
||||
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
|
||||
-------------------
|
||||
|
||||
2
koch.nim
2
koch.nim
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
const
|
||||
NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master
|
||||
NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master
|
||||
FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5"
|
||||
|
||||
when not defined(windows):
|
||||
|
||||
@@ -1256,7 +1256,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.
|
||||
@@ -1316,16 +1324,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:
|
||||
@@ -1528,18 +1526,17 @@ proc customPragmaNode(n: NimNode): NimNode =
|
||||
for i in 0..<identDefsStack.len: identDefsStack[i] = obj[2][i]
|
||||
while identDefsStack.len > 0:
|
||||
var identDefs = identDefsStack.pop()
|
||||
if identDefs.kind == nnkRecCase:
|
||||
identDefsStack.add(identDefs[0])
|
||||
for i in 1..<identDefs.len:
|
||||
let varNode = identDefs[i]
|
||||
# if it is and empty branch, skip
|
||||
if varNode[0].kind == nnkNilLit: continue
|
||||
if varNode[1].kind == nnkIdentDefs:
|
||||
identDefsStack.add(varNode[1])
|
||||
else: # nnkRecList
|
||||
for j in 0 ..< varNode[1].len:
|
||||
identDefsStack.add(varNode[1][j])
|
||||
|
||||
case identDefs.kind
|
||||
of nnkRecList:
|
||||
for child in identDefs.children:
|
||||
identDefsStack.add(child)
|
||||
of nnkRecCase:
|
||||
# Add condition definition
|
||||
identDefsStack.add(identDefs[0])
|
||||
# Add branches
|
||||
for i in 1 ..< identDefs.len:
|
||||
identDefsStack.add(identDefs[i].last)
|
||||
else:
|
||||
for i in 0 .. identDefs.len - 3:
|
||||
let varNode = identDefs[i]
|
||||
|
||||
@@ -110,7 +110,9 @@ proc dbQuote*(s: string): string =
|
||||
## DB quotes the string.
|
||||
result = "'"
|
||||
for c in items(s):
|
||||
if c == '\'': add(result, "''")
|
||||
case c
|
||||
of '\'': add(result, "''")
|
||||
of '\0': add(result, "\\0")
|
||||
else: add(result, c)
|
||||
add(result, '\'')
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
## **Note:** Import ``packages/docutils/rstgen`` to use this module
|
||||
|
||||
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
||||
algorithm, parseutils
|
||||
algorithm, parseutils, strscans
|
||||
|
||||
import ../../std/private/since
|
||||
|
||||
@@ -786,6 +786,16 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
|
||||
|
||||
|
||||
proc safeProtocol(linkStr: var string) =
|
||||
var protocol = ""
|
||||
if scanf(linkStr, "$w:", protocol):
|
||||
# if it has a protocol at all, ensure that it's not 'javascript:' or worse:
|
||||
if cmpIgnoreCase(protocol, "http") == 0 or cmpIgnoreCase(protocol, "https") == 0 or
|
||||
cmpIgnoreCase(protocol, "ftp") == 0:
|
||||
discard "it's fine"
|
||||
else:
|
||||
linkStr = ""
|
||||
|
||||
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
||||
dispA(d.target, result,
|
||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||
@@ -850,6 +860,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||
|
||||
# support for `:target:` links for images:
|
||||
var target = esc(d.target, getFieldValue(n, "target").strip())
|
||||
safeProtocol(target)
|
||||
|
||||
if target.len > 0:
|
||||
# `htmlOut` needs to be of the following format for link to work for images:
|
||||
# <a class="reference external" href="target"><img src=\"$1\"$2/></a>
|
||||
|
||||
@@ -280,19 +280,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 =
|
||||
@@ -305,16 +319,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)
|
||||
@@ -323,11 +341,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:
|
||||
@@ -351,9 +369,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
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
## application in production you should use a reverse proxy (for example nginx)
|
||||
## instead of allowing users to connect directly to this server.
|
||||
##
|
||||
## Basic usage
|
||||
## ===========
|
||||
## Example
|
||||
## =======
|
||||
##
|
||||
## This example will create an HTTP server on port 8080. The server will
|
||||
## respond to all requests with a ``200 OK`` response code and "Hello World"
|
||||
@@ -32,11 +32,10 @@
|
||||
## "Content-type": "text/plain; charset=utf-8"}
|
||||
## await req.respond(Http200, "Hello World", headers.newHttpHeaders())
|
||||
##
|
||||
## server.listen Port(5555)
|
||||
## server.listen Port(8080)
|
||||
## while true:
|
||||
## if server.shouldAcceptRequest(5):
|
||||
## var (address, client) = await server.socket.acceptAddr()
|
||||
## asyncCheck processClient(server, client, address, cb)
|
||||
## if server.shouldAcceptRequest():
|
||||
## await server.acceptRequest(cb)
|
||||
## else:
|
||||
## poll()
|
||||
##
|
||||
@@ -333,7 +332,7 @@ proc shouldAcceptRequest*(server: AsyncHttpServer;
|
||||
result = assumedDescriptorsPerRequest < 0 or
|
||||
(activeDescriptors() + assumedDescriptorsPerRequest < server.maxFDs)
|
||||
|
||||
proc acceptRequest*(server: AsyncHttpServer, port: Port,
|
||||
proc acceptRequest*(server: AsyncHttpServer,
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} =
|
||||
## Accepts a single request. Write an explicit loop around this proc so that
|
||||
## errors can be handled properly.
|
||||
@@ -343,7 +342,7 @@ proc acceptRequest*(server: AsyncHttpServer, port: Port,
|
||||
proc serve*(server: AsyncHttpServer, port: Port,
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.},
|
||||
address = "";
|
||||
assumedDescriptorsPerRequest = 5) {.async.} =
|
||||
assumedDescriptorsPerRequest = -1) {.async.} =
|
||||
## Starts the process of listening for incoming HTTP connections on the
|
||||
## specified address and port.
|
||||
##
|
||||
@@ -382,9 +381,8 @@ when not defined(testing) and isMainModule:
|
||||
|
||||
server.listen Port(5555)
|
||||
while true:
|
||||
if server.shouldAcceptRequest(5):
|
||||
var (address, client) = await server.socket.acceptAddr()
|
||||
asyncCheck processClient(server, client, address, cb)
|
||||
if server.shouldAcceptRequest():
|
||||
await server.acceptRequest(cb)
|
||||
else:
|
||||
poll()
|
||||
|
||||
|
||||
@@ -259,11 +259,9 @@ when defineSsl:
|
||||
ErrClearError()
|
||||
# Call the desired operation.
|
||||
opResult = op
|
||||
# Bit hackish here.
|
||||
# TODO: Introduce an async template transformation pragma?
|
||||
|
||||
# Send any remaining pending SSL data.
|
||||
yield sendPendingSslData(socket, flags)
|
||||
await sendPendingSslData(socket, flags)
|
||||
|
||||
# If the operation failed, try to see if SSL has some data to read
|
||||
# or write.
|
||||
@@ -321,10 +319,8 @@ template readInto(buf: pointer, size: int, socket: AsyncSocket,
|
||||
sslRead(socket.sslHandle, cast[cstring](buf), size.cint))
|
||||
res = opResult
|
||||
else:
|
||||
var recvIntoFut = asyncdispatch.recvInto(socket.fd.AsyncFD, buf, size, flags)
|
||||
yield recvIntoFut
|
||||
# Not in SSL mode.
|
||||
res = recvIntoFut.read()
|
||||
res = await asyncdispatch.recvInto(socket.fd.AsyncFD, buf, size, flags)
|
||||
res
|
||||
|
||||
template readIntoBuf(socket: AsyncSocket,
|
||||
|
||||
@@ -21,6 +21,7 @@ type
|
||||
queue: Deque[T]
|
||||
finished: bool
|
||||
cb: proc () {.closure, gcsafe.}
|
||||
error*: ref Exception
|
||||
|
||||
proc newFutureStream*[T](fromProc = "unspecified"): FutureStream[T] =
|
||||
## Create a new ``FutureStream``. This future's callback is activated when
|
||||
@@ -40,10 +41,19 @@ proc newFutureStream*[T](fromProc = "unspecified"): FutureStream[T] =
|
||||
|
||||
proc complete*[T](future: FutureStream[T]) =
|
||||
## Completes a ``FutureStream`` signalling the end of data.
|
||||
assert(future.error == nil, "Trying to complete failed stream")
|
||||
future.finished = true
|
||||
if not future.cb.isNil:
|
||||
future.cb()
|
||||
|
||||
proc fail*[T](future: FutureStream[T], error: ref Exception) =
|
||||
## Completes ``future`` with ``error``.
|
||||
assert(not future.finished)
|
||||
future.finished = true
|
||||
future.error = error
|
||||
if not future.cb.isNil:
|
||||
future.cb()
|
||||
|
||||
proc `callback=`*[T](future: FutureStream[T],
|
||||
cb: proc (future: FutureStream[T]) {.closure, gcsafe.}) =
|
||||
## Sets the callback proc to be called when data was placed inside the
|
||||
@@ -65,6 +75,10 @@ proc finished*[T](future: FutureStream[T]): bool =
|
||||
## no data waiting to be retrieved.
|
||||
result = future.finished and future.queue.len == 0
|
||||
|
||||
proc failed*[T](future: FutureStream[T]): bool =
|
||||
## Determines whether ``future`` completed with an error.
|
||||
return future.error != nil
|
||||
|
||||
proc write*[T](future: FutureStream[T], value: T): Future[void] =
|
||||
## Writes the specified value inside the specified future stream.
|
||||
##
|
||||
@@ -107,10 +121,17 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) =
|
||||
res[0] = true
|
||||
res[1] = fs.queue.popFirst()
|
||||
|
||||
resFut.complete(res)
|
||||
if fs.failed:
|
||||
resFut.fail(fs.error)
|
||||
else:
|
||||
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)
|
||||
|
||||
@@ -440,7 +440,7 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T =
|
||||
##
|
||||
## See also:
|
||||
## * `sugar.collect macro<sugar.html#collect.m%2Cuntyped%2Cuntyped>`_
|
||||
## * `fliter proc<#filter,openArray[T],proc(T)>`_
|
||||
## * `filter proc<#filter,openArray[T],proc(T)>`_
|
||||
## * `filterIt template<#filterIt.t,untyped,untyped>`_
|
||||
##
|
||||
runnableExamples:
|
||||
|
||||
@@ -2277,7 +2277,6 @@ proc `[]`*[A](t: CountTable[A], key: A): int =
|
||||
## See also:
|
||||
## * `getOrDefault<#getOrDefault,CountTable[A],A,int>`_ to return
|
||||
## a custom value if the key doesn't exist
|
||||
## * `mget proc<#mget,CountTable[A],A>`_
|
||||
## * `[]= proc<#[]%3D,CountTable[A],A,int>`_ for inserting a new
|
||||
## (key, value) pair in the table
|
||||
## * `hasKey proc<#hasKey,CountTable[A],A>`_ for checking if a key
|
||||
|
||||
@@ -321,7 +321,7 @@ proc getDefaultSSL(): SslContext =
|
||||
result = defaultSslContext
|
||||
when defined(ssl):
|
||||
if result == nil:
|
||||
defaultSslContext = newContext(verifyMode = CVerifyNone)
|
||||
defaultSslContext = newContext(verifyMode = CVerifyPeer)
|
||||
result = defaultSslContext
|
||||
doAssert result != nil, "failure to initialize the SSL context"
|
||||
|
||||
@@ -843,8 +843,11 @@ proc parseResponse(client: HttpClient | AsyncHttpClient,
|
||||
client.bodyStream = newFutureStream[string]("parseResponse")
|
||||
result.bodyStream = client.bodyStream
|
||||
assert(client.parseBodyFut.isNil or client.parseBodyFut.finished)
|
||||
# do not wait here for the body request to complete
|
||||
client.parseBodyFut = parseBody(client, result.headers, result.version)
|
||||
# do not wait here for the body request to complete
|
||||
client.parseBodyFut.addCallback do():
|
||||
if client.parseBodyFut.failed:
|
||||
client.bodyStream.fail(client.parseBodyFut.error)
|
||||
|
||||
proc newConnection(client: HttpClient | AsyncHttpClient,
|
||||
url: Uri) {.multisync.} =
|
||||
@@ -958,12 +961,15 @@ proc format(client: HttpClient | AsyncHttpClient,
|
||||
|
||||
proc override(fallback, override: HttpHeaders): HttpHeaders =
|
||||
# Right-biased map union for `HttpHeaders`
|
||||
if override.isNil:
|
||||
return fallback
|
||||
|
||||
result = newHttpHeaders()
|
||||
# Copy by value
|
||||
result.table[] = fallback.table[]
|
||||
|
||||
if override.isNil:
|
||||
# Return the copy of fallback so it does not get modified
|
||||
return result
|
||||
|
||||
for k, vs in override.table:
|
||||
result[k] = vs
|
||||
|
||||
@@ -1155,15 +1161,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,
|
||||
@@ -1174,13 +1180,16 @@ proc downloadFile*(client: AsyncHttpClient, url: string,
|
||||
|
||||
client.bodyStream = newFutureStream[string]("downloadFile")
|
||||
var file = openAsync(filename, fmWrite)
|
||||
defer: file.close()
|
||||
# Let `parseBody` write response data into client.bodyStream in the
|
||||
# background.
|
||||
asyncCheck parseBody(client, resp.headers, resp.version)
|
||||
let parseBodyFut = parseBody(client, resp.headers, resp.version)
|
||||
parseBodyFut.addCallback do():
|
||||
if parseBodyFut.failed:
|
||||
client.bodyStream.fail(parseBodyFut.error)
|
||||
# The `writeFromStream` proc will complete once all the data in the
|
||||
# `bodyStream` has been written to the file.
|
||||
await file.writeFromStream(client.bodyStream)
|
||||
file.close()
|
||||
|
||||
if resp.code.is4xx or resp.code.is5xx:
|
||||
raise newException(HttpRequestError, resp.status)
|
||||
|
||||
@@ -114,7 +114,7 @@ proc osLastError*(): OSErrorCode {.sideEffect.} =
|
||||
when defined(nimscript):
|
||||
discard
|
||||
elif defined(windows):
|
||||
result = OSErrorCode(getLastError())
|
||||
result = cast[OSErrorCode](getLastError())
|
||||
else:
|
||||
result = OSErrorCode(errno)
|
||||
{.pop.}
|
||||
|
||||
@@ -195,6 +195,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)
|
||||
@@ -304,7 +306,10 @@ proc `%`*(s: string): JsonNode =
|
||||
|
||||
proc `%`*(n: uint): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||
result = JsonNode(kind: JInt, num: BiggestInt(n))
|
||||
if n > cast[uint](int.high):
|
||||
result = newJRawNumber($n)
|
||||
else:
|
||||
result = JsonNode(kind: JInt, num: BiggestInt(n))
|
||||
|
||||
proc `%`*(n: int): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||
@@ -312,7 +317,10 @@ proc `%`*(n: int): JsonNode =
|
||||
|
||||
proc `%`*(n: BiggestUInt): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||
result = JsonNode(kind: JInt, num: BiggestInt(n))
|
||||
if n > cast[BiggestUInt](BiggestInt.high):
|
||||
result = newJRawNumber($n)
|
||||
else:
|
||||
result = JsonNode(kind: JInt, num: BiggestInt(n))
|
||||
|
||||
proc `%`*(n: BiggestInt): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
|
||||
@@ -800,7 +808,7 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
|
||||
for key, val in mpairs(node.fields):
|
||||
yield (key, val)
|
||||
|
||||
proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
||||
proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool, depth = 0): JsonNode =
|
||||
## Parses JSON from a JSON Parser `p`.
|
||||
case p.tok
|
||||
of tkString:
|
||||
@@ -836,6 +844,8 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
||||
result = newJNull()
|
||||
discard getTok(p)
|
||||
of tkCurlyLe:
|
||||
if depth > DepthLimit:
|
||||
raiseParseErr(p, "}")
|
||||
result = newJObject()
|
||||
discard getTok(p)
|
||||
while p.tok != tkCurlyRi:
|
||||
@@ -844,16 +854,18 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
|
||||
var key = p.a
|
||||
discard getTok(p)
|
||||
eat(p, tkColon)
|
||||
var val = parseJson(p, rawIntegers, rawFloats)
|
||||
var val = parseJson(p, rawIntegers, rawFloats, depth+1)
|
||||
result[key] = val
|
||||
if p.tok != tkComma: break
|
||||
discard getTok(p)
|
||||
eat(p, tkCurlyRi)
|
||||
of tkBracketLe:
|
||||
if depth > DepthLimit:
|
||||
raiseParseErr(p, "]")
|
||||
result = newJArray()
|
||||
discard getTok(p)
|
||||
while p.tok != tkBracketRi:
|
||||
result.add(parseJson(p, rawIntegers, rawFloats))
|
||||
result.add(parseJson(p, rawIntegers, rawFloats, depth+1))
|
||||
if p.tok != tkComma: break
|
||||
discard getTok(p)
|
||||
eat(p, tkBracketRi)
|
||||
@@ -1058,8 +1070,17 @@ when defined(nimFixedForwardGeneric):
|
||||
dst = jsonNode.copy
|
||||
|
||||
proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) =
|
||||
verifyJsonKind(jsonNode, {JInt}, jsonPath)
|
||||
dst = T(jsonNode.num)
|
||||
when T is uint|uint64 or (not defined(js) and int.sizeof == 4):
|
||||
verifyJsonKind(jsonNode, {JInt, JString}, jsonPath)
|
||||
case jsonNode.kind
|
||||
of JString:
|
||||
let x = parseBiggestUInt(jsonNode.str)
|
||||
dst = cast[T](x)
|
||||
else:
|
||||
dst = T(jsonNode.num)
|
||||
else:
|
||||
verifyJsonKind(jsonNode, {JInt}, jsonPath)
|
||||
dst = cast[T](jsonNode.num)
|
||||
|
||||
proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
|
||||
verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath)
|
||||
|
||||
@@ -207,9 +207,9 @@ proc getProtoByName*(name: string): int {.since: (1, 3, 5).} =
|
||||
let protoent = winlean.getprotobyname(name.cstring)
|
||||
else:
|
||||
let protoent = posix.getprotobyname(name.cstring)
|
||||
|
||||
|
||||
if protoent == nil:
|
||||
raise newException(OsError, "protocol not found")
|
||||
raise newException(OSError, "protocol not found")
|
||||
|
||||
result = protoent.p_proto.int
|
||||
|
||||
|
||||
@@ -24,6 +24,17 @@
|
||||
## `newContext<net.html#newContext%2Cstring%2Cstring%2Cstring%2Cstring%2Cstring>`_
|
||||
## procedure for additional details.
|
||||
##
|
||||
##
|
||||
## SSL on Windows
|
||||
## ==============
|
||||
##
|
||||
## On Windows the SSL library checks for valid certificates.
|
||||
## It uses the `cacert.pem` file for this purpose which was extracted
|
||||
## from `https://curl.se/ca/cacert.pem`. Besides
|
||||
## the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
|
||||
## also need to ship `cacert.pem` with your `.exe` file.
|
||||
##
|
||||
##
|
||||
## Examples
|
||||
## ========
|
||||
##
|
||||
@@ -611,7 +622,7 @@ when defineSsl:
|
||||
if newCTX.SSL_CTX_set_ecdh_auto(1) != 1:
|
||||
raiseSSLError()
|
||||
|
||||
when defined(nimDisableCertificateValidation) or defined(windows):
|
||||
when defined(nimDisableCertificateValidation):
|
||||
newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
|
||||
else:
|
||||
case verifyMode
|
||||
@@ -626,11 +637,13 @@ when defineSsl:
|
||||
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
|
||||
newCTX.loadCertificates(certFile, keyFile)
|
||||
|
||||
when not defined(nimDisableCertificateValidation) and not defined(windows):
|
||||
const VerifySuccess = 1 # SSL_CTX_load_verify_locations returns 1 on success.
|
||||
|
||||
when not defined(nimDisableCertificateValidation):
|
||||
if verifyMode != CVerifyNone:
|
||||
# Use the caDir and caFile parameters if set
|
||||
if caDir != "" or caFile != "":
|
||||
if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != 0:
|
||||
if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != VerifySuccess:
|
||||
raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).")
|
||||
|
||||
else:
|
||||
@@ -638,7 +651,7 @@ when defineSsl:
|
||||
# the SSL_CERT_FILE and SSL_CERT_DIR env vars
|
||||
var found = false
|
||||
for fn in scanSSLCertificates():
|
||||
if newCTX.SSL_CTX_load_verify_locations(fn, "") == 0:
|
||||
if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess:
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
@@ -676,12 +689,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
|
||||
@@ -702,7 +714,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)
|
||||
|
||||
@@ -756,10 +768,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
|
||||
|
||||
@@ -965,6 +965,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>`_
|
||||
|
||||
@@ -414,6 +414,8 @@ proc execProcesses*(cmds: openArray[string],
|
||||
raiseOSError(err)
|
||||
|
||||
if rexit >= 0:
|
||||
when defined(windows):
|
||||
let processHandle = q[rexit].fProcessHandle
|
||||
result = max(result, abs(q[rexit].peekExitCode()))
|
||||
if afterRunEvent != nil: afterRunEvent(idxs[rexit], q[rexit])
|
||||
close(q[rexit])
|
||||
@@ -428,7 +430,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||
else:
|
||||
when defined(windows):
|
||||
for k in 0..wcount - 1:
|
||||
if w[k] == q[rexit].fProcessHandle:
|
||||
if w[k] == processHandle:
|
||||
w[k] = w[wcount - 1]
|
||||
w[wcount - 1] = 0
|
||||
dec(wcount)
|
||||
@@ -525,10 +527,17 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
handle: Handle
|
||||
atTheEnd: bool
|
||||
|
||||
proc closeHandleCheck(handle: Handle) {.inline.} =
|
||||
if handle.closeHandle() == 0:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc fileClose[T: Handle | FileHandle](h: var T) {.inline.} =
|
||||
if h > 4:
|
||||
closeHandleCheck(h)
|
||||
h = INVALID_HANDLE_VALUE.T
|
||||
|
||||
proc hsClose(s: Stream) =
|
||||
# xxx here + elsewhere: check instead of discard; ignoring errors leads to
|
||||
# hard to track bugs
|
||||
discard FileHandleStream(s).handle.closeHandle
|
||||
FileHandleStream(s).handle.fileClose()
|
||||
|
||||
proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd
|
||||
|
||||
@@ -633,8 +642,8 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
|
||||
stdin = myDup(pipeIn, 0)
|
||||
stdout = myDup(pipeOut, 0)
|
||||
discard closeHandle(pipeIn)
|
||||
discard closeHandle(pipeOut)
|
||||
closeHandleCheck(pipeIn)
|
||||
closeHandleCheck(pipeOut)
|
||||
stderr = stdout
|
||||
|
||||
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
|
||||
@@ -645,9 +654,6 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc fileClose(h: Handle) {.inline.} =
|
||||
if h > 4: discard closeHandle(h)
|
||||
|
||||
proc startProcess(command: string, workingDir: string = "",
|
||||
args: openArray[string] = [], env: StringTableRef = nil,
|
||||
options: set[ProcessOption] = {poStdErrToStdOut}):
|
||||
@@ -742,13 +748,31 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
result.id = procInfo.dwProcessId
|
||||
result.exitFlag = false
|
||||
|
||||
proc closeThreadAndProcessHandle(p: Process) =
|
||||
if p.fThreadHandle != 0:
|
||||
closeHandleCheck(p.fThreadHandle)
|
||||
p.fThreadHandle = 0
|
||||
|
||||
if p.fProcessHandle != 0:
|
||||
closeHandleCheck(p.fProcessHandle)
|
||||
p.fProcessHandle = 0
|
||||
|
||||
proc close(p: Process) =
|
||||
if poParentStreams notin p.options:
|
||||
discard closeHandle(p.inHandle)
|
||||
discard closeHandle(p.outHandle)
|
||||
discard closeHandle(p.errHandle)
|
||||
discard closeHandle(p.fThreadHandle)
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
if p.inStream == nil:
|
||||
p.inHandle.fileClose()
|
||||
else:
|
||||
# p.inHandle can be already closed via inputStream.
|
||||
p.inStream.close
|
||||
|
||||
# You may NOT close outputStream and errorStream.
|
||||
assert p.outStream == nil or FileHandleStream(p.outStream).handle != INVALID_HANDLE_VALUE
|
||||
assert p.errStream == nil or FileHandleStream(p.errStream).handle != INVALID_HANDLE_VALUE
|
||||
|
||||
if p.outHandle != p.errHandle:
|
||||
p.errHandle.fileClose()
|
||||
p.outHandle.fileClose()
|
||||
p.closeThreadAndProcessHandle()
|
||||
|
||||
proc suspend(p: Process) =
|
||||
discard suspendThread(p.fThreadHandle)
|
||||
@@ -782,8 +806,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
if status != STILL_ACTIVE:
|
||||
p.exitFlag = true
|
||||
p.exitStatus = status
|
||||
discard closeHandle(p.fThreadHandle)
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
p.closeThreadAndProcessHandle()
|
||||
result = status
|
||||
else:
|
||||
result = -1
|
||||
@@ -799,8 +822,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
discard getExitCodeProcess(p.fProcessHandle, status)
|
||||
p.exitFlag = true
|
||||
p.exitStatus = status
|
||||
discard closeHandle(p.fThreadHandle)
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
p.closeThreadAndProcessHandle()
|
||||
result = status
|
||||
|
||||
proc inputStream(p: Process): Stream =
|
||||
|
||||
@@ -11,16 +11,48 @@
|
||||
## SSL_CERT_DIR environment variables.
|
||||
|
||||
import os, strutils
|
||||
from os import existsEnv, getEnv
|
||||
import strutils
|
||||
|
||||
# SECURITY: this unnecessarily scans through dirs/files regardless of the
|
||||
# actual host OS/distribution. Hopefully all the paths are writeble only by
|
||||
# root.
|
||||
|
||||
# FWIW look for files before scanning entire dirs.
|
||||
|
||||
const certificate_paths = [
|
||||
when defined(macosx):
|
||||
const certificatePaths = [
|
||||
"/etc/ssl/cert.pem",
|
||||
"/System/Library/OpenSSL/certs/cert.pem"
|
||||
]
|
||||
elif defined(linux):
|
||||
const certificatePaths = [
|
||||
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
|
||||
# NetBSD (security/mozilla-rootcerts)
|
||||
# SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/etc/ssl/certs/ca-certificates.crt",
|
||||
# OpenSUSE
|
||||
"/etc/ssl/ca-bundle.pem",
|
||||
# Red Hat 5+, Fedora, Centos
|
||||
"/etc/pki/tls/certs/ca-bundle.crt",
|
||||
# Red Hat 4
|
||||
"/usr/share/ssl/certs/ca-bundle.crt",
|
||||
# Fedora/RHEL
|
||||
"/etc/pki/tls/certs",
|
||||
# Android
|
||||
"/system/etc/security/cacerts",
|
||||
]
|
||||
elif defined(bsd):
|
||||
const certificatePaths = [
|
||||
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
|
||||
# NetBSD (security/mozilla-rootcerts)
|
||||
# SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/etc/ssl/certs/ca-certificates.crt",
|
||||
# FreeBSD (security/ca-root-nss package)
|
||||
"/usr/local/share/certs/ca-root-nss.crt",
|
||||
# OpenBSD, FreeBSD (optional symlink)
|
||||
"/etc/ssl/cert.pem",
|
||||
# FreeBSD
|
||||
"/usr/local/share/certs",
|
||||
# NetBSD
|
||||
"/etc/openssl/certs",
|
||||
]
|
||||
else:
|
||||
const certificatePaths = [
|
||||
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
|
||||
# NetBSD (security/mozilla-rootcerts)
|
||||
# SLES10/SLES11, https://golang.org/issue/12139
|
||||
@@ -37,8 +69,6 @@ const certificate_paths = [
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
||||
# OpenBSD, FreeBSD (optional symlink)
|
||||
"/etc/ssl/cert.pem",
|
||||
# Mac OS X
|
||||
"/System/Library/OpenSSL/certs/cert.pem",
|
||||
# Fedora/RHEL
|
||||
"/etc/pki/tls/certs",
|
||||
# Android
|
||||
@@ -47,7 +77,7 @@ const certificate_paths = [
|
||||
"/usr/local/share/certs",
|
||||
# NetBSD
|
||||
"/etc/openssl/certs",
|
||||
]
|
||||
]
|
||||
|
||||
when defined(haiku):
|
||||
const
|
||||
@@ -67,17 +97,30 @@ iterator scanSSLCertificates*(useEnvVars = false): string =
|
||||
## if `useEnvVars` is true, the SSL_CERT_FILE and SSL_CERT_DIR
|
||||
## environment variables can be used to override the certificate
|
||||
## directories to scan or specify a CA certificate file.
|
||||
if existsEnv("SSL_CERT_FILE"):
|
||||
if useEnvVars and existsEnv("SSL_CERT_FILE"):
|
||||
yield getEnv("SSL_CERT_FILE")
|
||||
|
||||
elif existsEnv("SSL_CERT_DIR"):
|
||||
elif useEnvVars and existsEnv("SSL_CERT_DIR"):
|
||||
let p = getEnv("SSL_CERT_DIR")
|
||||
for fn in joinPath(p, "*").walkFiles():
|
||||
yield fn
|
||||
|
||||
else:
|
||||
when not defined(haiku):
|
||||
for p in certificate_paths:
|
||||
when defined(windows):
|
||||
const cacert = "cacert.pem"
|
||||
let pem = getAppDir() / cacert
|
||||
if fileExists(pem):
|
||||
yield pem
|
||||
else:
|
||||
let path = getEnv("PATH")
|
||||
for candidate in split(path, PathSep):
|
||||
if candidate.len != 0:
|
||||
let x = (if candidate[0] == '"' and candidate[^1] == '"':
|
||||
substr(candidate, 1, candidate.len-2) else: candidate) / cacert
|
||||
if fileExists(x):
|
||||
yield x
|
||||
elif not defined(haiku):
|
||||
for p in certificatePaths:
|
||||
if p.endsWith(".pem") or p.endsWith(".crt"):
|
||||
if fileExists(p):
|
||||
yield p
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
## macro system.
|
||||
|
||||
import std/private/since
|
||||
import macros, typetraits
|
||||
import macros
|
||||
|
||||
proc checkPragma(ex, prag: var NimNode) =
|
||||
since (1, 3):
|
||||
@@ -219,7 +219,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).}
|
||||
error("The variable name cannot be `result`!", arg)
|
||||
params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg))
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newProc(newEmptyNode(), params, body, nnkProcDef))
|
||||
result.add(newProc(newEmptyNode(), params, body, nnkLambda))
|
||||
for arg in locals: result.add(arg)
|
||||
|
||||
since (1, 1):
|
||||
|
||||
@@ -28,29 +28,32 @@ proc arity*(t: typedesc): int {.magic: "TypeTrait".} =
|
||||
assert arity(array[3, int]) == 2
|
||||
assert arity((int, int, float, string)) == 4
|
||||
|
||||
proc genericHead*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
||||
proc genericHead*(t: typedesc): typedesc {.magic: "TypeTrait".} =
|
||||
## Accepts an instantiated generic type and returns its
|
||||
## uninstantiated form.
|
||||
##
|
||||
## For example:
|
||||
## * `seq[int].genericHead` will be just `seq`
|
||||
## * `seq[int].genericHead[float]` will be `seq[float]`
|
||||
##
|
||||
## A compile-time error will be produced if the supplied type
|
||||
## is not generic.
|
||||
##
|
||||
## See also:
|
||||
## * `stripGenericParams <#stripGenericParams,typedesc>`_
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## type
|
||||
## Functor[A] = concept f
|
||||
## type MatchedGenericType = genericHead(typeof(f))
|
||||
## # `f` will be a value of a type such as `Option[T]`
|
||||
## # `MatchedGenericType` will become the `Option` type
|
||||
runnableExamples:
|
||||
type
|
||||
Foo[T] = object
|
||||
FooInst = Foo[int]
|
||||
Foo2 = genericHead(FooInst)
|
||||
doAssert Foo2 is Foo and Foo is Foo2
|
||||
doAssert genericHead(Foo[seq[string]]) is Foo
|
||||
doAssert not compiles(genericHead(int))
|
||||
|
||||
type Generic = concept f
|
||||
type _ = genericHead(typeof(f))
|
||||
proc bar(a: Generic): typeof(a) = a
|
||||
doAssert bar(Foo[string].default) == Foo[string]()
|
||||
doAssert not compiles bar(string.default)
|
||||
|
||||
when false: # these don't work yet
|
||||
doAssert genericHead(Foo[int])[float] is Foo[float]
|
||||
doAssert seq[int].genericHead is seq
|
||||
|
||||
proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
||||
## This trait is similar to `genericHead <#genericHead,typedesc>`_, but
|
||||
@@ -105,7 +108,7 @@ since (1, 3, 5):
|
||||
doAssert elementType(myiter(3)) is int
|
||||
typeof(block: (for ai in a: ai))
|
||||
|
||||
import std/macros
|
||||
import macros
|
||||
|
||||
macro genericParamsImpl(T: typedesc): untyped =
|
||||
# auxiliary macro needed, can't do it directly in `genericParams`
|
||||
@@ -155,7 +158,6 @@ macro genericParamsImpl(T: typedesc): untyped =
|
||||
ret = newTree(nnkBracketExpr, @[bindSym"range", ai])
|
||||
else:
|
||||
since (1, 1):
|
||||
echo ai.typeKind
|
||||
ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai])
|
||||
result.add ret
|
||||
break
|
||||
|
||||
@@ -333,7 +333,7 @@ proc runeReverseOffset*(s: string, rev: Positive): (int, int) =
|
||||
## from the end (starting with 1) and the total
|
||||
## number of runes in the string.
|
||||
##
|
||||
## Returns a negative value for offset if there are to few runes in
|
||||
## Returns a negative value for offset if there are too few runes in
|
||||
## the string to satisfy the request.
|
||||
##
|
||||
## **Beware:** This can lead to unoptimized code and slow execution!
|
||||
@@ -346,16 +346,14 @@ proc runeReverseOffset*(s: string, rev: Positive): (int, int) =
|
||||
a = rev.int
|
||||
o = 0
|
||||
x = 0
|
||||
let times = 2*rev.int-s.runeLen # transformed from rev.int - a < s.runeLen - rev.int
|
||||
while o < s.len:
|
||||
let r = runeLenAt(s, o)
|
||||
o += r
|
||||
if a < 0:
|
||||
if a > times:
|
||||
x += r
|
||||
dec a
|
||||
|
||||
if a > 0:
|
||||
return (-a, rev.int-a)
|
||||
return (x, -a+rev.int)
|
||||
result = if a > 0: (-a, rev.int-a) else: (x, -a+rev.int)
|
||||
|
||||
proc runeAtPos*(s: string, pos: int): Rune =
|
||||
## Returns the rune at position ``pos``.
|
||||
|
||||
@@ -311,7 +311,7 @@ func removeDotSegments(path: string): string =
|
||||
discard collection.pop()
|
||||
i.inc 3
|
||||
continue
|
||||
elif path[i+1] == '/':
|
||||
elif i + 1 < path.len and path[i+1] == '/':
|
||||
i.inc 2
|
||||
continue
|
||||
currentSegment.add path[i]
|
||||
|
||||
@@ -25,7 +25,16 @@ proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} =
|
||||
# delegate to value's destroy operation
|
||||
`=destroy`(dest.value)
|
||||
|
||||
func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".}
|
||||
func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".} =
|
||||
## Create an isolated subgraph from the expression `value`.
|
||||
## Please read https://github.com/nim-lang/RFCs/issues/244
|
||||
## for more details.
|
||||
Isolated[T](value: value)
|
||||
|
||||
func unsafeIsolate*[T](value: sink T): Isolated[T] =
|
||||
## Creates an isolated subgraph from the expression `value`.
|
||||
Isolated[T](value: value)
|
||||
|
||||
func extract*[T](src: var Isolated[T]): T =
|
||||
## Returns the internal value of `src`.
|
||||
result = move(src.value)
|
||||
|
||||
@@ -13,7 +13,7 @@ runnableExamples:
|
||||
let j = a.toJson
|
||||
doAssert j.jsonTo(type(a)).toJson == j
|
||||
|
||||
import std/[json,strutils,tables,sets,strtabs,options]
|
||||
import json, strutils, tables, sets, strtabs, options
|
||||
|
||||
#[
|
||||
Future directions:
|
||||
@@ -27,7 +27,7 @@ add a way to customize serialization, for e.g.:
|
||||
objects.
|
||||
]#
|
||||
|
||||
import std/macros
|
||||
import macros
|
||||
|
||||
type
|
||||
Joptions* = object
|
||||
@@ -106,7 +106,7 @@ proc hasField[T](obj: T, field: string): bool =
|
||||
return true
|
||||
return false
|
||||
|
||||
macro accessField(obj: typed, name: static string): untyped =
|
||||
macro accessField(obj: typed, name: static string): untyped =
|
||||
newDotExpr(obj, ident(name))
|
||||
|
||||
template fromJsonFields(newObj, oldObj, json, discKeys, opt) =
|
||||
@@ -146,7 +146,7 @@ template fromJsonFields(newObj, oldObj, json, discKeys, opt) =
|
||||
json.len == numMatched
|
||||
else:
|
||||
json.len == num and num == numMatched
|
||||
|
||||
|
||||
checkJson ok, $(json.len, num, numMatched, $T, json)
|
||||
|
||||
proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions())
|
||||
@@ -187,7 +187,8 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) =
|
||||
of JInt: a = T(b.getBiggestInt())
|
||||
of JString: a = parseEnum[T](b.getStr())
|
||||
else: checkJson false, $($T, " ", b)
|
||||
elif T is Ordinal: a = T(to(b, int))
|
||||
elif T is uint|uint64: a = T(to(b, uint64))
|
||||
elif T is Ordinal: a = cast[T](to(b, int))
|
||||
elif T is pointer: a = cast[pointer](to(b, int))
|
||||
elif T is distinct:
|
||||
when nimvm:
|
||||
@@ -270,13 +271,14 @@ proc toJson*[T](a: T): JsonNode =
|
||||
# in simpler code for `toJson` and `fromJson`.
|
||||
elif T is distinct: result = toJson(a.distinctBase)
|
||||
elif T is bool: result = %(a)
|
||||
elif T is SomeInteger: result = %a
|
||||
elif T is Ordinal: result = %(a.ord)
|
||||
else: result = %a
|
||||
|
||||
proc fromJsonHook*[K, V](t: var (Table[K, V] | OrderedTable[K, V]),
|
||||
jsonNode: JsonNode) =
|
||||
## Enables `fromJson` for `Table` and `OrderedTable` types.
|
||||
##
|
||||
##
|
||||
## See also:
|
||||
## * `toJsonHook proc<#toJsonHook,(Table[K,V]|OrderedTable[K,V])>`_
|
||||
runnableExamples:
|
||||
@@ -312,7 +314,7 @@ proc toJsonHook*[K, V](t: (Table[K, V] | OrderedTable[K, V])): JsonNode =
|
||||
|
||||
proc fromJsonHook*[A](s: var SomeSet[A], jsonNode: JsonNode) =
|
||||
## Enables `fromJson` for `HashSet` and `OrderedSet` types.
|
||||
##
|
||||
##
|
||||
## See also:
|
||||
## * `toJsonHook proc<#toJsonHook,SomeSet[A]>`_
|
||||
runnableExamples:
|
||||
@@ -346,7 +348,7 @@ proc toJsonHook*[A](s: SomeSet[A]): JsonNode =
|
||||
|
||||
proc fromJsonHook*[T](self: var Option[T], jsonNode: JsonNode) =
|
||||
## Enables `fromJson` for `Option` types.
|
||||
##
|
||||
##
|
||||
## See also:
|
||||
## * `toJsonHook proc<#toJsonHook,Option[T]>`_
|
||||
runnableExamples:
|
||||
@@ -381,7 +383,7 @@ proc toJsonHook*[T](self: Option[T]): JsonNode =
|
||||
|
||||
proc fromJsonHook*(a: var StringTableRef, b: JsonNode) =
|
||||
## Enables `fromJson` for `StringTableRef` type.
|
||||
##
|
||||
##
|
||||
## See also:
|
||||
## * `toJsonHook` proc<#toJsonHook,StringTableRef>`_
|
||||
runnableExamples:
|
||||
@@ -399,7 +401,7 @@ proc fromJsonHook*(a: var StringTableRef, b: JsonNode) =
|
||||
|
||||
proc toJsonHook*(a: StringTableRef): JsonNode =
|
||||
## Enables `toJson` for `StringTableRef` type.
|
||||
##
|
||||
##
|
||||
## See also:
|
||||
## * `fromJsonHook` proc<#fromJsonHook,StringTableRef,JsonNode>`_
|
||||
runnableExamples:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -4,7 +4,7 @@ this can eventually be moved to std/os and `walkDirRec` can be implemented in te
|
||||
to avoid duplication
|
||||
]##
|
||||
|
||||
import std/[os,strutils]
|
||||
import os, strutils
|
||||
|
||||
type
|
||||
PathEntry* = object
|
||||
|
||||
@@ -6,31 +6,30 @@
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
## **Note:** Import `std/sha1` to use this module.
|
||||
##
|
||||
## [SHA-1 (Secure Hash Algorithm 1)](https://en.wikipedia.org/wiki/SHA-1)
|
||||
## is a cryptographic hash function which takes an input and produces
|
||||
## a 160-bit (20-byte) hash value known as a message digest.
|
||||
##
|
||||
## Basic usage
|
||||
## ===========
|
||||
##
|
||||
runnableExamples:
|
||||
let accessName = secureHash("John Doe")
|
||||
assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362"
|
||||
|
||||
## **Note:** Import ``std/sha1`` to use this module
|
||||
##
|
||||
## SHA-1 (Secure Hash Algorithm 1) is a cryptographic hash function which
|
||||
## takes an input and produces a 160-bit (20-byte) hash value known as a
|
||||
## message digest.
|
||||
##
|
||||
## .. code-block::
|
||||
## import std/sha1
|
||||
## let
|
||||
## a = secureHashFile("myFile.nim")
|
||||
## b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C")
|
||||
##
|
||||
## let accessName = secureHash("John Doe")
|
||||
## assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362"
|
||||
## if a == b:
|
||||
## echo "Files match"
|
||||
##
|
||||
## .. code-block::
|
||||
## import std/sha1
|
||||
##
|
||||
## let
|
||||
## a = secureHashFile("myFile.nim")
|
||||
## b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C")
|
||||
##
|
||||
## if a == b:
|
||||
## echo "Files match"
|
||||
##
|
||||
## **See also:**
|
||||
## * `base64 module<base64.html>`_ implements a base64 encoder and decoder
|
||||
## See also
|
||||
## ========
|
||||
## * `base64 module<base64.html>`_ implements a Base64 encoder and decoder
|
||||
## * `hashes module<hashes.html>`_ for efficient computations of hash values for diverse Nim types
|
||||
## * `md5 module<md5.html>`_ implements the MD5 checksum algorithm
|
||||
|
||||
@@ -40,7 +39,7 @@ from endians import bigEndian32, bigEndian64
|
||||
const Sha1DigestSize = 20
|
||||
|
||||
type
|
||||
Sha1Digest* = array[0 .. Sha1DigestSize-1, uint8]
|
||||
Sha1Digest* = array[0 .. Sha1DigestSize - 1, uint8]
|
||||
SecureHash* = distinct Sha1Digest
|
||||
|
||||
type
|
||||
@@ -49,10 +48,14 @@ type
|
||||
state: array[5, uint32]
|
||||
buf: array[64, byte]
|
||||
|
||||
# This implementation of the SHA1 algorithm was ported from the Chromium OS one
|
||||
# This implementation of the SHA-1 algorithm was ported from the Chromium OS one
|
||||
# with minor modifications that should not affect its functionality.
|
||||
|
||||
proc newSha1State*(): Sha1State =
|
||||
## Creates a `Sha1State`.
|
||||
##
|
||||
## If you use the `secureHash proc <#secureHash,openArray[char]>`_,
|
||||
## there's no need to call this function explicitly.
|
||||
result.count = 0
|
||||
result.state[0] = 0x67452301'u32
|
||||
result.state[1] = 0xEFCDAB89'u32
|
||||
@@ -146,6 +149,10 @@ proc transform(ctx: var Sha1State) =
|
||||
ctx.state[4] += e
|
||||
|
||||
proc update*(ctx: var Sha1State, data: openArray[char]) =
|
||||
## Updates the `Sha1State` with `data`.
|
||||
##
|
||||
## If you use the `secureHash proc <#secureHash,openArray[char]>`_,
|
||||
## there's no need to call this function explicitly.
|
||||
var i = ctx.count mod 64
|
||||
var j = 0
|
||||
var len = data.len
|
||||
@@ -177,6 +184,10 @@ proc update*(ctx: var Sha1State, data: openArray[char]) =
|
||||
ctx.count += data.len
|
||||
|
||||
proc finalize*(ctx: var Sha1State): Sha1Digest =
|
||||
## Finalizes the `Sha1State` and returns a `Sha1Digest`.
|
||||
##
|
||||
## If you use the `secureHash proc <#secureHash,openArray[char]>`_,
|
||||
## there's no need to call this function explicitly.
|
||||
var cnt = uint64(ctx.count * 8)
|
||||
# a 1 bit
|
||||
update(ctx, "\x80")
|
||||
@@ -195,24 +206,25 @@ proc finalize*(ctx: var Sha1State): Sha1Digest =
|
||||
# Public API
|
||||
|
||||
proc secureHash*(str: openArray[char]): SecureHash =
|
||||
## Generates a ``SecureHash`` from a ``str``.
|
||||
## Generates a `SecureHash` from `str`.
|
||||
##
|
||||
## **See also:**
|
||||
## * `secureHashFile proc <#secureHashFile,string>`_ for generating a ``SecureHash`` from a file
|
||||
## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash``
|
||||
## * `secureHashFile proc <#secureHashFile,string>`_ for generating a `SecureHash` from a file
|
||||
## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string `hash` to `SecureHash`
|
||||
runnableExamples:
|
||||
let hash = secureHash("Hello World")
|
||||
assert hash == parseSecureHash("0A4D55A8D778E5022FAB701977C5D840BBC486D0")
|
||||
|
||||
var state = newSha1State()
|
||||
state.update(str)
|
||||
SecureHash(state.finalize())
|
||||
|
||||
proc secureHashFile*(filename: string): SecureHash =
|
||||
## Generates a ``SecureHash`` from a file.
|
||||
## Generates a `SecureHash` from a file.
|
||||
##
|
||||
## **See also:**
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string
|
||||
## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash``
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a `SecureHash` from a string
|
||||
## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string `hash` to `SecureHash`
|
||||
const BufferLength = 8192
|
||||
|
||||
let f = open(filename)
|
||||
@@ -231,33 +243,35 @@ proc secureHashFile*(filename: string): SecureHash =
|
||||
SecureHash(state.finalize())
|
||||
|
||||
proc `$`*(self: SecureHash): string =
|
||||
## Returns the string representation of a ``SecureHash``.
|
||||
## Returns the string representation of a `SecureHash`.
|
||||
##
|
||||
## **See also:**
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a `SecureHash` from a string
|
||||
runnableExamples:
|
||||
let hash = secureHash("Hello World")
|
||||
assert $hash == "0A4D55A8D778E5022FAB701977C5D840BBC486D0"
|
||||
|
||||
result = ""
|
||||
for v in Sha1Digest(self):
|
||||
result.add(toHex(int(v), 2))
|
||||
|
||||
proc parseSecureHash*(hash: string): SecureHash =
|
||||
## Converts a string ``hash`` to ``SecureHash``.
|
||||
## Converts a string `hash` to a `SecureHash`.
|
||||
##
|
||||
## **See also:**
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string
|
||||
## * `secureHashFile proc <#secureHashFile,string>`_ for generating a ``SecureHash`` from a file
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a `SecureHash` from a string
|
||||
## * `secureHashFile proc <#secureHashFile,string>`_ for generating a `SecureHash` from a file
|
||||
runnableExamples:
|
||||
let
|
||||
hashStr = "0A4D55A8D778E5022FAB701977C5D840BBC486D0"
|
||||
secureHash = secureHash("Hello World")
|
||||
assert secureHash == parseSecureHash(hashStr)
|
||||
|
||||
for i in 0 ..< Sha1DigestSize:
|
||||
Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
|
||||
|
||||
proc `==`*(a, b: SecureHash): bool =
|
||||
## Checks if two ``SecureHash`` values are identical.
|
||||
## Checks if two `SecureHash` values are identical.
|
||||
runnableExamples:
|
||||
let
|
||||
a = secureHash("Hello World")
|
||||
@@ -265,5 +279,6 @@ proc `==`*(a, b: SecureHash): bool =
|
||||
c = parseSecureHash("0A4D55A8D778E5022FAB701977C5D840BBC486D0")
|
||||
assert a != b
|
||||
assert a == c
|
||||
|
||||
# Not a constant-time comparison, but that's acceptable in this context
|
||||
Sha1Digest(a) == Sha1Digest(b)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1215,7 +1215,7 @@ when defined(nimscript) or not defined(nimSeqsV2):
|
||||
## Generic code becomes much easier to write if the Nim naming scheme is
|
||||
## respected.
|
||||
|
||||
when defined(gcDestructors):
|
||||
when false: # defined(gcDestructors):
|
||||
proc add*[T](x: var seq[T], y: sink openArray[T]) {.noSideEffect.} =
|
||||
## Generic proc for adding a container `y` to a container `x`.
|
||||
##
|
||||
@@ -1754,6 +1754,7 @@ when not defined(js) and defined(nimV2):
|
||||
traceImpl: pointer
|
||||
disposeImpl: pointer
|
||||
typeInfoV1: pointer # for backwards compat, usually nil
|
||||
flags: int
|
||||
PNimTypeV2 = ptr TNimTypeV2
|
||||
|
||||
when notJSnotNims and defined(nimSeqsV2):
|
||||
@@ -1957,8 +1958,14 @@ type
|
||||
when NimStackTraceMsgs:
|
||||
frameMsgLen*: int ## end position in frameMsgBuf for this frame.
|
||||
|
||||
when defined(js):
|
||||
when defined(js) or defined(nimdoc):
|
||||
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
|
||||
## Appends `y` to `x` in place.
|
||||
runnableExamples:
|
||||
var tmp = ""
|
||||
tmp.add(cstring("ab"))
|
||||
tmp.add(cstring("cd"))
|
||||
doAssert tmp == "abcd"
|
||||
asm """
|
||||
if (`x` === null) { `x` = []; }
|
||||
var off = `x`.length;
|
||||
@@ -1967,7 +1974,15 @@ when defined(js):
|
||||
`x`[off+i] = `y`.charCodeAt(i);
|
||||
}
|
||||
"""
|
||||
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
|
||||
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} =
|
||||
## Appends `y` to `x` in place.
|
||||
## Only implemented for JS backend.
|
||||
runnableExamples:
|
||||
when defined(js):
|
||||
var tmp: cstring = ""
|
||||
tmp.add(cstring("ab"))
|
||||
tmp.add(cstring("cd"))
|
||||
doAssert tmp == cstring("abcd")
|
||||
|
||||
elif hasAlloc:
|
||||
{.push stackTrace: off, profiler: off.}
|
||||
@@ -2107,7 +2122,7 @@ const
|
||||
## is the minor number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 2
|
||||
NimPatch* {.intdefine.}: int = 9
|
||||
## is the patch number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer =
|
||||
sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
|
||||
var old = a.llmem # can be nil and is correct with nil
|
||||
a.llmem = cast[PLLChunk](osAllocPages(PageSize))
|
||||
when defined(avlcorruption):
|
||||
when defined(nimAvlcorruption):
|
||||
trackLocation(a.llmem, PageSize)
|
||||
incCurrMem(a, PageSize)
|
||||
a.llmem.size = PageSize - sizeof(LLChunk)
|
||||
@@ -276,7 +276,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
|
||||
a.freeAvlNodes = a.freeAvlNodes.link[0]
|
||||
else:
|
||||
result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode)))
|
||||
when defined(avlcorruption):
|
||||
when defined(nimAvlcorruption):
|
||||
cprintf("tracking location: %p\n", result)
|
||||
result.key = key
|
||||
result.upperBound = upperBound
|
||||
@@ -284,7 +284,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
|
||||
result.link[0] = bottom
|
||||
result.link[1] = bottom
|
||||
result.level = 1
|
||||
#when defined(avlcorruption):
|
||||
#when defined(nimAvlcorruption):
|
||||
# track("allocAvlNode", result, sizeof(AvlNode))
|
||||
sysAssert(bottom == addr(a.bottomData), "bottom data")
|
||||
sysAssert(bottom.link[0] == bottom, "bottom link[0]")
|
||||
@@ -1017,7 +1017,7 @@ when defined(nimTypeNames):
|
||||
template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||
{.push stackTrace: off.}
|
||||
|
||||
when defined(fulldebug):
|
||||
when defined(nimFulldebug):
|
||||
proc interiorAllocatedPtr*(p: pointer): pointer =
|
||||
result = interiorAllocatedPtr(allocator, p)
|
||||
|
||||
|
||||
@@ -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".}
|
||||
|
||||
@@ -160,7 +160,7 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} =
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
alignedDealloc(p -! hdrSize, alignment)
|
||||
|
||||
template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf)
|
||||
template `=dispose`*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf)
|
||||
#proc dispose*(x: pointer) = nimRawDispose(x)
|
||||
|
||||
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} =
|
||||
|
||||
@@ -52,8 +52,7 @@ template assert*(cond: untyped, msg = "") =
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## static: assert 1 == 9, "This assertion generates code when not built with -d:danger or --assertions:off"
|
||||
const expr = astToStr(cond)
|
||||
assertImpl(cond, msg, expr, compileOption("assertions"))
|
||||
assertImpl(cond, msg, astToStr(cond), compileOption("assertions"))
|
||||
|
||||
template doAssert*(cond: untyped, msg = "") =
|
||||
## Similar to ``assert`` but is always turned on regardless of ``--assertions``.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user