Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
b565c0234c
64 changed files with 853 additions and 2036 deletions
23
changelog.md
23
changelog.md
|
|
@ -12,6 +12,15 @@
|
||||||
`getBool`, `getFloat`, `getBiggestInt`. Also `getInt` procedure was added.
|
`getBool`, `getFloat`, `getBiggestInt`. Also `getInt` procedure was added.
|
||||||
- `reExtended` is no longer default for the `re` constructor in the `re`
|
- `reExtended` is no longer default for the `re` constructor in the `re`
|
||||||
module.
|
module.
|
||||||
|
- `newAsyncSocket` taking an `AsyncFD` now runs `setBlocking(false)` on the
|
||||||
|
fd.
|
||||||
|
- The `ReadyKey` type in the selectors module now contains an ``errorCode``
|
||||||
|
field to help distinguish between ``Event.Error`` events.
|
||||||
|
- Implemented an `accept` proc that works on a `SocketHandle` in
|
||||||
|
``nativesockets``.
|
||||||
|
- Implemented ``getIoHandler`` proc in the ``asyncdispatch`` module that allows
|
||||||
|
you to retrieve the underlying IO Completion Port or ``Selector[AsyncData]``
|
||||||
|
object in the specified dispatcher.
|
||||||
- The overloading rules changed slightly so that constrained generics are
|
- The overloading rules changed slightly so that constrained generics are
|
||||||
preferred over unconstrained generics. (Bug #6526)
|
preferred over unconstrained generics. (Bug #6526)
|
||||||
- It is now possible to forward declare object types so that mutually
|
- It is now possible to forward declare object types so that mutually
|
||||||
|
|
@ -226,3 +235,17 @@ styledEcho "Red on Green.", resetStyle
|
||||||
- ``\n`` is now only the single line feed character like in most
|
- ``\n`` is now only the single line feed character like in most
|
||||||
other programming languages. The new platform specific newline escape sequence is
|
other programming languages. The new platform specific newline escape sequence is
|
||||||
written as ``\p``. This change only affects the Windows platform.
|
written as ``\p``. This change only affects the Windows platform.
|
||||||
|
- Type inference for generic type parameters involving numeric types is now symetric. See
|
||||||
|
[Generic type inference for numeric types](https://nim-lang.org/docs/manual.html#generics-generic-type-inference-fornumeric-types)
|
||||||
|
for more information.
|
||||||
|
- The ``deprecated`` pragma now supports a user-definable warning message for procs.
|
||||||
|
|
||||||
|
```nim
|
||||||
|
|
||||||
|
proc bar {.deprecated: "use foo instead".} =
|
||||||
|
return
|
||||||
|
|
||||||
|
bar()
|
||||||
|
```
|
||||||
|
|
||||||
|
- The ``securehash`` module is now deprecated. Instead import ``std / sha1``.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
# abstract syntax tree + symbol table
|
# abstract syntax tree + symbol table
|
||||||
|
|
||||||
import
|
import
|
||||||
msgs, hashes, nversion, options, strutils, securehash, ropes, idents,
|
msgs, hashes, nversion, options, strutils, std / sha1, ropes, idents,
|
||||||
intsets, idgen
|
intsets, idgen
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -970,7 +970,8 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
|
||||||
addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
|
addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
|
||||||
discard cgsym(m, "TNimType")
|
discard cgsym(m, "TNimType")
|
||||||
if isDefined("nimTypeNames"):
|
if isDefined("nimTypeNames"):
|
||||||
var typename = typeToString(origType, preferName)
|
var typename = typeToString(if origType.typeInst != nil: origType.typeInst
|
||||||
|
else: origType, preferName)
|
||||||
if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
|
if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
|
||||||
typename = "anon ref object from " & $origType.skipTypes(skipPtrs).sym.info
|
typename = "anon ref object from " & $origType.skipTypes(skipPtrs).sym.info
|
||||||
addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
|
addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
||||||
nversion, nimsets, msgs, securehash, bitsets, idents, types,
|
nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
|
||||||
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
||||||
lowerings, semparallel, tables, sets, ndi
|
lowerings, semparallel, tables, sets, ndi
|
||||||
|
|
@ -908,7 +908,6 @@ proc addIntTypes(result: var Rope) {.inline.} =
|
||||||
platform.CPU[targetCPU].intSize.rope])
|
platform.CPU[targetCPU].intSize.rope])
|
||||||
|
|
||||||
proc getCopyright(cfile: Cfile): Rope =
|
proc getCopyright(cfile: Cfile): Rope =
|
||||||
const copyrightYear = "2017"
|
|
||||||
if optCompileOnly in gGlobalOptions:
|
if optCompileOnly in gGlobalOptions:
|
||||||
result = ("/* Generated by Nim Compiler v$1 */$N" &
|
result = ("/* Generated by Nim Compiler v$1 */$N" &
|
||||||
"/* (c) " & copyrightYear & " Andreas Rumpf */$N" &
|
"/* (c) " & copyrightYear & " Andreas Rumpf */$N" &
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
|
|
||||||
const
|
const
|
||||||
HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
|
HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
|
||||||
"Copyright (c) 2006-2017 by Andreas Rumpf\n"
|
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
||||||
|
|
||||||
const
|
const
|
||||||
Usage = slurp"../doc/basicopt.txt".replace("//", "")
|
Usage = slurp"../doc/basicopt.txt".replace("//", "")
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||||
securehash, streams
|
std / sha1, streams
|
||||||
|
|
||||||
#from debuginfo import writeDebugInfo
|
#from debuginfo import writeDebugInfo
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
## Module that implements ``gorge`` for the compiler.
|
## Module that implements ``gorge`` for the compiler.
|
||||||
|
|
||||||
import msgs, securehash, os, osproc, streams, strutils, options
|
import msgs, std / sha1, os, osproc, streams, strutils, options
|
||||||
|
|
||||||
proc readOutput(p: Process): (string, int) =
|
proc readOutput(p: Process): (string, int) =
|
||||||
result[0] = ""
|
result[0] = ""
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
|
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
|
||||||
semdata, passes, renderer, modulepaths
|
semdata, passes, renderer, modulepaths, sigmatch
|
||||||
|
|
||||||
proc evalImport*(c: PContext, n: PNode): PNode
|
proc evalImport*(c: PContext, n: PNode): PNode
|
||||||
proc evalFrom*(c: PContext, n: PNode): PNode
|
proc evalFrom*(c: PContext, n: PNode): PNode
|
||||||
|
|
@ -149,7 +149,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
|
||||||
localError(n.info, errGenerated, "A module cannot import itself")
|
localError(n.info, errGenerated, "A module cannot import itself")
|
||||||
if sfDeprecated in result.flags:
|
if sfDeprecated in result.flags:
|
||||||
message(n.info, warnDeprecated, result.name.s)
|
message(n.info, warnDeprecated, result.name.s)
|
||||||
#suggestSym(n.info, result, false)
|
suggestSym(n.info, result, c.graph.usageSym, false)
|
||||||
|
|
||||||
proc impMod(c: PContext; it: PNode) =
|
proc impMod(c: PContext; it: PNode) =
|
||||||
let m = myImportModule(c, it)
|
let m = myImportModule(c, it)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ implements the required case distinction.
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||||
nversion, nimsets, msgs, securehash, bitsets, idents, types, os,
|
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os,
|
||||||
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
||||||
intsets, cgmeth, lowerings
|
intsets, cgmeth, lowerings
|
||||||
|
|
||||||
|
|
@ -2284,11 +2284,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
of nkFloatLit..nkFloat64Lit:
|
of nkFloatLit..nkFloat64Lit:
|
||||||
let f = n.floatVal
|
let f = n.floatVal
|
||||||
if f != f: r.res = rope"NaN"
|
case classify(f)
|
||||||
elif f == 0.0: r.res = rope"0.0"
|
of fcNaN:
|
||||||
elif f == 0.5 * f:
|
r.res = rope"NaN"
|
||||||
if f > 0.0: r.res = rope"Infinity"
|
of fcNegZero:
|
||||||
else: r.res = rope"-Infinity"
|
r.res = rope"-0.0"
|
||||||
|
of fcZero:
|
||||||
|
r.res = rope"0.0"
|
||||||
|
of fcInf:
|
||||||
|
r.res = rope"Infinity"
|
||||||
|
of fcNegInf:
|
||||||
|
r.res = rope"-Infinity"
|
||||||
else: r.res = rope(f.toStrMaxPrecision)
|
else: r.res = rope(f.toStrMaxPrecision)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
|
|
@ -2390,7 +2396,7 @@ proc genHeader(target: TTarget): Rope =
|
||||||
if target == targetJS:
|
if target == targetJS:
|
||||||
result = (
|
result = (
|
||||||
"/* Generated by the Nim Compiler v$1 */$n" &
|
"/* Generated by the Nim Compiler v$1 */$n" &
|
||||||
"/* (c) 2017 Andreas Rumpf */$n$n" &
|
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
|
||||||
"var framePtr = null;$n" &
|
"var framePtr = null;$n" &
|
||||||
"var excHandler = 0;$n" &
|
"var excHandler = 0;$n" &
|
||||||
"var lastJSError = null;$n" &
|
"var lastJSError = null;$n" &
|
||||||
|
|
@ -2406,7 +2412,7 @@ proc genHeader(target: TTarget): Rope =
|
||||||
else:
|
else:
|
||||||
result = ("<?php$n" &
|
result = ("<?php$n" &
|
||||||
"/* Generated by the Nim Compiler v$1 */$n" &
|
"/* Generated by the Nim Compiler v$1 */$n" &
|
||||||
"/* (c) 2017 Andreas Rumpf */$n$n" &
|
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
|
||||||
"$$framePtr = null;$n" &
|
"$$framePtr = null;$n" &
|
||||||
"$$excHandler = 0;$n" &
|
"$$excHandler = 0;$n" &
|
||||||
"$$lastJSError = null;$n") %
|
"$$lastJSError = null;$n") %
|
||||||
|
|
@ -2464,7 +2470,7 @@ proc genClass(obj: PType; content: Rope; ext: string) =
|
||||||
else: nil
|
else: nil
|
||||||
let result = ("<?php$n" &
|
let result = ("<?php$n" &
|
||||||
"/* Generated by the Nim Compiler v$# */$n" &
|
"/* Generated by the Nim Compiler v$# */$n" &
|
||||||
"/* (c) 2017 Andreas Rumpf */$n$n" &
|
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
|
||||||
"require_once \"nimsystem.php\";$n" &
|
"require_once \"nimsystem.php\";$n" &
|
||||||
"class $#$# {$n$#$n}$n") %
|
"class $#$# {$n$#$n}$n") %
|
||||||
[rope(VersionAsString), cls, extends, content]
|
[rope(VersionAsString), cls, extends, content]
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
## Implements the module handling, including the caching of modules.
|
## Implements the module handling, including the caching of modules.
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options,
|
ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options,
|
||||||
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs
|
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,7 @@ const
|
||||||
errXhasSideEffects: "\'$1\' can have side effects",
|
errXhasSideEffects: "\'$1\' can have side effects",
|
||||||
errIteratorExpected: "iterator within for loop context expected",
|
errIteratorExpected: "iterator within for loop context expected",
|
||||||
errLetNeedsInit: "'let' symbol requires an initialization",
|
errLetNeedsInit: "'let' symbol requires an initialization",
|
||||||
errThreadvarCannotInit: "a thread var cannot be initialized explicitly",
|
errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread",
|
||||||
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
||||||
errIllegalCaptureX: "illegal capture '$1'",
|
errIllegalCaptureX: "illegal capture '$1'",
|
||||||
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
||||||
|
|
@ -1025,6 +1025,9 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
handleError(msg, eh, s)
|
handleError(msg, eh, s)
|
||||||
|
|
||||||
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
|
# this fixes bug #7080 so that it is at least obvious 'fatal'
|
||||||
|
# was executed.
|
||||||
|
errorOutputs = {eStdOut, eStdErr}
|
||||||
liMessage(info, msg, arg, doAbort)
|
liMessage(info, msg, arg, doAbort)
|
||||||
|
|
||||||
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ const
|
||||||
newScopeForIf* = true
|
newScopeForIf* = true
|
||||||
useCaas* = not defined(noCaas)
|
useCaas* = not defined(noCaas)
|
||||||
noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
|
noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
|
||||||
|
copyrightYear* = "2018"
|
||||||
|
|
||||||
type # please make sure we have under 32 options
|
type # please make sure we have under 32 options
|
||||||
# (improves code efficiency a lot!)
|
# (improves code efficiency a lot!)
|
||||||
|
|
|
||||||
|
|
@ -914,7 +914,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
addSon(result, parseTypeDesc(p))
|
addSon(result, parseTypeDesc(p))
|
||||||
else:
|
else:
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, newNodeP(nkEmpty, p))
|
||||||
if p.tok.tokType != tkEquals and withBothOptional notin flags:
|
if p.tok.tokType != tkEquals and withBothOptional notin flags:
|
||||||
parMessage(p, errColonOrEqualsExpected, p.tok)
|
parMessage(p, errColonOrEqualsExpected, p.tok)
|
||||||
if p.tok.tokType == tkEquals:
|
if p.tok.tokType == tkEquals:
|
||||||
|
|
@ -922,7 +922,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
addSon(result, parseExpr(p))
|
addSon(result, parseExpr(p))
|
||||||
else:
|
else:
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, newNodeP(nkEmpty, p))
|
||||||
|
|
||||||
proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||||
#| inlTupleDecl = 'tuple'
|
#| inlTupleDecl = 'tuple'
|
||||||
|
|
|
||||||
|
|
@ -667,10 +667,11 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
result = c.semOverloadedCall(c, result, n, {skTemplate}, {})
|
let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
|
||||||
if sfCustomPragma notin result[0].sym.flags:
|
if r.isNil or sfCustomPragma notin r[0].sym.flags:
|
||||||
invalidPragma(n)
|
invalidPragma(n)
|
||||||
|
else:
|
||||||
|
result = r
|
||||||
if n.kind == nkIdent:
|
if n.kind == nkIdent:
|
||||||
result = result[0]
|
result = result[0]
|
||||||
elif n.kind == nkExprColonExpr:
|
elif n.kind == nkExprColonExpr:
|
||||||
|
|
@ -809,7 +810,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
of wExplain:
|
of wExplain:
|
||||||
sym.flags.incl sfExplain
|
sym.flags.incl sfExplain
|
||||||
of wDeprecated:
|
of wDeprecated:
|
||||||
if it.kind in nkPragmaCallKinds: deprecatedStmt(c, it)
|
if sym != nil and sym.kind in routineKinds:
|
||||||
|
if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
|
||||||
|
incl(sym.flags, sfDeprecated)
|
||||||
|
elif it.kind in nkPragmaCallKinds: deprecatedStmt(c, it)
|
||||||
elif sym != nil: incl(sym.flags, sfDeprecated)
|
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||||
else: incl(c.module.flags, sfDeprecated)
|
else: incl(c.module.flags, sfDeprecated)
|
||||||
of wVarargs:
|
of wVarargs:
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
|
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
|
||||||
ropes, idents, securehash, idgen, types, rodutils, memfiles, tables
|
ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables
|
||||||
|
|
||||||
type
|
type
|
||||||
TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
|
TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,22 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## Serialization utilities for the compiler.
|
## Serialization utilities for the compiler.
|
||||||
import strutils
|
import strutils, math
|
||||||
|
|
||||||
proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.}
|
proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.}
|
||||||
|
|
||||||
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
||||||
if f != f:
|
case classify(f)
|
||||||
|
of fcNaN:
|
||||||
result = "NAN"
|
result = "NAN"
|
||||||
elif f == 0.0:
|
of fcNegZero:
|
||||||
|
result = "-0.0" & literalPostfix
|
||||||
|
of fcZero:
|
||||||
result = "0.0" & literalPostfix
|
result = "0.0" & literalPostfix
|
||||||
elif f == 0.5 * f:
|
of fcInf:
|
||||||
if f > 0.0: result = "INF"
|
result = "INF"
|
||||||
else: result = "-INF"
|
of fcNegInf:
|
||||||
|
result = "-INF"
|
||||||
else:
|
else:
|
||||||
when defined(nimNoArrayToCstringConversion):
|
when defined(nimNoArrayToCstringConversion):
|
||||||
result = newString(81)
|
result = newString(81)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
|
intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
|
||||||
condsyms, ropes, idents, securehash, rodread, passes, idgen,
|
condsyms, ropes, idents, std / sha1, rodread, passes, idgen,
|
||||||
rodutils, modulepaths
|
rodutils, modulepaths
|
||||||
|
|
||||||
from modulegraphs import ModuleGraph
|
from modulegraphs import ModuleGraph
|
||||||
|
|
|
||||||
|
|
@ -215,12 +215,17 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
|
|
||||||
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
|
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind;
|
||||||
let t = typeAllowed(typ, kind)
|
flags: TTypeAllowedFlags = {}) =
|
||||||
|
let t = typeAllowed(typ, kind, flags)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
|
if t == typ:
|
||||||
else: localError(info, "invalid type: '" & typeToString(t) &
|
localError(info, "invalid type: '" & typeToString(typ) &
|
||||||
"' in this context: '" & typeToString(typ) & "'")
|
"' for " & substr($kind, 2).toLowerAscii)
|
||||||
|
else:
|
||||||
|
localError(info, "invalid type: '" & typeToString(t) &
|
||||||
|
"' in this context: '" & typeToString(typ) &
|
||||||
|
"' for " & substr($kind, 2).toLowerAscii)
|
||||||
|
|
||||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||||
typeAllowedCheck(typ.n.info, typ, skProc)
|
typeAllowedCheck(typ.n.info, typ, skProc)
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
errors.safeAdd(CandidateError(
|
errors.safeAdd(CandidateError(
|
||||||
sym: sym,
|
sym: sym,
|
||||||
unmatchedVarParam: int z.mutabilityProblem,
|
unmatchedVarParam: int z.mutabilityProblem,
|
||||||
|
firstMismatch: z.firstMismatch,
|
||||||
diagnostics: z.diagnostics))
|
diagnostics: z.diagnostics))
|
||||||
else:
|
else:
|
||||||
# Symbol table has been modified. Restart and pre-calculate all syms
|
# Symbol table has been modified. Restart and pre-calculate all syms
|
||||||
|
|
@ -154,7 +155,20 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
else:
|
else:
|
||||||
add(candidates, err.sym.getProcHeader(prefer))
|
add(candidates, err.sym.getProcHeader(prefer))
|
||||||
add(candidates, "\n")
|
add(candidates, "\n")
|
||||||
if err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
if err.firstMismatch != 0 and n.len > 2:
|
||||||
|
add(candidates, "first type mismatch at position: " & $err.firstMismatch &
|
||||||
|
"\nrequired type: ")
|
||||||
|
if err.firstMismatch < err.sym.typ.len:
|
||||||
|
candidates.add typeToString(err.sym.typ.sons[err.firstMismatch])
|
||||||
|
else:
|
||||||
|
candidates.add "none"
|
||||||
|
if err.firstMismatch < n.len:
|
||||||
|
candidates.add "\nbut expression '"
|
||||||
|
candidates.add renderTree(n[err.firstMismatch])
|
||||||
|
candidates.add "' is of type: "
|
||||||
|
candidates.add typeToString(n[err.firstMismatch].typ)
|
||||||
|
candidates.add "\n"
|
||||||
|
elif err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
||||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" &
|
add(candidates, "for a 'var' type a variable needs to be passed, but '" &
|
||||||
renderTree(n[err.unmatchedVarParam]) & "' is immutable\n")
|
renderTree(n[err.unmatchedVarParam]) & "' is immutable\n")
|
||||||
for diag in err.diagnostics:
|
for diag in err.diagnostics:
|
||||||
|
|
@ -189,7 +203,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||||
while symx != nil:
|
while symx != nil:
|
||||||
if symx.kind in routineKinds:
|
if symx.kind in routineKinds:
|
||||||
errors.add(CandidateError(sym: symx,
|
errors.add(CandidateError(sym: symx,
|
||||||
unmatchedVarParam: 0,
|
unmatchedVarParam: 0, firstMismatch: 0,
|
||||||
diagnostics: nil))
|
diagnostics: nil))
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
symx = nextOverloadIter(o, c, headSymbol)
|
||||||
if errors.len == 0:
|
if errors.len == 0:
|
||||||
|
|
@ -263,9 +277,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
|
|
||||||
if overloadsState == csEmpty and result.state == csEmpty:
|
if overloadsState == csEmpty and result.state == csEmpty:
|
||||||
if nfDotField in n.flags and nfExplicitCall notin n.flags:
|
if nfDotField in n.flags and nfExplicitCall notin n.flags:
|
||||||
localError(n.info, errUndeclaredField, considerQuotedIdent(f).s)
|
localError(n.info, errUndeclaredField, considerQuotedIdent(f, n).s)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f).s)
|
localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f, n).s)
|
||||||
return
|
return
|
||||||
elif result.state != csMatch:
|
elif result.state != csMatch:
|
||||||
if nfExprCall in n.flags:
|
if nfExprCall in n.flags:
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of mDivF64:
|
of mDivF64:
|
||||||
if getFloat(b) == 0.0:
|
if getFloat(b) == 0.0:
|
||||||
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
|
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
|
||||||
|
elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n)
|
||||||
else: result = newFloatNodeT(Inf, n)
|
else: result = newFloatNodeT(Inf, n)
|
||||||
else:
|
else:
|
||||||
result = newFloatNodeT(getFloat(a) / getFloat(b), n)
|
result = newFloatNodeT(getFloat(a) / getFloat(b), n)
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,10 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = newNodeIT(nkObjConstr, n.info, t)
|
result = newNodeIT(nkObjConstr, n.info, t)
|
||||||
for child in n: result.add child
|
for child in n: result.add child
|
||||||
|
|
||||||
|
if t == nil:
|
||||||
|
localError(n.info, errGenerated, "object constructor needs an object type")
|
||||||
|
return
|
||||||
|
|
||||||
t = skipTypes(t, {tyGenericInst, tyAlias, tySink})
|
t = skipTypes(t, {tyGenericInst, tyAlias, tySink})
|
||||||
if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink})
|
if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink})
|
||||||
if t.kind != tyObject:
|
if t.kind != tyObject:
|
||||||
|
|
|
||||||
|
|
@ -593,17 +593,14 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
notNilCheck(tracked, n, paramType)
|
notNilCheck(tracked, n, paramType)
|
||||||
|
|
||||||
proc breaksBlock(n: PNode): bool =
|
proc breaksBlock(n: PNode): bool =
|
||||||
case n.kind
|
# sematic check doesn't allow statements after raise, break, return or
|
||||||
of nkStmtList, nkStmtListExpr:
|
# call to noreturn proc, so it is safe to check just the last statements
|
||||||
for c in n:
|
var it = n
|
||||||
if breaksBlock(c): return true
|
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
|
||||||
of nkBreakStmt, nkReturnStmt, nkRaiseStmt:
|
it = it.lastSon
|
||||||
return true
|
|
||||||
of nkCallKinds:
|
result = it.kind in {nkBreakStmt, nkReturnStmt, nkRaiseStmt} or
|
||||||
if n.sons[0].kind == nkSym and sfNoReturn in n.sons[0].sym.flags:
|
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||||
return true
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc trackCase(tracked: PEffects, n: PNode) =
|
proc trackCase(tracked: PEffects, n: PNode) =
|
||||||
track(tracked, n.sons[0])
|
track(tracked, n.sons[0])
|
||||||
|
|
@ -747,7 +744,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
# may not look like an assignment, but it is:
|
# may not look like an assignment, but it is:
|
||||||
let arg = n.sons[1]
|
let arg = n.sons[1]
|
||||||
initVarViaNew(tracked, arg)
|
initVarViaNew(tracked, arg)
|
||||||
if {tfNeedsInit} * arg.typ.lastSon.flags != {}:
|
if arg.typ.len != 0 and {tfNeedsInit} * arg.typ.lastSon.flags != {}:
|
||||||
if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
|
if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
|
||||||
n[2].intVal == 0:
|
n[2].intVal == 0:
|
||||||
# var s: seq[notnil]; newSeq(s, 0) is a special case!
|
# var s: seq[notnil]; newSeq(s, 0) is a special case!
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,9 @@ proc discardCheck(c: PContext, result: PNode) =
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
var s = "expression '" & $n & "' is of type '" &
|
var s = "expression '" & $n & "' is of type '" &
|
||||||
result.typ.typeToString & "' and has to be discarded"
|
result.typ.typeToString & "' and has to be discarded"
|
||||||
|
if result.info.line != n.info.line or
|
||||||
|
result.info.fileIndex != n.info.fileIndex:
|
||||||
|
s.add "; start of expression here: " & $result.info
|
||||||
if result.typ.kind == tyProc:
|
if result.typ.kind == tyProc:
|
||||||
s.add "; for a function call use ()"
|
s.add "; for a function call use ()"
|
||||||
localError(n.info, s)
|
localError(n.info, s)
|
||||||
|
|
@ -531,7 +534,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
|
|
||||||
# this can only happen for errornous var statements:
|
# this can only happen for errornous var statements:
|
||||||
if typ == nil: continue
|
if typ == nil: continue
|
||||||
typeAllowedCheck(a.info, typ, symkind)
|
typeAllowedCheck(a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {})
|
||||||
liftTypeBoundOps(c, typ, a.info)
|
liftTypeBoundOps(c, typ, a.info)
|
||||||
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
|
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ type
|
||||||
|
|
||||||
CandidateError* = object
|
CandidateError* = object
|
||||||
sym*: PSym
|
sym*: PSym
|
||||||
unmatchedVarParam*: int
|
unmatchedVarParam*, firstMismatch*: int
|
||||||
diagnostics*: seq[string]
|
diagnostics*: seq[string]
|
||||||
|
|
||||||
CandidateErrors* = seq[CandidateError]
|
CandidateErrors* = seq[CandidateError]
|
||||||
|
|
@ -68,6 +68,8 @@ type
|
||||||
# triggered with an idetools command in the
|
# triggered with an idetools command in the
|
||||||
# future.
|
# future.
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
firstMismatch*: int # position of the first type mismatch for
|
||||||
|
# better error messages
|
||||||
|
|
||||||
TTypeRelFlag* = enum
|
TTypeRelFlag* = enum
|
||||||
trDontBind
|
trDontBind
|
||||||
|
|
@ -913,6 +915,25 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
proc maxNumericType(prev, candidate: PType): PType =
|
||||||
|
let c = candidate.skipTypes({tyRange})
|
||||||
|
template greater(s) =
|
||||||
|
if c.kind in s: result = c
|
||||||
|
case prev.kind
|
||||||
|
of tyInt: greater({tyInt64})
|
||||||
|
of tyInt8: greater({tyInt, tyInt16, tyInt32, tyInt64})
|
||||||
|
of tyInt16: greater({tyInt, tyInt32, tyInt64})
|
||||||
|
of tyInt32: greater({tyInt64})
|
||||||
|
|
||||||
|
of tyUInt: greater({tyUInt64})
|
||||||
|
of tyUInt8: greater({tyUInt, tyUInt16, tyUInt32, tyUInt64})
|
||||||
|
of tyUInt16: greater({tyUInt, tyUInt32, tyUInt64})
|
||||||
|
of tyUInt32: greater({tyUInt64})
|
||||||
|
|
||||||
|
of tyFloat32: greater({tyFloat64, tyFloat128})
|
||||||
|
of tyFloat64: greater({tyFloat128})
|
||||||
|
else: discard
|
||||||
|
|
||||||
proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
flags: TTypeRelFlags = {}): TTypeRelation =
|
flags: TTypeRelFlags = {}): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# typeRel can be used to establish various relationships between types:
|
||||||
|
|
@ -1601,10 +1622,17 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
else:
|
||||||
|
# Special type binding rule for numeric types.
|
||||||
|
# See section "Generic type inference for numeric types" of the
|
||||||
|
# manual for further details:
|
||||||
|
let rebinding = maxNumericType(x.skipTypes({tyRange}), a)
|
||||||
|
if rebinding != nil:
|
||||||
|
put(c, f, rebinding)
|
||||||
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, x, a) # check if it fits
|
result = typeRel(c, x, a) # check if it fits
|
||||||
if result > isGeneric: result = isGeneric
|
if result > isGeneric: result = isGeneric
|
||||||
|
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
let prev = PType(idTableGet(c.bindings, f))
|
let prev = PType(idTableGet(c.bindings, f))
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
|
|
@ -1833,6 +1861,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
|
|
||||||
var r = typeRel(m, f, a)
|
var r = typeRel(m, f, a)
|
||||||
|
|
||||||
|
# This special typing rule for macros and templates is not documented
|
||||||
|
# anywhere and breaks symmetry. It's hard to get rid of though, my
|
||||||
|
# custom seqs example fails to compile without this:
|
||||||
if r != isNone and m.calleeSym != nil and
|
if r != isNone and m.calleeSym != nil and
|
||||||
m.calleeSym.kind in {skMacro, skTemplate}:
|
m.calleeSym.kind in {skMacro, skTemplate}:
|
||||||
# XXX: duplicating this is ugly, but we cannot (!) move this
|
# XXX: duplicating this is ugly, but we cannot (!) move this
|
||||||
|
|
@ -2220,6 +2251,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
n.sons[a], nOrig.sons[a])
|
n.sons[a], nOrig.sons[a])
|
||||||
if arg == nil:
|
if arg == nil:
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
|
m.firstMismatch = f
|
||||||
return
|
return
|
||||||
if m.baseTypeMatch:
|
if m.baseTypeMatch:
|
||||||
#assert(container == nil)
|
#assert(container == nil)
|
||||||
|
|
@ -2274,6 +2306,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
else:
|
else:
|
||||||
# no default value
|
# no default value
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
|
m.firstMismatch = f
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# use default value:
|
# use default value:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
# included from sigmatch.nim
|
# included from sigmatch.nim
|
||||||
|
|
||||||
import algorithm, prefixmatches
|
import algorithm, prefixmatches
|
||||||
|
from wordrecg import wDeprecated
|
||||||
|
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
import passes, tables # importer
|
import passes, tables # importer
|
||||||
|
|
@ -479,12 +480,23 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in
|
||||||
isDecl:
|
isDecl:
|
||||||
suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
|
suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
|
||||||
|
|
||||||
|
proc warnAboutDeprecated(info: TLineInfo; s: PSym) =
|
||||||
|
if s.kind in routineKinds:
|
||||||
|
let n = s.ast[pragmasPos]
|
||||||
|
if n.kind != nkEmpty:
|
||||||
|
for it in n:
|
||||||
|
if whichPragma(it) == wDeprecated and it.safeLen == 2 and
|
||||||
|
it[1].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
|
message(info, warnDeprecated, it[1].strVal & "; " & s.name.s)
|
||||||
|
return
|
||||||
|
message(info, warnDeprecated, s.name.s)
|
||||||
|
|
||||||
proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) =
|
proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
if s.kind == skEnumField and s.owner != nil:
|
if s.kind == skEnumField and s.owner != nil:
|
||||||
incl(s.owner.flags, sfUsed)
|
incl(s.owner.flags, sfUsed)
|
||||||
if {sfDeprecated, sfError} * s.flags != {}:
|
if {sfDeprecated, sfError} * s.flags != {}:
|
||||||
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
|
if sfDeprecated in s.flags: warnAboutDeprecated(info, s)
|
||||||
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
|
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
suggestSym(info, s, usageSym, false)
|
suggestSym(info, s, usageSym, false)
|
||||||
|
|
|
||||||
|
|
@ -716,7 +716,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
if n[0].isInfixAs():
|
if n[0].isInfixAs():
|
||||||
let excTypeNode = n[0][1]
|
let excTypeNode = n[0][1]
|
||||||
let actions = newTransNode(nkStmtList, n[1].info, 2)
|
let actions = newTransNode(nkStmtListExpr, n[1], 2)
|
||||||
# Generating `let exc = (excType)(getCurrentException())`
|
# Generating `let exc = (excType)(getCurrentException())`
|
||||||
# -> getCurrentException()
|
# -> getCurrentException()
|
||||||
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
|
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ proc isRange*(n: PNode): bool {.inline.} =
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc whichPragma*(n: PNode): TSpecialWord =
|
proc whichPragma*(n: PNode): TSpecialWord =
|
||||||
let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
|
let key = if n.kind in nkPragmaCallKinds and n.len > 0: n.sons[0] else: n
|
||||||
if key.kind == nkIdent: result = whichKeyword(key.ident)
|
if key.kind == nkIdent: result = whichKeyword(key.ident)
|
||||||
|
|
||||||
proc unnestStmts(n, result: PNode) =
|
proc unnestStmts(n, result: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -1058,11 +1058,12 @@ proc commonSuperclass*(a, b: PType): PType =
|
||||||
y = y.sons[0]
|
y = y.sons[0]
|
||||||
|
|
||||||
type
|
type
|
||||||
TTypeAllowedFlag = enum
|
TTypeAllowedFlag* = enum
|
||||||
taField,
|
taField,
|
||||||
taHeap
|
taHeap,
|
||||||
|
taConcept
|
||||||
|
|
||||||
TTypeAllowedFlags = set[TTypeAllowedFlag]
|
TTypeAllowedFlags* = set[TTypeAllowedFlag]
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
flags: TTypeAllowedFlags = {}): PType
|
flags: TTypeAllowedFlags = {}): PType
|
||||||
|
|
@ -1130,7 +1131,10 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
of tyVoid:
|
of tyVoid:
|
||||||
if taField notin flags: result = t
|
if taField notin flags: result = t
|
||||||
of tyTypeClasses:
|
of tyTypeClasses:
|
||||||
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
|
||||||
|
discard
|
||||||
|
elif kind notin {skParam, skResult}:
|
||||||
|
result = t
|
||||||
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
||||||
tyNone, tyForward, tyFromExpr:
|
tyNone, tyForward, tyFromExpr:
|
||||||
result = t
|
result = t
|
||||||
|
|
@ -1178,11 +1182,11 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
result = nil
|
result = nil
|
||||||
of tyUnused, tyOptAsRef: internalError("typeAllowedAux")
|
of tyUnused, tyOptAsRef: internalError("typeAllowedAux")
|
||||||
|
|
||||||
proc typeAllowed*(t: PType, kind: TSymKind): PType =
|
proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType =
|
||||||
# returns 'nil' on success and otherwise the part of the type that is
|
# returns 'nil' on success and otherwise the part of the type that is
|
||||||
# wrong!
|
# wrong!
|
||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
result = typeAllowedAux(marker, t, kind, {})
|
result = typeAllowedAux(marker, t, kind, flags)
|
||||||
|
|
||||||
proc align(address, alignment: BiggestInt): BiggestInt =
|
proc align(address, alignment: BiggestInt): BiggestInt =
|
||||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,7 @@ Cryptography and Hashing
|
||||||
* `base64 <base64.html>`_
|
* `base64 <base64.html>`_
|
||||||
This module implements a base64 encoder and decoder.
|
This module implements a base64 encoder and decoder.
|
||||||
|
|
||||||
* `securehash <securehash.html>`_
|
* `sha1 <sha1.html>`_
|
||||||
This module implements a sha1 encoder and decoder.
|
This module implements a sha1 encoder and decoder.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ The following example shows a generic binary tree can be modelled:
|
||||||
for str in preorder(root):
|
for str in preorder(root):
|
||||||
stdout.writeLine(str)
|
stdout.writeLine(str)
|
||||||
|
|
||||||
|
The ``T`` is called a `generic type parameter`:idx:.
|
||||||
|
|
||||||
|
|
||||||
Is operator
|
Is operator
|
||||||
-----------
|
-----------
|
||||||
|
|
@ -582,6 +584,7 @@ the concept body:
|
||||||
proc log(format: static[string], varargs[distinct StringRef])
|
proc log(format: static[string], varargs[distinct StringRef])
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
VTable types
|
VTable types
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
@ -709,3 +712,30 @@ definition):
|
||||||
|
|
||||||
But a ``bind`` is rarely useful because symbol binding from the definition
|
But a ``bind`` is rarely useful because symbol binding from the definition
|
||||||
scope is the default.
|
scope is the default.
|
||||||
|
|
||||||
|
|
||||||
|
Generic type inference for numeric types
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
A `numeric`:idx: type is any signed, unsigned integer type, floating point
|
||||||
|
type or a subrange thereof. Let ``maxNumericType(T1, T2)`` be the "greater"
|
||||||
|
type of ``T1`` and ``T2``, that is the type that uses more bits. For
|
||||||
|
example ``maxNumericType(int32, int64) == int64``. ``maxNumericType`` is only
|
||||||
|
defined for numeric types of the same class (signed, unsigned, floating point).
|
||||||
|
``maxNumericType`` strips away subranges,
|
||||||
|
``maxNumericType(subrangeof(int16), int8)`` produces ``int16`` not its
|
||||||
|
subrange. The definition ``maxNumericType`` is extended to take a variable
|
||||||
|
number of arguments in the obvious way;
|
||||||
|
``maxNumericType(x, y, z) == maxNumericType(maxNumericType(x, y), z)``.
|
||||||
|
|
||||||
|
A generic type parameter ``T`` that is bound to multiple numeric types ``N1``,
|
||||||
|
``N2``, ``N3``, ... during type checking is inferred to
|
||||||
|
be ``maxNumericType(N1, N2, N3, ...)``. This special type inference rule ensures
|
||||||
|
that the builtin arithmetic operators can be written in an intuitive way:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc `@`[T: int|int16|int32](x, y: T): T
|
||||||
|
|
||||||
|
4'i32 @ 6'i64 # inferred to be of type ``int64``
|
||||||
|
|
||||||
|
4'i64 @ 6'i32 # inferred to be of type ``int64``
|
||||||
|
|
|
||||||
|
|
@ -181,11 +181,11 @@ Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
|
||||||
and `FloatInexactError`:idx:.
|
and `FloatInexactError`:idx:.
|
||||||
These exceptions inherit from the `FloatingPointError`:idx: base class.
|
These exceptions inherit from the `FloatingPointError`:idx: base class.
|
||||||
|
|
||||||
Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control
|
Nim provides the pragmas `nanChecks`:idx: and `infChecks`:idx: to control
|
||||||
whether the IEEE exceptions are ignored or trap a Nim exception:
|
whether the IEEE exceptions are ignored or trap a Nim exception:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
{.NanChecks: on, InfChecks: on.}
|
{.nanChecks: on, infChecks: on.}
|
||||||
var a = 1.0
|
var a = 1.0
|
||||||
var b = 0.0
|
var b = 0.0
|
||||||
echo b / b # raises FloatInvalidOpError
|
echo b / b # raises FloatInvalidOpError
|
||||||
|
|
@ -195,7 +195,7 @@ In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError``
|
||||||
are never raised. ``FloatOverflowError`` is raised instead of
|
are never raised. ``FloatOverflowError`` is raised instead of
|
||||||
``FloatDivByZeroError``.
|
``FloatDivByZeroError``.
|
||||||
There is also a `floatChecks`:idx: pragma that is a short-cut for the
|
There is also a `floatChecks`:idx: pragma that is a short-cut for the
|
||||||
combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are
|
combination of ``nanChecks`` and ``infChecks`` pragmas. ``floatChecks`` are
|
||||||
turned off as default.
|
turned off as default.
|
||||||
|
|
||||||
The only operations that are affected by the ``floatChecks`` pragma are
|
The only operations that are affected by the ``floatChecks`` pragma are
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
The set type models the mathematical notion of a set. The set's basetype can
|
The set type models the mathematical notion of a set. The set's basetype can
|
||||||
only be an ordinal type of a certain size, namely:
|
only be an ordinal type of a certain size, namely:
|
||||||
|
|
||||||
* ``int8``-``int16``
|
* ``int8``-``int16``
|
||||||
* ``uint8``/``byte``-``uint16``
|
* ``uint8``/``byte``-``uint16``
|
||||||
* ``char``
|
* ``char``
|
||||||
* ``enum``
|
* ``enum``
|
||||||
|
|
||||||
or equivalent. The reason is that sets are implemented as high
|
or equivalent. The reason is that sets are implemented as high
|
||||||
performance bit vectors. Attempting to declare a set with a larger type will
|
performance bit vectors. Attempting to declare a set with a larger type will
|
||||||
result in an error:
|
result in an error:
|
||||||
|
|
|
||||||
|
|
@ -1032,7 +1032,7 @@ procs for these conversions.
|
||||||
|
|
||||||
Type Conversion
|
Type Conversion
|
||||||
---------------
|
---------------
|
||||||
Conversion between basic types is performed by using the
|
Conversion between numerical types is performed by using the
|
||||||
type as a function:
|
type as a function:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
|
||||||
|
|
@ -265,9 +265,15 @@ when defined(windows) or defined(nimdoc):
|
||||||
setGlobalDispatcher(newDispatcher())
|
setGlobalDispatcher(newDispatcher())
|
||||||
result = gDisp
|
result = gDisp
|
||||||
|
|
||||||
|
proc getIoHandler*(disp: PDispatcher): Handle =
|
||||||
|
## Returns the underlying IO Completion Port handle (Windows) or selector
|
||||||
|
## (Unix) for the specified dispatcher.
|
||||||
|
return disp.ioPort
|
||||||
|
|
||||||
proc register*(fd: AsyncFD) =
|
proc register*(fd: AsyncFD) =
|
||||||
## Registers ``fd`` with the dispatcher.
|
## Registers ``fd`` with the dispatcher.
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
|
|
||||||
if createIoCompletionPort(fd.Handle, p.ioPort,
|
if createIoCompletionPort(fd.Handle, p.ioPort,
|
||||||
cast[CompletionKey](fd), 1) == 0:
|
cast[CompletionKey](fd), 1) == 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
@ -757,6 +763,9 @@ when defined(windows) or defined(nimdoc):
|
||||||
## Unregisters ``fd``.
|
## Unregisters ``fd``.
|
||||||
getGlobalDispatcher().handles.excl(fd)
|
getGlobalDispatcher().handles.excl(fd)
|
||||||
|
|
||||||
|
proc contains*(disp: PDispatcher, fd: AsyncFD): bool =
|
||||||
|
return fd in disp.handles
|
||||||
|
|
||||||
{.push stackTrace:off.}
|
{.push stackTrace:off.}
|
||||||
proc waitableCallback(param: pointer,
|
proc waitableCallback(param: pointer,
|
||||||
timerOrWaitFired: WINBOOL): void {.stdcall.} =
|
timerOrWaitFired: WINBOOL): void {.stdcall.} =
|
||||||
|
|
@ -977,7 +986,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
proc newAsyncEvent*(): AsyncEvent =
|
proc newAsyncEvent*(): AsyncEvent =
|
||||||
## Creates a new thread-safe ``AsyncEvent`` object.
|
## Creates a new thread-safe ``AsyncEvent`` object.
|
||||||
##
|
##
|
||||||
## New ``AsyncEvent`` object is not automatically registered with # TODO: Why? -- DP
|
## New ``AsyncEvent`` object is not automatically registered with
|
||||||
## dispatcher like ``AsyncSocket``.
|
## dispatcher like ``AsyncSocket``.
|
||||||
var sa = SECURITY_ATTRIBUTES(
|
var sa = SECURITY_ATTRIBUTES(
|
||||||
nLength: sizeof(SECURITY_ATTRIBUTES).cint,
|
nLength: sizeof(SECURITY_ATTRIBUTES).cint,
|
||||||
|
|
@ -1095,6 +1104,9 @@ else:
|
||||||
setGlobalDispatcher(newDispatcher())
|
setGlobalDispatcher(newDispatcher())
|
||||||
result = gDisp
|
result = gDisp
|
||||||
|
|
||||||
|
proc getIoHandler*(disp: PDispatcher): Selector[AsyncData] =
|
||||||
|
return disp.selector
|
||||||
|
|
||||||
proc register*(fd: AsyncFD) =
|
proc register*(fd: AsyncFD) =
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
var data = newAsyncData()
|
var data = newAsyncData()
|
||||||
|
|
@ -1111,6 +1123,9 @@ else:
|
||||||
proc unregister*(ev: AsyncEvent) =
|
proc unregister*(ev: AsyncEvent) =
|
||||||
getGlobalDispatcher().selector.unregister(SelectEvent(ev))
|
getGlobalDispatcher().selector.unregister(SelectEvent(ev))
|
||||||
|
|
||||||
|
proc contains*(disp: PDispatcher, fd: AsyncFd): bool =
|
||||||
|
return fd.SocketHandle in disp.selector
|
||||||
|
|
||||||
proc addRead*(fd: AsyncFD, cb: Callback) =
|
proc addRead*(fd: AsyncFD, cb: Callback) =
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
var newEvents = {Event.Read}
|
var newEvents = {Event.Read}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ proc newAsyncFile*(fd: AsyncFd): AsyncFile =
|
||||||
## Creates `AsyncFile` with a previously opened file descriptor `fd`.
|
## Creates `AsyncFile` with a previously opened file descriptor `fd`.
|
||||||
new result
|
new result
|
||||||
result.fd = fd
|
result.fd = fd
|
||||||
register(result.fd)
|
register(fd)
|
||||||
|
|
||||||
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
## Opens a file specified by the path in ``filename`` using
|
## Opens a file specified by the path in ``filename`` using
|
||||||
|
|
@ -97,16 +97,16 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
let fd = createFileW(newWideCString(filename), desiredAccess,
|
let fd = createFileW(newWideCString(filename), desiredAccess,
|
||||||
FILE_SHARE_READ,
|
FILE_SHARE_READ,
|
||||||
nil, creationDisposition, flags, 0).AsyncFd
|
nil, creationDisposition, flags, 0)
|
||||||
else:
|
else:
|
||||||
let fd = createFileA(filename, desiredAccess,
|
let fd = createFileA(filename, desiredAccess,
|
||||||
FILE_SHARE_READ,
|
FILE_SHARE_READ,
|
||||||
nil, creationDisposition, flags, 0).AsyncFd
|
nil, creationDisposition, flags, 0)
|
||||||
|
|
||||||
if fd.Handle == INVALID_HANDLE_VALUE:
|
if fd == INVALID_HANDLE_VALUE:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
result = newAsyncFile(fd)
|
result = newAsyncFile(fd.AsyncFd)
|
||||||
|
|
||||||
if mode == fmAppend:
|
if mode == fmAppend:
|
||||||
result.offset = getFileSize(result)
|
result.offset = getFileSize(result)
|
||||||
|
|
@ -115,11 +115,11 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
let flags = getPosixFlags(mode)
|
let flags = getPosixFlags(mode)
|
||||||
# RW (Owner), RW (Group), R (Other)
|
# RW (Owner), RW (Group), R (Other)
|
||||||
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
|
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
|
||||||
let fd = open(filename, flags, perm).AsyncFD
|
let fd = open(filename, flags, perm)
|
||||||
if fd.cint == -1:
|
if fd == -1:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
result = newAsyncFile(fd)
|
result = newAsyncFile(fd.AsyncFd)
|
||||||
|
|
||||||
proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] =
|
proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] =
|
||||||
## Read ``size`` bytes from the specified file asynchronously starting at
|
## Read ``size`` bytes from the specified file asynchronously starting at
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,7 @@ proc asyncCheck*[T](future: Future[T]) =
|
||||||
## finished with an error.
|
## finished with an error.
|
||||||
##
|
##
|
||||||
## This should be used instead of ``discard`` to discard void futures.
|
## This should be used instead of ``discard`` to discard void futures.
|
||||||
|
assert(not future.isNil, "Future is nil")
|
||||||
future.callback =
|
future.callback =
|
||||||
proc () =
|
proc () =
|
||||||
if future.failed:
|
if future.failed:
|
||||||
|
|
|
||||||
|
|
@ -140,9 +140,16 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
|
||||||
sockType: SockType = SOCK_STREAM,
|
sockType: SockType = SOCK_STREAM,
|
||||||
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
|
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
|
||||||
## Creates a new ``AsyncSocket`` based on the supplied params.
|
## Creates a new ``AsyncSocket`` based on the supplied params.
|
||||||
|
##
|
||||||
|
## The supplied ``fd``'s non-blocking state will be enabled implicitly.
|
||||||
|
##
|
||||||
|
## **Note**: This procedure will **NOT** register ``fd`` with the global
|
||||||
|
## async dispatcher. You need to do this manually. If you have used
|
||||||
|
## ``newAsyncNativeSocket`` to create ``fd`` then it's already registered.
|
||||||
assert fd != osInvalidSocket.AsyncFD
|
assert fd != osInvalidSocket.AsyncFD
|
||||||
new(result)
|
new(result)
|
||||||
result.fd = fd.SocketHandle
|
result.fd = fd.SocketHandle
|
||||||
|
fd.SocketHandle.setBlocking(false)
|
||||||
result.isBuffered = buffered
|
result.isBuffered = buffered
|
||||||
result.domain = domain
|
result.domain = domain
|
||||||
result.sockType = sockType
|
result.sockType = sockType
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ template checkFd(s, f) =
|
||||||
if f >= s.maxFD:
|
if f >= s.maxFD:
|
||||||
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
|
|
@ -156,7 +156,7 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
raiseIOSelectorsError(osLastError())
|
raiseIOSelectorsError(osLastError())
|
||||||
inc(s.count)
|
inc(s.count)
|
||||||
|
|
||||||
proc updateHandle*[T](s: Selector[T], fd: SocketHandle, events: set[Event]) =
|
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event]) =
|
||||||
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
||||||
Event.User, Event.Oneshot, Event.Error}
|
Event.User, Event.Oneshot, Event.Error}
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
|
|
@ -392,9 +392,19 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||||
let pevents = resTable[i].events
|
let pevents = resTable[i].events
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0)
|
||||||
var rkey = ReadyKey(fd: int(fdi), events: {})
|
var rkey = ReadyKey(fd: fdi, events: {})
|
||||||
|
|
||||||
if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0:
|
if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0:
|
||||||
|
if (pevents and EPOLLHUP) != 0:
|
||||||
|
rkey.errorCode = ECONNRESET.OSErrorCode
|
||||||
|
else:
|
||||||
|
# Try reading SO_ERROR from fd.
|
||||||
|
var error: cint
|
||||||
|
var size = sizeof(error).SockLen
|
||||||
|
if getsockopt(fdi.SocketHandle, SOL_SOCKET, SO_ERROR, addr(error),
|
||||||
|
addr(size)) == 0'i32:
|
||||||
|
rkey.errorCode = error.OSErrorCode
|
||||||
|
|
||||||
rkey.events.incl(Event.Error)
|
rkey.events.incl(Event.Error)
|
||||||
if (pevents and EPOLLOUT) != 0:
|
if (pevents and EPOLLOUT) != 0:
|
||||||
rkey.events.incl(Event.Write)
|
rkey.events.incl(Event.Write)
|
||||||
|
|
@ -482,7 +492,7 @@ template isEmpty*[T](s: Selector[T]): bool =
|
||||||
(s.count == 0)
|
(s.count == 0)
|
||||||
|
|
||||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||||
return s.fds[fd].ident != 0
|
return s.fds[fd.int].ident != 0
|
||||||
|
|
||||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
|
|
@ -516,3 +526,6 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
|
||||||
body1
|
body1
|
||||||
else:
|
else:
|
||||||
body2
|
body2
|
||||||
|
|
||||||
|
proc getFd*[T](s: Selector[T]): int =
|
||||||
|
return s.epollFd.int
|
||||||
|
|
@ -217,7 +217,7 @@ else:
|
||||||
raiseIOSelectorsError(osLastError())
|
raiseIOSelectorsError(osLastError())
|
||||||
s.changes.setLen(0)
|
s.changes.setLen(0)
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
|
|
@ -235,7 +235,7 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
when not declared(CACHE_EVENTS):
|
when not declared(CACHE_EVENTS):
|
||||||
flushKQueue(s)
|
flushKQueue(s)
|
||||||
|
|
||||||
proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event]) =
|
events: set[Event]) =
|
||||||
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
||||||
Event.User, Event.Oneshot, Event.Error}
|
Event.User, Event.Oneshot, Event.Error}
|
||||||
|
|
@ -503,6 +503,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||||
|
|
||||||
if (kevent.flags and EV_ERROR) != 0:
|
if (kevent.flags and EV_ERROR) != 0:
|
||||||
rkey.events = {Event.Error}
|
rkey.events = {Event.Error}
|
||||||
|
rkey.errorCode = kevent.data.OSErrorCode
|
||||||
|
|
||||||
case kevent.filter:
|
case kevent.filter:
|
||||||
of EVFILT_READ:
|
of EVFILT_READ:
|
||||||
|
|
@ -569,6 +570,13 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||||
doAssert(true, "Unsupported kqueue filter in the queue!")
|
doAssert(true, "Unsupported kqueue filter in the queue!")
|
||||||
|
|
||||||
if (kevent.flags and EV_EOF) != 0:
|
if (kevent.flags and EV_EOF) != 0:
|
||||||
|
if kevent.fflags != 0:
|
||||||
|
rkey.errorCode = kevent.fflags.OSErrorCode
|
||||||
|
else:
|
||||||
|
# This assumes we are dealing with sockets.
|
||||||
|
# TODO: For future-proofing it might be a good idea to give the
|
||||||
|
# user access to the raw `kevent`.
|
||||||
|
rkey.errorCode = ECONNRESET.OSErrorCode
|
||||||
rkey.events.incl(Event.Error)
|
rkey.events.incl(Event.Error)
|
||||||
|
|
||||||
results[k] = rkey
|
results[k] = rkey
|
||||||
|
|
@ -585,7 +593,7 @@ template isEmpty*[T](s: Selector[T]): bool =
|
||||||
(s.count == 0)
|
(s.count == 0)
|
||||||
|
|
||||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||||
return s.fds[fd].ident != 0
|
return s.fds[fd.int].ident != 0
|
||||||
|
|
||||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
|
|
@ -619,3 +627,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
|
||||||
body1
|
body1
|
||||||
else:
|
else:
|
||||||
body2
|
body2
|
||||||
|
|
||||||
|
|
||||||
|
proc getFd*[T](s: Selector[T]): int =
|
||||||
|
return s.kqFD.int
|
||||||
|
|
@ -141,7 +141,7 @@ template checkFd(s, f) =
|
||||||
if f >= s.maxFD:
|
if f >= s.maxFD:
|
||||||
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
var fdi = int(fd)
|
var fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
|
|
@ -149,7 +149,7 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
setKey(s, fdi, events, 0, data)
|
setKey(s, fdi, events, 0, data)
|
||||||
if events != {}: s.pollAdd(fdi.cint, events)
|
if events != {}: s.pollAdd(fdi.cint, events)
|
||||||
|
|
||||||
proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event]) =
|
events: set[Event]) =
|
||||||
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
||||||
Event.User, Event.Oneshot, Event.Error}
|
Event.User, Event.Oneshot, Event.Error}
|
||||||
|
|
@ -280,7 +280,7 @@ template isEmpty*[T](s: Selector[T]): bool =
|
||||||
(s.count == 0)
|
(s.count == 0)
|
||||||
|
|
||||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||||
return s.fds[fd].ident != 0
|
return s.fds[fd.int].ident != 0
|
||||||
|
|
||||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
|
|
@ -314,3 +314,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
|
||||||
body1
|
body1
|
||||||
else:
|
else:
|
||||||
body2
|
body2
|
||||||
|
|
||||||
|
|
||||||
|
proc getFd*[T](s: Selector[T]): int =
|
||||||
|
return -1
|
||||||
|
|
@ -229,7 +229,7 @@ proc delKey[T](s: Selector[T], fd: SocketHandle) =
|
||||||
doAssert(i < FD_SETSIZE,
|
doAssert(i < FD_SETSIZE,
|
||||||
"Descriptor [" & $int(fd) & "] is not registered in the queue!")
|
"Descriptor [" & $int(fd) & "] is not registered in the queue!")
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
when not defined(windows):
|
when not defined(windows):
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
|
|
@ -255,7 +255,7 @@ proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||||
IOFD_SET(ev.rsock, addr s.rSet)
|
IOFD_SET(ev.rsock, addr s.rSet)
|
||||||
inc(s.count)
|
inc(s.count)
|
||||||
|
|
||||||
proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
events: set[Event]) =
|
events: set[Event]) =
|
||||||
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
|
||||||
Event.User, Event.Oneshot, Event.Error}
|
Event.User, Event.Oneshot, Event.Error}
|
||||||
|
|
@ -453,3 +453,6 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value,
|
||||||
else:
|
else:
|
||||||
body2
|
body2
|
||||||
|
|
||||||
|
|
||||||
|
proc getFd*[T](s: Selector[T]): int =
|
||||||
|
return -1
|
||||||
|
|
@ -187,12 +187,12 @@ proc toSockType*(protocol: Protocol): SockType =
|
||||||
proc newNativeSocket*(domain: Domain = AF_INET,
|
proc newNativeSocket*(domain: Domain = AF_INET,
|
||||||
sockType: SockType = SOCK_STREAM,
|
sockType: SockType = SOCK_STREAM,
|
||||||
protocol: Protocol = IPPROTO_TCP): SocketHandle =
|
protocol: Protocol = IPPROTO_TCP): SocketHandle =
|
||||||
## Creates a new socket; returns `InvalidSocket` if an error occurs.
|
## Creates a new socket; returns `osInvalidSocket` if an error occurs.
|
||||||
socket(toInt(domain), toInt(sockType), toInt(protocol))
|
socket(toInt(domain), toInt(sockType), toInt(protocol))
|
||||||
|
|
||||||
proc newNativeSocket*(domain: cint, sockType: cint,
|
proc newNativeSocket*(domain: cint, sockType: cint,
|
||||||
protocol: cint): SocketHandle =
|
protocol: cint): SocketHandle =
|
||||||
## Creates a new socket; returns `InvalidSocket` if an error occurs.
|
## Creates a new socket; returns `osInvalidSocket` if an error occurs.
|
||||||
##
|
##
|
||||||
## Use this overload if one of the enums specified above does
|
## Use this overload if one of the enums specified above does
|
||||||
## not contain what you need.
|
## not contain what you need.
|
||||||
|
|
@ -666,6 +666,19 @@ proc selectWrite*(writefds: var seq[SocketHandle],
|
||||||
|
|
||||||
pruneSocketSet(writefds, (wr))
|
pruneSocketSet(writefds, (wr))
|
||||||
|
|
||||||
|
proc accept*(fd: SocketHandle): (SocketHandle, string) =
|
||||||
|
## Accepts a new client connection.
|
||||||
|
##
|
||||||
|
## Returns (osInvalidSocket, "") if an error occurred.
|
||||||
|
var sockAddress: Sockaddr_in
|
||||||
|
var addrLen = sizeof(sockAddress).SockLen
|
||||||
|
var sock = accept(fd, cast[ptr SockAddr](addr(sockAddress)),
|
||||||
|
addr(addrLen))
|
||||||
|
if sock == osInvalidSocket:
|
||||||
|
return (osInvalidSocket, "")
|
||||||
|
else:
|
||||||
|
return (sock, $inet_ntoa(sockAddress.sin_addr))
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var wsa: WSAData
|
var wsa: WSAData
|
||||||
if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
|
if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
|
||||||
|
|
|
||||||
|
|
@ -753,10 +753,8 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
## flag is specified then this error will not be raised and instead
|
## flag is specified then this error will not be raised and instead
|
||||||
## accept will be called again.
|
## accept will be called again.
|
||||||
assert(client != nil)
|
assert(client != nil)
|
||||||
var sockAddress: Sockaddr_in
|
let ret = accept(server.fd)
|
||||||
var addrLen = sizeof(sockAddress).SockLen
|
let sock = ret[0]
|
||||||
var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
|
|
||||||
addr(addrLen))
|
|
||||||
|
|
||||||
if sock == osInvalidSocket:
|
if sock == osInvalidSocket:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
|
|
@ -764,6 +762,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
acceptAddr(server, client, address, flags)
|
acceptAddr(server, client, address, flags)
|
||||||
raiseOSError(err)
|
raiseOSError(err)
|
||||||
else:
|
else:
|
||||||
|
address = ret[1]
|
||||||
client.fd = sock
|
client.fd = sock
|
||||||
client.isBuffered = server.isBuffered
|
client.isBuffered = server.isBuffered
|
||||||
|
|
||||||
|
|
@ -776,9 +775,6 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
let ret = SSLAccept(client.sslHandle)
|
let ret = SSLAccept(client.sslHandle)
|
||||||
socketError(client, ret, false)
|
socketError(client, ret, false)
|
||||||
|
|
||||||
# Client socket is set above.
|
|
||||||
address = $inet_ntoa(sockAddress.sin_addr)
|
|
||||||
|
|
||||||
when false: #defineSsl:
|
when false: #defineSsl:
|
||||||
proc acceptAddrSSL*(server: Socket, client: var Socket,
|
proc acceptAddrSSL*(server: Socket, client: var Socket,
|
||||||
address: var string): SSLAcceptResult {.
|
address: var string): SSLAcceptResult {.
|
||||||
|
|
|
||||||
|
|
@ -139,10 +139,15 @@ proc findExe*(exe: string, followSymlinks: bool = true;
|
||||||
## is added the `ExeExts <#ExeExts>`_ file extensions if it has none.
|
## is added the `ExeExts <#ExeExts>`_ file extensions if it has none.
|
||||||
## If the system supports symlinks it also resolves them until it
|
## If the system supports symlinks it also resolves them until it
|
||||||
## meets the actual file. This behavior can be disabled if desired.
|
## meets the actual file. This behavior can be disabled if desired.
|
||||||
|
template checkCurrentDir() =
|
||||||
for ext in extensions:
|
for ext in extensions:
|
||||||
result = addFileExt(exe, ext)
|
result = addFileExt(exe, ext)
|
||||||
if existsFile(result): return
|
if existsFile(result): return
|
||||||
var path = string(getEnv("PATH"))
|
when defined(posix):
|
||||||
|
if '/' in exe: checkCurrentDir()
|
||||||
|
else:
|
||||||
|
checkCurrentDir()
|
||||||
|
let path = string(getEnv("PATH"))
|
||||||
for candidate in split(path, PathSep):
|
for candidate in split(path, PathSep):
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var x = (if candidate[0] == '"' and candidate[^1] == '"':
|
var x = (if candidate[0] == '"' and candidate[^1] == '"':
|
||||||
|
|
|
||||||
|
|
@ -1,195 +1,6 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# The Nim Compiler
|
|
||||||
# (c) Copyright 2015 Nim Contributors
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
import strutils
|
|
||||||
|
|
||||||
const Sha1DigestSize = 20
|
|
||||||
|
|
||||||
type
|
|
||||||
Sha1Digest = array[0 .. Sha1DigestSize-1, uint8]
|
|
||||||
SecureHash* = distinct Sha1Digest
|
|
||||||
|
|
||||||
# Copyright (c) 2011, Micael Hildenborg
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
# * Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer in the
|
|
||||||
# documentation and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of Micael Hildenborg nor the
|
|
||||||
# names of its contributors may be used to endorse or promote products
|
|
||||||
# derived from this software without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
|
||||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
|
||||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
# Ported to Nim by Erik O'Leary
|
|
||||||
|
|
||||||
type
|
|
||||||
Sha1State* = array[0 .. 5-1, uint32]
|
|
||||||
Sha1Buffer = array[0 .. 80-1, uint32]
|
|
||||||
|
|
||||||
template clearBuffer(w: Sha1Buffer, len = 16) =
|
|
||||||
zeroMem(addr(w), len * sizeof(uint32))
|
|
||||||
|
|
||||||
proc init*(result: var Sha1State) =
|
|
||||||
result[0] = 0x67452301'u32
|
|
||||||
result[1] = 0xefcdab89'u32
|
|
||||||
result[2] = 0x98badcfe'u32
|
|
||||||
result[3] = 0x10325476'u32
|
|
||||||
result[4] = 0xc3d2e1f0'u32
|
|
||||||
|
|
||||||
proc innerHash(state: var Sha1State, w: var Sha1Buffer) =
|
|
||||||
var
|
|
||||||
a = state[0]
|
|
||||||
b = state[1]
|
|
||||||
c = state[2]
|
|
||||||
d = state[3]
|
|
||||||
e = state[4]
|
|
||||||
|
|
||||||
var round = 0
|
|
||||||
|
|
||||||
template rot(value, bits: uint32): uint32 =
|
|
||||||
(value shl bits) or (value shr (32 - bits))
|
|
||||||
|
|
||||||
template sha1(fun, val: uint32) =
|
|
||||||
let t = rot(a, 5) + fun + e + val + w[round]
|
|
||||||
e = d
|
|
||||||
d = c
|
|
||||||
c = rot(b, 30)
|
|
||||||
b = a
|
|
||||||
a = t
|
|
||||||
|
|
||||||
template process(body: untyped) =
|
|
||||||
w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1)
|
|
||||||
body
|
|
||||||
inc(round)
|
|
||||||
|
|
||||||
template wrap(dest, value: untyped) =
|
|
||||||
let v = dest + value
|
|
||||||
dest = v
|
|
||||||
|
|
||||||
while round < 16:
|
|
||||||
sha1((b and c) or (not b and d), 0x5a827999'u32)
|
|
||||||
inc(round)
|
|
||||||
|
|
||||||
while round < 20:
|
|
||||||
process:
|
|
||||||
sha1((b and c) or (not b and d), 0x5a827999'u32)
|
|
||||||
|
|
||||||
while round < 40:
|
|
||||||
process:
|
|
||||||
sha1(b xor c xor d, 0x6ed9eba1'u32)
|
|
||||||
|
|
||||||
while round < 60:
|
|
||||||
process:
|
|
||||||
sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32)
|
|
||||||
|
|
||||||
while round < 80:
|
|
||||||
process:
|
|
||||||
sha1(b xor c xor d, 0xca62c1d6'u32)
|
|
||||||
|
|
||||||
wrap state[0], a
|
|
||||||
wrap state[1], b
|
|
||||||
wrap state[2], c
|
|
||||||
wrap state[3], d
|
|
||||||
wrap state[4], e
|
|
||||||
|
|
||||||
proc sha1(src: cstring; len: int): Sha1Digest =
|
|
||||||
#Initialize state
|
|
||||||
var state: Sha1State
|
|
||||||
init(state)
|
|
||||||
|
|
||||||
#Create w buffer
|
|
||||||
var w: Sha1Buffer
|
|
||||||
|
|
||||||
#Loop through all complete 64byte blocks.
|
|
||||||
let byteLen = len
|
|
||||||
let endOfFullBlocks = byteLen - 64
|
|
||||||
var endCurrentBlock = 0
|
|
||||||
var currentBlock = 0
|
|
||||||
|
|
||||||
while currentBlock <= endOfFullBlocks:
|
|
||||||
endCurrentBlock = currentBlock + 64
|
|
||||||
|
|
||||||
var i = 0
|
|
||||||
while currentBlock < endCurrentBlock:
|
|
||||||
w[i] = uint32(src[currentBlock+3]) or
|
|
||||||
uint32(src[currentBlock+2]) shl 8'u32 or
|
|
||||||
uint32(src[currentBlock+1]) shl 16'u32 or
|
|
||||||
uint32(src[currentBlock]) shl 24'u32
|
|
||||||
currentBlock += 4
|
|
||||||
inc(i)
|
|
||||||
|
|
||||||
innerHash(state, w)
|
|
||||||
|
|
||||||
#Handle last and not full 64 byte block if existing
|
|
||||||
endCurrentBlock = byteLen - currentBlock
|
|
||||||
clearBuffer(w)
|
|
||||||
var lastBlockBytes = 0
|
|
||||||
|
|
||||||
while lastBlockBytes < endCurrentBlock:
|
|
||||||
|
|
||||||
var value = uint32(src[lastBlockBytes + currentBlock]) shl
|
|
||||||
((3'u32 - uint32(lastBlockBytes and 3)) shl 3)
|
|
||||||
|
|
||||||
w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value
|
|
||||||
inc(lastBlockBytes)
|
|
||||||
|
|
||||||
w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or (
|
|
||||||
0x80'u32 shl ((3'u32 - uint32(lastBlockBytes and 3)) shl 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
if endCurrentBlock >= 56:
|
|
||||||
innerHash(state, w)
|
|
||||||
clearBuffer(w)
|
|
||||||
|
|
||||||
w[15] = uint32(byteLen) shl 3
|
|
||||||
innerHash(state, w)
|
|
||||||
|
|
||||||
# Store hash in result pointer, and make sure we get in in the correct order
|
|
||||||
# on both endian models.
|
|
||||||
for i in 0 .. Sha1DigestSize-1:
|
|
||||||
result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255)
|
|
||||||
|
|
||||||
proc sha1(src: string): Sha1Digest =
|
|
||||||
## Calculate SHA1 from input string
|
|
||||||
sha1(src, src.len)
|
|
||||||
|
|
||||||
proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
|
|
||||||
proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
|
|
||||||
proc `$`*(self: SecureHash): string =
|
|
||||||
result = ""
|
|
||||||
for v in Sha1Digest(self):
|
|
||||||
result.add(toHex(int(v), 2))
|
|
||||||
|
|
||||||
proc parseSecureHash*(hash: string): SecureHash =
|
|
||||||
for i in 0 ..< Sha1DigestSize:
|
|
||||||
Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
|
|
||||||
|
|
||||||
proc `==`*(a, b: SecureHash): bool =
|
|
||||||
# Not a constant-time comparison, but that's acceptable in this context
|
|
||||||
Sha1Digest(a) == Sha1Digest(b)
|
|
||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
## This module is a deprecated alias for the ``sha1`` module.
|
||||||
let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]")
|
{.deprecated.}
|
||||||
doAssert hash1 == hash1
|
|
||||||
doAssert parseSecureHash($hash1) == hash1
|
include "../std/sha1"
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ when defined(nimdoc):
|
||||||
Timer, ## Timer descriptor is completed
|
Timer, ## Timer descriptor is completed
|
||||||
Signal, ## Signal is raised
|
Signal, ## Signal is raised
|
||||||
Process, ## Process is finished
|
Process, ## Process is finished
|
||||||
Vnode, ## BSD specific file change happens
|
Vnode, ## BSD specific file change
|
||||||
User, ## User event is raised
|
User, ## User event is raised
|
||||||
Error, ## Error happens while waiting, for descriptor
|
Error, ## Error occurred while waiting for descriptor
|
||||||
VnodeWrite, ## NOTE_WRITE (BSD specific, write to file occurred)
|
VnodeWrite, ## NOTE_WRITE (BSD specific, write to file occurred)
|
||||||
VnodeDelete, ## NOTE_DELETE (BSD specific, unlink of file occurred)
|
VnodeDelete, ## NOTE_DELETE (BSD specific, unlink of file occurred)
|
||||||
VnodeExtend, ## NOTE_EXTEND (BSD specific, file extended)
|
VnodeExtend, ## NOTE_EXTEND (BSD specific, file extended)
|
||||||
|
|
@ -69,6 +69,8 @@ when defined(nimdoc):
|
||||||
## An object which holds result for descriptor
|
## An object which holds result for descriptor
|
||||||
fd* : int ## file/socket descriptor
|
fd* : int ## file/socket descriptor
|
||||||
events*: set[Event] ## set of events
|
events*: set[Event] ## set of events
|
||||||
|
errorCode*: OSErrorCode ## additional error code information for
|
||||||
|
## Error events
|
||||||
|
|
||||||
SelectEvent* = object
|
SelectEvent* = object
|
||||||
## An object which holds user defined event
|
## An object which holds user defined event
|
||||||
|
|
@ -79,13 +81,14 @@ when defined(nimdoc):
|
||||||
proc close*[T](s: Selector[T]) =
|
proc close*[T](s: Selector[T]) =
|
||||||
## Closes the selector.
|
## Closes the selector.
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle, events: set[Event],
|
proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
data: T) =
|
events: set[Event], data: T) =
|
||||||
## Registers file/socket descriptor ``fd`` to selector ``s``
|
## Registers file/socket descriptor ``fd`` to selector ``s``
|
||||||
## with events set in ``events``. The ``data`` is application-defined
|
## with events set in ``events``. The ``data`` is application-defined
|
||||||
## data, which will be passed when an event is triggered.
|
## data, which will be passed when an event is triggered.
|
||||||
|
|
||||||
proc updateHandle*[T](s: Selector[T], fd: SocketHandle, events: set[Event]) =
|
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||||
|
events: set[Event]) =
|
||||||
## Update file/socket descriptor ``fd``, registered in selector
|
## Update file/socket descriptor ``fd``, registered in selector
|
||||||
## ``s`` with new events set ``event``.
|
## ``s`` with new events set ``event``.
|
||||||
|
|
||||||
|
|
@ -221,11 +224,15 @@ when defined(nimdoc):
|
||||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||||
## Determines whether selector contains a file descriptor.
|
## Determines whether selector contains a file descriptor.
|
||||||
|
|
||||||
|
proc getFd*[T](s: Selector[T]): int =
|
||||||
|
## Retrieves the underlying selector's file descriptor.
|
||||||
|
##
|
||||||
|
## For *poll* and *select* selectors ``-1`` is returned.
|
||||||
|
|
||||||
else:
|
else:
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
import locks
|
import locks
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
SharedArray[T] = UncheckedArray[T]
|
SharedArray[T] = UncheckedArray[T]
|
||||||
|
|
||||||
|
|
@ -234,7 +241,6 @@ else:
|
||||||
|
|
||||||
proc deallocSharedArray[T](sa: ptr SharedArray[T]) =
|
proc deallocSharedArray[T](sa: ptr SharedArray[T]) =
|
||||||
deallocShared(cast[pointer](sa))
|
deallocShared(cast[pointer](sa))
|
||||||
|
|
||||||
type
|
type
|
||||||
Event* {.pure.} = enum
|
Event* {.pure.} = enum
|
||||||
Read, Write, Timer, Signal, Process, Vnode, User, Error, Oneshot,
|
Read, Write, Timer, Signal, Process, Vnode, User, Error, Oneshot,
|
||||||
|
|
@ -247,6 +253,7 @@ else:
|
||||||
ReadyKey* = object
|
ReadyKey* = object
|
||||||
fd* : int
|
fd* : int
|
||||||
events*: set[Event]
|
events*: set[Event]
|
||||||
|
errorCode*: OSErrorCode
|
||||||
|
|
||||||
SelectorKey[T] = object
|
SelectorKey[T] = object
|
||||||
ident: int
|
ident: int
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||||
i.inc(2) # Skip //
|
i.inc(2) # Skip //
|
||||||
var authority = ""
|
var authority = ""
|
||||||
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
||||||
if authority == "":
|
if authority.len > 0:
|
||||||
raise newException(ValueError, "Expected authority got nothing.")
|
|
||||||
parseAuthority(authority, result)
|
parseAuthority(authority, result)
|
||||||
else:
|
else:
|
||||||
result.opaque = true
|
result.opaque = true
|
||||||
|
|
@ -466,6 +465,15 @@ when isMainModule:
|
||||||
doAssert test.port == "dom96"
|
doAssert test.port == "dom96"
|
||||||
doAssert test.path == "/packages"
|
doAssert test.path == "/packages"
|
||||||
|
|
||||||
|
block:
|
||||||
|
let str = "file:///foo/bar/baz.txt"
|
||||||
|
let test = parseUri(str)
|
||||||
|
doAssert test.scheme == "file"
|
||||||
|
doAssert test.username == ""
|
||||||
|
doAssert test.hostname == ""
|
||||||
|
doAssert test.port == ""
|
||||||
|
doAssert test.path == "/foo/bar/baz.txt"
|
||||||
|
|
||||||
# Remove dot segments tests
|
# Remove dot segments tests
|
||||||
block:
|
block:
|
||||||
doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz"
|
doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz"
|
||||||
|
|
|
||||||
195
lib/std/sha1.nim
Normal file
195
lib/std/sha1.nim
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2015 Nim Contributors
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
const Sha1DigestSize = 20
|
||||||
|
|
||||||
|
type
|
||||||
|
Sha1Digest = array[0 .. Sha1DigestSize-1, uint8]
|
||||||
|
SecureHash* = distinct Sha1Digest
|
||||||
|
|
||||||
|
# Copyright (c) 2011, Micael Hildenborg
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Micael Hildenborg nor the
|
||||||
|
# names of its contributors may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||||
|
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# Ported to Nim by Erik O'Leary
|
||||||
|
|
||||||
|
type
|
||||||
|
Sha1State* = array[0 .. 5-1, uint32]
|
||||||
|
Sha1Buffer = array[0 .. 80-1, uint32]
|
||||||
|
|
||||||
|
template clearBuffer(w: Sha1Buffer, len = 16) =
|
||||||
|
zeroMem(addr(w), len * sizeof(uint32))
|
||||||
|
|
||||||
|
proc init*(result: var Sha1State) =
|
||||||
|
result[0] = 0x67452301'u32
|
||||||
|
result[1] = 0xefcdab89'u32
|
||||||
|
result[2] = 0x98badcfe'u32
|
||||||
|
result[3] = 0x10325476'u32
|
||||||
|
result[4] = 0xc3d2e1f0'u32
|
||||||
|
|
||||||
|
proc innerHash(state: var Sha1State, w: var Sha1Buffer) =
|
||||||
|
var
|
||||||
|
a = state[0]
|
||||||
|
b = state[1]
|
||||||
|
c = state[2]
|
||||||
|
d = state[3]
|
||||||
|
e = state[4]
|
||||||
|
|
||||||
|
var round = 0
|
||||||
|
|
||||||
|
template rot(value, bits: uint32): uint32 =
|
||||||
|
(value shl bits) or (value shr (32u32 - bits))
|
||||||
|
|
||||||
|
template sha1(fun, val: uint32) =
|
||||||
|
let t = rot(a, 5) + fun + e + val + w[round]
|
||||||
|
e = d
|
||||||
|
d = c
|
||||||
|
c = rot(b, 30)
|
||||||
|
b = a
|
||||||
|
a = t
|
||||||
|
|
||||||
|
template process(body: untyped) =
|
||||||
|
w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1)
|
||||||
|
body
|
||||||
|
inc(round)
|
||||||
|
|
||||||
|
template wrap(dest, value: untyped) =
|
||||||
|
let v = dest + value
|
||||||
|
dest = v
|
||||||
|
|
||||||
|
while round < 16:
|
||||||
|
sha1((b and c) or (not b and d), 0x5a827999'u32)
|
||||||
|
inc(round)
|
||||||
|
|
||||||
|
while round < 20:
|
||||||
|
process:
|
||||||
|
sha1((b and c) or (not b and d), 0x5a827999'u32)
|
||||||
|
|
||||||
|
while round < 40:
|
||||||
|
process:
|
||||||
|
sha1(b xor c xor d, 0x6ed9eba1'u32)
|
||||||
|
|
||||||
|
while round < 60:
|
||||||
|
process:
|
||||||
|
sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32)
|
||||||
|
|
||||||
|
while round < 80:
|
||||||
|
process:
|
||||||
|
sha1(b xor c xor d, 0xca62c1d6'u32)
|
||||||
|
|
||||||
|
wrap state[0], a
|
||||||
|
wrap state[1], b
|
||||||
|
wrap state[2], c
|
||||||
|
wrap state[3], d
|
||||||
|
wrap state[4], e
|
||||||
|
|
||||||
|
proc sha1(src: cstring; len: int): Sha1Digest =
|
||||||
|
#Initialize state
|
||||||
|
var state: Sha1State
|
||||||
|
init(state)
|
||||||
|
|
||||||
|
#Create w buffer
|
||||||
|
var w: Sha1Buffer
|
||||||
|
|
||||||
|
#Loop through all complete 64byte blocks.
|
||||||
|
let byteLen = len
|
||||||
|
let endOfFullBlocks = byteLen - 64
|
||||||
|
var endCurrentBlock = 0
|
||||||
|
var currentBlock = 0
|
||||||
|
|
||||||
|
while currentBlock <= endOfFullBlocks:
|
||||||
|
endCurrentBlock = currentBlock + 64
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
while currentBlock < endCurrentBlock:
|
||||||
|
w[i] = uint32(src[currentBlock+3]) or
|
||||||
|
uint32(src[currentBlock+2]) shl 8'u32 or
|
||||||
|
uint32(src[currentBlock+1]) shl 16'u32 or
|
||||||
|
uint32(src[currentBlock]) shl 24'u32
|
||||||
|
currentBlock += 4
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
innerHash(state, w)
|
||||||
|
|
||||||
|
#Handle last and not full 64 byte block if existing
|
||||||
|
endCurrentBlock = byteLen - currentBlock
|
||||||
|
clearBuffer(w)
|
||||||
|
var lastBlockBytes = 0
|
||||||
|
|
||||||
|
while lastBlockBytes < endCurrentBlock:
|
||||||
|
|
||||||
|
var value = uint32(src[lastBlockBytes + currentBlock]) shl
|
||||||
|
((3'u32 - uint32(lastBlockBytes and 3)) shl 3)
|
||||||
|
|
||||||
|
w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value
|
||||||
|
inc(lastBlockBytes)
|
||||||
|
|
||||||
|
w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or (
|
||||||
|
0x80'u32 shl ((3'u32 - uint32(lastBlockBytes and 3)) shl 3)
|
||||||
|
)
|
||||||
|
|
||||||
|
if endCurrentBlock >= 56:
|
||||||
|
innerHash(state, w)
|
||||||
|
clearBuffer(w)
|
||||||
|
|
||||||
|
w[15] = uint32(byteLen) shl 3
|
||||||
|
innerHash(state, w)
|
||||||
|
|
||||||
|
# Store hash in result pointer, and make sure we get in in the correct order
|
||||||
|
# on both endian models.
|
||||||
|
for i in 0 .. Sha1DigestSize-1:
|
||||||
|
result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255)
|
||||||
|
|
||||||
|
proc sha1(src: string): Sha1Digest =
|
||||||
|
## Calculate SHA1 from input string
|
||||||
|
sha1(src, src.len)
|
||||||
|
|
||||||
|
proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
|
||||||
|
proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
|
||||||
|
proc `$`*(self: SecureHash): string =
|
||||||
|
result = ""
|
||||||
|
for v in Sha1Digest(self):
|
||||||
|
result.add(toHex(int(v), 2))
|
||||||
|
|
||||||
|
proc parseSecureHash*(hash: string): SecureHash =
|
||||||
|
for i in 0 ..< Sha1DigestSize:
|
||||||
|
Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
|
||||||
|
|
||||||
|
proc `==`*(a, b: SecureHash): bool =
|
||||||
|
# Not a constant-time comparison, but that's acceptable in this context
|
||||||
|
Sha1Digest(a) == Sha1Digest(b)
|
||||||
|
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]")
|
||||||
|
doAssert hash1 == hash1
|
||||||
|
doAssert parseSecureHash($hash1) == hash1
|
||||||
|
|
@ -1955,13 +1955,13 @@ const
|
||||||
## that you cannot compare a floating point value to this value
|
## that you cannot compare a floating point value to this value
|
||||||
## and expect a reasonable result - use the `classify` procedure
|
## and expect a reasonable result - use the `classify` procedure
|
||||||
## in the module ``math`` for checking for NaN.
|
## in the module ``math`` for checking for NaN.
|
||||||
NimMajor*: int = 0
|
NimMajor* {.intdefine.}: int = 0
|
||||||
## is the major number of Nim's version.
|
## is the major number of Nim's version.
|
||||||
|
|
||||||
NimMinor*: int = 17
|
NimMinor* {.intdefine.}: int = 17
|
||||||
## is the minor number of Nim's version.
|
## is the minor number of Nim's version.
|
||||||
|
|
||||||
NimPatch*: int = 3
|
NimPatch* {.intdefine.}: int = 3
|
||||||
## is the patch number of Nim's version.
|
## is the patch number of Nim's version.
|
||||||
|
|
||||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||||
|
|
@ -3025,9 +3025,9 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
||||||
## Returns true iff `f` is at the end.
|
## Returns true iff `f` is at the end.
|
||||||
|
|
||||||
proc readChar*(f: File): char {.tags: [ReadIOEffect], deprecated.}
|
proc readChar*(f: File): char {.tags: [ReadIOEffect].}
|
||||||
## Reads a single character from the stream `f`. **Deprecated** since
|
## Reads a single character from the stream `f`. Should not be used in
|
||||||
## version 0.16.2. Use some variant of ``readBuffer`` instead.
|
## performance sensitive code.
|
||||||
|
|
||||||
proc flushFile*(f: File) {.tags: [WriteIOEffect].}
|
proc flushFile*(f: File) {.tags: [WriteIOEffect].}
|
||||||
## Flushes `f`'s buffer.
|
## Flushes `f`'s buffer.
|
||||||
|
|
@ -3769,7 +3769,6 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
|
||||||
# by ``assert``.
|
# by ``assert``.
|
||||||
type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect,
|
type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect,
|
||||||
tags: [].}
|
tags: [].}
|
||||||
{.deprecated: [THide: Hide].}
|
|
||||||
Hide(raiseAssert)(msg)
|
Hide(raiseAssert)(msg)
|
||||||
|
|
||||||
template assert*(cond: bool, msg = "") =
|
template assert*(cond: bool, msg = "") =
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ type
|
||||||
slBitmap: array[RealFli, uint32]
|
slBitmap: array[RealFli, uint32]
|
||||||
matrix: array[RealFli, array[MaxSli, PBigChunk]]
|
matrix: array[RealFli, array[MaxSli, PBigChunk]]
|
||||||
llmem: PLLChunk
|
llmem: PLLChunk
|
||||||
currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
|
currMem, maxMem, freeMem, occ: int # memory sizes (allocated from OS)
|
||||||
lastSize: int # needed for the case that OS gives us pages linearly
|
lastSize: int # needed for the case that OS gives us pages linearly
|
||||||
chunkStarts: IntSet
|
chunkStarts: IntSet
|
||||||
root, deleted, last, freeAvlNodes: PAvlNode
|
root, deleted, last, freeAvlNodes: PAvlNode
|
||||||
|
|
@ -421,7 +421,7 @@ const nimMaxHeap {.intdefine.} = 0
|
||||||
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
|
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
|
||||||
when not defined(emscripten):
|
when not defined(emscripten):
|
||||||
if not a.blockChunkSizeIncrease:
|
if not a.blockChunkSizeIncrease:
|
||||||
let usedMem = a.currMem # - a.freeMem
|
let usedMem = a.occ #a.currMem # - a.freeMem
|
||||||
when nimMaxHeap != 0:
|
when nimMaxHeap != 0:
|
||||||
if usedMem > nimMaxHeap * 1024 * 1024:
|
if usedMem > nimMaxHeap * 1024 * 1024:
|
||||||
raiseOutOfMem()
|
raiseOutOfMem()
|
||||||
|
|
@ -567,7 +567,6 @@ proc splitChunk(a: var MemRegion, c: PBigChunk, size: int) =
|
||||||
addChunkToMatrix(a, rest)
|
addChunkToMatrix(a, rest)
|
||||||
|
|
||||||
proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
|
proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
|
||||||
# use first fit for now:
|
|
||||||
sysAssert(size > 0, "getBigChunk 2")
|
sysAssert(size > 0, "getBigChunk 2")
|
||||||
var size = size # roundup(size, PageSize)
|
var size = size # roundup(size, PageSize)
|
||||||
var fl, sl: int
|
var fl, sl: int
|
||||||
|
|
@ -627,6 +626,85 @@ else:
|
||||||
c = c.next
|
c = c.next
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
when false:
|
||||||
|
var
|
||||||
|
rsizes: array[50_000, int]
|
||||||
|
rsizesLen: int
|
||||||
|
|
||||||
|
proc trackSize(size: int) =
|
||||||
|
rsizes[rsizesLen] = size
|
||||||
|
inc rsizesLen
|
||||||
|
|
||||||
|
proc untrackSize(size: int) =
|
||||||
|
for i in 0 .. rsizesLen-1:
|
||||||
|
if rsizes[i] == size:
|
||||||
|
rsizes[i] = rsizes[rsizesLen-1]
|
||||||
|
dec rsizesLen
|
||||||
|
return
|
||||||
|
c_fprintf(stdout, "%ld\n", size)
|
||||||
|
sysAssert(false, "untracked size!")
|
||||||
|
else:
|
||||||
|
template trackSize(x) = discard
|
||||||
|
template untrackSize(x) = discard
|
||||||
|
|
||||||
|
when false:
|
||||||
|
# not yet used by the GCs
|
||||||
|
proc rawTryAlloc(a: var MemRegion; requestedSize: int): pointer =
|
||||||
|
sysAssert(allocInv(a), "rawAlloc: begin")
|
||||||
|
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
|
||||||
|
sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small")
|
||||||
|
var size = roundup(requestedSize, MemAlign)
|
||||||
|
inc a.occ, size
|
||||||
|
trackSize(size)
|
||||||
|
sysAssert(size >= requestedSize, "insufficient allocated size!")
|
||||||
|
#c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
|
||||||
|
if size <= SmallChunkSize-smallChunkOverhead():
|
||||||
|
# allocate a small block: for small chunks, we use only its next pointer
|
||||||
|
var s = size div MemAlign
|
||||||
|
var c = a.freeSmallChunks[s]
|
||||||
|
if c == nil:
|
||||||
|
result = nil
|
||||||
|
else:
|
||||||
|
sysAssert c.size == size, "rawAlloc 6"
|
||||||
|
if c.freeList == nil:
|
||||||
|
sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
|
||||||
|
"rawAlloc 7")
|
||||||
|
result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc)
|
||||||
|
inc(c.acc, size)
|
||||||
|
else:
|
||||||
|
result = c.freeList
|
||||||
|
sysAssert(c.freeList.zeroField == 0, "rawAlloc 8")
|
||||||
|
c.freeList = c.freeList.next
|
||||||
|
dec(c.free, size)
|
||||||
|
sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9")
|
||||||
|
if c.free < size:
|
||||||
|
listRemove(a.freeSmallChunks[s], c)
|
||||||
|
sysAssert(allocInv(a), "rawAlloc: end listRemove test")
|
||||||
|
sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %%
|
||||||
|
size == 0, "rawAlloc 21")
|
||||||
|
sysAssert(allocInv(a), "rawAlloc: end small size")
|
||||||
|
else:
|
||||||
|
inc size, bigChunkOverhead()
|
||||||
|
var fl, sl: int
|
||||||
|
mappingSearch(size, fl, sl)
|
||||||
|
sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk")
|
||||||
|
let c = findSuitableBlock(a, fl, sl)
|
||||||
|
if c != nil:
|
||||||
|
removeChunkFromMatrix2(a, c, fl, sl)
|
||||||
|
if c.size >= size + PageSize:
|
||||||
|
splitChunk(a, c, size)
|
||||||
|
# set 'used' to to true:
|
||||||
|
c.prevSize = 1
|
||||||
|
incl(a, a.chunkStarts, pageIndex(c))
|
||||||
|
dec(a.freeMem, size)
|
||||||
|
result = addr(c.data)
|
||||||
|
sysAssert((cast[ByteAddress](c) and (MemAlign-1)) == 0, "rawAlloc 13")
|
||||||
|
sysAssert((cast[ByteAddress](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary")
|
||||||
|
if a.root == nil: a.root = getBottom(a)
|
||||||
|
add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size)
|
||||||
|
else:
|
||||||
|
result = nil
|
||||||
|
|
||||||
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||||
sysAssert(allocInv(a), "rawAlloc: begin")
|
sysAssert(allocInv(a), "rawAlloc: begin")
|
||||||
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
|
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
|
||||||
|
|
@ -676,6 +754,8 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||||
sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %%
|
sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %%
|
||||||
size == 0, "rawAlloc 21")
|
size == 0, "rawAlloc 21")
|
||||||
sysAssert(allocInv(a), "rawAlloc: end small size")
|
sysAssert(allocInv(a), "rawAlloc: end small size")
|
||||||
|
inc a.occ, size
|
||||||
|
trackSize(c.size)
|
||||||
else:
|
else:
|
||||||
size = requestedSize + bigChunkOverhead() # roundup(requestedSize+bigChunkOverhead(), PageSize)
|
size = requestedSize + bigChunkOverhead() # roundup(requestedSize+bigChunkOverhead(), PageSize)
|
||||||
# allocate a large block
|
# allocate a large block
|
||||||
|
|
@ -687,6 +767,8 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||||
sysAssert((cast[ByteAddress](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary")
|
sysAssert((cast[ByteAddress](c) and PageMask) == 0, "rawAlloc: Not aligned on a page boundary")
|
||||||
if a.root == nil: a.root = getBottom(a)
|
if a.root == nil: a.root = getBottom(a)
|
||||||
add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size)
|
add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size)
|
||||||
|
inc a.occ, c.size
|
||||||
|
trackSize(c.size)
|
||||||
sysAssert(isAccessible(a, result), "rawAlloc 14")
|
sysAssert(isAccessible(a, result), "rawAlloc 14")
|
||||||
sysAssert(allocInv(a), "rawAlloc: end")
|
sysAssert(allocInv(a), "rawAlloc: end")
|
||||||
when logAlloc: cprintf("var pointer_%p = alloc(%ld)\n", result, requestedSize)
|
when logAlloc: cprintf("var pointer_%p = alloc(%ld)\n", result, requestedSize)
|
||||||
|
|
@ -703,6 +785,9 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||||
# `p` is within a small chunk:
|
# `p` is within a small chunk:
|
||||||
var c = cast[PSmallChunk](c)
|
var c = cast[PSmallChunk](c)
|
||||||
var s = c.size
|
var s = c.size
|
||||||
|
dec a.occ, s
|
||||||
|
untrackSize(s)
|
||||||
|
sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case A)"
|
||||||
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
|
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
|
||||||
s == 0, "rawDealloc 3")
|
s == 0, "rawDealloc 3")
|
||||||
var f = cast[ptr FreeCell](p)
|
var f = cast[ptr FreeCell](p)
|
||||||
|
|
@ -733,6 +818,9 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||||
when overwriteFree: c_memset(p, -1'i32, c.size -% bigChunkOverhead())
|
when overwriteFree: c_memset(p, -1'i32, c.size -% bigChunkOverhead())
|
||||||
# free big chunk
|
# free big chunk
|
||||||
var c = cast[PBigChunk](c)
|
var c = cast[PBigChunk](c)
|
||||||
|
dec a.occ, c.size
|
||||||
|
untrackSize(c.size)
|
||||||
|
sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case B)"
|
||||||
a.deleted = getBottom(a)
|
a.deleted = getBottom(a)
|
||||||
del(a, a.root, cast[int](addr(c.data)))
|
del(a, a.root, cast[int](addr(c.data)))
|
||||||
freeBigChunk(a, c)
|
freeBigChunk(a, c)
|
||||||
|
|
@ -851,7 +939,8 @@ proc deallocOsPages(a: var MemRegion) =
|
||||||
proc getFreeMem(a: MemRegion): int {.inline.} = result = a.freeMem
|
proc getFreeMem(a: MemRegion): int {.inline.} = result = a.freeMem
|
||||||
proc getTotalMem(a: MemRegion): int {.inline.} = result = a.currMem
|
proc getTotalMem(a: MemRegion): int {.inline.} = result = a.currMem
|
||||||
proc getOccupiedMem(a: MemRegion): int {.inline.} =
|
proc getOccupiedMem(a: MemRegion): int {.inline.} =
|
||||||
result = a.currMem - a.freeMem
|
result = a.occ
|
||||||
|
# a.currMem - a.freeMem
|
||||||
|
|
||||||
# ---------------------- thread memory region -------------------------------
|
# ---------------------- thread memory region -------------------------------
|
||||||
|
|
||||||
|
|
@ -893,7 +982,7 @@ template instantiateForRegion(allocator: untyped) =
|
||||||
#sysAssert(result == countFreeMem())
|
#sysAssert(result == countFreeMem())
|
||||||
|
|
||||||
proc getTotalMem(): int = return allocator.currMem
|
proc getTotalMem(): int = return allocator.currMem
|
||||||
proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
|
proc getOccupiedMem(): int = return allocator.occ #getTotalMem() - getFreeMem()
|
||||||
proc getMaxMem*(): int = return getMaxMem(allocator)
|
proc getMaxMem*(): int = return getMaxMem(allocator)
|
||||||
|
|
||||||
# -------------------- shared heap region ----------------------------------
|
# -------------------- shared heap region ----------------------------------
|
||||||
|
|
@ -944,7 +1033,8 @@ template instantiateForRegion(allocator: untyped) =
|
||||||
sharedMemStatsShared(sharedHeap.currMem)
|
sharedMemStatsShared(sharedHeap.currMem)
|
||||||
|
|
||||||
proc getOccupiedSharedMem(): int =
|
proc getOccupiedSharedMem(): int =
|
||||||
sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
|
sharedMemStatsShared(sharedHeap.occ)
|
||||||
|
#sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
|
||||||
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
||||||
|
|
||||||
# forward declarations:
|
# forward declarations:
|
||||||
proc collectCT(gch: var GcHeap) {.benign.}
|
proc collectCT(gch: var GcHeap; size: int) {.benign.}
|
||||||
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
|
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
|
||||||
proc doOperation(p: pointer, op: WalkOp) {.benign.}
|
proc doOperation(p: pointer, op: WalkOp) {.benign.}
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
||||||
|
|
@ -277,7 +277,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||||
incTypeSize typ, size
|
incTypeSize typ, size
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch, size + sizeof(Cell))
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
# now it is buffered in the ZCT
|
# now it is buffered in the ZCT
|
||||||
|
|
@ -332,7 +332,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch, newsize + sizeof(Cell))
|
||||||
var ol = usrToCell(old)
|
var ol = usrToCell(old)
|
||||||
sysAssert(ol.typ != nil, "growObj: 1")
|
sysAssert(ol.typ != nil, "growObj: 1")
|
||||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||||
|
|
@ -494,8 +494,9 @@ proc collectCTBody(gch: var GcHeap) =
|
||||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||||
|
|
||||||
proc collectCT(gch: var GcHeap) =
|
proc collectCT(gch: var GcHeap; size: int) =
|
||||||
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
|
if (getOccupiedMem(gch.region) >= gch.cycleThreshold or
|
||||||
|
size > getFreeMem(gch.region)) and gch.recGcLock == 0:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
|
|
@ -530,7 +531,7 @@ when not defined(useNimRtl):
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
var oldThreshold = gch.cycleThreshold
|
var oldThreshold = gch.cycleThreshold
|
||||||
gch.cycleThreshold = 0 # forces cycle collection
|
gch.cycleThreshold = 0 # forces cycle collection
|
||||||
collectCT(gch)
|
collectCT(gch, 0)
|
||||||
gch.cycleThreshold = oldThreshold
|
gch.cycleThreshold = oldThreshold
|
||||||
release(gch)
|
release(gch)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,22 @@ when not declared(c_fwrite):
|
||||||
# C routine that is used here:
|
# C routine that is used here:
|
||||||
proc c_fread(buf: pointer, size, n: csize, f: File): csize {.
|
proc c_fread(buf: pointer, size, n: csize, f: File): csize {.
|
||||||
importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
|
importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
|
||||||
proc c_fseek(f: File, offset: clong, whence: cint): cint {.
|
when defined(windows):
|
||||||
|
when not defined(amd64):
|
||||||
|
proc c_fseek(f: File, offset: int64, whence: cint): cint {.
|
||||||
importc: "fseek", header: "<stdio.h>", tags: [].}
|
importc: "fseek", header: "<stdio.h>", tags: [].}
|
||||||
proc c_ftell(f: File): clong {.
|
proc c_ftell(f: File): int64 {.
|
||||||
importc: "ftell", header: "<stdio.h>", tags: [].}
|
importc: "ftell", header: "<stdio.h>", tags: [].}
|
||||||
|
else:
|
||||||
|
proc c_fseek(f: File, offset: int64, whence: cint): cint {.
|
||||||
|
importc: "_fseeki64", header: "<stdio.h>", tags: [].}
|
||||||
|
proc c_ftell(f: File): int64 {.
|
||||||
|
importc: "_ftelli64", header: "<stdio.h>", tags: [].}
|
||||||
|
else:
|
||||||
|
proc c_fseek(f: File, offset: int64, whence: cint): cint {.
|
||||||
|
importc: "fseeko", header: "<stdio.h>", tags: [].}
|
||||||
|
proc c_ftell(f: File): int64 {.
|
||||||
|
importc: "ftello", header: "<stdio.h>", tags: [].}
|
||||||
proc c_ferror(f: File): cint {.
|
proc c_ferror(f: File): cint {.
|
||||||
importc: "ferror", header: "<stdio.h>", tags: [].}
|
importc: "ferror", header: "<stdio.h>", tags: [].}
|
||||||
proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
|
proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
|
||||||
|
|
@ -210,12 +222,12 @@ proc readAllBuffer(file: File): string =
|
||||||
result.add(buffer)
|
result.add(buffer)
|
||||||
break
|
break
|
||||||
|
|
||||||
proc rawFileSize(file: File): int =
|
proc rawFileSize(file: File): int64 =
|
||||||
# this does not raise an error opposed to `getFileSize`
|
# this does not raise an error opposed to `getFileSize`
|
||||||
var oldPos = c_ftell(file)
|
var oldPos = c_ftell(file)
|
||||||
discard c_fseek(file, 0, 2) # seek the end of the file
|
discard c_fseek(file, 0, 2) # seek the end of the file
|
||||||
result = c_ftell(file)
|
result = c_ftell(file)
|
||||||
discard c_fseek(file, clong(oldPos), 0)
|
discard c_fseek(file, oldPos, 0)
|
||||||
|
|
||||||
proc endOfFile(f: File): bool =
|
proc endOfFile(f: File): bool =
|
||||||
var c = c_fgetc(f)
|
var c = c_fgetc(f)
|
||||||
|
|
@ -223,7 +235,7 @@ proc endOfFile(f: File): bool =
|
||||||
return c < 0'i32
|
return c < 0'i32
|
||||||
#result = c_feof(f) != 0
|
#result = c_feof(f) != 0
|
||||||
|
|
||||||
proc readAllFile(file: File, len: int): string =
|
proc readAllFile(file: File, len: int64): string =
|
||||||
# We acquire the filesize beforehand and hope it doesn't change.
|
# We acquire the filesize beforehand and hope it doesn't change.
|
||||||
# Speeds things up.
|
# Speeds things up.
|
||||||
result = newString(len)
|
result = newString(len)
|
||||||
|
|
@ -363,7 +375,7 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
|
||||||
result = f != nil
|
result = f != nil
|
||||||
|
|
||||||
proc setFilePos(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) =
|
proc setFilePos(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) =
|
||||||
if c_fseek(f, clong(pos), cint(relativeTo)) != 0:
|
if c_fseek(f, pos, cint(relativeTo)) != 0:
|
||||||
raiseEIO("cannot set file position")
|
raiseEIO("cannot set file position")
|
||||||
|
|
||||||
proc getFilePos(f: File): int64 =
|
proc getFilePos(f: File): int64 =
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -95,6 +95,7 @@ This project exists thanks to all the people who contribute. [Read on to find ou
|
||||||
[](#backers) [](#sponsors)
|
[](#backers) [](#sponsors)
|
||||||
[![Setup a bounty via Bountysource][badge-nim-bountysource]][nim-bountysource]
|
[![Setup a bounty via Bountysource][badge-nim-bountysource]][nim-bountysource]
|
||||||
[![Donate Bitcoins][badge-nim-bitcoin]][nim-bitcoin]
|
[![Donate Bitcoins][badge-nim-bitcoin]][nim-bitcoin]
|
||||||
|
[](https://www.codetriage.com/nim-lang/nim)
|
||||||
|
|
||||||
We welcome all contributions to Nim regardless of how small or large
|
We welcome all contributions to Nim regardless of how small or large
|
||||||
they are. Everything from spelling fixes to new modules to be included in the
|
they are. Everything from spelling fixes to new modules to be included in the
|
||||||
|
|
|
||||||
9
tests/ccgbugs/t7079.nim
Normal file
9
tests/ccgbugs/t7079.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
discard """
|
||||||
|
action: run
|
||||||
|
targets: '''c js'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
let x = -0.0
|
||||||
|
doAssert classify(x) == fcNegZero
|
||||||
|
doAssert classify(1 / -0.0) == fcNegInf
|
||||||
|
|
@ -1,25 +1,48 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "type mismatch: got (Bar[system.int])"
|
errormsg: "type mismatch: got (Bar[system.int])"
|
||||||
nimout: '''
|
nimout: '''
|
||||||
t3330.nim(40, 4) Error: type mismatch: got (Bar[system.int])
|
t3330.nim(63, 4) Error: type mismatch: got (Bar[system.int])
|
||||||
but expected one of:
|
but expected one of:
|
||||||
proc test(foo: Foo[int])
|
proc test(foo: Foo[int])
|
||||||
t3330.nim(25, 8) Hint: Non-matching candidates for add(k, string, T)
|
t3330.nim(48, 8) Hint: Non-matching candidates for add(k, string, T)
|
||||||
proc add(x: var string; y: string)
|
proc add(x: var string; y: string)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var string
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
proc add(x: var string; y: char)
|
proc add(x: var string; y: char)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var string
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
proc add(result: var string; x: int64)
|
proc add(result: var string; x: int64)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var string
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
proc add(result: var string; x: float)
|
proc add(result: var string; x: float)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var string
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
proc add(x: var string; y: cstring)
|
proc add(x: var string; y: cstring)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var string
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
proc add[T](x: var seq[T]; y: openArray[T])
|
proc add[T](x: var seq[T]; y: openArray[T])
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var seq[T]
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
proc add[T](x: var seq[T]; y: T)
|
proc add[T](x: var seq[T]; y: T)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: var seq[T]
|
||||||
|
but expression 'k' is of type: Alias
|
||||||
|
|
||||||
t3330.nim(25, 8) template/generic instantiation from here
|
t3330.nim(48, 8) template/generic instantiation from here
|
||||||
t3330.nim(32, 6) Foo: 'bar.value' cannot be assigned to
|
t3330.nim(55, 6) Foo: 'bar.value' cannot be assigned to
|
||||||
t3330.nim(25, 8) template/generic instantiation from here
|
t3330.nim(48, 8) template/generic instantiation from here
|
||||||
t3330.nim(33, 6) Foo: 'bar.x' cannot be assigned to
|
t3330.nim(56, 6) Foo: 'bar.x' cannot be assigned to
|
||||||
'''
|
|
||||||
|
expression: test(bar)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Foo[T] = concept k
|
Foo[T] = concept k
|
||||||
add(k, string, T)
|
add(k, string, T)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 10
|
line: 10
|
||||||
errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded'''
|
errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded; start of expression here: tneedsdiscard.nim(7, 2)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc p =
|
proc p =
|
||||||
|
|
|
||||||
22
tests/errmsgs/tdetailed_position.nim
Normal file
22
tests/errmsgs/tdetailed_position.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
discard """
|
||||||
|
cmd: "nim check $file"
|
||||||
|
errormsg: "type mismatch: got (int literal(1), int literal(2), int literal(3))"
|
||||||
|
nimout: '''
|
||||||
|
but expected one of:
|
||||||
|
proc main(a, b, c: string)
|
||||||
|
first type mismatch at position: 1
|
||||||
|
required type: string
|
||||||
|
but expression '1' is of type: int literal(1)
|
||||||
|
|
||||||
|
expression: main(1, 2, 3)
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
const
|
||||||
|
myconst = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
proc main(a, b, c: string) {.deprecated: "use foo " & "instead " & myconst.} =
|
||||||
|
return
|
||||||
|
|
||||||
|
main(1, 2, 3)
|
||||||
11
tests/errmsgs/twrongcolon.nim
Normal file
11
tests/errmsgs/twrongcolon.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "in expression '("
|
||||||
|
nimout: '''
|
||||||
|
Error: in expression '(
|
||||||
|
890)': identifier expected, but found ''
|
||||||
|
'''
|
||||||
|
|
||||||
|
line: 11
|
||||||
|
"""
|
||||||
|
|
||||||
|
var n: int : 890
|
||||||
|
|
@ -21,5 +21,13 @@ proc test2() =
|
||||||
testTemplate(Exception)
|
testTemplate(Exception)
|
||||||
doAssert(not declared(foobar))
|
doAssert(not declared(foobar))
|
||||||
|
|
||||||
|
|
||||||
|
proc testTryAsExpr(i: int) =
|
||||||
|
let x = try: i
|
||||||
|
except ValueError as ex:
|
||||||
|
echo(ex.msg)
|
||||||
|
-1
|
||||||
|
|
||||||
test[Exception]()
|
test[Exception]()
|
||||||
test2()
|
test2()
|
||||||
|
testTryAsExpr(5)
|
||||||
|
|
|
||||||
12
tests/generics/tspecial_numeric_inference.nim
Normal file
12
tests/generics/tspecial_numeric_inference.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
output: '''int64
|
||||||
|
int64'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
proc `@`[T: SomeInteger](x, y: T): T = x
|
||||||
|
|
||||||
|
echo(type(5'i64 @ 6'i32))
|
||||||
|
|
||||||
|
echo(type(5'i32 @ 6'i64))
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
unittest, osproc, streams, os
|
unittest, osproc, streams, os, strformat
|
||||||
const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
|
const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
|
||||||
const TEST_FILE = "tests/testdata/string.txt"
|
const TEST_FILE = "tests/testdata/string.txt"
|
||||||
|
|
||||||
|
|
@ -23,3 +23,26 @@ suite "io":
|
||||||
test "file":
|
test "file":
|
||||||
check:
|
check:
|
||||||
readFile(TEST_FILE) == STRING_DATA
|
readFile(TEST_FILE) == STRING_DATA
|
||||||
|
|
||||||
|
|
||||||
|
proc verifyFileSize(sz: int64) =
|
||||||
|
# issue 7121, large file size (2-4GB and >4Gb)
|
||||||
|
const fn = "tmpfile112358"
|
||||||
|
let size_in_mb = sz div 1_000_000
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
discard execProcess(&"fsutil file createnew {fn} {sz}" )
|
||||||
|
else:
|
||||||
|
discard execProcess(&"dd if=/dev/zero of={fn} bs=1000000 count={size_in_mb}")
|
||||||
|
|
||||||
|
doAssert os.getFileSize(fn) == sz # Verify OS filesize by string
|
||||||
|
|
||||||
|
var f = open(fn)
|
||||||
|
doAssert f.getFileSize() == sz # Verify file handle filesize
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
os.removeFile(fn)
|
||||||
|
|
||||||
|
#disable tests for automatic testers
|
||||||
|
#for s in [50_000_000'i64, 3_000_000_000, 5_000_000_000]:
|
||||||
|
# verifyFileSize(s)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ when haveZipLib:
|
||||||
|
|
||||||
import
|
import
|
||||||
os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation,
|
os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation,
|
||||||
securehash
|
std / sha1
|
||||||
|
|
||||||
const
|
const
|
||||||
maxOS = 20 # max number of OSes
|
maxOS = 20 # max number of OSes
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ srcdoc2: "pure/asyncfile;pure/asyncftpclient;pure/lenientops"
|
||||||
srcdoc2: "pure/md5;pure/rationals"
|
srcdoc2: "pure/md5;pure/rationals"
|
||||||
srcdoc2: "posix/posix;pure/distros;pure/oswalkdir"
|
srcdoc2: "posix/posix;pure/distros;pure/oswalkdir"
|
||||||
srcdoc2: "pure/collections/heapqueue"
|
srcdoc2: "pure/collections/heapqueue"
|
||||||
srcdoc2: "pure/fenv;pure/securehash;impure/rdstdin;pure/strformat"
|
srcdoc2: "pure/fenv;std/sha1;impure/rdstdin;pure/strformat"
|
||||||
srcdoc2: "pure/segfaults"
|
srcdoc2: "pure/segfaults"
|
||||||
srcdoc2: "pure/basic2d;pure/basic3d;pure/mersenne;pure/coro;pure/httpcore"
|
srcdoc2: "pure/basic2d;pure/basic3d;pure/mersenne;pure/coro;pure/httpcore"
|
||||||
srcdoc2: "pure/bitops;pure/nimtracker;pure/punycode;pure/volatile;js/asyncjs"
|
srcdoc2: "pure/bitops;pure/nimtracker;pure/punycode;pure/volatile;js/asyncjs"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue