Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq
2018-02-09 16:38:53 +01:00
64 changed files with 853 additions and 2036 deletions

View File

@@ -12,6 +12,15 @@
`getBool`, `getFloat`, `getBiggestInt`. Also `getInt` procedure was added.
- `reExtended` is no longer default for the `re` constructor in the `re`
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
preferred over unconstrained generics. (Bug #6526)
- 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
other programming languages. The new platform specific newline escape sequence is
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``.

View File

@@ -10,7 +10,7 @@
# abstract syntax tree + symbol table
import
msgs, hashes, nversion, options, strutils, securehash, ropes, idents,
msgs, hashes, nversion, options, strutils, std / sha1, ropes, idents,
intsets, idgen
type

View File

@@ -970,7 +970,8 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
discard cgsym(m, "TNimType")
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:
typename = "anon ref object from " & $origType.skipTypes(skipPtrs).sym.info
addf(m.s[cfsTypeInit3], "$1.name = $2;$n",

View File

@@ -11,7 +11,7 @@
import
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,
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel, tables, sets, ndi
@@ -908,7 +908,6 @@ proc addIntTypes(result: var Rope) {.inline.} =
platform.CPU[targetCPU].intSize.rope])
proc getCopyright(cfile: Cfile): Rope =
const copyrightYear = "2017"
if optCompileOnly in gGlobalOptions:
result = ("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) " & copyrightYear & " Andreas Rumpf */$N" &

View File

@@ -54,7 +54,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
const
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
Usage = slurp"../doc/basicopt.txt".replace("//", "")

View File

@@ -14,7 +14,7 @@
import
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
securehash, streams
std / sha1, streams
#from debuginfo import writeDebugInfo

View File

@@ -9,7 +9,7 @@
## 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) =
result[0] = ""

View File

@@ -11,7 +11,7 @@
import
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 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")
if sfDeprecated in result.flags:
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) =
let m = myImportModule(c, it)

View File

@@ -31,7 +31,7 @@ implements the required case distinction.
import
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,
intsets, cgmeth, lowerings
@@ -2284,11 +2284,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr
of nkFloatLit..nkFloat64Lit:
let f = n.floatVal
if f != f: r.res = rope"NaN"
elif f == 0.0: r.res = rope"0.0"
elif f == 0.5 * f:
if f > 0.0: r.res = rope"Infinity"
else: r.res = rope"-Infinity"
case classify(f)
of fcNaN:
r.res = rope"NaN"
of fcNegZero:
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)
r.kind = resExpr
of nkCallKinds:
@@ -2390,7 +2396,7 @@ proc genHeader(target: TTarget): Rope =
if target == targetJS:
result = (
"/* 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 excHandler = 0;$n" &
"var lastJSError = null;$n" &
@@ -2406,7 +2412,7 @@ proc genHeader(target: TTarget): Rope =
else:
result = ("<?php$n" &
"/* Generated by the Nim Compiler v$1 */$n" &
"/* (c) 2017 Andreas Rumpf */$n$n" &
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
"$$framePtr = null;$n" &
"$$excHandler = 0;$n" &
"$$lastJSError = null;$n") %
@@ -2464,7 +2470,7 @@ proc genClass(obj: PType; content: Rope; ext: string) =
else: nil
let result = ("<?php$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" &
"class $#$# {$n$#$n}$n") %
[rope(VersionAsString), cls, extends, content]

View File

@@ -10,7 +10,7 @@
## Implements the module handling, including the caching of modules.
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
when false:

View File

@@ -26,7 +26,7 @@ type
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
errExceptionExpected, errExceptionAlreadyHandled,
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
@@ -370,7 +370,7 @@ const
errXhasSideEffects: "\'$1\' can have side effects",
errIteratorExpected: "iterator within for loop context expected",
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",
errIllegalCaptureX: "illegal capture '$1'",
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
@@ -1025,6 +1025,9 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
handleError(msg, eh, s)
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)
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =

View File

@@ -18,6 +18,7 @@ const
newScopeForIf* = true
useCaas* = not defined(noCaas)
noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
copyrightYear* = "2018"
type # please make sure we have under 32 options
# (improves code efficiency a lot!)

View File

@@ -914,7 +914,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
optInd(p, result)
addSon(result, parseTypeDesc(p))
else:
addSon(result, ast.emptyNode)
addSon(result, newNodeP(nkEmpty, p))
if p.tok.tokType != tkEquals and withBothOptional notin flags:
parMessage(p, errColonOrEqualsExpected, p.tok)
if p.tok.tokType == tkEquals:
@@ -922,7 +922,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
optInd(p, result)
addSon(result, parseExpr(p))
else:
addSon(result, ast.emptyNode)
addSon(result, newNodeP(nkEmpty, p))
proc parseTuple(p: var TParser, indentAllowed = false): PNode =
#| inlTupleDecl = 'tuple'

View File

@@ -658,7 +658,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
proc semCustomPragma(c: PContext, n: PNode): PNode =
assert(n.kind in nkPragmaCallKinds + {nkIdent})
if n.kind == nkIdent:
result = newTree(nkCall, n)
elif n.kind == nkExprColonExpr:
@@ -667,14 +667,15 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
else:
result = n
result = c.semOverloadedCall(c, result, n, {skTemplate}, {})
if sfCustomPragma notin result[0].sym.flags:
let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
if r.isNil or sfCustomPragma notin r[0].sym.flags:
invalidPragma(n)
if n.kind == nkIdent:
result = result[0]
elif n.kind == nkExprColonExpr:
result.kind = n.kind # pragma(arg) -> pragma: arg
else:
result = r
if n.kind == nkIdent:
result = result[0]
elif n.kind == nkExprColonExpr:
result.kind = n.kind # pragma(arg) -> pragma: arg
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool =
@@ -809,7 +810,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wExplain:
sym.flags.incl sfExplain
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)
else: incl(c.module.flags, sfDeprecated)
of wVarargs:
@@ -1016,7 +1020,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
else: sym.flags.incl sfUsed
of wLiftLocals: discard
else: invalidPragma(it)
else:
else:
n.sons[i] = semCustomPragma(c, it)

View File

@@ -90,7 +90,7 @@
import
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
TReasonForRecompile* = enum ## all the reasons that can trigger recompilation

View File

@@ -8,18 +8,22 @@
#
## 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 toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
if f != f:
case classify(f)
of fcNaN:
result = "NAN"
elif f == 0.0:
of fcNegZero:
result = "-0.0" & literalPostfix
of fcZero:
result = "0.0" & literalPostfix
elif f == 0.5 * f:
if f > 0.0: result = "INF"
else: result = "-INF"
of fcInf:
result = "INF"
of fcNegInf:
result = "-INF"
else:
when defined(nimNoArrayToCstringConversion):
result = newString(81)

View File

@@ -13,7 +13,7 @@
import
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
from modulegraphs import ModuleGraph

View File

@@ -215,12 +215,17 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
let t = typeAllowed(typ, kind)
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, flags)
if t != nil:
if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
else: localError(info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) & "'")
if t == typ:
localError(info, "invalid type: '" & 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.} =
typeAllowedCheck(typ.n.info, typ, skProc)

View File

@@ -106,6 +106,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
errors.safeAdd(CandidateError(
sym: sym,
unmatchedVarParam: int z.mutabilityProblem,
firstMismatch: z.firstMismatch,
diagnostics: z.diagnostics))
else:
# Symbol table has been modified. Restart and pre-calculate all syms
@@ -154,7 +155,20 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
else:
add(candidates, err.sym.getProcHeader(prefer))
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 '" &
renderTree(n[err.unmatchedVarParam]) & "' is immutable\n")
for diag in err.diagnostics:
@@ -189,7 +203,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
while symx != nil:
if symx.kind in routineKinds:
errors.add(CandidateError(sym: symx,
unmatchedVarParam: 0,
unmatchedVarParam: 0, firstMismatch: 0,
diagnostics: nil))
symx = nextOverloadIter(o, c, headSymbol)
if errors.len == 0:
@@ -263,9 +277,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
if overloadsState == csEmpty and result.state == csEmpty:
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:
localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f).s)
localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f, n).s)
return
elif result.state != csMatch:
if nfExprCall in n.flags:

View File

@@ -225,6 +225,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mDivF64:
if getFloat(b) == 0.0:
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(getFloat(a) / getFloat(b), n)

View File

@@ -260,6 +260,10 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newNodeIT(nkObjConstr, n.info, t)
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})
if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink})
if t.kind != tyObject:

View File

@@ -593,17 +593,14 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
notNilCheck(tracked, n, paramType)
proc breaksBlock(n: PNode): bool =
case n.kind
of nkStmtList, nkStmtListExpr:
for c in n:
if breaksBlock(c): return true
of nkBreakStmt, nkReturnStmt, nkRaiseStmt:
return true
of nkCallKinds:
if n.sons[0].kind == nkSym and sfNoReturn in n.sons[0].sym.flags:
return true
else:
discard
# sematic check doesn't allow statements after raise, break, return or
# call to noreturn proc, so it is safe to check just the last statements
var it = n
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon
result = it.kind in {nkBreakStmt, nkReturnStmt, nkRaiseStmt} or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
proc trackCase(tracked: PEffects, n: PNode) =
track(tracked, n.sons[0])
@@ -747,7 +744,7 @@ proc track(tracked: PEffects, n: PNode) =
# may not look like an assignment, but it is:
let arg = n.sons[1]
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
n[2].intVal == 0:
# var s: seq[notnil]; newSeq(s, 0) is a special case!

View File

@@ -150,9 +150,12 @@ proc discardCheck(c: PContext, result: PNode) =
while n.kind in skipForDiscardable: n = n.lastSon
var s = "expression '" & $n & "' is of type '" &
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:
s.add "; for a function call use ()"
localError(n.info, s)
localError(n.info, s)
proc semIf(c: PContext, n: PNode): PNode =
result = n
@@ -531,7 +534,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
# this can only happen for errornous var statements:
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)
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
if a.kind == nkVarTuple:

View File

@@ -24,7 +24,7 @@ type
CandidateError* = object
sym*: PSym
unmatchedVarParam*: int
unmatchedVarParam*, firstMismatch*: int
diagnostics*: seq[string]
CandidateErrors* = seq[CandidateError]
@@ -67,7 +67,9 @@ type
# or when the explain pragma is used. may be
# triggered with an idetools command in the
# 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
trDontBind
@@ -913,6 +915,25 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
else:
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,
flags: TTypeRelFlags = {}): TTypeRelation =
# typeRel can be used to establish various relationships between types:
@@ -1602,9 +1623,16 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
elif x.kind == tyGenericParam:
result = isGeneric
else:
result = typeRel(c, x, a) # check if it fits
if result > isGeneric: result = isGeneric
# 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:
result = typeRel(c, x, a) # check if it fits
if result > isGeneric: result = isGeneric
of tyStatic:
let prev = PType(idTableGet(c.bindings, f))
if prev == nil:
@@ -1833,8 +1861,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
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
m.calleeSym.kind in {skMacro, skTemplate}:
m.calleeSym.kind in {skMacro, skTemplate}:
# XXX: duplicating this is ugly, but we cannot (!) move this
# directly into typeRel using return-like templates
incMatches(m, r)
@@ -2220,6 +2251,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
n.sons[a], nOrig.sons[a])
if arg == nil:
m.state = csNoMatch
m.firstMismatch = f
return
if m.baseTypeMatch:
#assert(container == nil)
@@ -2274,6 +2306,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
else:
# no default value
m.state = csNoMatch
m.firstMismatch = f
break
else:
# use default value:

View File

@@ -33,6 +33,7 @@
# included from sigmatch.nim
import algorithm, prefixmatches
from wordrecg import wDeprecated
when defined(nimsuggest):
import passes, tables # importer
@@ -479,12 +480,23 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in
isDecl:
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) =
incl(s.flags, sfUsed)
if s.kind == skEnumField and s.owner != nil:
incl(s.owner.flags, sfUsed)
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)
when defined(nimsuggest):
suggestSym(info, s, usageSym, false)

View File

@@ -716,7 +716,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
result = transformSons(c, n)
if n[0].isInfixAs():
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())`
# -> getCurrentException()
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))

View File

@@ -118,7 +118,7 @@ proc isRange*(n: PNode): bool {.inline.} =
result = true
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)
proc unnestStmts(n, result: PNode) =

View File

@@ -1058,11 +1058,12 @@ proc commonSuperclass*(a, b: PType): PType =
y = y.sons[0]
type
TTypeAllowedFlag = enum
TTypeAllowedFlag* = enum
taField,
taHeap
taHeap,
taConcept
TTypeAllowedFlags = set[TTypeAllowedFlag]
TTypeAllowedFlags* = set[TTypeAllowedFlag]
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
flags: TTypeAllowedFlags = {}): PType
@@ -1130,7 +1131,10 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
of tyVoid:
if taField notin flags: result = t
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,
tyNone, tyForward, tyFromExpr:
result = t
@@ -1178,11 +1182,11 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = nil
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
# wrong!
var marker = initIntSet()
result = typeAllowedAux(marker, t, kind, {})
result = typeAllowedAux(marker, t, kind, flags)
proc align(address, alignment: BiggestInt): BiggestInt =
result = (address + (alignment - 1)) and not (alignment - 1)

View File

@@ -384,7 +384,7 @@ Cryptography and Hashing
* `base64 <base64.html>`_
This module implements a base64 encoder and decoder.
* `securehash <securehash.html>`_
* `sha1 <sha1.html>`_
This module implements a sha1 encoder and decoder.

View File

@@ -63,6 +63,8 @@ The following example shows a generic binary tree can be modelled:
for str in preorder(root):
stdout.writeLine(str)
The ``T`` is called a `generic type parameter`:idx:.
Is operator
-----------
@@ -314,7 +316,7 @@ The concept types can be parametric just like the regular generic types:
.. code-block:: nim
### matrixalgo.nim
import typetraits
type
@@ -360,7 +362,7 @@ The concept types can be parametric just like the regular generic types:
template Rows*(M: type Matrix): expr = M.M
template Cols*(M: type Matrix): expr = M.N
template ValueType*(M: type Matrix): typedesc = M.T
-------------
### usage.nim
@@ -582,60 +584,61 @@ the concept body:
proc log(format: static[string], varargs[distinct StringRef])
VTable types
------------
..
VTable types
------------
Concepts allow Nim to define a great number of algorithms, using only
static polymorphism and without erasing any type information or sacrificing
any execution speed. But when polymorphic collections of objects are required,
the user must use one of the provided type erasure techniques - either common
base types or VTable types.
Concepts allow Nim to define a great number of algorithms, using only
static polymorphism and without erasing any type information or sacrificing
any execution speed. But when polymorphic collections of objects are required,
the user must use one of the provided type erasure techniques - either common
base types or VTable types.
VTable types are represented as "fat pointers" storing a reference to an
object together with a reference to a table of procs implementing a set of
required operations (the so called vtable).
VTable types are represented as "fat pointers" storing a reference to an
object together with a reference to a table of procs implementing a set of
required operations (the so called vtable).
In contrast to other programming languages, the vtable in Nim is stored
externally to the object, allowing you to create multiple different vtable
views for the same object. Thus, the polymorphism in Nim is unbounded -
any type can implement an unlimited number of protocols or interfaces not
originally envisioned by the type's author.
In contrast to other programming languages, the vtable in Nim is stored
externally to the object, allowing you to create multiple different vtable
views for the same object. Thus, the polymorphism in Nim is unbounded -
any type can implement an unlimited number of protocols or interfaces not
originally envisioned by the type's author.
Any concept type can be turned into a VTable type by using the ``vtref``
or the ``vtptr`` compiler magics. Under the hood, these magics generate
a converter type class, which converts the regular instances of the matching
types to the corresponding VTable type.
Any concept type can be turned into a VTable type by using the ``vtref``
or the ``vtptr`` compiler magics. Under the hood, these magics generate
a converter type class, which converts the regular instances of the matching
types to the corresponding VTable type.
.. code-block:: nim
type
IntEnumerable = vtref Enumerable[int]
.. code-block:: nim
type
IntEnumerable = vtref Enumerable[int]
MyObject = object
enumerables: seq[IntEnumerable]
streams: seq[OutputStream.vtref]
MyObject = object
enumerables: seq[IntEnumerable]
streams: seq[OutputStream.vtref]
proc addEnumerable(o: var MyObject, e: IntEnumerable) =
o.enumerables.add e
proc addEnumerable(o: var MyObject, e: IntEnumerable) =
o.enumerables.add e
proc addStream(o: var MyObject, e: OutputStream.vtref) =
o.streams.add e
proc addStream(o: var MyObject, e: OutputStream.vtref) =
o.streams.add e
The procs that will be included in the vtable are derived from the concept
body and include all proc calls for which all param types were specified as
concrete types. All such calls should include exactly one param of the type
matched against the concept (not necessarily in the first position), which
will be considered the value bound to the vtable.
The procs that will be included in the vtable are derived from the concept
body and include all proc calls for which all param types were specified as
concrete types. All such calls should include exactly one param of the type
matched against the concept (not necessarily in the first position), which
will be considered the value bound to the vtable.
Overloads will be created for all captured procs, accepting the vtable type
in the position of the captured underlying object.
Overloads will be created for all captured procs, accepting the vtable type
in the position of the captured underlying object.
Under these rules, it's possible to obtain a vtable type for a concept with
unbound type parameters or one instantiated with metatypes (type classes),
but it will include a smaller number of captured procs. A completely empty
vtable will be reported as an error.
Under these rules, it's possible to obtain a vtable type for a concept with
unbound type parameters or one instantiated with metatypes (type classes),
but it will include a smaller number of captured procs. A completely empty
vtable will be reported as an error.
The ``vtref`` magic produces types which can be bound to ``ref`` types and
the ``vtptr`` magic produced types bound to ``ptr`` types.
The ``vtref`` magic produces types which can be bound to ``ref`` types and
the ``vtptr`` magic produced types bound to ``ptr`` types.
Symbol lookup in generics
@@ -709,3 +712,30 @@ definition):
But a ``bind`` is rarely useful because symbol binding from the definition
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``

View File

@@ -181,11 +181,11 @@ Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
and `FloatInexactError`:idx:.
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:
.. code-block:: nim
{.NanChecks: on, InfChecks: on.}
{.nanChecks: on, infChecks: on.}
var a = 1.0
var b = 0.0
echo b / b # raises FloatInvalidOpError
@@ -195,7 +195,7 @@ In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError``
are never raised. ``FloatOverflowError`` is raised instead of
``FloatDivByZeroError``.
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.
The only operations that are affected by the ``floatChecks`` pragma are

View File

@@ -1,9 +1,11 @@
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:
* ``int8``-``int16``
* ``uint8``/``byte``-``uint16``
* ``char``
* ``enum``
or equivalent. The reason is that sets are implemented as high
performance bit vectors. Attempting to declare a set with a larger type will
result in an error:

View File

@@ -1032,7 +1032,7 @@ procs for these conversions.
Type Conversion
---------------
Conversion between basic types is performed by using the
Conversion between numerical types is performed by using the
type as a function:
.. code-block:: nim

View File

@@ -265,9 +265,15 @@ when defined(windows) or defined(nimdoc):
setGlobalDispatcher(newDispatcher())
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) =
## Registers ``fd`` with the dispatcher.
let p = getGlobalDispatcher()
if createIoCompletionPort(fd.Handle, p.ioPort,
cast[CompletionKey](fd), 1) == 0:
raiseOSError(osLastError())
@@ -757,6 +763,9 @@ when defined(windows) or defined(nimdoc):
## Unregisters ``fd``.
getGlobalDispatcher().handles.excl(fd)
proc contains*(disp: PDispatcher, fd: AsyncFD): bool =
return fd in disp.handles
{.push stackTrace:off.}
proc waitableCallback(param: pointer,
timerOrWaitFired: WINBOOL): void {.stdcall.} =
@@ -977,7 +986,7 @@ when defined(windows) or defined(nimdoc):
proc newAsyncEvent*(): AsyncEvent =
## 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``.
var sa = SECURITY_ATTRIBUTES(
nLength: sizeof(SECURITY_ATTRIBUTES).cint,
@@ -1095,6 +1104,9 @@ else:
setGlobalDispatcher(newDispatcher())
result = gDisp
proc getIoHandler*(disp: PDispatcher): Selector[AsyncData] =
return disp.selector
proc register*(fd: AsyncFD) =
let p = getGlobalDispatcher()
var data = newAsyncData()
@@ -1110,6 +1122,9 @@ else:
proc unregister*(ev: AsyncEvent) =
getGlobalDispatcher().selector.unregister(SelectEvent(ev))
proc contains*(disp: PDispatcher, fd: AsyncFd): bool =
return fd.SocketHandle in disp.selector
proc addRead*(fd: AsyncFD, cb: Callback) =
let p = getGlobalDispatcher()

View File

@@ -85,7 +85,7 @@ proc newAsyncFile*(fd: AsyncFd): AsyncFile =
## Creates `AsyncFile` with a previously opened file descriptor `fd`.
new result
result.fd = fd
register(result.fd)
register(fd)
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
## Opens a file specified by the path in ``filename`` using
@@ -97,16 +97,16 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
when useWinUnicode:
let fd = createFileW(newWideCString(filename), desiredAccess,
FILE_SHARE_READ,
nil, creationDisposition, flags, 0).AsyncFd
nil, creationDisposition, flags, 0)
else:
let fd = createFileA(filename, desiredAccess,
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())
result = newAsyncFile(fd)
result = newAsyncFile(fd.AsyncFd)
if mode == fmAppend:
result.offset = getFileSize(result)
@@ -115,11 +115,11 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
let flags = getPosixFlags(mode)
# RW (Owner), RW (Group), R (Other)
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
let fd = open(filename, flags, perm).AsyncFD
if fd.cint == -1:
let fd = open(filename, flags, perm)
if fd == -1:
raiseOSError(osLastError())
result = newAsyncFile(fd)
result = newAsyncFile(fd.AsyncFd)
proc readBuffer*(f: AsyncFile, buf: pointer, size: int): Future[int] =
## Read ``size`` bytes from the specified file asynchronously starting at

View File

@@ -342,6 +342,7 @@ proc asyncCheck*[T](future: Future[T]) =
## finished with an error.
##
## This should be used instead of ``discard`` to discard void futures.
assert(not future.isNil, "Future is nil")
future.callback =
proc () =
if future.failed:

View File

@@ -140,9 +140,16 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
sockType: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
## 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
new(result)
result.fd = fd.SocketHandle
fd.SocketHandle.setBlocking(false)
result.isBuffered = buffered
result.domain = domain
result.sockType = sockType

View File

@@ -141,7 +141,7 @@ template checkFd(s, f) =
if f >= s.maxFD:
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) =
let fdi = int(fd)
s.checkFd(fdi)
@@ -156,7 +156,7 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
raiseIOSelectorsError(osLastError())
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,
Event.User, Event.Oneshot, Event.Error}
let fdi = int(fd)
@@ -392,9 +392,19 @@ proc selectInto*[T](s: Selector[T], timeout: int,
let pevents = resTable[i].events
var pkey = addr(s.fds[fdi])
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 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)
if (pevents and EPOLLOUT) != 0:
rkey.events.incl(Event.Write)
@@ -482,7 +492,7 @@ template isEmpty*[T](s: Selector[T]): bool =
(s.count == 0)
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 =
let fdi = int(fd)
@@ -516,3 +526,6 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
body1
else:
body2
proc getFd*[T](s: Selector[T]): int =
return s.epollFd.int

View File

@@ -217,7 +217,7 @@ else:
raiseIOSelectorsError(osLastError())
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) =
let fdi = int(fd)
s.checkFd(fdi)
@@ -235,7 +235,7 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
when not declared(CACHE_EVENTS):
flushKQueue(s)
proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
events: set[Event]) =
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
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:
rkey.events = {Event.Error}
rkey.errorCode = kevent.data.OSErrorCode
case kevent.filter:
of EVFILT_READ:
@@ -569,6 +570,13 @@ proc selectInto*[T](s: Selector[T], timeout: int,
doAssert(true, "Unsupported kqueue filter in the queue!")
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)
results[k] = rkey
@@ -585,7 +593,7 @@ template isEmpty*[T](s: Selector[T]): bool =
(s.count == 0)
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 =
let fdi = int(fd)
@@ -619,3 +627,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
body1
else:
body2
proc getFd*[T](s: Selector[T]): int =
return s.kqFD.int

View File

@@ -141,7 +141,7 @@ template checkFd(s, f) =
if f >= s.maxFD:
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) =
var fdi = int(fd)
s.checkFd(fdi)
@@ -149,7 +149,7 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
setKey(s, fdi, events, 0, data)
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]) =
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
Event.User, Event.Oneshot, Event.Error}
@@ -280,7 +280,7 @@ template isEmpty*[T](s: Selector[T]): bool =
(s.count == 0)
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 =
let fdi = int(fd)
@@ -314,3 +314,7 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
body1
else:
body2
proc getFd*[T](s: Selector[T]): int =
return -1

View File

@@ -229,7 +229,7 @@ proc delKey[T](s: Selector[T], fd: SocketHandle) =
doAssert(i < FD_SETSIZE,
"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) =
when not defined(windows):
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)
inc(s.count)
proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
events: set[Event]) =
let maskEvents = {Event.Timer, Event.Signal, Event.Process, Event.Vnode,
Event.User, Event.Oneshot, Event.Error}
@@ -453,3 +453,6 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value,
else:
body2
proc getFd*[T](s: Selector[T]): int =
return -1

View File

@@ -187,12 +187,12 @@ proc toSockType*(protocol: Protocol): SockType =
proc newNativeSocket*(domain: Domain = AF_INET,
sockType: SockType = SOCK_STREAM,
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))
proc newNativeSocket*(domain: cint, sockType: cint,
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
## not contain what you need.
@@ -666,6 +666,19 @@ proc selectWrite*(writefds: var seq[SocketHandle],
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):
var wsa: WSAData
if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())

View File

@@ -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
## accept will be called again.
assert(client != nil)
var sockAddress: Sockaddr_in
var addrLen = sizeof(sockAddress).SockLen
var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
addr(addrLen))
let ret = accept(server.fd)
let sock = ret[0]
if sock == osInvalidSocket:
let err = osLastError()
@@ -764,6 +762,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
acceptAddr(server, client, address, flags)
raiseOSError(err)
else:
address = ret[1]
client.fd = sock
client.isBuffered = server.isBuffered
@@ -776,9 +775,6 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
let ret = SSLAccept(client.sslHandle)
socketError(client, ret, false)
# Client socket is set above.
address = $inet_ntoa(sockAddress.sin_addr)
when false: #defineSsl:
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): SSLAcceptResult {.

View File

@@ -139,10 +139,15 @@ proc findExe*(exe: string, followSymlinks: bool = true;
## is added the `ExeExts <#ExeExts>`_ file extensions if it has none.
## If the system supports symlinks it also resolves them until it
## meets the actual file. This behavior can be disabled if desired.
for ext in extensions:
result = addFileExt(exe, ext)
if existsFile(result): return
var path = string(getEnv("PATH"))
template checkCurrentDir() =
for ext in extensions:
result = addFileExt(exe, ext)
if existsFile(result): return
when defined(posix):
if '/' in exe: checkCurrentDir()
else:
checkCurrentDir()
let path = string(getEnv("PATH"))
for candidate in split(path, PathSep):
when defined(windows):
var x = (if candidate[0] == '"' and candidate[^1] == '"':
@@ -824,7 +829,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
iterator walkDirRec*(dir: string, yieldFilter = {pcFile},
followFilter = {pcDir}): string {.tags: [ReadDirEffect].} =
## Recursively walks over the directory `dir` and yields for each file
## Recursively walks over the directory `dir` and yields for each file
## or directory in `dir`.
## The full path for each file or directory is returned.
## **Warning**:

View File

@@ -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:
let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]")
doAssert hash1 == hash1
doAssert parseSecureHash($hash1) == hash1
## This module is a deprecated alias for the ``sha1`` module.
{.deprecated.}
include "../std/sha1"

