mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 11:23:40 +00:00
Compare commits
76 Commits
v1.4.4
...
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 |
@@ -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
|
||||
|
||||
|
||||
35
changelog.md
35
changelog.md
@@ -2,7 +2,21 @@
|
||||
|
||||
|
||||
|
||||
## 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
|
||||
@@ -31,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
|
||||
|
||||
@@ -44,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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -35,7 +35,7 @@ import
|
||||
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
transf, injectdestructors, sourcemap
|
||||
|
||||
import std/[json, sets, math, tables, intsets, strutils]
|
||||
import json, sets, math, tables, intsets, strutils
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -1427,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:
|
||||
@@ -2551,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)
|
||||
@@ -2588,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!")
|
||||
|
||||
@@ -495,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:
|
||||
@@ -750,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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -631,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:
|
||||
|
||||
@@ -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)
|
||||
@@ -2101,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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -5029,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
|
||||
=========
|
||||
|
||||
@@ -5940,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
|
||||
|
||||
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
|
||||
-------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
## server.listen Port(8080)
|
||||
## while true:
|
||||
## if server.shouldAcceptRequest():
|
||||
## asyncCheck server.acceptRequest(cb)
|
||||
## await server.acceptRequest(cb)
|
||||
## else:
|
||||
## poll()
|
||||
##
|
||||
@@ -382,7 +382,7 @@ when not defined(testing) and isMainModule:
|
||||
server.listen Port(5555)
|
||||
while true:
|
||||
if server.shouldAcceptRequest():
|
||||
asyncCheck server.acceptRequest(cb)
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -622,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
|
||||
@@ -689,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
|
||||
@@ -715,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)
|
||||
|
||||
@@ -769,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>`_
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
## macro system.
|
||||
|
||||
import std/private/since
|
||||
import macros, typetraits
|
||||
import macros
|
||||
|
||||
proc checkPragma(ex, prag: var NimNode) =
|
||||
since (1, 3):
|
||||
|
||||
@@ -108,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`
|
||||
|
||||
@@ -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``.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,8 +33,8 @@ runnableExamples:
|
||||
## * `hashes module<hashes.html>`_ for efficient computations of hash values for diverse Nim types
|
||||
## * `md5 module<md5.html>`_ implements the MD5 checksum algorithm
|
||||
|
||||
import std/strutils
|
||||
from std/endians import bigEndian32, bigEndian64
|
||||
import strutils
|
||||
from endians import bigEndian32, bigEndian64
|
||||
|
||||
const Sha1DigestSize = 20
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
@@ -2121,7 +2122,7 @@ const
|
||||
## is the minor number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 4
|
||||
NimPatch* {.intdefine.}: int = 9
|
||||
## is the patch number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
|
||||
@@ -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".}
|
||||
|
||||
@@ -29,7 +29,7 @@ type
|
||||
programCounter*: uint ## Program counter - will be used to get the rest of the info,
|
||||
## when `$` is called on this type. We can't use
|
||||
## "cuintptr_t" in here.
|
||||
procnameStr*, filenameStr*: string ## GC-ed objects holding the cstrings in "procname" and "filename"
|
||||
procnameStr*, filenameStr*: string ## GC-ed alternatives to "procname" and "filename"
|
||||
|
||||
Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \
|
||||
## Base exception class.
|
||||
|
||||
@@ -440,9 +440,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
|
||||
pushCurrentException(e)
|
||||
{.emit: "throw e;".}
|
||||
elif defined(nimQuirky) or gotoBasedExceptions:
|
||||
# XXX This check should likely also be done in the setjmp case below.
|
||||
if e != currException:
|
||||
pushCurrentException(e)
|
||||
pushCurrentException(e)
|
||||
when gotoBasedExceptions:
|
||||
inc nimInErrorMode
|
||||
else:
|
||||
|
||||
@@ -435,7 +435,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
@@ -450,7 +450,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
{.pop.}
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
# generates a new object and sets its reference counter to 1
|
||||
incTypeSize typ, size
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||
@@ -663,16 +663,16 @@ proc collectCycles(gch: var GcHeap) =
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
sysAssert(allocInv(gch.region), "gcMark begin")
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[ByteAddress](cell)
|
||||
var c = cast[ByteAddress](p)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
|
||||
if objStart != nil:
|
||||
# mark the cell:
|
||||
incRef(objStart)
|
||||
add(gch.decStack, objStart)
|
||||
when false:
|
||||
let cell = usrToCell(p)
|
||||
if isAllocatedPtr(gch.region, cell):
|
||||
sysAssert false, "allocated pointer but not interior?"
|
||||
# mark the cell:
|
||||
|
||||
@@ -455,11 +455,10 @@ proc markGlobals(gch: var GcHeap) =
|
||||
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[ByteAddress](cell)
|
||||
var c = cast[ByteAddress](p)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
|
||||
if objStart != nil:
|
||||
mark(gch, objStart)
|
||||
|
||||
|
||||
@@ -90,9 +90,21 @@ proc free(s: Cell; desc: PNimTypeV2) {.inline.} =
|
||||
|
||||
nimRawDispose(p, desc.align)
|
||||
|
||||
template orcAssert(cond, msg) =
|
||||
when logOrc:
|
||||
if not cond:
|
||||
cfprintf(cstderr, "[Bug!] %s\n", msg)
|
||||
quit 1
|
||||
|
||||
when logOrc:
|
||||
proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.}
|
||||
|
||||
proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inline.} =
|
||||
let p = cast[ptr pointer](q)
|
||||
if p[] != nil:
|
||||
|
||||
orcAssert strstr(desc.name, "TType") == nil, "following a TType but it's acyclic!"
|
||||
|
||||
var j = cast[ptr GcEnv](env)
|
||||
j.traceStack.add(head p[], desc)
|
||||
|
||||
@@ -102,12 +114,6 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inline.} =
|
||||
var j = cast[ptr GcEnv](env)
|
||||
j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[])
|
||||
|
||||
template orcAssert(cond, msg) =
|
||||
when logOrc:
|
||||
if not cond:
|
||||
cfprintf(cstderr, "[Bug!] %s\n", msg)
|
||||
quit 1
|
||||
|
||||
var
|
||||
roots {.threadvar.}: CellSeq
|
||||
|
||||
@@ -349,6 +355,8 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) =
|
||||
collectCycles()
|
||||
#writeCell("[added root]", s)
|
||||
|
||||
orcAssert strstr(desc.name, "TType") == nil, "added a TType as a root!"
|
||||
|
||||
proc GC_runOrc* =
|
||||
## Forces a cycle collection pass.
|
||||
collectCycles()
|
||||
|
||||
@@ -124,3 +124,7 @@ proc setLen[T](s: var seq[T], newlen: Natural) =
|
||||
if xu.p == nil or xu.p.cap < newlen:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
||||
xu.len = newlen
|
||||
|
||||
proc newSeq[T](s: var seq[T], len: Natural) =
|
||||
shrink(s, 0)
|
||||
setLen(s, len)
|
||||
|
||||
@@ -240,15 +240,16 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||
var ti = 0
|
||||
let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
||||
|
||||
result = i - start
|
||||
let endPos = i
|
||||
result = endPos - start
|
||||
i = start
|
||||
# re-parse without error checking, any error should be handled by the code above.
|
||||
if i < s.len and s[i] == '.': i.inc
|
||||
while i < s.len and s[i] in {'0'..'9','+','-'}:
|
||||
if i < endPos and s[i] == '.': i.inc
|
||||
while i < endPos and s[i] in {'0'..'9','+','-'}:
|
||||
if ti < maxlen:
|
||||
t[ti] = s[i]; inc(ti)
|
||||
inc(i)
|
||||
while i < s.len and s[i] in {'.', '_'}: # skip underscore and decimal point
|
||||
while i < endPos and s[i] in {'.', '_'}: # skip underscore and decimal point
|
||||
inc(i)
|
||||
|
||||
# insert exponent
|
||||
|
||||
@@ -52,14 +52,23 @@ when sslVersion != "":
|
||||
from posix import SocketHandle
|
||||
|
||||
elif useWinVersion:
|
||||
when not defined(nimOldDlls) and defined(cpu64):
|
||||
when defined(openssl10) or defined(nimOldDlls):
|
||||
when defined(cpu64):
|
||||
const
|
||||
DLLSSLName* = "(ssleay32|ssleay64).dll"
|
||||
DLLUtilName* = "(libeay32|libeay64).dll"
|
||||
else:
|
||||
const
|
||||
DLLSSLName* = "ssleay32.dll"
|
||||
DLLUtilName* = "libeay32.dll"
|
||||
elif defined(cpu64):
|
||||
const
|
||||
DLLSSLName* = "(libssl-1_1-x64|ssleay64|libssl64).dll"
|
||||
DLLUtilName* = "(libcrypto-1_1-x64|libeay64).dll"
|
||||
else:
|
||||
const
|
||||
DLLSSLName* = "(libssl-1_1|ssleay32|libssl32).dll"
|
||||
DLLUtilName* = "(libcrypto-1_1|libeay32).dll"
|
||||
DLLUtilName* = "(libcrypto-1_1|libeay32).dll"
|
||||
|
||||
from winlean import SocketHandle
|
||||
else:
|
||||
@@ -809,6 +818,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows):
|
||||
|
||||
proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
# Certificates store
|
||||
|
||||
type PX509_STORE* = SslPtr
|
||||
|
||||
@@ -216,7 +216,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||
|
||||
test "stackrefleak"
|
||||
test "cyclecollector"
|
||||
test "trace_globals"
|
||||
testWithoutBoehm "trace_globals"
|
||||
|
||||
proc longGCTests(r: var TResults, cat: Category, options: string) =
|
||||
when defined(windows):
|
||||
|
||||
@@ -36,9 +36,9 @@ pkg1 "dashing", "nim c tests/functional.nim"
|
||||
pkg1 "delaunay"
|
||||
pkg1 "docopt"
|
||||
pkg1 "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
|
||||
pkg1 "elvis"
|
||||
# pkg1 "elvis"
|
||||
# pkg1 "fidget"
|
||||
pkg1 "fragments", "nim c -r fragments/dsl.nim"
|
||||
# pkg1 "fragments", "nim c -r fragments/dsl.nim"
|
||||
pkg1 "gara"
|
||||
pkg1 "ggplotnim", "nim c -d:noCairo -r tests/tests.nim"
|
||||
# pkg1 "gittyup", "nimble test", "https://github.com/disruptek/gittyup"
|
||||
@@ -85,12 +85,12 @@ pkg2 "nimquery"
|
||||
pkg2 "nimsl"
|
||||
pkg2 "nimsvg"
|
||||
pkg2 "nimterop", "nimble minitest"
|
||||
pkg2 "nimwc", "nim c nimwc.nim"
|
||||
# pkg2 "nimwc", "nim c nimwc.nim"
|
||||
# pkg2 "nimx", "nim c --threads:on test/main.nim"
|
||||
# pkg2 "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
||||
pkg2 "norm", "nim c -r tests/sqlite/trows.nim"
|
||||
pkg2 "npeg", "nimble testarc"
|
||||
pkg2 "numericalnim", "nim c -r tests/test_integrate.nim"
|
||||
pkg2 "numericalnim", "nimble nimCI"
|
||||
pkg2 "optionsutils"
|
||||
pkg2 "ormin", "nim c -o:orminn ormin.nim"
|
||||
pkg2 "parsetoml"
|
||||
@@ -98,7 +98,7 @@ pkg2 "patty"
|
||||
pkg2 "plotly", "nim c examples/all.nim"
|
||||
pkg2 "pnm"
|
||||
pkg2 "polypbren"
|
||||
pkg2 "prologue", "nimble tcompile"
|
||||
# pkg2 "prologue", "nimble tcompile"
|
||||
pkg2 "protobuf", "nim c -o:protobuff -r src/protobuf.nim"
|
||||
pkg2 "pylib"
|
||||
pkg2 "rbtree"
|
||||
@@ -114,7 +114,7 @@ pkg2 "snip", "nimble test", "https://github.com/genotrance/snip"
|
||||
pkg2 "strslice"
|
||||
pkg2 "strunicode", "nim c -r src/strunicode.nim"
|
||||
pkg2 "synthesis"
|
||||
pkg2 "telebot", "nim c -o:tbot -r src/telebot.nim"
|
||||
# pkg2 "telebot", "nim c -o:tbot -r src/telebot.nim"
|
||||
pkg2 "tempdir"
|
||||
pkg2 "templates"
|
||||
pkg2 "tensordsl", "nim c -r tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git"
|
||||
|
||||
13
tests/arc/tnewseq_legacy.nim
Normal file
13
tests/arc/tnewseq_legacy.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
discard """
|
||||
output: "(allocCount: 201, deallocCount: 201)"
|
||||
cmd: "nim c --gc:orc -d:nimAllocStats $file"
|
||||
"""
|
||||
|
||||
proc main(prefix: string) =
|
||||
var c: seq[string]
|
||||
for i in 0..<100:
|
||||
newSeq(c, 100)
|
||||
c[i] = prefix & $i
|
||||
|
||||
main("abc")
|
||||
echo getAllocStats()
|
||||
@@ -590,3 +590,14 @@ block t12466:
|
||||
a[0'u16 + i] = i
|
||||
for i in 0'u16 ..< 8'u16:
|
||||
a[0'u16 + i] = i
|
||||
|
||||
block t18643:
|
||||
# https://github.com/nim-lang/Nim/issues/18643
|
||||
let a: array[0, int] = []
|
||||
var caught = false
|
||||
let b = 9999999
|
||||
try:
|
||||
echo a[b]
|
||||
except IndexDefect:
|
||||
caught = true
|
||||
doAssert caught, "IndexDefect not caught!"
|
||||
|
||||
@@ -86,7 +86,7 @@ Async traceback:
|
||||
asyncfutures\.nim\(\d+?\)\s+?read
|
||||
\]#
|
||||
Exception message: b failure
|
||||
Exception type:
|
||||
|
||||
|
||||
bar failure
|
||||
Async traceback:
|
||||
@@ -114,7 +114,7 @@ Async traceback:
|
||||
asyncfutures\.nim\(\d+?\)\s+?read
|
||||
\]#
|
||||
Exception message: bar failure
|
||||
Exception type:
|
||||
|
||||
"""
|
||||
|
||||
# TODO: is asyncmacro good enough location for fooIter traceback/debugging? just put the callsite info for all?
|
||||
|
||||
16
tests/ccgbugs/tmangle.nim
Normal file
16
tests/ccgbugs/tmangle.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
block:
|
||||
proc hello() =
|
||||
let NAN_INFINITY = 12
|
||||
doAssert NAN_INFINITY == 12
|
||||
let INF = "2.0"
|
||||
doAssert INF == "2.0"
|
||||
let NAN = 2.3
|
||||
doAssert NAN == 2.3
|
||||
|
||||
hello()
|
||||
|
||||
block:
|
||||
proc hello(NAN: float) =
|
||||
doAssert NAN == 2.0
|
||||
|
||||
hello(2.0)
|
||||
@@ -1,7 +1,9 @@
|
||||
discard """
|
||||
targets: "cpp"
|
||||
output: '''6.0
|
||||
output: '''
|
||||
6.0
|
||||
0'''
|
||||
disabled: "windows" # pending bug #18011
|
||||
"""
|
||||
|
||||
# bug #4730
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user