mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 03:13:41 +00:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb03c4b937 | ||
|
|
ba8f657635 | ||
|
|
6238f2ee1e | ||
|
|
7aff6ded84 | ||
|
|
fe8b84496f | ||
|
|
7f834c69fb | ||
|
|
9a58bddc55 | ||
|
|
9ebf537341 | ||
|
|
5ea5d82507 | ||
|
|
d85b7dde7b | ||
|
|
1d301e354f | ||
|
|
a7570ff0c2 | ||
|
|
86c8977726 | ||
|
|
2ee078cdf8 | ||
|
|
ebc114c526 | ||
|
|
6da0bf80c3 | ||
|
|
2e896e3360 | ||
|
|
d922751d98 | ||
|
|
ca1f97951c | ||
|
|
a48abc262c | ||
|
|
c18726f4a1 | ||
|
|
965b37ab4a | ||
|
|
7deedd3601 | ||
|
|
2db37e2e0e | ||
|
|
aa98aee18d | ||
|
|
3fb7979211 | ||
|
|
5ffa88e7e0 | ||
|
|
5788d288ad | ||
|
|
793bd0a977 | ||
|
|
90cf7177ca | ||
|
|
98894e5e07 | ||
|
|
040adf415b | ||
|
|
bdb3cc3a8a | ||
|
|
435eca6232 | ||
|
|
6d75a9c996 | ||
|
|
6e0c052509 | ||
|
|
c5bf0d6fa9 | ||
|
|
2b9c458692 | ||
|
|
28049053e8 | ||
|
|
a82cfb2d54 | ||
|
|
e3810646eb | ||
|
|
0888ac4097 | ||
|
|
c2982d5a9d | ||
|
|
212dcafcaa | ||
|
|
f04c8f0ba4 | ||
|
|
67bdbb676e | ||
|
|
93552e2e31 | ||
|
|
1ee94744e3 | ||
|
|
db70fec7ca | ||
|
|
252bebd16e | ||
|
|
a27459fc08 | ||
|
|
8c3f500338 | ||
|
|
9af27994c9 | ||
|
|
ee6b9d37c0 | ||
|
|
71c0b6e76c | ||
|
|
b3a12b4e3f | ||
|
|
a832fa65c4 | ||
|
|
6c5eaa955d | ||
|
|
e9e93bd0ca |
@@ -1,25 +1,19 @@
|
||||
# see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd
|
||||
image: freebsd/latest
|
||||
|
||||
# packages:
|
||||
# - databases/sqlite3
|
||||
# - devel/boehm-gc-threaded
|
||||
# - devel/pcre
|
||||
# - devel/sdl20
|
||||
# - devel/sfml
|
||||
# - www/node
|
||||
# - devel/gmake
|
||||
# - devel/git
|
||||
packages:
|
||||
- databases/sqlite3
|
||||
- devel/boehm-gc-threaded
|
||||
- devel/pcre
|
||||
- devel/sdl20
|
||||
- devel/sfml
|
||||
- www/node
|
||||
- devel/gmake
|
||||
sources:
|
||||
- https://github.com/nim-lang/Nim
|
||||
environment:
|
||||
CC: /usr/bin/clang
|
||||
tasks:
|
||||
- setup: |
|
||||
# workaround https://github.com/timotheecour/Nim/issues/76
|
||||
sudo pkg update -q -f
|
||||
sudo pkg install -y -q databases/sqlite3 devel/boehm-gc-threaded devel/pcre \
|
||||
devel/sdl20 devel/sfml www/node devel/gmake devel/git
|
||||
cd Nim
|
||||
git clone --depth 1 -q https://github.com/nim-lang/csources.git
|
||||
gmake -C csources -j $(sysctl -n hw.ncpu)
|
||||
|
||||
4
.github/workflows/ci.yml.disabled
vendored
4
.github/workflows/ci.yml.disabled
vendored
@@ -85,11 +85,11 @@ jobs:
|
||||
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
|
||||
7z x dist/mingw64.7z -odist
|
||||
7z x dist/dlls.zip -obin
|
||||
echo "::add-path::${{ github.workspace }}/dist/mingw64/bin"
|
||||
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "::add-path::${{ github.workspace }}/bin"
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Build csources'
|
||||
shell: bash
|
||||
|
||||
4
.github/workflows/ci_docs.yml
vendored
4
.github/workflows/ci_docs.yml
vendored
@@ -49,11 +49,11 @@ jobs:
|
||||
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
|
||||
7z x dist/mingw64.7z -odist
|
||||
7z x dist/dlls.zip -obin
|
||||
echo "::add-path::${{ github.workspace }}/dist/mingw64/bin"
|
||||
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "::add-path::${{ github.workspace }}/bin"
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Get current csources version'
|
||||
id: csources-version
|
||||
|
||||
4
.github/workflows/ci_ssl.yml
vendored
4
.github/workflows/ci_ssl.yml
vendored
@@ -47,11 +47,11 @@ jobs:
|
||||
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
|
||||
7z x dist/mingw64.7z -odist
|
||||
7z x dist/dlls.zip -obin
|
||||
echo "::add-path::${{ github.workspace }}/dist/mingw64/bin"
|
||||
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "::add-path::${{ github.workspace }}/bin"
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Build 1-stage compiler from csources'
|
||||
shell: bash
|
||||
|
||||
14
changelog.md
14
changelog.md
@@ -125,6 +125,20 @@
|
||||
Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore.
|
||||
`CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again.
|
||||
- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`.
|
||||
- On Windows the SSL library now checks for valid certificates.
|
||||
It uses the `cacert.pem` file for this purpose which was extracted
|
||||
from `https://curl.se/ca/cacert.pem`. Besides
|
||||
the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
|
||||
now also need to ship `cacert.pem` with your `.exe` file.
|
||||
|
||||
|
||||
- Make `{.requiresInit.}` pragma to work for `distinct` types.
|
||||
|
||||
|
||||
- Added `asyncdispatch.activeDescriptors` that returns the number of currently
|
||||
active async event handles/file descriptors
|
||||
- Added `asyncdispatch.maxDescriptors` that returns the maximum number of
|
||||
active async event handles/file descriptors.
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
@@ -1085,7 +1085,7 @@ proc safeLen*(n: PNode): int {.inline.} =
|
||||
|
||||
proc safeArrLen*(n: PNode): int {.inline.} =
|
||||
## works for array-like objects (strings passed as openArray in VM).
|
||||
if n.kind in {nkStrLit..nkTripleStrLit}:result = n.strVal.len
|
||||
if n.kind in {nkStrLit..nkTripleStrLit}: result = n.strVal.len
|
||||
elif n.kind in {nkNone..nkFloat128Lit}: result = 0
|
||||
else: result = n.len
|
||||
|
||||
|
||||
@@ -833,6 +833,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||
[rdLoc(test), strLit, raiseInstr(p)])
|
||||
|
||||
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
assert e[0].kind == nkDotExpr
|
||||
if optFieldCheck in p.options:
|
||||
var a: TLoc
|
||||
genRecordFieldAux(p, e[0], d, a)
|
||||
@@ -1981,30 +1982,25 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
|
||||
checkUnsignedConversions notin p.config.legacyFeatures):
|
||||
discard "no need to generate a check because it was disabled"
|
||||
else:
|
||||
let raiser =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
discard cgsym(p.module, raiser)
|
||||
# This seems to be bug-compatible with Nim version 1 but what we
|
||||
# should really do here is to check if uint64Value < high(int)
|
||||
let n0t = n[0].typ
|
||||
|
||||
let boundaryCast =
|
||||
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
|
||||
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
|
||||
"(NI64)"
|
||||
else:
|
||||
""
|
||||
# emit range check:
|
||||
if n0t.kind in {tyUInt, tyUInt64}:
|
||||
linefmt(p, cpsStmts, "if ($1 > ($6)($3)){ #raiseRangeErrorNoArgs(); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), getTypeDesc(p.module, n0t)])
|
||||
else:
|
||||
let raiser =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
discard cgsym(p.module, raiser)
|
||||
|
||||
let boundaryCast =
|
||||
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
|
||||
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
|
||||
"(NI64)"
|
||||
else:
|
||||
""
|
||||
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), boundaryCast])
|
||||
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
|
||||
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
|
||||
raiser, raiseInstr(p), boundaryCast])
|
||||
putIntoDest(p, d, n, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
|
||||
|
||||
@@ -2670,7 +2666,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
expr(p, n[1][0], d)
|
||||
of nkObjDownConv: downConv(p, n, d)
|
||||
of nkObjUpConv: upConv(p, n, d)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
|
||||
of nkChckRangeF: genRangeChck(p, n, d)
|
||||
of nkChckRange64: genRangeChck(p, n, d)
|
||||
of nkChckRange: genRangeChck(p, n, d)
|
||||
of nkStringToCString: convStrToCStr(p, n, d)
|
||||
of nkCStringToString: convCStrToStr(p, n, d)
|
||||
of nkLambdaKinds:
|
||||
|
||||
@@ -25,10 +25,10 @@ proc getTraverseProc(p: BProc, v: PSym): Rope =
|
||||
|
||||
proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
|
||||
if sfThread in v.flags:
|
||||
appcg(p.module, p.module.initProc.procSec(cpsInit),
|
||||
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
|
||||
"$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc])
|
||||
else:
|
||||
appcg(p.module, p.module.initProc.procSec(cpsInit),
|
||||
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
|
||||
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
||||
|
||||
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
|
||||
@@ -244,7 +244,7 @@ proc safeLineNm(info: TLineInfo): int =
|
||||
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
|
||||
assert line >= 0
|
||||
if optLineDir in conf.options:
|
||||
if optLineDir in conf.options and line > 0:
|
||||
r.addf("$N#line $2 $1$N",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
@@ -1645,7 +1645,7 @@ proc genInitCode(m: BModule) =
|
||||
writeSection(preInitProc, cpsLocals)
|
||||
writeSection(preInitProc, cpsInit, m.hcrOn)
|
||||
writeSection(preInitProc, cpsStmts)
|
||||
prc.addf("}$N", [])
|
||||
prc.addf("}/* preInitProc end */$N", [])
|
||||
|
||||
# add new scope for following code, because old vcc compiler need variable
|
||||
# be defined at the top of the block
|
||||
|
||||
@@ -117,3 +117,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasInvariant")
|
||||
defineSymbol("nimHasStacktraceMsgs")
|
||||
defineSymbol("nimHasStacktracesModule")
|
||||
defineSymbol("nimHasJsBigIntBackend")
|
||||
|
||||
@@ -6,12 +6,12 @@ Name: "Nim"
|
||||
Version: "$version"
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
|
||||
macosx: i386;amd64;powerpc64
|
||||
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64
|
||||
macosx: i386;amd64;powerpc64;arm64
|
||||
solaris: i386;amd64;sparc;sparc64
|
||||
freebsd: i386;amd64;powerpc64;arm;arm64
|
||||
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
|
||||
netbsd: i386;amd64
|
||||
openbsd: i386;amd64
|
||||
openbsd: i386;amd64;arm;arm64
|
||||
dragonfly: i386;amd64
|
||||
haiku: i386;amd64
|
||||
android: i386;arm;arm64
|
||||
@@ -111,6 +111,7 @@ Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/downlo
|
||||
Files: "bin/makelink.exe"
|
||||
Files: "bin/7zG.exe"
|
||||
Files: "bin/*.dll"
|
||||
Files: "bin/cacert.pem"
|
||||
|
||||
[UnixBin]
|
||||
Files: "bin/nim"
|
||||
|
||||
@@ -1591,7 +1591,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
var t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
|
||||
result = putToSeq("0", indirect)
|
||||
if $t.sym.loc.r == "bigint":
|
||||
result = putToSeq("0n", indirect)
|
||||
else:
|
||||
result = putToSeq("0", indirect)
|
||||
of tyFloat..tyFloat128:
|
||||
result = putToSeq("0.0", indirect)
|
||||
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned:
|
||||
@@ -2124,11 +2127,17 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if dest.kind == src.kind:
|
||||
# no-op conversion
|
||||
return
|
||||
case dest.kind:
|
||||
of tyBool:
|
||||
let toInt = (dest.kind in tyInt..tyInt32)
|
||||
let fromInt = (src.kind in tyInt..tyInt32)
|
||||
let toUint = (dest.kind in tyUInt..tyUInt32)
|
||||
let fromUint = (src.kind in tyUInt..tyUInt32)
|
||||
if toUint and (fromInt or fromUint):
|
||||
let trimmer = unsignedTrimmer(dest.size)
|
||||
r.res = "($1 $2)" % [r.res, trimmer]
|
||||
elif dest.kind == tyBool:
|
||||
r.res = "(!!($1))" % [r.res]
|
||||
r.kind = resExpr
|
||||
of tyInt:
|
||||
elif toInt:
|
||||
r.res = "(($1)|0)" % [r.res]
|
||||
else:
|
||||
# TODO: What types must we handle here?
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osAny
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny
|
||||
|
||||
type
|
||||
TInfoOSProp* = enum
|
||||
@@ -177,6 +177,10 @@ const
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
|
||||
props: {ospNeedsPIC, ospPosix}),
|
||||
(name: "FreeRTOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospPosix}),
|
||||
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
@@ -189,7 +193,7 @@ type
|
||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||
cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips,
|
||||
cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430,
|
||||
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuWasm32
|
||||
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32
|
||||
|
||||
type
|
||||
TEndian* = enum
|
||||
@@ -222,7 +226,9 @@ const
|
||||
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)]
|
||||
|
||||
type
|
||||
|
||||
@@ -20,7 +20,7 @@ const
|
||||
|
||||
const
|
||||
declPragmas = {wImportc, wImportObjC, wImportCpp, wImportJs, wExportc, wExportCpp,
|
||||
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed, wAlign}
|
||||
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed}
|
||||
## common pragmas for declarations, to a good approximation
|
||||
procPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
wMagic, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
|
||||
@@ -54,22 +54,22 @@ const
|
||||
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
|
||||
wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume}
|
||||
lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv,
|
||||
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
|
||||
wThread, wAsmNoStackFrame,
|
||||
wRaises, wLocks, wTags, wRequires, wEnsures,
|
||||
wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these?
|
||||
wGcSafe, wCodegenDecl, wNoInit}
|
||||
typePragmas* = declPragmas + {wMagic, wAcyclic,
|
||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
||||
wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
|
||||
fieldPragmas* = declPragmas + {
|
||||
wGuard, wBitsize, wCursor, wRequiresInit} - {wExportNims, wNodecl} # why exclude these?
|
||||
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
|
||||
wRequiresInit, wAlign} - {wExportNims, wNodecl} # why exclude these?
|
||||
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
|
||||
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
|
||||
wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor}
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wAlign}
|
||||
constPragmas* = declPragmas + {wHeader, wMagic,
|
||||
wGensym, wInject,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
|
||||
|
||||
@@ -715,6 +715,9 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
result.typ = n.typ
|
||||
of nkBracketExpr: result = foldArrayAccess(m, n, g)
|
||||
of nkDotExpr: result = foldFieldAccess(m, n, g)
|
||||
of nkCheckedFieldExpr:
|
||||
assert n[0].kind == nkDotExpr
|
||||
result = foldFieldAccess(m, n[0], g)
|
||||
of nkStmtListExpr:
|
||||
var i = 0
|
||||
while i <= n.len - 2:
|
||||
|
||||
@@ -1028,6 +1028,11 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||
return n
|
||||
of nkExceptBranch:
|
||||
result = transformExceptBranch(c, n)
|
||||
of nkCheckedFieldExpr:
|
||||
result = transformSons(c, n)
|
||||
if result[0].kind != nkDotExpr:
|
||||
# simplfied beyond a dot expression --> simplify further.
|
||||
result = result[0]
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
when false:
|
||||
|
||||
@@ -173,6 +173,6 @@ proc extractRange*(k: TNodeKind, n: PNode, a, b: int): PNode =
|
||||
proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} =
|
||||
# symbols that expand to a complex constant (array, etc.) should not be
|
||||
# inlined, unless it's the empty array:
|
||||
result = orig.kind == nkSym and
|
||||
result = orig.kind != cnst.kind and
|
||||
cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
|
||||
cnst.len > ord(cnst.kind == nkObjConstr)
|
||||
|
||||
@@ -71,7 +71,7 @@ const
|
||||
tyInferred, tySink, tyLent, tyOwned}
|
||||
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
|
||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||
typedescInst* = abstractInst + {tyTypeDesc, tyOwned}
|
||||
typedescInst* = abstractInst + {tyTypeDesc, tyOwned, tyUserTypeClass}
|
||||
|
||||
proc invalidGenericInst*(f: PType): bool =
|
||||
result = f.kind == tyGenericInst and lastSon(f) == nil
|
||||
|
||||
@@ -1959,14 +1959,6 @@ proc genProc*(c: PCtx; s: PSym): int
|
||||
|
||||
proc matches(s: PSym; x: string): bool =
|
||||
let y = x.split('.')
|
||||
var s = s
|
||||
for i in 1..y.len:
|
||||
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
|
||||
return false
|
||||
s = s.owner
|
||||
result = true
|
||||
|
||||
proc matches(s: PSym; y: varargs[string]): bool =
|
||||
var s = s
|
||||
for i in 1..y.len:
|
||||
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
|
||||
@@ -2027,11 +2019,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
elif s.kind == skMethod:
|
||||
localError(c.config, n.info, "cannot call method " & s.name.s &
|
||||
" at compile time")
|
||||
elif matches(s, "stdlib", "marshal", "to"):
|
||||
elif matches(s, "stdlib.marshal.to"):
|
||||
# XXX marshal load&store should not be opcodes, but use the
|
||||
# general callback mechanisms.
|
||||
genMarshalLoad(c, n, dest)
|
||||
elif matches(s, "stdlib", "marshal", "$$"):
|
||||
elif matches(s, "stdlib.marshal.$$"):
|
||||
genMarshalStore(c, n, dest)
|
||||
else:
|
||||
genCall(c, n, dest)
|
||||
|
||||
@@ -2483,9 +2483,10 @@ matches) is preferred:
|
||||
Overloading based on 'var T'
|
||||
----------------------------
|
||||
|
||||
If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary
|
||||
type checking, the argument is checked to be an `l-value`:idx:. ``var T``
|
||||
matches better than just ``T`` then.
|
||||
If the formal parameter ``f`` is of type ``var T``
|
||||
in addition to the ordinary type checking,
|
||||
the argument is checked to be an `l-value`:idx:.
|
||||
``var T`` matches better than just ``T`` then.
|
||||
|
||||
.. code-block:: nim
|
||||
proc sayHi(x: int): string =
|
||||
@@ -5714,12 +5715,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
|
||||
@@ -5981,10 +5982,10 @@ noSideEffect pragma
|
||||
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
||||
effects. This means that the proc/iterator only changes locations that are
|
||||
reachable from its parameters and the return value only depends on the
|
||||
arguments. If none of its parameters have the type ``var T``
|
||||
or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||
verify this.
|
||||
arguments. If none of its parameters have the type ``var T`` or ``ref T``
|
||||
or ``ptr T`` this means no locations are modified. It is a static error to
|
||||
mark a proc/iterator to have no side effect if the compiler cannot verify
|
||||
this.
|
||||
|
||||
As a special semantic rule, the built-in `debugEcho
|
||||
<system.html#debugEcho,varargs[typed,]>`_ pretends to be free of side effects,
|
||||
|
||||
2
koch.nim
2
koch.nim
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
const
|
||||
NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master
|
||||
NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master
|
||||
|
||||
when not defined(windows):
|
||||
const
|
||||
|
||||
@@ -1262,7 +1262,15 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
|
||||
else:
|
||||
badNodeKind someProc, "body="
|
||||
|
||||
proc basename*(a: NimNode): NimNode {.compileTime, benign.}
|
||||
proc basename*(a: NimNode): NimNode {.raises: [].} =
|
||||
## Pull an identifier from prefix/postfix expressions.
|
||||
case a.kind
|
||||
of nnkIdent: result = a
|
||||
of nnkPostfix, nnkPrefix: result = a[1]
|
||||
of nnkPragmaExpr: result = basename(a[0])
|
||||
else:
|
||||
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
|
||||
repr(a), a)
|
||||
|
||||
proc `$`*(node: NimNode): string {.compileTime.} =
|
||||
## Get the string of an identifier node.
|
||||
@@ -1325,16 +1333,6 @@ proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
|
||||
a[i + 1] = a[i]
|
||||
a[pos] = b
|
||||
|
||||
proc basename*(a: NimNode): NimNode =
|
||||
## Pull an identifier from prefix/postfix expressions.
|
||||
case a.kind
|
||||
of nnkIdent: result = a
|
||||
of nnkPostfix, nnkPrefix: result = a[1]
|
||||
of nnkPragmaExpr: result = basename(a[0])
|
||||
else:
|
||||
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
|
||||
repr(a), a)
|
||||
|
||||
proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
|
||||
case a.kind
|
||||
of nnkIdent:
|
||||
|
||||
@@ -62,7 +62,6 @@ from pcre import nil
|
||||
import nre/private/util
|
||||
import tables
|
||||
from strutils import `%`
|
||||
from math import ceil
|
||||
import options
|
||||
from unicode import runeLenAt
|
||||
|
||||
@@ -734,8 +733,25 @@ proc replace*(str: string, pattern: Regex, sub: string): string =
|
||||
replaceImpl(str, pattern,
|
||||
formatStr(sub, match.captures[name], match.captures[id - 1]))
|
||||
|
||||
let SpecialCharMatcher = re"([\\+*?[^\]$(){}=!<>|:-])"
|
||||
proc escapeRe*(str: string): string =
|
||||
## Escapes the string so it doesn’t match any special characters.
|
||||
proc escapeRe*(str: string): string {.gcsafe.} =
|
||||
## Escapes the string so it doesn't match any special characters.
|
||||
## Incompatible with the Extra flag (``X``).
|
||||
str.replace(SpecialCharMatcher, "\\$1")
|
||||
##
|
||||
## Escaped char: `\ + * ? [ ^ ] $ ( ) { } = ! < > | : -`
|
||||
runnableExamples:
|
||||
doAssert escapeRe("fly+wind") == "fly\\+wind"
|
||||
doAssert escapeRe("!") == "\\!"
|
||||
doAssert escapeRe("nim*") == "nim\\*"
|
||||
|
||||
#([\\+*?[^\]$(){}=!<>|:-])
|
||||
const SpecialCharMatcher = {'\\', '+', '*', '?', '[', '^', ']', '$', '(',
|
||||
')', '{', '}', '=', '!', '<', '>', '|', ':',
|
||||
'-'}
|
||||
|
||||
for c in items(str):
|
||||
case c
|
||||
of SpecialCharMatcher:
|
||||
result.add("\\")
|
||||
result.add(c)
|
||||
else:
|
||||
result.add(c)
|
||||
|
||||
@@ -1892,3 +1892,25 @@ proc waitFor*[T](fut: Future[T]): T =
|
||||
poll()
|
||||
|
||||
fut.read
|
||||
|
||||
proc activeDescriptors*(): int {.inline.} =
|
||||
## Returns the current number of active file descriptors for the current
|
||||
## event loop. This is a cheap operation that does not involve a system call.
|
||||
when defined(windows):
|
||||
result = getGlobalDispatcher().handles.len
|
||||
elif not defined(nimdoc):
|
||||
result = getGlobalDispatcher().selector.count
|
||||
|
||||
when defined(posix):
|
||||
import posix
|
||||
|
||||
proc maxDescriptors*(): int {.raises: OSError.} =
|
||||
## Returns the maximum number of active file descriptors for the current
|
||||
## process. This involves a system call.
|
||||
when defined(windows):
|
||||
result = 16_700_000
|
||||
else:
|
||||
var fdLim: RLimit
|
||||
if getrlimit(RLIMIT_NOFILE, fdLim) < 0:
|
||||
raiseOSError(osLastError())
|
||||
result = int(fdLim.rlim_cur) - 1
|
||||
|
||||
@@ -11,24 +11,36 @@
|
||||
##
|
||||
## This HTTP server has not been designed to be used in production, but
|
||||
## for testing applications locally. Because of this, when deploying your
|
||||
## application you should use a reverse proxy (for example nginx) instead of
|
||||
## allowing users to connect directly to this server.
|
||||
## application in production you should use a reverse proxy (for example nginx)
|
||||
## instead of allowing users to connect directly to this server.
|
||||
##
|
||||
## Basic usage
|
||||
## ===========
|
||||
## Example
|
||||
## =======
|
||||
##
|
||||
## This example will create an HTTP server on port 8080. The server will
|
||||
## respond to all requests with a ``200 OK`` response code and "Hello World"
|
||||
## as the response body.
|
||||
##
|
||||
## .. code-block::nim
|
||||
## import asynchttpserver, asyncdispatch
|
||||
## .. code-block:: Nim
|
||||
##
|
||||
## var server = newAsyncHttpServer()
|
||||
## proc cb(req: Request) {.async.} =
|
||||
## await req.respond(Http200, "Hello World")
|
||||
## import asynchttpserver, asyncdispatch
|
||||
##
|
||||
## waitFor server.serve(Port(8080), cb)
|
||||
## proc main {.async.} =
|
||||
## var server = newAsyncHttpServer()
|
||||
## proc cb(req: Request) {.async.} =
|
||||
## let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",
|
||||
## "Content-type": "text/plain; charset=utf-8"}
|
||||
## await req.respond(Http200, "Hello World", headers.newHttpHeaders())
|
||||
##
|
||||
## server.listen Port(8080)
|
||||
## while true:
|
||||
## if server.shouldAcceptRequest():
|
||||
## asyncCheck server.acceptRequest(cb)
|
||||
## else:
|
||||
## poll()
|
||||
##
|
||||
## asyncCheck main()
|
||||
## runForever()
|
||||
|
||||
import asyncnet, asyncdispatch, parseutils, uri, strutils
|
||||
import httpcore
|
||||
@@ -58,14 +70,12 @@ type
|
||||
reuseAddr: bool
|
||||
reusePort: bool
|
||||
maxBody: int ## The maximum content-length that will be read for the body.
|
||||
maxFDs: int
|
||||
|
||||
proc newAsyncHttpServer*(reuseAddr = true, reusePort = false,
|
||||
maxBody = 8388608): AsyncHttpServer =
|
||||
## Creates a new ``AsyncHttpServer`` instance.
|
||||
new result
|
||||
result.reuseAddr = reuseAddr
|
||||
result.reusePort = reusePort
|
||||
result.maxBody = maxBody
|
||||
result = AsyncHttpServer(reuseAddr: reuseAddr, reusePort: reusePort, maxBody: maxBody)
|
||||
|
||||
proc addHeaders(msg: var string, headers: HttpHeaders) =
|
||||
for k, v in headers:
|
||||
@@ -294,13 +304,9 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string
|
||||
)
|
||||
if not retry: break
|
||||
|
||||
proc serve*(server: AsyncHttpServer, port: Port,
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.},
|
||||
address = "") {.async.} =
|
||||
## Starts the process of listening for incoming HTTP connections on the
|
||||
## specified address and port.
|
||||
##
|
||||
## When a request is made by a client the specified callback will be called.
|
||||
proc listen*(server: AsyncHttpServer; port: Port; address = "") =
|
||||
## Listen to the given port and address.
|
||||
server.maxFDs = maxDescriptors()
|
||||
server.socket = newAsyncSocket()
|
||||
if server.reuseAddr:
|
||||
server.socket.setSockOpt(OptReuseAddr, true)
|
||||
@@ -309,9 +315,44 @@ proc serve*(server: AsyncHttpServer, port: Port,
|
||||
server.socket.bindAddr(port, address)
|
||||
server.socket.listen()
|
||||
|
||||
proc shouldAcceptRequest*(server: AsyncHttpServer;
|
||||
assumedDescriptorsPerRequest = 5): bool {.inline.} =
|
||||
## Returns true if the process's current number of opened file
|
||||
## descriptors is still within the maximum limit and so it's reasonable to
|
||||
## accept yet another request.
|
||||
result = assumedDescriptorsPerRequest < 0 or
|
||||
(activeDescriptors() + assumedDescriptorsPerRequest < server.maxFDs)
|
||||
|
||||
proc acceptRequest*(server: AsyncHttpServer,
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} =
|
||||
## Accepts a single request. Write an explicit loop around this proc so that
|
||||
## errors can be handled properly.
|
||||
var (address, client) = await server.socket.acceptAddr()
|
||||
asyncCheck processClient(server, client, address, callback)
|
||||
|
||||
proc serve*(server: AsyncHttpServer, port: Port,
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.},
|
||||
address = "";
|
||||
assumedDescriptorsPerRequest = -1) {.async.} =
|
||||
## Starts the process of listening for incoming HTTP connections on the
|
||||
## specified address and port.
|
||||
##
|
||||
## When a request is made by a client the specified callback will be called.
|
||||
##
|
||||
## If `assumedDescriptorsPerRequest` is 0 or greater the server cares about
|
||||
## the process's maximum file descriptor limit. It then ensures that the
|
||||
## process still has the resources for `assumedDescriptorsPerRequest`
|
||||
## file descriptors before accepting a connection.
|
||||
##
|
||||
## You should prefer to call `acceptRequest` instead with a custom server
|
||||
## loop so that you're in control over the error handling and logging.
|
||||
listen server, port, address
|
||||
while true:
|
||||
var (address, client) = await server.socket.acceptAddr()
|
||||
asyncCheck processClient(server, client, address, callback)
|
||||
if shouldAcceptRequest(server, assumedDescriptorsPerRequest):
|
||||
var (address, client) = await server.socket.acceptAddr()
|
||||
asyncCheck processClient(server, client, address, callback)
|
||||
else:
|
||||
poll()
|
||||
#echo(f.isNil)
|
||||
#echo(f.repr)
|
||||
|
||||
@@ -320,7 +361,7 @@ proc close*(server: AsyncHttpServer) =
|
||||
server.socket.close()
|
||||
|
||||
when not defined(testing) and isMainModule:
|
||||
proc main =
|
||||
proc main {.async.} =
|
||||
var server = newAsyncHttpServer()
|
||||
proc cb(req: Request) {.async.} =
|
||||
#echo(req.reqMethod, " ", req.url)
|
||||
@@ -329,6 +370,12 @@ when not defined(testing) and isMainModule:
|
||||
"Content-type": "text/plain; charset=utf-8"}
|
||||
await req.respond(Http200, "Hello World", headers.newHttpHeaders())
|
||||
|
||||
asyncCheck server.serve(Port(5555), cb)
|
||||
runForever()
|
||||
main()
|
||||
server.listen Port(5555)
|
||||
while true:
|
||||
if server.shouldAcceptRequest():
|
||||
asyncCheck server.acceptRequest(cb)
|
||||
else:
|
||||
poll()
|
||||
|
||||
asyncCheck main()
|
||||
runForever()
|
||||
|
||||
@@ -198,7 +198,8 @@ proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} =
|
||||
for i in 1 ..< len(params):
|
||||
expectKind(params[i], nnkIdentDefs)
|
||||
if params[i][1].kind == nnkBracketExpr and
|
||||
params[i][1][0].eqIdent("futurevar"):
|
||||
params[i][1][0].eqIdent(FutureVar.astToStr):
|
||||
## eqIdent: first char is case sensitive!!!
|
||||
result.add(params[i][0])
|
||||
|
||||
proc isInvalidReturnType(typeName: string): bool =
|
||||
|
||||
@@ -110,7 +110,11 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) =
|
||||
resFut.complete(res)
|
||||
|
||||
# If the saved callback isn't nil then let's call it.
|
||||
if not savedCb.isNil: savedCb()
|
||||
if not savedCb.isNil:
|
||||
if fs.queue.len > 0:
|
||||
savedCb()
|
||||
else:
|
||||
future.cb = savedCb
|
||||
|
||||
if future.queue.len > 0 or future.finished:
|
||||
newCb(future)
|
||||
|
||||
@@ -317,7 +317,7 @@ proc getDefaultSSL(): SslContext =
|
||||
result = defaultSslContext
|
||||
when defined(ssl):
|
||||
if result == nil:
|
||||
defaultSslContext = newContext(verifyMode = CVerifyNone)
|
||||
defaultSslContext = newContext(verifyMode = CVerifyPeer)
|
||||
result = defaultSslContext
|
||||
doAssert result != nil, "failure to initialize the SSL context"
|
||||
|
||||
@@ -1140,15 +1140,15 @@ proc downloadFile*(client: HttpClient, url: string, filename: string) =
|
||||
client.getBody = true
|
||||
let resp = client.get(url)
|
||||
|
||||
if resp.code.is4xx or resp.code.is5xx:
|
||||
raise newException(HttpRequestError, resp.status)
|
||||
|
||||
client.bodyStream = newFileStream(filename, fmWrite)
|
||||
if client.bodyStream.isNil:
|
||||
fileError("Unable to open file")
|
||||
parseBody(client, resp.headers, resp.version)
|
||||
client.bodyStream.close()
|
||||
|
||||
if resp.code.is4xx or resp.code.is5xx:
|
||||
raise newException(HttpRequestError, resp.status)
|
||||
|
||||
proc downloadFile*(client: AsyncHttpClient, url: string,
|
||||
filename: string): Future[void] =
|
||||
proc downloadFileEx(client: AsyncHttpClient,
|
||||
|
||||
@@ -114,7 +114,7 @@ proc osLastError*(): OSErrorCode {.sideEffect.} =
|
||||
when defined(nimscript):
|
||||
discard
|
||||
elif defined(windows):
|
||||
result = OSErrorCode(getLastError())
|
||||
result = cast[OSErrorCode](getLastError())
|
||||
else:
|
||||
result = OSErrorCode(errno)
|
||||
{.pop.}
|
||||
|
||||
@@ -55,7 +55,7 @@ when hasThreadSupport:
|
||||
maxFD: int
|
||||
numFD: int
|
||||
fds: ptr SharedArray[SelectorKey[T]]
|
||||
count: int
|
||||
count*: int
|
||||
Selector*[T] = ptr SelectorImpl[T]
|
||||
else:
|
||||
type
|
||||
@@ -64,7 +64,7 @@ else:
|
||||
maxFD: int
|
||||
numFD: int
|
||||
fds: seq[SelectorKey[T]]
|
||||
count: int
|
||||
count*: int
|
||||
Selector*[T] = ref SelectorImpl[T]
|
||||
type
|
||||
SelectEventImpl = object
|
||||
|
||||
@@ -30,7 +30,7 @@ when defined(macosx) or defined(freebsd) or defined(dragonfly):
|
||||
proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t,
|
||||
newp: pointer, newplen: csize_t): cint
|
||||
{.importc: "sysctl",header: """#include <sys/types.h>
|
||||
#include <sys/sysctl.h>"""}
|
||||
#include <sys/sysctl.h>""".}
|
||||
elif defined(netbsd) or defined(openbsd):
|
||||
# OpenBSD and NetBSD don't have KERN_MAXFILESPERPROC, so we are using
|
||||
# KERN_MAXFILES, because KERN_MAXFILES is always bigger,
|
||||
@@ -39,7 +39,7 @@ elif defined(netbsd) or defined(openbsd):
|
||||
proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t,
|
||||
newp: pointer, newplen: csize_t): cint
|
||||
{.importc: "sysctl",header: """#include <sys/param.h>
|
||||
#include <sys/sysctl.h>"""}
|
||||
#include <sys/sysctl.h>""".}
|
||||
|
||||
when hasThreadSupport:
|
||||
type
|
||||
@@ -48,7 +48,7 @@ when hasThreadSupport:
|
||||
maxFD: int
|
||||
changes: ptr SharedArray[KEvent]
|
||||
fds: ptr SharedArray[SelectorKey[T]]
|
||||
count: int
|
||||
count*: int
|
||||
changesLock: Lock
|
||||
changesSize: int
|
||||
changesLength: int
|
||||
@@ -61,7 +61,7 @@ else:
|
||||
maxFD: int
|
||||
changes: seq[KEvent]
|
||||
fds: seq[SelectorKey[T]]
|
||||
count: int
|
||||
count*: int
|
||||
sock: cint
|
||||
Selector*[T] = ref SelectorImpl[T]
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ when hasThreadSupport:
|
||||
pollcnt: int
|
||||
fds: ptr SharedArray[SelectorKey[T]]
|
||||
pollfds: ptr SharedArray[TPollFd]
|
||||
count: int
|
||||
count*: int
|
||||
lock: Lock
|
||||
Selector*[T] = ptr SelectorImpl[T]
|
||||
else:
|
||||
@@ -31,7 +31,7 @@ else:
|
||||
pollcnt: int
|
||||
fds: seq[SelectorKey[T]]
|
||||
pollfds: seq[TPollFd]
|
||||
count: int
|
||||
count*: int
|
||||
Selector*[T] = ref SelectorImpl[T]
|
||||
|
||||
type
|
||||
|
||||
@@ -58,7 +58,7 @@ when hasThreadSupport:
|
||||
eSet: FdSet
|
||||
maxFD: int
|
||||
fds: ptr SharedArray[SelectorKey[T]]
|
||||
count: int
|
||||
count*: int
|
||||
lock: Lock
|
||||
Selector*[T] = ptr SelectorImpl[T]
|
||||
else:
|
||||
@@ -69,7 +69,7 @@ else:
|
||||
eSet: FdSet
|
||||
maxFD: int
|
||||
fds: seq[SelectorKey[T]]
|
||||
count: int
|
||||
count*: int
|
||||
Selector*[T] = ref SelectorImpl[T]
|
||||
|
||||
type
|
||||
|
||||
@@ -22,6 +22,17 @@
|
||||
## In order to use the SSL procedures defined in this module, you will need to
|
||||
## compile your application with the ``-d:ssl`` flag.
|
||||
##
|
||||
##
|
||||
## SSL on Windows
|
||||
## ==============
|
||||
##
|
||||
## On Windows the SSL library checks for valid certificates.
|
||||
## It uses the `cacert.pem` file for this purpose which was extracted
|
||||
## from `https://curl.se/ca/cacert.pem`. Besides
|
||||
## the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
|
||||
## also need to ship `cacert.pem` with your `.exe` file.
|
||||
##
|
||||
##
|
||||
## Examples
|
||||
## ========
|
||||
##
|
||||
@@ -572,7 +583,7 @@ when defineSsl:
|
||||
if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1:
|
||||
raiseSSLError()
|
||||
|
||||
when defined(nimDisableCertificateValidation) or defined(windows):
|
||||
when defined(nimDisableCertificateValidation):
|
||||
newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
|
||||
else:
|
||||
case verifyMode
|
||||
@@ -587,11 +598,13 @@ when defineSsl:
|
||||
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
|
||||
newCTX.loadCertificates(certFile, keyFile)
|
||||
|
||||
when not defined(nimDisableCertificateValidation) and not defined(windows):
|
||||
const VerifySuccess = 1 # SSL_CTX_load_verify_locations returns 1 on success.
|
||||
|
||||
when not defined(nimDisableCertificateValidation):
|
||||
if verifyMode != CVerifyNone:
|
||||
# Use the caDir and caFile parameters if set
|
||||
if caDir != "" or caFile != "":
|
||||
if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != 0:
|
||||
if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != VerifySuccess:
|
||||
raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).")
|
||||
|
||||
else:
|
||||
@@ -599,7 +612,7 @@ when defineSsl:
|
||||
# the SSL_CERT_FILE and SSL_CERT_DIR env vars
|
||||
var found = false
|
||||
for fn in scanSSLCertificates():
|
||||
if newCTX.SSL_CTX_load_verify_locations(fn, "") == 0:
|
||||
if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess:
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
@@ -716,10 +729,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.")
|
||||
|
||||
|
||||
@@ -1156,6 +1156,7 @@ when not defined(windows) and not weirdTarget:
|
||||
else: result = S_ISLNK(rawInfo.st_mode)
|
||||
|
||||
const
|
||||
maxSymlinkLen = 1024
|
||||
ExeExts* = ## Platform specific file extension for executables.
|
||||
## On Windows ``["exe", "cmd", "bat"]``, on Posix ``[""]``.
|
||||
when defined(windows): ["exe", "cmd", "bat"] else: [""]
|
||||
@@ -1197,11 +1198,11 @@ proc findExe*(exe: string, followSymlinks: bool = true;
|
||||
when not defined(windows):
|
||||
while followSymlinks: # doubles as if here
|
||||
if x.checkSymlink:
|
||||
var r = newString(256)
|
||||
var len = readlink(x, r, 256)
|
||||
var r = newString(maxSymlinkLen)
|
||||
var len = readlink(x, r, maxSymlinkLen)
|
||||
if len < 0:
|
||||
raiseOSError(osLastError(), exe)
|
||||
if len > 256:
|
||||
if len > maxSymlinkLen:
|
||||
r = newString(len+1)
|
||||
len = readlink(x, r, len)
|
||||
setLen(r, len)
|
||||
@@ -2517,11 +2518,11 @@ proc expandSymlink*(symlinkPath: string): string {.noNimScript.} =
|
||||
when defined(windows):
|
||||
result = symlinkPath
|
||||
else:
|
||||
result = newString(256)
|
||||
var len = readlink(symlinkPath, result, 256)
|
||||
result = newString(maxSymlinkLen)
|
||||
var len = readlink(symlinkPath, result, maxSymlinkLen)
|
||||
if len < 0:
|
||||
raiseOSError(osLastError(), symlinkPath)
|
||||
if len > 256:
|
||||
if len > maxSymlinkLen:
|
||||
result = newString(len+1)
|
||||
len = readlink(symlinkPath, result, len)
|
||||
setLen(result, len)
|
||||
@@ -2811,9 +2812,9 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly)):
|
||||
|
||||
when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)):
|
||||
proc getApplAux(procPath: string): string =
|
||||
result = newString(256)
|
||||
var len = readlink(procPath, result, 256)
|
||||
if len > 256:
|
||||
result = newString(maxSymlinkLen)
|
||||
var len = readlink(procPath, result, maxSymlinkLen)
|
||||
if len > maxSymlinkLen:
|
||||
result = newString(len+1)
|
||||
len = readlink(procPath, result, len)
|
||||
setLen(result, len)
|
||||
|
||||
@@ -381,6 +381,8 @@ proc execProcesses*(cmds: openArray[string],
|
||||
raiseOSError(err)
|
||||
|
||||
if rexit >= 0:
|
||||
when defined(windows):
|
||||
let processHandle = q[rexit].fProcessHandle
|
||||
result = max(result, abs(q[rexit].peekExitCode()))
|
||||
if afterRunEvent != nil: afterRunEvent(idxs[rexit], q[rexit])
|
||||
close(q[rexit])
|
||||
@@ -395,7 +397,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||
else:
|
||||
when defined(windows):
|
||||
for k in 0..wcount - 1:
|
||||
if w[k] == q[rexit].fProcessHandle:
|
||||
if w[k] == processHandle:
|
||||
w[k] = w[wcount - 1]
|
||||
w[wcount - 1] = 0
|
||||
dec(wcount)
|
||||
@@ -441,10 +443,17 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
handle: Handle
|
||||
atTheEnd: bool
|
||||
|
||||
proc closeHandleCheck(handle: Handle) {.inline.} =
|
||||
if handle.closeHandle() == 0:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc fileClose[T: Handle | FileHandle](h: var T) {.inline.} =
|
||||
if h > 4:
|
||||
closeHandleCheck(h)
|
||||
h = INVALID_HANDLE_VALUE.T
|
||||
|
||||
proc hsClose(s: Stream) =
|
||||
# xxx here + elsewhere: check instead of discard; ignoring errors leads to
|
||||
# hard to track bugs
|
||||
discard FileHandleStream(s).handle.closeHandle
|
||||
FileHandleStream(s).handle.fileClose()
|
||||
|
||||
proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd
|
||||
|
||||
@@ -549,8 +558,8 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
|
||||
stdin = myDup(pipeIn, 0)
|
||||
stdout = myDup(pipeOut, 0)
|
||||
discard closeHandle(pipeIn)
|
||||
discard closeHandle(pipeOut)
|
||||
closeHandleCheck(pipeIn)
|
||||
closeHandleCheck(pipeOut)
|
||||
stderr = stdout
|
||||
|
||||
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
|
||||
@@ -561,9 +570,6 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc fileClose(h: Handle) {.inline.} =
|
||||
if h > 4: discard closeHandle(h)
|
||||
|
||||
proc startProcess(command: string, workingDir: string = "",
|
||||
args: openArray[string] = [], env: StringTableRef = nil,
|
||||
options: set[ProcessOption] = {poStdErrToStdOut}):
|
||||
@@ -658,13 +664,31 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
result.id = procInfo.dwProcessId
|
||||
result.exitFlag = false
|
||||
|
||||
proc closeThreadAndProcessHandle(p: Process) =
|
||||
if p.fThreadHandle != 0:
|
||||
closeHandleCheck(p.fThreadHandle)
|
||||
p.fThreadHandle = 0
|
||||
|
||||
if p.fProcessHandle != 0:
|
||||
closeHandleCheck(p.fProcessHandle)
|
||||
p.fProcessHandle = 0
|
||||
|
||||
proc close(p: Process) =
|
||||
if poParentStreams notin p.options:
|
||||
discard closeHandle(p.inHandle)
|
||||
discard closeHandle(p.outHandle)
|
||||
discard closeHandle(p.errHandle)
|
||||
discard closeHandle(p.fThreadHandle)
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
if p.inStream == nil:
|
||||
p.inHandle.fileClose()
|
||||
else:
|
||||
# p.inHandle can be already closed via inputStream.
|
||||
p.inStream.close
|
||||
|
||||
# You may NOT close outputStream and errorStream.
|
||||
assert p.outStream == nil or FileHandleStream(p.outStream).handle != INVALID_HANDLE_VALUE
|
||||
assert p.errStream == nil or FileHandleStream(p.errStream).handle != INVALID_HANDLE_VALUE
|
||||
|
||||
if p.outHandle != p.errHandle:
|
||||
p.errHandle.fileClose()
|
||||
p.outHandle.fileClose()
|
||||
p.closeThreadAndProcessHandle()
|
||||
|
||||
proc suspend(p: Process) =
|
||||
discard suspendThread(p.fThreadHandle)
|
||||
@@ -698,8 +722,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
if status != STILL_ACTIVE:
|
||||
p.exitFlag = true
|
||||
p.exitStatus = status
|
||||
discard closeHandle(p.fThreadHandle)
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
p.closeThreadAndProcessHandle()
|
||||
result = status
|
||||
else:
|
||||
result = -1
|
||||
@@ -715,8 +738,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
discard getExitCodeProcess(p.fProcessHandle, status)
|
||||
p.exitFlag = true
|
||||
p.exitStatus = status
|
||||
discard closeHandle(p.fThreadHandle)
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
p.closeThreadAndProcessHandle()
|
||||
result = status
|
||||
|
||||
proc inputStream(p: Process): Stream =
|
||||
|
||||
@@ -672,8 +672,8 @@ proc getPrecedence(p: SqlParser): int =
|
||||
else:
|
||||
result = - 1
|
||||
|
||||
proc parseExpr(p: var SqlParser): SqlNode
|
||||
proc parseSelect(p: var SqlParser): SqlNode
|
||||
proc parseExpr(p: var SqlParser): SqlNode {.gcsafe.}
|
||||
proc parseSelect(p: var SqlParser): SqlNode {.gcsafe.}
|
||||
|
||||
proc identOrLiteral(p: var SqlParser): SqlNode =
|
||||
case p.tok.kind
|
||||
@@ -1201,7 +1201,7 @@ proc addIden(s: var SqlWriter, thing: string) =
|
||||
iden = '"' & iden & '"'
|
||||
s.add(iden)
|
||||
|
||||
proc ra(n: SqlNode, s: var SqlWriter)
|
||||
proc ra(n: SqlNode, s: var SqlWriter) {.gcsafe.}
|
||||
|
||||
proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") =
|
||||
if n.len > 0:
|
||||
|
||||
@@ -204,8 +204,8 @@ proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} =
|
||||
if x.left.length > j:
|
||||
x = x.left
|
||||
else:
|
||||
dec(j, x.left.length)
|
||||
x = x.right
|
||||
dec(j, x.len)
|
||||
|
||||
iterator leaves*(r: Rope): string =
|
||||
## iterates over any leaf string in the rope `r`.
|
||||
@@ -262,7 +262,7 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
|
||||
while true:
|
||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if frmt[i] notin {'0'..'9'}: break
|
||||
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
|
||||
add(result, args[j-1])
|
||||
of '{':
|
||||
inc(i)
|
||||
|
||||
@@ -11,16 +11,48 @@
|
||||
## SSL_CERT_DIR environment variables.
|
||||
|
||||
import os, strutils
|
||||
from ospaths import existsEnv, getEnv
|
||||
import strutils
|
||||
|
||||
# SECURITY: this unnecessarily scans through dirs/files regardless of the
|
||||
# actual host OS/distribution. Hopefully all the paths are writeble only by
|
||||
# root.
|
||||
|
||||
# FWIW look for files before scanning entire dirs.
|
||||
|
||||
const certificate_paths = [
|
||||
when defined(macosx):
|
||||
const certificatePaths = [
|
||||
"/etc/ssl/cert.pem",
|
||||
"/System/Library/OpenSSL/certs/cert.pem"
|
||||
]
|
||||
elif defined(linux):
|
||||
const certificatePaths = [
|
||||
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
|
||||
# NetBSD (security/mozilla-rootcerts)
|
||||
# SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/etc/ssl/certs/ca-certificates.crt",
|
||||
# OpenSUSE
|
||||
"/etc/ssl/ca-bundle.pem",
|
||||
# Red Hat 5+, Fedora, Centos
|
||||
"/etc/pki/tls/certs/ca-bundle.crt",
|
||||
# Red Hat 4
|
||||
"/usr/share/ssl/certs/ca-bundle.crt",
|
||||
# Fedora/RHEL
|
||||
"/etc/pki/tls/certs",
|
||||
# Android
|
||||
"/system/etc/security/cacerts",
|
||||
]
|
||||
elif defined(bsd):
|
||||
const certificatePaths = [
|
||||
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
|
||||
# NetBSD (security/mozilla-rootcerts)
|
||||
# SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/etc/ssl/certs/ca-certificates.crt",
|
||||
# FreeBSD (security/ca-root-nss package)
|
||||
"/usr/local/share/certs/ca-root-nss.crt",
|
||||
# OpenBSD, FreeBSD (optional symlink)
|
||||
"/etc/ssl/cert.pem",
|
||||
# FreeBSD
|
||||
"/usr/local/share/certs",
|
||||
# NetBSD
|
||||
"/etc/openssl/certs",
|
||||
]
|
||||
else:
|
||||
const certificatePaths = [
|
||||
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
|
||||
# NetBSD (security/mozilla-rootcerts)
|
||||
# SLES10/SLES11, https://golang.org/issue/12139
|
||||
@@ -37,8 +69,6 @@ const certificate_paths = [
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
||||
# OpenBSD, FreeBSD (optional symlink)
|
||||
"/etc/ssl/cert.pem",
|
||||
# Mac OS X
|
||||
"/System/Library/OpenSSL/certs/cert.pem",
|
||||
# Fedora/RHEL
|
||||
"/etc/pki/tls/certs",
|
||||
# Android
|
||||
@@ -47,7 +77,7 @@ const certificate_paths = [
|
||||
"/usr/local/share/certs",
|
||||
# NetBSD
|
||||
"/etc/openssl/certs",
|
||||
]
|
||||
]
|
||||
|
||||
when defined(haiku):
|
||||
const
|
||||
@@ -67,17 +97,30 @@ iterator scanSSLCertificates*(useEnvVars = false): string =
|
||||
## if `useEnvVars` is true, the SSL_CERT_FILE and SSL_CERT_DIR
|
||||
## environment variables can be used to override the certificate
|
||||
## directories to scan or specify a CA certificate file.
|
||||
if existsEnv("SSL_CERT_FILE"):
|
||||
if useEnvVars and existsEnv("SSL_CERT_FILE"):
|
||||
yield getEnv("SSL_CERT_FILE")
|
||||
|
||||
elif existsEnv("SSL_CERT_DIR"):
|
||||
elif useEnvVars and existsEnv("SSL_CERT_DIR"):
|
||||
let p = getEnv("SSL_CERT_DIR")
|
||||
for fn in joinPath(p, "*").walkFiles():
|
||||
yield fn
|
||||
|
||||
else:
|
||||
when not defined(haiku):
|
||||
for p in certificate_paths:
|
||||
when defined(windows):
|
||||
const cacert = "cacert.pem"
|
||||
let pem = getAppDir() / cacert
|
||||
if fileExists(pem):
|
||||
yield pem
|
||||
else:
|
||||
let path = getEnv("PATH")
|
||||
for candidate in split(path, PathSep):
|
||||
if candidate.len != 0:
|
||||
let x = (if candidate[0] == '"' and candidate[^1] == '"':
|
||||
substr(candidate, 1, candidate.len-2) else: candidate) / cacert
|
||||
if fileExists(x):
|
||||
yield x
|
||||
elif not defined(haiku):
|
||||
for p in certificatePaths:
|
||||
if p.endsWith(".pem") or p.endsWith(".crt"):
|
||||
if existsFile(p):
|
||||
yield p
|
||||
|
||||
@@ -928,11 +928,11 @@ proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.no
|
||||
# handle negative overflow
|
||||
if n == 0 and handleNegative: n = not(BiggestUInt 0)
|
||||
|
||||
proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} =
|
||||
proc toHex*[T: SomeInteger](x: T, len: Positive): string {.noSideEffect.} =
|
||||
## Converts `x` to its hexadecimal representation.
|
||||
##
|
||||
## The resulting string will be exactly `len` characters long. No prefix like
|
||||
## ``0x`` is generated.
|
||||
## ``0x`` is generated. `x` is treated as an unsigned value.
|
||||
runnableExamples:
|
||||
let
|
||||
a = 62'u64
|
||||
@@ -940,23 +940,8 @@ proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} =
|
||||
doAssert a.toHex(3) == "03E"
|
||||
doAssert b.toHex(3) == "001"
|
||||
doAssert b.toHex(4) == "1001"
|
||||
toHexImpl(x, len, false)
|
||||
|
||||
proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||
rtl, extern: "nsuToHex".} =
|
||||
## Converts `x` to its hexadecimal representation.
|
||||
##
|
||||
## The resulting string will be exactly `len` characters long. No prefix like
|
||||
## ``0x`` is generated. `x` is treated as an unsigned value.
|
||||
runnableExamples:
|
||||
let
|
||||
a = 62
|
||||
b = 4097
|
||||
c = -8
|
||||
doAssert a.toHex(3) == "03E"
|
||||
doAssert b.toHex(3) == "001"
|
||||
doAssert b.toHex(4) == "1001"
|
||||
doAssert c.toHex(6) == "FFFFF8"
|
||||
doAssert toHex(62, 3) == "03E"
|
||||
doAssert toHex(-8, 6) == "FFFFF8"
|
||||
toHexImpl(cast[BiggestUInt](x), len, x < 0)
|
||||
|
||||
proc toHex*[T: SomeInteger](x: T): string {.noSideEffect.} =
|
||||
|
||||
@@ -188,7 +188,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).}
|
||||
for arg in locals:
|
||||
params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg))
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newProc(newEmptyNode(), params, body, nnkProcDef))
|
||||
result.add(newProc(newEmptyNode(), params, body, nnkLambda))
|
||||
for arg in locals: result.add(arg)
|
||||
|
||||
when (NimMajor, NimMinor) >= (1, 1):
|
||||
|
||||
@@ -284,7 +284,7 @@ proc removeDotSegments(path: string): string =
|
||||
discard collection.pop()
|
||||
i.inc 3
|
||||
continue
|
||||
elif path[i+1] == '/':
|
||||
elif i + 1 < path.len and path[i+1] == '/':
|
||||
i.inc 2
|
||||
continue
|
||||
currentSegment.add path[i]
|
||||
|
||||
@@ -213,7 +213,22 @@ proc secureHashFile*(filename: string): SecureHash =
|
||||
## **See also:**
|
||||
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string
|
||||
## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash``
|
||||
secureHash(readFile(filename))
|
||||
const BufferLength = 8192
|
||||
|
||||
let f = open(filename)
|
||||
var state = newSha1State()
|
||||
var buffer = newString(BufferLength)
|
||||
while true:
|
||||
let length = readChars(f, buffer, 0, BufferLength)
|
||||
if length == 0:
|
||||
break
|
||||
buffer.setLen(length)
|
||||
state.update(buffer)
|
||||
if length != BufferLength:
|
||||
break
|
||||
close(f)
|
||||
|
||||
SecureHash(state.finalize())
|
||||
|
||||
proc `$`*(self: SecureHash): string =
|
||||
## Returns the string representation of a ``SecureHash``.
|
||||
|
||||
@@ -2058,7 +2058,7 @@ const
|
||||
NimMinor* {.intdefine.}: int = 2
|
||||
## is the minor number of Nim's version.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 8
|
||||
NimPatch* {.intdefine.}: int = 12
|
||||
## is the patch number of Nim's version.
|
||||
|
||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
|
||||
@@ -250,7 +250,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer =
|
||||
sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
|
||||
var old = a.llmem # can be nil and is correct with nil
|
||||
a.llmem = cast[PLLChunk](osAllocPages(PageSize))
|
||||
when defined(avlcorruption):
|
||||
when defined(nimAvlcorruption):
|
||||
trackLocation(a.llmem, PageSize)
|
||||
incCurrMem(a, PageSize)
|
||||
a.llmem.size = PageSize - sizeof(LLChunk)
|
||||
@@ -273,7 +273,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
|
||||
a.freeAvlNodes = a.freeAvlNodes.link[0]
|
||||
else:
|
||||
result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode)))
|
||||
when defined(avlcorruption):
|
||||
when defined(nimAvlcorruption):
|
||||
cprintf("tracking location: %p\n", result)
|
||||
result.key = key
|
||||
result.upperBound = upperBound
|
||||
@@ -281,7 +281,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
|
||||
result.link[0] = bottom
|
||||
result.link[1] = bottom
|
||||
result.level = 1
|
||||
#when defined(avlcorruption):
|
||||
#when defined(nimAvlcorruption):
|
||||
# track("allocAvlNode", result, sizeof(AvlNode))
|
||||
sysAssert(bottom == addr(a.bottomData), "bottom data")
|
||||
sysAssert(bottom.link[0] == bottom, "bottom link[0]")
|
||||
@@ -1013,7 +1013,7 @@ when defined(nimTypeNames):
|
||||
template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||
{.push stackTrace: off.}
|
||||
|
||||
when defined(fulldebug):
|
||||
when defined(nimFulldebug):
|
||||
proc interiorAllocatedPtr*(p: pointer): pointer =
|
||||
result = interiorAllocatedPtr(allocator, p)
|
||||
|
||||
|
||||
@@ -38,9 +38,6 @@ proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} =
|
||||
# todo: better error reporting
|
||||
sysFatal(RangeError, "value out of range")
|
||||
|
||||
proc raiseRangeErrorNoArgs() {.compilerproc, noinline.} =
|
||||
sysFatal(RangeError, "value out of range")
|
||||
|
||||
proc raiseObjectConversionError() {.compilerproc, noinline.} =
|
||||
sysFatal(ObjectConversionError, "invalid object conversion")
|
||||
|
||||
|
||||
@@ -436,7 +436,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
@@ -451,7 +451,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
{.pop.}
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
# generates a new object and sets its reference counter to 1
|
||||
incTypeSize typ, size
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||
@@ -662,16 +662,16 @@ proc collectCycles(gch: var GcHeap) =
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
sysAssert(allocInv(gch.region), "gcMark begin")
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[ByteAddress](cell)
|
||||
var c = cast[ByteAddress](p)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
|
||||
if objStart != nil:
|
||||
# mark the cell:
|
||||
incRef(objStart)
|
||||
add(gch.decStack, objStart)
|
||||
when false:
|
||||
let cell = usrToCell(p)
|
||||
if isAllocatedPtr(gch.region, cell):
|
||||
sysAssert false, "allocated pointer but not interior?"
|
||||
# mark the cell:
|
||||
|
||||
@@ -454,11 +454,10 @@ proc markGlobals(gch: var GcHeap) =
|
||||
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[ByteAddress](cell)
|
||||
var c = cast[ByteAddress](p)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
|
||||
if objStart != nil:
|
||||
mark(gch, objStart)
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ const
|
||||
debugGC = false # we wish to debug the GC...
|
||||
logGC = false
|
||||
traceGC = false # extensive debugging
|
||||
alwaysCycleGC = defined(smokeCycles)
|
||||
alwaysGC = defined(fulldebug) # collect after every memory
|
||||
alwaysCycleGC = defined(nimSmokeCycles)
|
||||
alwaysGC = defined(nimFulldebug) # collect after every memory
|
||||
# allocation (for debugging)
|
||||
leakDetector = defined(leakDetector)
|
||||
leakDetector = defined(nimLeakDetector)
|
||||
overwriteFree = defined(nimBurnFree) # overwrite memory with 0xFF before free
|
||||
trackAllocationSource = leakDetector
|
||||
|
||||
@@ -30,7 +30,7 @@ const
|
||||
coalescRight = true
|
||||
coalescLeft = true
|
||||
logAlloc = false
|
||||
useCellIds = defined(corruption)
|
||||
useCellIds = defined(nimCorruption)
|
||||
|
||||
type
|
||||
PPointer = ptr pointer
|
||||
|
||||
@@ -719,6 +719,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows):
|
||||
|
||||
proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
# Certificates store
|
||||
|
||||
type PX509_STORE* = SslPtr
|
||||
|
||||
@@ -217,6 +217,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||
|
||||
test "stackrefleak"
|
||||
test "cyclecollector"
|
||||
test "trace_globals"
|
||||
|
||||
proc longGCTests(r: var TResults, cat: Category, options: string) =
|
||||
when defined(windows):
|
||||
|
||||
@@ -9,7 +9,7 @@ pkg "argparse"
|
||||
pkg "arraymancer", true, "nim c tests/tests_cpu.nim"
|
||||
pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim"
|
||||
pkg "asyncmysql", true
|
||||
pkg "bigints", url = "https://github.com/Araq/nim-bigints"
|
||||
pkg "bigints"
|
||||
pkg "binaryheap", false, "nim c -r binaryheap.nim"
|
||||
# pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39
|
||||
pkg "bncurve", true
|
||||
@@ -24,7 +24,7 @@ pkg "coco", true
|
||||
pkg "combparser"
|
||||
pkg "compactdict"
|
||||
pkg "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension"
|
||||
pkg "criterion"
|
||||
# pkg "criterion"
|
||||
pkg "dashing", false, "nim c tests/functional.nim"
|
||||
pkg "docopt"
|
||||
pkg "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
|
||||
@@ -55,7 +55,7 @@ pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim"
|
||||
pkg "nimgame2", true, "nim c nimgame2/nimgame.nim"
|
||||
pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim"
|
||||
# pkg "nimlsp", true
|
||||
pkg "nimly", true
|
||||
# pkg "nimly", true
|
||||
# pkg "nimongo", true, "nimble test_ci"
|
||||
pkg "nimpy", false, "nim c -r tests/nimfrompy.nim"
|
||||
pkg "nimquery"
|
||||
@@ -63,10 +63,10 @@ pkg "nimsl", true
|
||||
pkg "nimsvg"
|
||||
# pkg "nimterop", true
|
||||
# pkg "nimx", true, "nim c --threads:on test/main.nim"
|
||||
pkg "norm", true, "nim c -r tests/tsqliterows.nim"
|
||||
# pkg "norm", true, "nim c -r tests/tsqliterows.nim"
|
||||
pkg "npeg"
|
||||
pkg "ormin", true, "nim c -o:orminn ormin.nim"
|
||||
pkg "parsetoml"
|
||||
# pkg "parsetoml"
|
||||
pkg "patty"
|
||||
pkg "plotly", true, "nim c --oldgensym:on examples/all.nim"
|
||||
pkg "pnm"
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
discard """
|
||||
action: compile
|
||||
"""
|
||||
# XXX: action should be run!
|
||||
|
||||
import asyncdispatch
|
||||
|
||||
proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} =
|
||||
|
||||
@@ -5,8 +5,8 @@ nimout: '''
|
||||
type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>
|
||||
but expected one of:
|
||||
proc serve(server: AsyncHttpServer; port: Port;
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.};
|
||||
address = ""): owned(Future[void])
|
||||
callback: proc (request: Request): Future[void] {.closure, gcsafe.};
|
||||
address = ""; assumedDescriptorsPerRequest = -1): owned(Future[void])
|
||||
first type mismatch at position: 3
|
||||
required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.}
|
||||
but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: <unknown>.}
|
||||
|
||||
22
tests/gc/trace_globals.nim
Normal file
22
tests/gc/trace_globals.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
discard """
|
||||
output: '''10000000
|
||||
10000000
|
||||
10000000'''
|
||||
"""
|
||||
|
||||
# bug #17085
|
||||
|
||||
proc init(): string =
|
||||
for a in 0..<10000000:
|
||||
result.add 'c'
|
||||
|
||||
proc f() =
|
||||
var a {.global.} = init()
|
||||
var b {.global.} = init()
|
||||
var c {.global.} = init()
|
||||
|
||||
echo a.len
|
||||
echo b.len
|
||||
echo c.len
|
||||
|
||||
f()
|
||||
58
tests/js/tbigint_backend.nim
Normal file
58
tests/js/tbigint_backend.nim
Normal file
@@ -0,0 +1,58 @@
|
||||
proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".}
|
||||
## Returns the name of the JsObject's JavaScript type as a cstring.
|
||||
# xxx replace jsffi.jsTypeOf with this definition and add tests
|
||||
|
||||
type JsBigIntImpl {.importc: "bigint".} = int
|
||||
type JsBigInt = distinct JsBigIntImpl
|
||||
|
||||
doAssert JsBigInt isnot int
|
||||
func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".}
|
||||
func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".}
|
||||
func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".}
|
||||
func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".}
|
||||
func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".}
|
||||
func inc2*(x: var JsBigInt) {.importjs: "#++".}
|
||||
func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".}
|
||||
func `$`*(this: JsBigInt): string =
|
||||
$toCstring(this)
|
||||
|
||||
block:
|
||||
doAssert defined(nimHasJsBigIntBackend)
|
||||
let z1 = big"10"
|
||||
let z2 = big"15"
|
||||
doAssert z1 == big"10"
|
||||
doAssert z1 == z1
|
||||
doAssert z1 != z2
|
||||
var s: seq[cstring]
|
||||
for i in z1 .. z2:
|
||||
s.add $i
|
||||
doAssert s == @["10".cstring, "11", "12", "13", "14", "15"]
|
||||
block:
|
||||
var a=big"3"
|
||||
a.inc
|
||||
doAssert a == big"4"
|
||||
block:
|
||||
var z: JsBigInt
|
||||
doAssert $z == "0"
|
||||
doAssert z.jsTypeOf == "bigint" # would fail without codegen change
|
||||
doAssert z != big(1)
|
||||
doAssert z == big"0" # ditto
|
||||
|
||||
# ditto below
|
||||
block:
|
||||
let z: JsBigInt = big"1"
|
||||
doAssert $z == "1"
|
||||
doAssert z.jsTypeOf == "bigint"
|
||||
doAssert z == big"1"
|
||||
|
||||
block:
|
||||
let z = JsBigInt.default
|
||||
doAssert $z == "0"
|
||||
doAssert z.jsTypeOf == "bigint"
|
||||
doAssert z == big"0"
|
||||
|
||||
block:
|
||||
var a: seq[JsBigInt]
|
||||
a.setLen 3
|
||||
doAssert a[^1].jsTypeOf == "bigint"
|
||||
doAssert a[^1] == big"0"
|
||||
33
tests/misc/t8404.nim
Normal file
33
tests/misc/t8404.nim
Normal file
@@ -0,0 +1,33 @@
|
||||
discard """
|
||||
targets: "c cpp js"
|
||||
"""
|
||||
template main() =
|
||||
block: # bug #8404
|
||||
# can conv
|
||||
template float2int(T) =
|
||||
var a = -1.0
|
||||
let b = T(a)
|
||||
doAssert b < 0
|
||||
let c = b + 1
|
||||
doAssert c is T
|
||||
doAssert c == 0
|
||||
|
||||
float2int(int8)
|
||||
float2int(int16)
|
||||
float2int(int32)
|
||||
float2int(int64)
|
||||
|
||||
block:
|
||||
# can handle middle conv
|
||||
# `/` can trigger int to float
|
||||
template float2int(T) =
|
||||
let n = T(1 / 256)
|
||||
doAssert n == 0
|
||||
|
||||
float2int(int8)
|
||||
float2int(int16)
|
||||
float2int(int32)
|
||||
# float2int(int64)
|
||||
main()
|
||||
static:
|
||||
main()
|
||||
@@ -75,14 +75,3 @@ let rangeVar = 0'u64 ..< limit
|
||||
doAssert repr(rangeVar) == """[a = 0,
|
||||
b = 0]
|
||||
"""
|
||||
|
||||
# bug #15210
|
||||
|
||||
let a3 = not 0'u64
|
||||
var success = false
|
||||
try:
|
||||
discard a3.int64
|
||||
except RangeError:
|
||||
success = true
|
||||
|
||||
doAssert success, "conversion should fail at runtime"
|
||||
|
||||
7
tests/proc/tlambdapragma.nim
Normal file
7
tests/proc/tlambdapragma.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
discard """
|
||||
errormsg: "invalid pragma: exportc"
|
||||
"""
|
||||
|
||||
let _ = proc () {.exportc.} =
|
||||
# this would previously cause a codegen error
|
||||
discard
|
||||
@@ -99,7 +99,7 @@ when not defined(windows):
|
||||
let t = spawn runServer(port)
|
||||
sleep(100)
|
||||
|
||||
var client = newHttpClient()
|
||||
var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone))
|
||||
try:
|
||||
log "client: connect"
|
||||
discard client.getContent("https://127.0.0.1:12345")
|
||||
|
||||
4
tests/stdlib/tmacros.nim
Normal file
4
tests/stdlib/tmacros.nim
Normal file
@@ -0,0 +1,4 @@
|
||||
import macros
|
||||
|
||||
block: # bug #17454
|
||||
proc f(v: NimNode): string {.raises: [].} = $v
|
||||
73
tests/stdlib/tropes.nim
Normal file
73
tests/stdlib/tropes.nim
Normal file
@@ -0,0 +1,73 @@
|
||||
import ropes
|
||||
|
||||
|
||||
block:
|
||||
let r: Rope = nil
|
||||
doAssert r[0] == '\0'
|
||||
|
||||
block:
|
||||
var
|
||||
r1 = rope("Hello")
|
||||
r2 = rope("Nim-Lang")
|
||||
|
||||
let r = r1 & r2
|
||||
let s = $r
|
||||
for i in 0 ..< r.len:
|
||||
doAssert r[i] == s[i]
|
||||
|
||||
doAssert r[66] == '\0'
|
||||
|
||||
block:
|
||||
let r = rope("Hello, Nim-Lang")
|
||||
|
||||
let s = $r
|
||||
for i in 0 ..< r.len:
|
||||
doAssert r[i] == s[i]
|
||||
|
||||
doAssert r[66] == '\0'
|
||||
|
||||
block:
|
||||
var r: Rope
|
||||
r.add rope("Nim ")
|
||||
r.add rope("is ")
|
||||
r.add rope("a ")
|
||||
r.add rope("great ")
|
||||
r.add rope("language")
|
||||
|
||||
let s = $r
|
||||
for i in 0 ..< r.len:
|
||||
doAssert r[i] == s[i]
|
||||
|
||||
doAssert r[66] == '\0'
|
||||
|
||||
block:
|
||||
var r: Rope
|
||||
r.add rope("My Conquest")
|
||||
r.add rope(" is ")
|
||||
r.add rope("the Sea of Stars")
|
||||
|
||||
let s = $r
|
||||
for i in 0 ..< r.len:
|
||||
doAssert r[i] == s[i]
|
||||
|
||||
doAssert r[66] == '\0'
|
||||
|
||||
block:
|
||||
var r: Rope
|
||||
r.add rope("My Conquest")
|
||||
r.add rope(" is ")
|
||||
r.add rope("the Sea of Stars")
|
||||
|
||||
var i: int
|
||||
for item in r:
|
||||
doAssert r[i] == item
|
||||
inc i
|
||||
|
||||
doAssert r[66] == '\0'
|
||||
|
||||
block:
|
||||
let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")]
|
||||
doAssert $r1 == "Nim is a great language"
|
||||
|
||||
let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")]
|
||||
doAssert $r2 == "Nim is a great language"
|
||||
@@ -3,6 +3,7 @@ discard """
|
||||
(name: "hello")
|
||||
(-1, 0)
|
||||
(FirstName: "James", LastName: "Franco")
|
||||
[1, 2, 3]
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -70,3 +71,20 @@ static: # issue #11861
|
||||
var ifb2: InheritedFromBase
|
||||
initBase(ifb2)
|
||||
doAssert(ifb2.txt == "Initialized string from base")
|
||||
|
||||
# bug #16069
|
||||
type
|
||||
E = enum
|
||||
val1, val2
|
||||
Obj = object
|
||||
case k: E
|
||||
of val1:
|
||||
x: array[3, int]
|
||||
of val2:
|
||||
y: uint32
|
||||
|
||||
const
|
||||
foo = [1, 2, 3]
|
||||
arr = Obj(k: val1, x: foo)
|
||||
|
||||
echo arr.x
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
discard """
|
||||
targets: "c cpp js"
|
||||
"""
|
||||
|
||||
#[
|
||||
test for vmops.nim
|
||||
]#
|
||||
|
||||
Reference in New Issue
Block a user