View File

@@ -54,9 +54,9 @@ when defined(nimdoc):
Timer, ## Timer descriptor is completed
Signal, ## Signal is raised
Process, ## Process is finished
Vnode, ## BSD specific file change happens
Vnode, ## BSD specific file change
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)
VnodeDelete, ## NOTE_DELETE (BSD specific, unlink of file occurred)
VnodeExtend, ## NOTE_EXTEND (BSD specific, file extended)
@@ -69,6 +69,8 @@ when defined(nimdoc):
## An object which holds result for descriptor
fd* : int ## file/socket descriptor
events*: set[Event] ## set of events
errorCode*: OSErrorCode ## additional error code information for
## Error events
SelectEvent* = object
## An object which holds user defined event
@@ -79,13 +81,14 @@ when defined(nimdoc):
proc close*[T](s: Selector[T]) =
## Closes the selector.
proc registerHandle*[T](s: Selector[T], fd: SocketHandle, events: set[Event],
data: T) =
proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
events: set[Event], data: T) =
## Registers file/socket descriptor ``fd`` to selector ``s``
## with events set in ``events``. The ``data`` is application-defined
## 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
## ``s`` with new events set ``event``.
@@ -221,11 +224,15 @@ when defined(nimdoc):
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
## 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:
when hasThreadSupport:
import locks
type
SharedArray[T] = UncheckedArray[T]
@@ -234,7 +241,6 @@ else:
proc deallocSharedArray[T](sa: ptr SharedArray[T]) =
deallocShared(cast[pointer](sa))
type
Event* {.pure.} = enum
Read, Write, Timer, Signal, Process, Vnode, User, Error, Oneshot,
@@ -247,6 +253,7 @@ else:
ReadyKey* = object
fd* : int
events*: set[Event]
errorCode*: OSErrorCode
SelectorKey[T] = object
ident: int
@@ -264,7 +271,7 @@ else:
msg.add("Internal Error\n")
var err = newException(IOSelectorsException, msg)
raise err
proc setNonBlocking(fd: cint) {.inline.} =
setBlocking(fd.SocketHandle, false)

View File

@@ -178,9 +178,8 @@ proc parseUri*(uri: string, result: var Uri) =
i.inc(2) # Skip //
var authority = ""
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
if authority == "":
raise newException(ValueError, "Expected authority got nothing.")
parseAuthority(authority, result)
if authority.len > 0:
parseAuthority(authority, result)
else:
result.opaque = true
@@ -465,6 +464,15 @@ when isMainModule:
doAssert test.hostname == "github.com"
doAssert test.port == "dom96"
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
block:

195
lib/std/sha1.nim Normal file
View 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

View File

@@ -1955,13 +1955,13 @@ const
## that you cannot compare a floating point value to this value
## and expect a reasonable result - use the `classify` procedure
## in the module ``math`` for checking for NaN.
NimMajor*: int = 0
NimMajor* {.intdefine.}: int = 0
## is the major number of Nim's version.
NimMinor*: int = 17
NimMinor* {.intdefine.}: int = 17
## is the minor number of Nim's version.
NimPatch*: int = 3
NimPatch* {.intdefine.}: int = 3
## is the patch number of Nim's version.
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
@@ -3025,9 +3025,9 @@ when not defined(JS): #and not defined(nimscript):
proc endOfFile*(f: File): bool {.tags: [], benign.}
## Returns true iff `f` is at the end.
proc readChar*(f: File): char {.tags: [ReadIOEffect], deprecated.}
## Reads a single character from the stream `f`. **Deprecated** since
## version 0.16.2. Use some variant of ``readBuffer`` instead.
proc readChar*(f: File): char {.tags: [ReadIOEffect].}
## Reads a single character from the stream `f`. Should not be used in
## performance sensitive code.
proc flushFile*(f: File) {.tags: [WriteIOEffect].}
## Flushes `f`'s buffer.
@@ -3769,7 +3769,6 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
# by ``assert``.
type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect,
tags: [].}
{.deprecated: [THide: Hide].}
Hide(raiseAssert)(msg)
template assert*(cond: bool, msg = "") =

View File

@@ -104,7 +104,7 @@ type
slBitmap: array[RealFli, uint32]
matrix: array[RealFli, array[MaxSli, PBigChunk]]
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
chunkStarts: IntSet
root, deleted, last, freeAvlNodes: PAvlNode
@@ -421,7 +421,7 @@ const nimMaxHeap {.intdefine.} = 0
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
when not defined(emscripten):
if not a.blockChunkSizeIncrease:
let usedMem = a.currMem # - a.freeMem
let usedMem = a.occ #a.currMem # - a.freeMem
when nimMaxHeap != 0:
if usedMem > nimMaxHeap * 1024 * 1024:
raiseOutOfMem()
@@ -567,7 +567,6 @@ proc splitChunk(a: var MemRegion, c: PBigChunk, size: int) =
addChunkToMatrix(a, rest)
proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
# use first fit for now:
sysAssert(size > 0, "getBigChunk 2")
var size = size # roundup(size, PageSize)
var fl, sl: int
@@ -627,6 +626,85 @@ else:
c = c.next
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 =
sysAssert(allocInv(a), "rawAlloc: begin")
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()) %%
size == 0, "rawAlloc 21")
sysAssert(allocInv(a), "rawAlloc: end small size")
inc a.occ, size
trackSize(c.size)
else:
size = requestedSize + bigChunkOverhead() # roundup(requestedSize+bigChunkOverhead(), PageSize)
# 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")
if a.root == nil: a.root = getBottom(a)
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(allocInv(a), "rawAlloc: end")
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:
var c = cast[PSmallChunk](c)
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()) %%
s == 0, "rawDealloc 3")
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())
# free big chunk
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)
del(a, a.root, cast[int](addr(c.data)))
freeBigChunk(a, c)
@@ -851,7 +939,8 @@ proc deallocOsPages(a: var MemRegion) =
proc getFreeMem(a: MemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: MemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: MemRegion): int {.inline.} =
result = a.currMem - a.freeMem
result = a.occ
# a.currMem - a.freeMem
# ---------------------- thread memory region -------------------------------
@@ -893,7 +982,7 @@ template instantiateForRegion(allocator: untyped) =
#sysAssert(result == countFreeMem())
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)
# -------------------- shared heap region ----------------------------------
@@ -944,7 +1033,8 @@ template instantiateForRegion(allocator: untyped) =
sharedMemStatsShared(sharedHeap.currMem)
proc getOccupiedSharedMem(): int =
sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
sharedMemStatsShared(sharedHeap.occ)
#sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
{.pop.}
{.pop.}

View File

@@ -125,7 +125,7 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
# forward declarations:
proc collectCT(gch: var GcHeap) {.benign.}
proc collectCT(gch: var GcHeap; size: int) {.benign.}
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
proc doOperation(p: pointer, 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
acquire(gch)
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)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# 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 =
acquire(gch)
collectCT(gch)
collectCT(gch, newsize + sizeof(Cell))
var ol = usrToCell(old)
sysAssert(ol.typ != nil, "growObj: 1")
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)
sysAssert(allocInv(gch.region), "collectCT: end")
proc collectCT(gch: var GcHeap) =
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
proc collectCT(gch: var GcHeap; size: int) =
if (getOccupiedMem(gch.region) >= gch.cycleThreshold or
size > getFreeMem(gch.region)) and gch.recGcLock == 0:
collectCTBody(gch)
when not defined(useNimRtl):
@@ -530,7 +531,7 @@ when not defined(useNimRtl):
acquire(gch)
var oldThreshold = gch.cycleThreshold
gch.cycleThreshold = 0 # forces cycle collection
collectCT(gch)
collectCT(gch, 0)
gch.cycleThreshold = oldThreshold
release(gch)

View File

@@ -47,10 +47,22 @@ when not declared(c_fwrite):
# C routine that is used here:
proc c_fread(buf: pointer, size, n: csize, f: File): csize {.
importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
proc c_fseek(f: File, offset: clong, whence: cint): cint {.
importc: "fseek", header: "<stdio.h>", tags: [].}
proc c_ftell(f: File): clong {.
importc: "ftell", header: "<stdio.h>", tags: [].}
when defined(windows):
when not defined(amd64):
proc c_fseek(f: File, offset: int64, whence: cint): cint {.
importc: "fseek", header: "<stdio.h>", tags: [].}
proc c_ftell(f: File): int64 {.
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 {.
importc: "ferror", header: "<stdio.h>", tags: [].}
proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
@@ -210,12 +222,12 @@ proc readAllBuffer(file: File): string =
result.add(buffer)
break
proc rawFileSize(file: File): int =
proc rawFileSize(file: File): int64 =
# this does not raise an error opposed to `getFileSize`
var oldPos = c_ftell(file)
discard c_fseek(file, 0, 2) # seek the end of the file
result = c_ftell(file)
discard c_fseek(file, clong(oldPos), 0)
discard c_fseek(file, oldPos, 0)
proc endOfFile(f: File): bool =
var c = c_fgetc(f)
@@ -223,7 +235,7 @@ proc endOfFile(f: File): bool =
return c < 0'i32
#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.
# Speeds things up.
result = newString(len)
@@ -363,7 +375,7 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
result = f != nil
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")
proc getFilePos(f: File): int64 =

File diff suppressed because it is too large Load Diff

View File

@@ -95,6 +95,7 @@ This project exists thanks to all the people who contribute. [Read on to find ou
[![Backers on Open Collective](https://opencollective.com/nim/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/nim/sponsors/badge.svg)](#sponsors)
[![Setup a bounty via Bountysource][badge-nim-bountysource]][nim-bountysource]
[![Donate Bitcoins][badge-nim-bitcoin]][nim-bitcoin]
[![Open Source Helpers](https://www.codetriage.com/nim-lang/nim/badges/users.svg)](https://www.codetriage.com/nim-lang/nim)
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

9
tests/ccgbugs/t7079.nim Normal file
View 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

View File

@@ -1,25 +1,48 @@
discard """
errormsg: "type mismatch: got (Bar[system.int])"
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:
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)
first type mismatch at position: 1
required type: var string
but expression 'k' is of type: Alias
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)
first type mismatch at position: 1
required type: var string
but expression 'k' is of type: Alias
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)
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])
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)
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(32, 6) Foo: 'bar.value' cannot be assigned to
t3330.nim(25, 8) template/generic instantiation from here
t3330.nim(33, 6) Foo: 'bar.x' cannot be assigned to
'''
t3330.nim(48, 8) template/generic instantiation from here
t3330.nim(55, 6) Foo: 'bar.value' cannot be assigned to
t3330.nim(48, 8) template/generic instantiation from here
t3330.nim(56, 6) Foo: 'bar.x' cannot be assigned to
expression: test(bar)'''
"""
type
Foo[T] = concept k
add(k, string, T)

View File

@@ -1,6 +1,6 @@
discard """
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 =

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

View File

@@ -0,0 +1,11 @@
discard """
errormsg: "in expression '("
nimout: '''
Error: in expression '(
890)': identifier expected, but found ''
'''
line: 11
"""
var n: int : 890

View File

@@ -21,5 +21,13 @@ proc test2() =
testTemplate(Exception)
doAssert(not declared(foobar))
proc testTryAsExpr(i: int) =
let x = try: i
except ValueError as ex:
echo(ex.msg)
-1
test[Exception]()
test2()
test2()
testTryAsExpr(5)

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

View File

@@ -1,5 +1,5 @@
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 TEST_FILE = "tests/testdata/string.txt"
@@ -23,3 +23,26 @@ suite "io":
test "file":
check:
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)

View File

@@ -15,7 +15,7 @@ when haveZipLib:
import
os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation,
securehash
std / sha1
const
maxOS = 20 # max number of OSes

View File

@@ -65,7 +65,7 @@ srcdoc2: "pure/asyncfile;pure/asyncftpclient;pure/lenientops"
srcdoc2: "pure/md5;pure/rationals"
srcdoc2: "posix/posix;pure/distros;pure/oswalkdir"
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/basic2d;pure/basic3d;pure/mersenne;pure/coro;pure/httpcore"
srcdoc2: "pure/bitops;pure/nimtracker;pure/punycode;pure/volatile;js/asyncjs"