Merge branch 'devel' into faster-nimsuggest

This commit is contained in:
Andreas Rumpf 2017-02-17 10:48:01 +01:00
commit ba29ca0c63
52 changed files with 1048 additions and 281 deletions

View file

@ -7,10 +7,7 @@ cache:
# - i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z # - i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z
matrix: matrix:
fast_finish: true # set this flag to immediately finish build once one of the jobs fails. fast_finish: true
allow_failures:
- platform: x64
# - platform: x86
environment: environment:
matrix: matrix:

View file

@ -1541,8 +1541,7 @@ proc skipGenericOwner*(s: PSym): PSym =
## Generic instantiations are owned by their originating generic ## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straight to the owner ## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc). ## of the generic itself (the module or the enclosing proc).
result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags == result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
{sfFromGeneric}:
s.owner.owner s.owner.owner
else: else:
s.owner s.owner

View file

@ -388,6 +388,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
[istr, makeYamlString($n.kind)] [istr, makeYamlString($n.kind)]
addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
if maxRecDepth != 0: if maxRecDepth != 0:
addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
case n.kind case n.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])

View file

@ -220,7 +220,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
optAsgnLoc(src, t, field), newflags) optAsgnLoc(src, t, field), newflags)
proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
t: PNode) = t: PNode, typ: PType) =
if t == nil: return if t == nil: return
let newflags = let newflags =
if src.s == OnStatic: if src.s == OnStatic:
@ -232,10 +232,11 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
case t.kind case t.kind
of nkSym: of nkSym:
let field = t.sym let field = t.sym
if field.loc.r == nil: fillObjectFields(p.module, typ)
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
optAsgnLoc(src, field.typ, field.loc.r), newflags) optAsgnLoc(src, field.typ, field.loc.r), newflags)
of nkRecList: of nkRecList:
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child) for child in items(t): genOptAsgnObject(p, dest, src, newflags, child, typ)
else: discard else: discard
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
@ -315,9 +316,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
genGenericAsgn(p, dest, src, flags) genGenericAsgn(p, dest, src, flags)
elif needsComplexAssignment(ty): elif needsComplexAssignment(ty):
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
discard getTypeDesc(p.module, dest.t) discard getTypeDesc(p.module, ty)
internalAssert ty.n != nil internalAssert ty.n != nil
genOptAsgnObject(p, dest, src, flags, ty.n) genOptAsgnObject(p, dest, src, flags, ty.n, ty)
else: else:
genGenericAsgn(p, dest, src, flags) genGenericAsgn(p, dest, src, flags)
else: else:

View file

@ -1103,8 +1103,8 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
genAssignment(p, a, tmp, {}) genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
genLineDir(p, e)
if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags: if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
genLineDir(p, e)
genGotoVar(p, e.sons[1]) genGotoVar(p, e.sons[1])
elif not fieldDiscriminantCheckNeeded(p, e): elif not fieldDiscriminantCheckNeeded(p, e):
var a: TLoc var a: TLoc
@ -1114,8 +1114,11 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
if fastAsgn: incl(a.flags, lfNoDeepCopy) if fastAsgn: incl(a.flags, lfNoDeepCopy)
assert(a.t != nil) assert(a.t != nil)
loadInto(p, e.sons[0], e.sons[1], a) let ri = e.sons[1]
genLineDir(p, ri)
loadInto(p, e.sons[0], ri, a)
else: else:
genLineDir(p, e)
asgnFieldDiscriminant(p, e) asgnFieldDiscriminant(p, e)
proc genStmts(p: BProc, t: PNode) = proc genStmts(p: BProc, t: PNode) =

View file

@ -57,8 +57,8 @@ proc generateThreadLocalStorage(m: BModule) =
proc generateThreadVarsSize(m: BModule) = proc generateThreadVarsSize(m: BModule) =
if nimtv != nil: if nimtv != nil:
let externc = if gCmd != cmdCompileToCpp and let externc = if gCmd == cmdCompileToCpp or
sfCompileToCpp in m.module.flags: "extern \"C\"" sfCompileToCpp in m.module.flags: "extern \"C\" "
else: "" else: ""
addf(m.s[cfsProcs], addf(m.s[cfsProcs],
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n", "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",

View file

@ -715,10 +715,13 @@ proc genProcAux(m: BModule, prc: PSym) =
add(generatedProc, ~"}$N") add(generatedProc, ~"}$N")
add(m.s[cfsProcs], generatedProc) add(m.s[cfsProcs], generatedProc)
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} = proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
result = sfCompileToCpp in m.module.flags and result = (sfCompileToCpp in m.module.flags and
sfCompileToCpp notin sym.getModule().flags and sfCompileToCpp notin sym.getModule().flags and
gCmd != cmdCompileToCpp gCmd != cmdCompileToCpp) or (
sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
sym.magic == mNone and
gCmd == cmdCompileToCpp)
proc genProcPrototype(m: BModule, sym: PSym) = proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym) useHeader(m, sym)
@ -732,7 +735,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
var header = genProcHeader(m, sym) var header = genProcHeader(m, sym)
if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props: if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props:
header = "__declspec(noreturn) " & header header = "__declspec(noreturn) " & header
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): if sym.typ.callConv != ccInline and requiresExternC(m, sym):
header = "extern \"C\" " & header header = "extern \"C\" " & header
if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
header.add(" __attribute__((naked))") header.add(" __attribute__((naked))")

View file

@ -566,16 +566,18 @@ proc needsExeExt(): bool {.inline.} =
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
(platform.hostOS == osWindows) (platform.hostOS == osWindows)
proc getCompilerExe(compiler: TSystemCC): string = proc getCompilerExe(compiler: TSystemCC; cfile: string): string =
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"):
else: CC[compiler].compilerExe CC[compiler].cppCompiler
else:
CC[compiler].compilerExe
if result.len == 0: if result.len == 0:
rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name) rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
proc getLinkerExe(compiler: TSystemCC): string = proc getLinkerExe(compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: compiler.getCompilerExe else: compiler.getCompilerExe("")
proc getCompileCFileCmd*(cfile: Cfile): string = proc getCompileCFileCmd*(cfile: Cfile): string =
var c = cCompiler var c = cCompiler
@ -596,7 +598,7 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
var options = cFileSpecificOptions(cfile.cname) var options = cFileSpecificOptions(cfile.cname)
var exe = getConfigVar(c, ".exe") var exe = getConfigVar(c, ".exe")
if exe.len == 0: exe = c.getCompilerExe if exe.len == 0: exe = c.getCompilerExe(cfile.cname)
if needsExeExt(): exe = addFileExt(exe, "exe") if needsExeExt(): exe = addFileExt(exe, "exe")
if optGenDynLib in gGlobalOptions and if optGenDynLib in gGlobalOptions and
@ -614,7 +616,7 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
compilePattern = joinPath(ccompilerpath, exe) compilePattern = joinPath(ccompilerpath, exe)
else: else:
includeCmd = "" includeCmd = ""
compilePattern = c.getCompilerExe compilePattern = c.getCompilerExe(cfile.cname)
var cf = if noAbsolutePaths(): extractFilename(cfile.cname) var cf = if noAbsolutePaths(): extractFilename(cfile.cname)
else: cfile.cname else: cfile.cname

View file

@ -178,6 +178,11 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
if result.kind != kind: if result.kind != kind:
localError(n.info, "cannot use symbol of kind '" & localError(n.info, "cannot use symbol of kind '" &
$result.kind & "' as a '" & $kind & "'") $result.kind & "' as a '" & $kind & "'")
if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
# declarative context, so produce a fresh gensym:
result = copySym(result)
result.ast = n.sym.ast
put(c.p, n.sym, result)
# when there is a nested proc inside a template, semtmpl # when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the # will assign a wrong owner during the first pass over the
# template; we must fix it here: see #909 # template; we must fix it here: see #909

View file

@ -39,6 +39,7 @@ type
next*: PProcCon # used for stacking procedure contexts next*: PProcCon # used for stacking procedure contexts
wasForwarded*: bool # whether the current proc has a separate header wasForwarded*: bool # whether the current proc has a separate header
bracketExpr*: PNode # current bracket expression (for ^ support) bracketExpr*: PNode # current bracket expression (for ^ support)
mapping*: TIdTable
TInstantiationPair* = object TInstantiationPair* = object
genericSym*: PSym genericSym*: PSym
@ -147,6 +148,35 @@ proc lastOptionEntry*(c: PContext): POptionEntry =
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
proc put*(p: PProcCon; key, val: PSym) =
if p.mapping.data == nil: initIdTable(p.mapping)
#echo "put into table ", key.info
p.mapping.idTablePut(key, val)
proc get*(p: PProcCon; key: PSym): PSym =
if p.mapping.data == nil: return nil
result = PSym(p.mapping.idTableGet(key))
proc getGenSym*(c: PContext; s: PSym): PSym =
if sfGenSym notin s.flags: return s
var it = c.p
while it != nil:
result = get(it, s)
if result != nil:
#echo "got from table ", result.name.s, " ", result.info
return result
it = it.next
result = s
proc considerGenSyms*(c: PContext; n: PNode) =
if n.kind == nkSym:
let s = getGenSym(c, n.sym)
if n.sym != s:
n.sym = s
else:
for i in 0..<n.safeLen:
considerGenSyms(c, n.sons[i])
proc newOptionEntry*(): POptionEntry = proc newOptionEntry*(): POptionEntry =
new(result) new(result)
result.options = gOptions result.options = gOptions

View file

@ -922,7 +922,8 @@ proc readTypeParameter(c: PContext, typ: PType,
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
#echo "came here: returned nil" #echo "came here: returned nil"
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
let s = getGenSym(c, sym)
case s.kind case s.kind
of skConst: of skConst:
markUsed(n.info, s) markUsed(n.info, s)
@ -1093,11 +1094,11 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
return readTypeParameter(c, ty, i, n.info) return readTypeParameter(c, ty, i, n.info)
of tyObject, tyTuple: of tyObject, tyTuple:
if ty.n != nil and ty.n.kind == nkRecList: if ty.n != nil and ty.n.kind == nkRecList:
for field in ty.n: let field = lookupInRecord(ty.n, i)
if field.sym.name == i: if field != nil:
n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ]) n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ])
n.typ.n = copyTree(n) n.typ.n = copyTree(n)
return n return n
else: else:
# echo "TYPE FIELD ACCESS" # echo "TYPE FIELD ACCESS"
# debug ty # debug ty

View file

@ -628,7 +628,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of {skProc, skMethod}: of {skProc, skMethod}:
result = n result = n
of skType: of skType:
result = newSymNodeTypeDesc(s, n.info) # XXX gensym'ed symbols can come here and cannot be resolved. This is
# dirty, but correct.
if s.typ != nil:
result = newSymNodeTypeDesc(s, n.info)
of skGenericParam: of skGenericParam:
if s.typ.kind == tyStatic: if s.typ.kind == tyStatic:
if s.typ.n != nil: if s.typ.n != nil:
@ -656,7 +659,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
localError(a.info, errCannotEvalXBecauseIncompletelyDefined, localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof") "sizeof")
result = nil result = nil
elif skipTypes(a.typ, typedescInst).kind in elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
IntegralTypes+NilableTypes+{tySet}: IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}: #{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(a.typ), n) result = newIntNodeT(getSize(a.typ), n)

View file

@ -106,15 +106,18 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
#if n.kind == nkSym and sfGenSym in n.sym.flags: #if n.kind == nkSym and sfGenSym in n.sym.flags:
# if n.sym.owner != orig: # if n.sym.owner != orig:
# echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner
if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and if n.kind == nkSym and sfGenSym in n.sym.flags: # and
# (n.sym.owner == orig or n.sym.owner.kind in {skPackage}): # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}):
let s = n.sym let s = n.sym
var x = PSym(idTableGet(symMap, s)) var x = PSym(idTableGet(symMap, s))
if x == nil: if x != nil:
n.sym = x
elif s.owner.kind == skPackage:
#echo "copied this ", s.name.s
x = copySym(s, false) x = copySym(s, false)
x.owner = owner x.owner = owner
idTablePut(symMap, s, x) idTablePut(symMap, s, x)
n.sym = x n.sym = x
else: else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap) for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap)

View file

@ -1360,6 +1360,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
proc determineType(c: PContext, s: PSym) = proc determineType(c: PContext, s: PSym) =
if s.typ != nil: return if s.typ != nil: return
#if s.magic != mNone: return #if s.magic != mNone: return
#if s.ast.isNil: return
discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType) discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType)
proc semIterator(c: PContext, n: PNode): PNode = proc semIterator(c: PContext, n: PNode): PNode =

View file

@ -172,7 +172,7 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(n), c.owner, n.info) result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
incl(result.flags, sfGenSym) incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed) incl(result.flags, sfShadowed)
if c.scopeN == 0: incl(result.flags, sfFromGeneric) #if c.scopeN == 0: incl(result.flags, sfFromGeneric)
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# locals default to 'gensym': # locals default to 'gensym':

View file

@ -297,7 +297,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
proc semTypeIdent(c: PContext, n: PNode): PSym = proc semTypeIdent(c: PContext, n: PNode): PSym =
if n.kind == nkSym: if n.kind == nkSym:
result = n.sym result = getGenSym(c, n.sym)
else: else:
when defined(nimfix): when defined(nimfix):
result = pickSym(c, n, skType) result = pickSym(c, n, skType)
@ -1319,8 +1319,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
prev.id = s.typ.id prev.id = s.typ.id
result = prev result = prev
of nkSym: of nkSym:
if n.sym.kind == skType and n.sym.typ != nil: let s = getGenSym(c, n.sym)
var t = n.sym.typ if s.kind == skType and s.typ != nil:
var t = s.typ
let alias = maybeAliasType(c, t, prev) let alias = maybeAliasType(c, t, prev)
if alias != nil: if alias != nil:
result = alias result = alias
@ -1332,7 +1333,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
markUsed(n.info, n.sym) markUsed(n.info, n.sym)
styleCheckUse(n.info, n.sym) styleCheckUse(n.info, n.sym)
else: else:
if n.sym.kind != skError: localError(n.info, errTypeExpected) if s.kind != skError: localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)
of nkObjectTy: result = semObjectNode(c, n, prev) of nkObjectTy: result = semObjectNode(c, n, prev)
of nkTupleTy: result = semTuple(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev)

View file

@ -1583,12 +1583,14 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
result = c.semOperand(c, a, flags) result = c.semOperand(c, a, flags)
else: else:
result = a result = a
considerGenSyms(c, result)
proc prepareOperand(c: PContext; a: PNode): PNode = proc prepareOperand(c: PContext; a: PNode): PNode =
if a.typ.isNil: if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType}) result = c.semOperand(c, a, {efDetermineType})
else: else:
result = a result = a
considerGenSyms(c, result)
proc prepareNamedParam(a: PNode) = proc prepareNamedParam(a: PNode) =
if a.sons[0].kind != nkIdent: if a.sons[0].kind != nkIdent:

View file

@ -869,7 +869,12 @@ proc transform(c: PTransf, n: PNode): PTransNode =
else: else:
result = transformSons(c, n) result = transformSons(c, n)
of nkIdentDefs, nkConstDef: of nkIdentDefs, nkConstDef:
result = transformSons(c, n) when true:
result = transformSons(c, n)
else:
result = n.PTransNode
let L = n.len-1
result[L] = transform(c, n.sons[L])
# XXX comment handling really sucks: # XXX comment handling really sucks:
if importantComments(): if importantComments():
PNode(result).comment = n.comment PNode(result).comment = n.comment

View file

@ -38,7 +38,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool =
# don't go nuts here: same symbol as string is enough: # don't go nuts here: same symbol as string is enough:
result = a.sym.name.id == b.sym.name.id result = a.sym.name.id == b.sym.name.id
of nkIdent: result = a.ident.id == b.ident.id of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkEmpty, nkNilLit, nkType: result = true of nkEmpty, nkNilLit, nkType: result = true

View file

@ -461,3 +461,11 @@ can then attach a GC to this thread via
It is **not** safe to disable the garbage collector and enable it after the It is **not** safe to disable the garbage collector and enable it after the
call from your background thread even if the code you are calling is short call from your background thread even if the code you are calling is short
lived. lived.
Before the thread exits, you should tear down the thread's GC to prevent memory
leaks by calling
.. code-block:: nim
system.tearDownForeignThreadGc()

View file

@ -361,7 +361,7 @@ iterator:
.. code-block:: nim .. code-block:: nim
echo "Counting to ten: " echo "Counting to ten: "
for i in countup(1, 10): for i in countup(1, 10):
echo $i echo i
# --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many
@ -374,7 +374,7 @@ Each value is ``echo``-ed. This code does the same:
echo "Counting to 10: " echo "Counting to 10: "
var i = 1 var i = 1
while i <= 10: while i <= 10:
echo $i echo i
inc(i) # increment i by 1 inc(i) # increment i by 1
# --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
@ -383,7 +383,7 @@ Counting down can be achieved as easily (but is less often needed):
.. code-block:: nim .. code-block:: nim
echo "Counting down from 10 to 1: " echo "Counting down from 10 to 1: "
for i in countdown(10, 1): for i in countdown(10, 1):
echo $i echo i
# --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
Since counting up occurs so often in programs, Nim also has a `.. Since counting up occurs so often in programs, Nim also has a `..
@ -827,7 +827,7 @@ Let's return to the boring counting example:
.. code-block:: nim .. code-block:: nim
echo "Counting to ten: " echo "Counting to ten: "
for i in countup(1, 10): for i in countup(1, 10):
echo $i echo i
Can a `countup <system.html#countup>`_ proc be written that supports this Can a `countup <system.html#countup>`_ proc be written that supports this
loop? Lets try: loop? Lets try:
@ -1035,15 +1035,15 @@ there is a difference between the ``$`` and ``repr`` outputs:
myString = "nim" myString = "nim"
myInteger = 42 myInteger = 42
myFloat = 3.14 myFloat = 3.14
echo $myBool, ":", repr(myBool) echo myBool, ":", repr(myBool)
# --> true:true # --> true:true
echo $myCharacter, ":", repr(myCharacter) echo myCharacter, ":", repr(myCharacter)
# --> n:'n' # --> n:'n'
echo $myString, ":", repr(myString) echo myString, ":", repr(myString)
# --> nim:0x10fa8c050"nim" # --> nim:0x10fa8c050"nim"
echo $myInteger, ":", repr(myInteger) echo myInteger, ":", repr(myInteger)
# --> 42:42 # --> 42:42
echo $myFloat, ":", repr(myFloat) echo myFloat, ":", repr(myFloat)
# --> 3.1400000000000001e+00:3.1400000000000001e+00 # --> 3.1400000000000001e+00:3.1400000000000001e+00
@ -1075,7 +1075,7 @@ at runtime by 0, the second by 1 and so on. Example:
north, east, south, west north, east, south, west
var x = south # `x` is of type `Direction`; its value is `south` var x = south # `x` is of type `Direction`; its value is `south`
echo $x # writes "south" to `stdout` echo x # writes "south" to `stdout`
All comparison operators can be used with enumeration types. All comparison operators can be used with enumeration types.
@ -1289,7 +1289,7 @@ value. Here the ``for`` statement is looping over the results from the
.. code-block:: nim .. code-block:: nim
for i in @[3, 4, 5]: for i in @[3, 4, 5]:
echo $i echo i
# --> 3 # --> 3
# --> 4 # --> 4
# --> 5 # --> 5

View file

@ -223,8 +223,9 @@ proc bundleWinTools() =
copyExe("tools/finish".exe, "finish".exe) copyExe("tools/finish".exe, "finish".exe)
removeFile("tools/finish".exe) removeFile("tools/finish".exe)
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe") nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " & when false:
r"--path:..\ui tools\downloader.nim") nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " &
r"--path:..\ui tools\downloader.nim")
proc zip(args: string) = proc zip(args: string) =
bundleNimbleSrc() bundleNimbleSrc()

View file

@ -69,16 +69,14 @@ import db_common
export db_common export db_common
type type
DbConn* = PPGconn ## encapsulates a database connection DbConn* = PPGconn ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be Row* = seq[string] ## a row of a dataset. NULL database values will be
## converted to nil. ## converted to nil.
InstantRow* = tuple[res: PPGresult, line: int32] ## a handle that can be InstantRow* = object ## a handle that can be
## used to get a row's res: PPGresult ## used to get a row's
## column text on demand line: int ## column text on demand
SqlPrepared* = distinct string ## a identifier for the prepared queries SqlPrepared* = distinct string ## a identifier for the prepared queries
{.deprecated: [TRow: Row, TDbConn: DbConn, TSqlPrepared: SqlPrepared].}
{.deprecated: [TRow: Row, TDbConn: DbConn,
TSqlPrepared: SqlPrepared].}
proc dbError*(db: DbConn) {.noreturn.} = proc dbError*(db: DbConn) {.noreturn.} =
## raises a DbError exception. ## raises a DbError exception.
@ -213,7 +211,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery,
## on demand using []. Returned handle is valid only within iterator body. ## on demand using []. Returned handle is valid only within iterator body.
var res = setupQuery(db, query, args) var res = setupQuery(db, query, args)
for i in 0..pqNtuples(res)-1: for i in 0..pqNtuples(res)-1:
yield (res: res, line: i) yield InstantRow(res: res, line: i)
pqClear(res) pqClear(res)
iterator instantRows*(db: DbConn, stmtName: SqlPrepared, iterator instantRows*(db: DbConn, stmtName: SqlPrepared,
@ -223,16 +221,170 @@ iterator instantRows*(db: DbConn, stmtName: SqlPrepared,
## on demand using []. Returned handle is valid only within iterator body. ## on demand using []. Returned handle is valid only within iterator body.
var res = setupQuery(db, stmtName, args) var res = setupQuery(db, stmtName, args)
for i in 0..pqNtuples(res)-1: for i in 0..pqNtuples(res)-1:
yield (res: res, line: i) yield InstantRow(res: res, line: i)
pqClear(res) pqClear(res)
proc `[]`*(row: InstantRow, col: int32): string {.inline.} = proc getColumnType(res: PPGresult, col: int) : DbType =
## returns text for given column of the row ## returns DbType for given column in the row
$pqgetvalue(row.res, row.line, col) ## defined in pg_type.h file in the postgres source code
## Wire representation for types: http://www.npgsql.org/dev/types.html
var oid = pqftype(res, int32(col))
## The integer returned is the internal OID number of the type
case oid
of 16: return DbType(kind: DbTypeKind.dbBool, name: "bool")
of 17: return DbType(kind: DbTypeKind.dbBlob, name: "bytea")
proc len*(row: InstantRow): int32 {.inline.} = of 21: return DbType(kind: DbTypeKind.dbInt, name: "int2", size: 2)
of 23: return DbType(kind: DbTypeKind.dbInt, name: "int4", size: 4)
of 20: return DbType(kind: DbTypeKind.dbInt, name: "int8", size: 8)
of 1560: return DbType(kind: DbTypeKind.dbBit, name: "bit")
of 1562: return DbType(kind: DbTypeKind.dbInt, name: "varbit")
of 18: return DbType(kind: DbTypeKind.dbFixedChar, name: "char")
of 19: return DbType(kind: DbTypeKind.dbFixedChar, name: "name")
of 1042: return DbType(kind: DbTypeKind.dbFixedChar, name: "bpchar")
of 25: return DbType(kind: DbTypeKind.dbVarchar, name: "text")
of 1043: return DbType(kind: DbTypeKind.dbVarChar, name: "varchar")
of 2275: return DbType(kind: DbTypeKind.dbVarchar, name: "cstring")
of 700: return DbType(kind: DbTypeKind.dbFloat, name: "float4")
of 701: return DbType(kind: DbTypeKind.dbFloat, name: "float8")
of 790: return DbType(kind: DbTypeKind.dbDecimal, name: "money")
of 1700: return DbType(kind: DbTypeKind.dbDecimal, name: "numeric")
of 704: return DbType(kind: DbTypeKind.dbTimeInterval, name: "tinterval")
of 702: return DbType(kind: DbTypeKind.dbTimestamp, name: "abstime")
of 703: return DbType(kind: DbTypeKind.dbTimeInterval, name: "reltime")
of 1082: return DbType(kind: DbTypeKind.dbDate, name: "date")
of 1083: return DbType(kind: DbTypeKind.dbTime, name: "time")
of 1114: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamp")
of 1184: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamptz")
of 1186: return DbType(kind: DbTypeKind.dbTimeInterval, name: "interval")
of 1266: return DbType(kind: DbTypeKind.dbTime, name: "timetz")
of 114: return DbType(kind: DbTypeKind.dbJson, name: "json")
of 142: return DbType(kind: DbTypeKind.dbXml, name: "xml")
of 3802: return DbType(kind: DbTypeKind.dbJson, name: "jsonb")
of 600: return DbType(kind: DbTypeKind.dbPoint, name: "point")
of 601: return DbType(kind: DbTypeKind.dbLseg, name: "lseg")
of 602: return DbType(kind: DbTypeKind.dbPath, name: "path")
of 603: return DbType(kind: DbTypeKind.dbBox, name: "box")
of 604: return DbType(kind: DbTypeKind.dbPolygon, name: "polygon")
of 628: return DbType(kind: DbTypeKind.dbLine, name: "line")
of 718: return DbType(kind: DbTypeKind.dbCircle, name: "circle")
of 650: return DbType(kind: DbTypeKind.dbInet, name: "cidr")
of 829: return DbType(kind: DbTypeKind.dbMacAddress, name: "macaddr")
of 869: return DbType(kind: DbTypeKind.dbInet, name: "inet")
of 2950: return DbType(kind: DbTypeKind.dbVarchar, name: "uuid")
of 3614: return DbType(kind: DbTypeKind.dbVarchar, name: "tsvector")
of 3615: return DbType(kind: DbTypeKind.dbVarchar, name: "tsquery")
of 2970: return DbType(kind: DbTypeKind.dbVarchar, name: "txid_snapshot")
of 27: return DbType(kind: DbTypeKind.dbComposite, name: "tid")
of 1790: return DbType(kind: DbTypeKind.dbComposite, name: "refcursor")
of 2249: return DbType(kind: DbTypeKind.dbComposite, name: "record")
of 3904: return DbType(kind: DbTypeKind.dbComposite, name: "int4range")
of 3906: return DbType(kind: DbTypeKind.dbComposite, name: "numrange")
of 3908: return DbType(kind: DbTypeKind.dbComposite, name: "tsrange")
of 3910: return DbType(kind: DbTypeKind.dbComposite, name: "tstzrange")
of 3912: return DbType(kind: DbTypeKind.dbComposite, name: "daterange")
of 3926: return DbType(kind: DbTypeKind.dbComposite, name: "int8range")
of 22: return DbType(kind: DbTypeKind.dbArray, name: "int2vector")
of 30: return DbType(kind: DbTypeKind.dbArray, name: "oidvector")
of 143: return DbType(kind: DbTypeKind.dbArray, name: "xml[]")
of 199: return DbType(kind: DbTypeKind.dbArray, name: "json[]")
of 629: return DbType(kind: DbTypeKind.dbArray, name: "line[]")
of 651: return DbType(kind: DbTypeKind.dbArray, name: "cidr[]")
of 719: return DbType(kind: DbTypeKind.dbArray, name: "circle[]")
of 791: return DbType(kind: DbTypeKind.dbArray, name: "money[]")
of 1000: return DbType(kind: DbTypeKind.dbArray, name: "bool[]")
of 1001: return DbType(kind: DbTypeKind.dbArray, name: "bytea[]")
of 1002: return DbType(kind: DbTypeKind.dbArray, name: "char[]")
of 1003: return DbType(kind: DbTypeKind.dbArray, name: "name[]")
of 1005: return DbType(kind: DbTypeKind.dbArray, name: "int2[]")
of 1006: return DbType(kind: DbTypeKind.dbArray, name: "int2vector[]")
of 1007: return DbType(kind: DbTypeKind.dbArray, name: "int4[]")
of 1008: return DbType(kind: DbTypeKind.dbArray, name: "regproc[]")
of 1009: return DbType(kind: DbTypeKind.dbArray, name: "text[]")
of 1028: return DbType(kind: DbTypeKind.dbArray, name: "oid[]")
of 1010: return DbType(kind: DbTypeKind.dbArray, name: "tid[]")
of 1011: return DbType(kind: DbTypeKind.dbArray, name: "xid[]")
of 1012: return DbType(kind: DbTypeKind.dbArray, name: "cid[]")
of 1013: return DbType(kind: DbTypeKind.dbArray, name: "oidvector[]")
of 1014: return DbType(kind: DbTypeKind.dbArray, name: "bpchar[]")
of 1015: return DbType(kind: DbTypeKind.dbArray, name: "varchar[]")
of 1016: return DbType(kind: DbTypeKind.dbArray, name: "int8[]")
of 1017: return DbType(kind: DbTypeKind.dbArray, name: "point[]")
of 1018: return DbType(kind: DbTypeKind.dbArray, name: "lseg[]")
of 1019: return DbType(kind: DbTypeKind.dbArray, name: "path[]")
of 1020: return DbType(kind: DbTypeKind.dbArray, name: "box[]")
of 1021: return DbType(kind: DbTypeKind.dbArray, name: "float4[]")
of 1022: return DbType(kind: DbTypeKind.dbArray, name: "float8[]")
of 1023: return DbType(kind: DbTypeKind.dbArray, name: "abstime[]")
of 1024: return DbType(kind: DbTypeKind.dbArray, name: "reltime[]")
of 1025: return DbType(kind: DbTypeKind.dbArray, name: "tinterval[]")
of 1027: return DbType(kind: DbTypeKind.dbArray, name: "polygon[]")
of 1040: return DbType(kind: DbTypeKind.dbArray, name: "macaddr[]")
of 1041: return DbType(kind: DbTypeKind.dbArray, name: "inet[]")
of 1263: return DbType(kind: DbTypeKind.dbArray, name: "cstring[]")
of 1115: return DbType(kind: DbTypeKind.dbArray, name: "timestamp[]")
of 1182: return DbType(kind: DbTypeKind.dbArray, name: "date[]")
of 1183: return DbType(kind: DbTypeKind.dbArray, name: "time[]")
of 1185: return DbType(kind: DbTypeKind.dbArray, name: "timestamptz[]")
of 1187: return DbType(kind: DbTypeKind.dbArray, name: "interval[]")
of 1231: return DbType(kind: DbTypeKind.dbArray, name: "numeric[]")
of 1270: return DbType(kind: DbTypeKind.dbArray, name: "timetz[]")
of 1561: return DbType(kind: DbTypeKind.dbArray, name: "bit[]")
of 1563: return DbType(kind: DbTypeKind.dbArray, name: "varbit[]")
of 2201: return DbType(kind: DbTypeKind.dbArray, name: "refcursor[]")
of 2951: return DbType(kind: DbTypeKind.dbArray, name: "uuid[]")
of 3643: return DbType(kind: DbTypeKind.dbArray, name: "tsvector[]")
of 3645: return DbType(kind: DbTypeKind.dbArray, name: "tsquery[]")
of 3807: return DbType(kind: DbTypeKind.dbArray, name: "jsonb[]")
of 2949: return DbType(kind: DbTypeKind.dbArray, name: "txid_snapshot[]")
of 3905: return DbType(kind: DbTypeKind.dbArray, name: "int4range[]")
of 3907: return DbType(kind: DbTypeKind.dbArray, name: "numrange[]")
of 3909: return DbType(kind: DbTypeKind.dbArray, name: "tsrange[]")
of 3911: return DbType(kind: DbTypeKind.dbArray, name: "tstzrange[]")
of 3913: return DbType(kind: DbTypeKind.dbArray, name: "daterange[]")
of 3927: return DbType(kind: DbTypeKind.dbArray, name: "int8range[]")
of 2287: return DbType(kind: DbTypeKind.dbArray, name: "record[]")
of 705: return DbType(kind: DbTypeKind.dbUnknown, name: "unknown")
else: return DbType(kind: DbTypeKind.dbUnknown, name: $oid) ## Query the system table pg_type to determine exactly which type is referenced.
proc setColumnInfo(columns: var DbColumns; res: PPGresult; L: int32) =
setLen(columns, L)
for i in 0..<L:
columns[i].name = $pqfname(res, i)
columns[i].typ = getColumnType(res, i)
columns[i].tableName = $(pqftable(res, i)) ## Returns the OID of the table from which the given column was fetched.
## Query the system table pg_class to determine exactly which table is referenced.
#columns[i].primaryKey = libpq does not have a function for that
#columns[i].foreignKey = libpq does not have a function for that
iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery;
args: varargs[string, `$`]): InstantRow
{.tags: [ReadDbEffect].} =
var res = setupQuery(db, query, args)
setColumnInfo(columns, res, pqnfields(res))
for i in 0..<pqntuples(res):
yield InstantRow(res: res, line: i)
pqClear(res)
proc `[]`*(row: InstantRow; col: int): string {.inline.} =
## returns text for given column of the row
$pqgetvalue(row.res, int32(row.line), int32(col))
proc len*(row: InstantRow): int {.inline.} =
## returns number of columns in the row ## returns number of columns in the row
pqNfields(row.res) int(pqNfields(row.res))
proc getRow*(db: DbConn, query: SqlQuery, proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} = args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =

View file

@ -290,7 +290,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string],
for i in 1..int(res)-1: for i in 1..int(res)-1:
var a = rawMatches[i * 2] var a = rawMatches[i * 2]
var b = rawMatches[i * 2 + 1] var b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)-1) if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
else: matches[i-1] = nil else: matches[i-1] = nil
return rawMatches[0] return rawMatches[0]

View file

@ -46,7 +46,7 @@ proc reverse*[T](a: var openArray[T], first, last: Natural) =
proc reverse*[T](a: var openArray[T]) = proc reverse*[T](a: var openArray[T]) =
## reverses the array `a`. ## reverses the array `a`.
reverse(a, 0, a.high) reverse(a, 0, max(0, a.high))
proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] =
## returns the reverse of the array `a[first..last]`. ## returns the reverse of the array `a[first..last]`.

View file

@ -77,8 +77,10 @@ proc pop*[T](heap: var HeapQueue[T]): T =
proc del*[T](heap: var HeapQueue[T], index: int) = proc del*[T](heap: var HeapQueue[T], index: int) =
## Removes element at `index`, maintaining the heap invariant. ## Removes element at `index`, maintaining the heap invariant.
swap(seq[T](heap)[^1], seq[T](heap)[index]) swap(seq[T](heap)[^1], seq[T](heap)[index])
seq[T](heap).setLen(heap.len - 1) let newLen = heap.len - 1
heap.siftup(index) seq[T](heap).setLen(newLen)
if index < newLen:
heap.siftup(index)
proc replace*[T](heap: var HeapQueue[T], item: T): T = proc replace*[T](heap: var HeapQueue[T], item: T): T =
## Pop and return the current smallest value, and add the new item. ## Pop and return the current smallest value, and add the new item.
@ -101,16 +103,19 @@ proc pushpop*[T](heap: var HeapQueue[T], item: T): T =
return item return item
when isMainModule: when isMainModule:
proc toSortedSeq[T](h: HeapQueue[T]): seq[T] =
var tmp = h
result = @[]
while tmp.len > 0:
result.add(pop(tmp))
block: # Simple sanity test block: # Simple sanity test
var heap = newHeapQueue[int]() var heap = newHeapQueue[int]()
let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
for item in data: for item in data:
push(heap, item) push(heap, item)
doAssert(heap[0] == 0) doAssert(heap[0] == 0)
var sort = newSeq[int]() doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
while heap.len > 0:
sort.add(pop(heap))
doAssert(sort == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
block: # Test del block: # Test del
var heap = newHeapQueue[int]() var heap = newHeapQueue[int]()
@ -121,11 +126,27 @@ when isMainModule:
doAssert(heap[0] == 1) doAssert(heap[0] == 1)
heap.del(seq[int](heap).find(7)) heap.del(seq[int](heap).find(7))
heap.del(seq[int](heap).find(5)) doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9])
heap.del(seq[int](heap).find(6))
heap.del(seq[int](heap).find(2))
var sort = newSeq[int]() heap.del(seq[int](heap).find(5))
while heap.len > 0: doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9])
sort.add(pop(heap))
doAssert(sort == @[1, 3, 4, 8, 9]) heap.del(seq[int](heap).find(6))
doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9])
heap.del(seq[int](heap).find(2))
doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9])
block: # Test del last
var heap = newHeapQueue[int]()
let data = [1, 2, 3]
for item in data: push(heap, item)
heap.del(2)
doAssert(heap.toSortedSeq == @[1, 2])
heap.del(1)
doAssert(heap.toSortedSeq == @[1])
heap.del(0)
doAssert(heap.toSortedSeq == @[])

View file

@ -225,7 +225,7 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) =
else: else:
result = ("<your package manager here> install " & p, true) result = ("<your package manager here> install " & p, true)
else: else:
result = ("brew install " & p, true) result = ("brew install " & p, false)
proc foreignDep*(foreignPackageName: string) = proc foreignDep*(foreignPackageName: string) =
## Registers 'foreignPackageName' to the internal list of foreign deps. ## Registers 'foreignPackageName' to the internal list of foreign deps.

View file

@ -127,6 +127,15 @@ proc hash*(x: string): Hash =
h = h !& ord(x[i]) h = h !& ord(x[i])
result = !$h result = !$h
proc hash*(x: cstring): Hash =
## efficient hashing of null-terminated strings
var h: Hash = 0
var i = 0
while x[i] != 0.char:
h = h !& ord(x[i])
inc i
result = !$h
proc hash*(sBuf: string, sPos, ePos: int): Hash = proc hash*(sBuf: string, sPos, ePos: int): Hash =
## efficient hashing of a string buffer, from starting ## efficient hashing of a string buffer, from starting
## position `sPos` to ending position `ePos` ## position `sPos` to ending position `ePos`
@ -239,6 +248,7 @@ proc hash*[A](x: set[A]): Hash =
when isMainModule: when isMainModule:
doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) ) doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) )
doAssert( hash("aa bb aaaa1234") == hash(cstring("aa bb aaaa1234")) )
doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") ) doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") )
doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") ) doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") )
let xx = @['H','e','l','l','o'] let xx = @['H','e','l','l','o']

View file

@ -206,6 +206,8 @@ proc parseHeader*(line: string): tuple[key: string, value: seq[string]] =
inc(i) # skip : inc(i) # skip :
if i < len(line): if i < len(line):
i += parseList(line, result.value, i) i += parseList(line, result.value, i)
elif result.key.len > 0:
result.value = @[""]
else: else:
result.value = @[] result.value = @[]
@ -319,3 +321,5 @@ when isMainModule:
test = newHttpHeaders() test = newHttpHeaders()
test[key] = value test[key] = value
doAssert test["foobar"] == "" doAssert test["foobar"] == ""
doAssert parseHeader("foobar:") == ("foobar", @[""])

View file

@ -1002,8 +1002,8 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {. iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
tags: [ReadDirEffect].} = tags: [ReadDirEffect].} =
## walks over the directory `dir` and yields for each file in `dir`. The ## Recursively walks over the directory `dir` and yields for each file in `dir`.
## full path for each file is returned. ## The full path for each file is returned. Directories are not returned.
## **Warning**: ## **Warning**:
## Modifying the directory structure while the iterator ## Modifying the directory structure while the iterator
## is traversing may result in undefined behavior! ## is traversing may result in undefined behavior!

View file

@ -250,18 +250,18 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
elif result != 0: elif result != 0:
number = int(res) number = int(res)
# overflowChecks doesn't work with uint64 # overflowChecks doesn't work with BiggestUInt
proc rawParseUInt(s: string, b: var uint64, start = 0): int = proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
var var
res = 0'u64 res = 0.BiggestUInt
prev = 0'u64 prev = 0.BiggestUInt
i = start i = start
if s[i] == '+': inc(i) # Allow if s[i] == '+': inc(i) # Allow
if s[i] in {'0'..'9'}: if s[i] in {'0'..'9'}:
b = 0 b = 0
while s[i] in {'0'..'9'}: while s[i] in {'0'..'9'}:
prev = res prev = res
res = res * 10 + (ord(s[i]) - ord('0')).uint64 res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
if prev > res: if prev > res:
return 0 # overflowChecks emulation return 0 # overflowChecks emulation
inc(i) inc(i)
@ -269,13 +269,13 @@ proc rawParseUInt(s: string, b: var uint64, start = 0): int =
b = res b = res
result = i - start result = i - start
proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {. proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
rtl, extern: "npuParseBiggestUInt", noSideEffect.} = rtl, extern: "npuParseBiggestUInt", noSideEffect.} =
## parses an unsigned integer starting at `start` and stores the value ## parses an unsigned integer starting at `start` and stores the value
## into `number`. ## into `number`.
## Result is the number of processed chars or 0 if there is no integer ## Result is the number of processed chars or 0 if there is no integer
## or overflow detected. ## or overflow detected.
var res: uint64 var res: BiggestUInt
# use 'res' for exception safety (don't write to 'number' in case of an # use 'res' for exception safety (don't write to 'number' in case of an
# overflow exception): # overflow exception):
result = rawParseUInt(s, res, start) result = rawParseUInt(s, res, start)
@ -287,12 +287,12 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {.
## into `number`. ## into `number`.
## Result is the number of processed chars or 0 if there is no integer or ## Result is the number of processed chars or 0 if there is no integer or
## overflow detected. ## overflow detected.
var res: uint64 var res: BiggestUInt
result = parseBiggestUInt(s, res, start) result = parseBiggestUInt(s, res, start)
if (sizeof(uint) <= 4) and when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
(res > 0xFFFF_FFFF'u64): if res > 0xFFFF_FFFF'u64:
raise newException(OverflowError, "overflow") raise newException(OverflowError, "overflow")
elif result != 0: if result != 0:
number = uint(res) number = uint(res)
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.

View file

@ -939,7 +939,7 @@ proc parseUInt*(s: string): uint {.noSideEffect, procvar,
if L != s.len or L == 0: if L != s.len or L == 0:
raise newException(ValueError, "invalid unsigned integer: " & s) raise newException(ValueError, "invalid unsigned integer: " & s)
proc parseBiggestUInt*(s: string): uint64 {.noSideEffect, procvar, proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar,
rtl, extern: "nsuParseBiggestUInt".} = rtl, extern: "nsuParseBiggestUInt".} =
## Parses a decimal unsigned integer value contained in `s`. ## Parses a decimal unsigned integer value contained in `s`.
## ##

View file

@ -1512,6 +1512,17 @@ type
## compiler supports. Currently this is ``float64``, but it is ## compiler supports. Currently this is ``float64``, but it is
## platform-dependant in general. ## platform-dependant in general.
when defined(JS):
type BiggestUInt* = uint32
## is an alias for the biggest unsigned integer type the Nim compiler
## supports. Currently this is ``uint32`` for JS and ``uint64`` for other
## targets.
else:
type BiggestUInt* = uint64
## is an alias for the biggest unsigned integer type the Nim compiler
## supports. Currently this is ``uint32`` for JS and ``uint64`` for other
## targets.
{.deprecated: [TAddress: ByteAddress].} {.deprecated: [TAddress: ByteAddress].}
when defined(windows): when defined(windows):

View file

@ -128,13 +128,7 @@ iterator items(stack: ptr GcStack): ptr GcStack =
yield s yield s
s = s.next s = s.next
# There will be problems with GC in foreign threads if `threads` option is off or TLS emulation is enabled when declared(threadType):
const allowForeignThreadGc = compileOption("threads") and not compileOption("tlsEmulation")
when allowForeignThreadGc:
var
localGcInitialized {.rtlThreadVar.}: bool
proc setupForeignThreadGc*() {.gcsafe.} = proc setupForeignThreadGc*() {.gcsafe.} =
## Call this if you registered a callback that will be run from a thread not ## Call this if you registered a callback that will be run from a thread not
## under your control. This has a cheap thread-local guard, so the GC for ## under your control. This has a cheap thread-local guard, so the GC for
@ -143,16 +137,33 @@ when allowForeignThreadGc:
## ##
## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off``
## switches are used ## switches are used
if not localGcInitialized: if threadType == ThreadType.None:
localGcInitialized = true
initAllocator() initAllocator()
var stackTop {.volatile.}: pointer var stackTop {.volatile.}: pointer
setStackBottom(addr(stackTop)) setStackBottom(addr(stackTop))
initGC() initGC()
threadType = ThreadType.ForeignThread
proc tearDownForeignThreadGc*() {.gcsafe.} =
## Call this to tear down the GC, previously initialized by ``setupForeignThreadGc``.
## If GC has not been previously initialized, or has already been torn down, the
## call does nothing.
##
## This function is available only when ``--threads:on`` and ``--tlsEmulation:off``
## switches are used
if threadType != ThreadType.ForeignThread:
return
when declared(deallocOsPages): deallocOsPages()
threadType = ThreadType.None
when declared(gch): zeroMem(addr gch, sizeof(gch))
else: else:
template setupForeignThreadGc*() = template setupForeignThreadGc*() =
{.error: "setupForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".} {.error: "setupForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".}
template tearDownForeignThreadGc*() =
{.error: "tearDownForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".}
# ----------------- stack management -------------------------------------- # ----------------- stack management --------------------------------------
# inspired from Smart Eiffel # inspired from Smart Eiffel

View file

@ -67,7 +67,7 @@ proc checkErr(f: File) =
{.push stackTrace:off, profiler:off.} {.push stackTrace:off, profiler:off.}
proc readBuffer(f: File, buffer: pointer, len: Natural): int = proc readBuffer(f: File, buffer: pointer, len: Natural): int =
result = c_fread(buffer, 1, len, f) result = c_fread(buffer, 1, len, f)
checkErr(f) if result != len: checkErr(f)
proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int = proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
@ -118,8 +118,9 @@ const
proc close*(f: File) = discard c_fclose(f) proc close*(f: File) = discard c_fclose(f)
proc readChar(f: File): char = proc readChar(f: File): char =
let x = c_fgetc(f) let x = c_fgetc(f)
if x == -1: raiseEOF() if x < 0:
checkErr(f) checkErr(f)
raiseEOF()
result = char(x) result = char(x)
proc flushFile*(f: File) = discard c_fflush(f) proc flushFile*(f: File) = discard c_fflush(f)
@ -140,7 +141,7 @@ proc readLine(f: File, line: var TaintedString): bool =
# fgets doesn't append an \L # fgets doesn't append an \L
c_memset(addr line.string[pos], '\L'.ord, sp) c_memset(addr line.string[pos], '\L'.ord, sp)
var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil
checkErr(f) if not fgetsSuccess: checkErr(f)
let m = c_memchr(addr line.string[pos], '\L'.ord, sp) let m = c_memchr(addr line.string[pos], '\L'.ord, sp)
if m != nil: if m != nil:
# \l found: Could be our own or the one by fgets, in any case, we're done # \l found: Could be our own or the one by fgets, in any case, we're done
@ -170,21 +171,23 @@ proc readLine(f: File): TaintedString =
proc write(f: File, i: int) = proc write(f: File, i: int) =
when sizeof(int) == 8: when sizeof(int) == 8:
c_fprintf(f, "%lld", i) if c_fprintf(f, "%lld", i) < 0: checkErr(f)
else: else:
c_fprintf(f, "%ld", i) if c_fprintf(f, "%ld", i) < 0: checkErr(f)
proc write(f: File, i: BiggestInt) = proc write(f: File, i: BiggestInt) =
when sizeof(BiggestInt) == 8: when sizeof(BiggestInt) == 8:
c_fprintf(f, "%lld", i) if c_fprintf(f, "%lld", i) < 0: checkErr(f)
else: else:
c_fprintf(f, "%ld", i) if c_fprintf(f, "%ld", i) < 0: checkErr(f)
proc write(f: File, b: bool) = proc write(f: File, b: bool) =
if b: write(f, "true") if b: write(f, "true")
else: write(f, "false") else: write(f, "false")
proc write(f: File, r: float32) = c_fprintf(f, "%g", r) proc write(f: File, r: float32) =
proc write(f: File, r: BiggestFloat) = c_fprintf(f, "%g", r) if c_fprintf(f, "%g", r) < 0: checkErr(f)
proc write(f: File, r: BiggestFloat) =
if c_fprintf(f, "%g", r) < 0: checkErr(f)
proc write(f: File, c: char) = discard c_putc(ord(c), f) proc write(f: File, c: char) = discard c_putc(ord(c), f)
proc write(f: File, a: varargs[string, `$`]) = proc write(f: File, a: varargs[string, `$`]) =
@ -212,7 +215,10 @@ proc rawFileSize(file: File): int =
discard c_fseek(file, clong(oldPos), 0) discard c_fseek(file, clong(oldPos), 0)
proc endOfFile(f: File): bool = proc endOfFile(f: File): bool =
result = c_feof(f) != 0 var c = c_fgetc(f)
discard c_ungetc(c, f)
return c < 0'i32
#result = c_feof(f) != 0
proc readAllFile(file: File, len: int): string = proc readAllFile(file: File, len: int): string =
# We acquire the filesize beforehand and hope it doesn't change. # We acquire the filesize beforehand and hope it doesn't change.

View file

@ -285,7 +285,19 @@ when useStackMaskHack:
when not defined(useNimRtl): when not defined(useNimRtl):
when not useStackMaskHack: when not useStackMaskHack:
#when not defined(createNimRtl): initStackBottom() #when not defined(createNimRtl): initStackBottom()
when declared(initGC): initGC() when declared(initGC):
initGC()
when not emulatedThreadVars:
type ThreadType {.pure.} = enum
None = 0,
NimThread = 1,
ForeignThread = 2
var
threadType {.rtlThreadVar.}: ThreadType
threadType = ThreadType.NimThread
when emulatedThreadVars: when emulatedThreadVars:
if nimThreadVarsSize() > sizeof(ThreadLocalStorage): if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
@ -442,6 +454,8 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
# init the GC for refc/markandsweep # init the GC for refc/markandsweep
setStackBottom(addr(p)) setStackBottom(addr(p))
initGC() initGC()
when declared(threadType):
threadType = ThreadType.NimThread
when declared(registerThread): when declared(registerThread):
thrd.stackBottom = addr(thrd) thrd.stackBottom = addr(thrd)
registerThread(thrd) registerThread(thrd)

237
readme.md
View file

@ -1,146 +1,175 @@
# <img src="https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png" width="36"> Nim [![Build Status](https://travis-ci.org/nim-lang/Nim.svg?branch=devel)](https://travis-ci.org/nim-lang/Nim) # ![Logo][image-nim-logo] Nim [![Build Status][badge-nim-travisci]][nim-travisci]
This repo contains the Nim compiler, Nim's stdlib, tools and This repository contains the Nim compiler, Nim's stdlib, tools and documentation.
documentation. For more information about Nim, including downloads For more information about Nim, including downloads and documentation for
and documentation for the latest release, check out the latest release, check out [Nim's website][nim-site].
[Nim's website](http://nim-lang.org).
## Community
[![Join the IRC chat][badge-nim-irc]][nim-irc]
[![Join the Gitter chat][badge-nim-gitter]][nim-gitter]
[![Get help][badge-nim-forum-gethelp]][nim-forum]
[![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest]
[![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter]
* The [forum][nim-forum] - the best place to ask questions and to discuss Nim.
* [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time.
Also where most development decisions get made.
* [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There
is a bridge between Gitter and the IRC channel.
* [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related
topics that includes posts about Nim.
## Compiling ## Compiling
Compiling the Nim compiler is quite straightforward. Because The compiler currently officially supports the following platform and
the Nim compiler itself is written in the Nim programming language architecture combinations:
the C source of an older version of the compiler are needed to bootstrap the
latest version. The C sources are available in a separate
repo [here](http://github.com/nim-lang/csources).
The compiler currently supports the following platform and architecture
combinations:
* Windows (Windows XP or greater) - x86 and x86_64 * Windows (Windows XP or greater) - x86 and x86_64
* Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
* Mac OS X 10.04 or higher - x86, x86_64 and ppc64 * Mac OS X (10.04 or greater) - x86, x86_64 and ppc64
In reality a lot more are supported, however they are not tested regularly. More platforms are supported, however they are not tested regularly and they
may not be as stable as the above-listed platforms.
To build from source you will need: Compiling the Nim compiler is quite straightforward if you follow these steps:
* gcc 3.x or later recommended. Other alternatives which may work First, the C source of an older version of the Nim compiler is needed to
are: clang, Visual C++, Intel's C++ compiler bootstrap the latest version because the Nim compiler itself is written in the
* git or wget Nim programming language. Those C sources are available within the
[``nim-lang/csources``][csources-repo] repository.
**Note:** When installing ``gcc`` on Ubuntu (and likely other distros) ensure Next, to build from source you will need:
that the ``build-essentials`` package is installed also.
If you are on a fairly modern *nix system, the following steps should work: * A C compiler such as ``gcc`` 3.x/later or an alternative such as ``clang``,
``Visual C++`` or ``Intel C++``. It is recommended to use ``gcc`` 3.x or
later.
* Either ``git`` or ``wget`` to download the needed source repositories.
* The ``build-essentials`` package when using ``gcc`` on Ubuntu (and likely
other distros as well).
Then, if you are on a \*nix system or Windows, the following steps should compile
Nim from source using ``gcc``, ``git`` and the ``koch`` build tool (in the place
of ``sh build.sh`` you should substitute ``build.bat`` on x86 Windows or
``build64.bat`` on x86_64 Windows):
``` ```
$ git clone https://github.com/nim-lang/Nim.git $ git clone https://github.com/nim-lang/Nim.git
$ cd Nim $ cd Nim
$ git clone --depth 1 https://github.com/nim-lang/csources $ git clone --depth 1 https://github.com/nim-lang/csources.git
$ cd csources && sh build.sh $ cd csources
$ cd .. $ sh build.sh
$ cd ../
$ bin/nim c koch $ bin/nim c koch
$ ./koch boot -d:release $ ./koch boot -d:release
``` ```
You should then add the ``bin`` directory to your PATH, to make it easily Finally, once you have finished the build steps (on Windows, Mac or Linux) you
executable on your system. should add the ``bin`` directory to your PATH.
The above steps can be performed on Windows in a similar fashion, the ## Koch
``build.bat`` and ``build64.bat`` (for x86_64 systems) are provided to be used ``koch`` is the build tool used to build various parts of Nim and to generate
instead of ``build.sh``. documentation and the website, among other things. The ``koch`` tool can also
be used to run the Nim test suite.
The ``koch`` tool is the Nim build tool, more ``koch`` related options are Assuming that you added Nim's ``bin`` directory to your PATH, you may execute
documented in [doc/koch.rst](doc/koch.rst). the tests using ``./koch tests``. The tests take a while to run, but you
can run a subset of tests by specifying a category (for example
``./koch tests cat async``).
For more information on the ``koch`` build tool please see the documentation
within the [doc/koch.rst](doc/koch.rst) file.
## Nimble ## Nimble
[Nimble](https://github.com/nim-lang/nimble) is Nim's package manager. For the ``nimble`` is Nim's package manager and it can be acquired from the
source based installations, where you added Nim's ``bin`` directory to your PATH, [``nim-lang/nimble``][nimble-repo] repository. Assuming that you added Nim's
the easiest way of installing Nimble is via: ``bin`` directory to your PATH, you may install Nimble from source by running
``koch nimble`` within the root of the cloned repository.
```
$ koch nimble
```
## Community
[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim)
[![Join the Gitter channel](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nim-lang/Nim)
[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org)
[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15)
[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang)
* The [forum](http://forum.nim-lang.org/) - the best place to ask questions and to discuss Nim.
* [IRC (Freenode#nim)](https://webchat.freenode.net/?channels=nim) - a place to discuss
Nim in real-time, this is also where most development decision get made!
* [Gitter](https://gitter.im/nim-lang/Nim) allows to discuss Nim from your browser, one click to join.
There is a bridge between Gitter and IRC channels.
* [Stackoverflow](http://stackoverflow.com/questions/tagged/nim)
## Contributing ## Contributing
[![Contribute to Nim via Gratipay][badge-nim-gratipay]][nim-gratipay]
[![Setup a bounty via Bountysource][badge-nim-bountysource]][nim-bountysource]
[![Donate Bitcoins][badge-nim-bitcoin]][nim-bitcoin]
[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/) We welcome everyone's contributions to Nim independent of how small or how large
[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim) they are. Anything from small spelling fixes to large modules intended to
be included in the standard library are welcome and appreciated. Before you get
We welcome everyone's contributions to Nim. No matter how small or large started contributing, you should familiarize yourself with the repository structure:
the contribution is, anything from small spelling fixes to large modules
intended to be included in the standard library are accepted. Before
you get started, you should know the following about this repositories
structure:
* ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built. * ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built.
* ``compiler/`` - the compiler source code, all the Nim source code files in this * ``compiler/`` - the compiler source code. Also includes nimfix, and plugins within
directory implement the compiler. This also includes nimfix, and plugins ``compiler/nimfix`` and ``compiler/plugins`` respectively. Nimsuggest was moved to
which live in ``compiler/nimfix`` and ``compiler/plugins`` the [``nim-lang/nimsuggest``][nimsuggest-repo] repository, though it previously also
respectively. Nimsuggest used to live in the ``compiler`` directory also, lived within the ``compiler/`` directory.
but was moved to https://github.com/nim-lang/nimsuggest.
* ``config/`` - the configuration for the compiler and documentation generator. * ``config/`` - the configuration for the compiler and documentation generator.
* ``doc/`` - the documentation files in reStructuredText format. * ``doc/`` - the documentation files in reStructuredText format.
* ``lib/`` - where the standard library lives. * ``lib/`` - the standard library, including:
* ``pure/`` - modules in the standard library written in pure Nim. * ``pure/`` - modules in the standard library written in pure Nim.
* ``impure/`` - modules in the standard library written in pure Nim which * ``impure/`` - modules in the standard library written in pure Nim with
depend on libraries written in other languages. dependencies written in other languages.
* ``wrappers/`` - modules which wrap libraries written in other languages. * ``wrappers/`` - modules which wrap dependencies written in other languages.
* ``tests/`` - contains tests for the compiler and standard library, organised by * ``tests/`` - contains categorized tests for the compiler and standard library.
category. * ``tools/`` - the tools including ``niminst`` and ``nimweb`` (mostly invoked via
* ``tools/`` - the tools including ``niminst`` and ``nimweb``, most of these are invoked ``koch``).
via ``koch``. * ``web/`` - [the Nim website][nim-site].
* ``web/`` - the Nim website (http://nim-lang.org). * ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website,
* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, documentation and generate the documentation.
and more.
Most importantly, the ``koch`` tool can be used to run the test suite. To do so compile it first If you are not familiar with making a pull request using GitHub and/or git, please
by executing ``nim c koch``, then execute ``./koch tests``. The test suite takes a while to run, read [this guide][pull-request-instructions].
but you can run specific tests by specifying a category to run, for example ``./koch tests cat async``.
Make sure that the tests all pass before Ideally you should make sure that all tests pass before submitting a pull request.
[submitting your pull request](https://help.github.com/articles/using-pull-requests/). However, if you are short on time, you can just run the tests specific to your
If you're short on time, you can changes by only running the corresponding categories of tests. Travis CI verifies
just run the tests specific to your change. Just run the category which corresponds to the change that all tests pass before allowing the pull request to be accepted, so only
you've made. When you create your pull request, Travis CI will verify that all the tests pass running specific tests should be harmless.
anyway.
If you're looking for things to do, take a look at our If you're looking for ways to contribute, please look at our [issue tracker][nim-issues].
[issue tracker](https://github.com/nim-lang/Nim/issues). There is always plenty of issues There are always plenty of issues labelled [``Easy``][nim-issues-easy]; these should
labelled [``Easy``](https://github.com/nim-lang/Nim/labels/Easy), these should be a good be a good starting point for an initial contribution to Nim.
starting point if this is your first contribution to Nim.
You can also help with the development of Nim by making donations. You can do so You can also help with the development of Nim by making donations. Donations can be
in many ways: made using:
* [Gratipay](https://gratipay.com/nim/) * [Gratipay][nim-gratipay]
* [Bountysource](https://www.bountysource.com/teams/nim) * [Bountysource][nim-bountysource]
* Bitcoin - 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ * [Bitcoin][nim-bitcoin]
Finally, if you have any questions feel free to submit a question on the issue tracker, If you have any questions feel free to submit a question on the
on the [Nim forum](http://forum.nim-lang.org), or on IRC. [Nim forum][nim-forum], or via IRC on [the \#nim channel][nim-irc].
## License ## License
The compiler and the standard library are licensed under the MIT license, The compiler and the standard library are licensed under the MIT license, except
except for some modules where the documentation suggests otherwise. This means for some modules which explicitly state otherwise. As a result you may use any
that you can use any license for your own programs developed with Nim, compatible license (essentially any license) for your own programs developed with
allowing you to create commercial applications. Nim. You are explicitly permitted to develop commercial applications using Nim.
Read copying.txt for more details. Please read the [copying.txt](copying.txt) file for more details.
Copyright (c) 2006-2017 Andreas Rumpf. Copyright © 2006-2017 Andreas Rumpf, all rights reserved.
All rights reserved.
[nim-site]: https://nim-lang.org
[nim-forum]: https://forum.nim-lang.org
[nim-issues]: https://github.com/nim-lang/Nim/issues
[nim-issues-easy]: https://github.com/nim-lang/Nim/labels/Easy
[nim-irc]: https://webchat.freenode.net/?channels=nim
[nim-travisci]: https://travis-ci.org/nim-lang/Nim
[nim-twitter]: https://twitter.com/nim_lang
[nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim
[nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15
[nim-gitter]: https://gitter.im/nim-lang/Nim
[nim-gratipay]: https://gratipay.com/nim/
[nim-bountysource]: https://www.bountysource.com/teams/nim
[nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
[nimble-repo]: https://github.com/nim-lang/nimble
[nimsuggest-repo]: https://github.com/nim-lang/nimsuggest
[csources-repo]: https://github.com/nim-lang/csources
[badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square
[badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square
[badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square
[badge-nim-forum-gethelp]: https://img.shields.io/badge/Forum-get%20help-4eb899.svg?style=flat-square
[badge-nim-twitter]: https://img.shields.io/twitter/follow/nim_lang.svg?style=social
[badge-nim-stackoverflow]: https://img.shields.io/badge/stackoverflow-nim_tag-yellow.svg?style=flat-square
[badge-nim-gratipay]: https://img.shields.io/gratipay/team/nim.svg?style=flat-square
[badge-nim-bountysource]: https://img.shields.io/bountysource/team/nim/activity.svg?style=flat-square
[badge-nim-bitcoin]: https://img.shields.io/badge/bitcoin-1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ-D69134.svg?style=flat-square
[image-nim-logo]: https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png&container=focus&resize_w=36&refresh=21600
[pull-request-instructions]: https://help.github.com/articles/using-pull-requests/

View file

@ -0,0 +1,26 @@
discard """
output: '''false'''
"""
# bug #5402
import lists
type
Container[T] = ref object
obj: T
ListOfContainers[T] = ref object
list: DoublyLinkedList[Container[T]]
proc contains[T](this: ListOfContainers[T], obj: T): bool =
for item in this.list.items():
if item.obj == obj: return true
return false
proc newListOfContainers[T](): ListOfContainers[T] =
new(result)
result.list = initDoublyLinkedList[Container[T]]()
let q = newListOfContainers[int64]()
echo q.contains(123)

View file

@ -0,0 +1,23 @@
discard """
outputsub: '''tproper_stacktrace3.nim(21) main'''
exitcode: 1
"""
# bug #5400
type Container = object
val: int
proc actualResolver(x: ptr Container): ptr Container = x
template resolve(): untyped = actualResolver(db)
proc myfail(): int =
doAssert false
proc main() =
var db: ptr Container = nil
# actualResolver(db).val = myfail() # actualResolver is not included in stack trace.
resolve().val = myfail() # resolve template is included in stack trace.
main()

88
tests/gc/foreign_thr.nim Normal file
View file

@ -0,0 +1,88 @@
discard """
output: '''
Hello from thread
Hello from thread
Hello from thread
Hello from thread
'''
cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file"
"""
# Copied from stdlib
import strutils
const
StackGuardSize = 4096
ThreadStackMask = 1024*256*sizeof(int)-1
ThreadStackSize = ThreadStackMask+1 - StackGuardSize
type ThreadFunc = proc() {.thread.}
when defined(posix):
import posix
proc runInForeignThread(f: ThreadFunc) =
proc wrapper(p: pointer): pointer {.noconv.} =
let thr = cast[ThreadFunc](p)
setupForeignThreadGc()
thr()
tearDownForeignThreadGc()
setupForeignThreadGc()
thr()
tearDownForeignThreadGc()
result = nil
var attrs {.noinit.}: PthreadAttr
doAssert pthread_attr_init(addr attrs) == 0
doAssert pthread_attr_setstacksize(addr attrs, ThreadStackSize) == 0
var tid: Pthread
doAssert pthread_create(addr tid, addr attrs, wrapper, f) == 0
doAssert pthread_join(tid, nil) == 0
elif defined(windows):
import winlean
type
WinThreadProc = proc (x: pointer): int32 {.stdcall.}
proc createThread(lpThreadAttributes: pointer, dwStackSize: DWORD,
lpStartAddress: WinThreadProc,
lpParameter: pointer,
dwCreationFlags: DWORD,
lpThreadId: var DWORD): Handle {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
proc wrapper(p: pointer): int32 {.stdcall.} =
let thr = cast[ThreadFunc](p)
setupForeignThreadGc()
thr()
tearDownForeignThreadGc()
setupForeignThreadGc()
thr()
tearDownForeignThreadGc()
result = 0'i32
proc runInForeignThread(f: ThreadFunc) =
var dummyThreadId: DWORD
var h = createThread(nil, ThreadStackSize.int32, wrapper.WinThreadProc, cast[pointer](f), 0, dummyThreadId)
doAssert h != 0.Handle
doAssert waitForSingleObject(h, -1'i32) == 0.DWORD
else:
{.fatal: "Unknown system".}
proc runInNativeThread(f: ThreadFunc) =
proc wrapper(f: ThreadFunc) {.thread.} =
# These operations must be NOP
setupForeignThreadGc()
tearDownForeignThreadGc()
f()
f()
var thr: Thread[ThreadFunc]
createThread(thr, wrapper, f)
joinThread(thr)
proc f {.thread.} =
var msg = "Hello " & "from thread"
echo msg
runInForeignThread(f)
runInNativeThread(f)

View file

@ -0,0 +1,17 @@
type
Test = object
x: int
case p: bool
of true:
a: int
else:
case q: bool
of true:
b: int
else:
discard
proc f[T](t: typedesc[T]): int =
1
assert Test.f == 1

View file

@ -19,7 +19,7 @@ when true:
q(B()) # This call reported as ambiguous. q(B()) # This call reported as ambiguous.
# bug #2219 # bug #2219
template testPred(a: expr) = template testPred(a: untyped) =
block: block:
type A = object of RootObj type A = object of RootObj
type B = object of A type B = object of A

11
tests/stdlib/tbug5382.nim Normal file
View file

@ -0,0 +1,11 @@
discard """
output: '''
02
'''
"""
import re
let regexp = re"^\/([0-9]{2})\.html$"
var matches: array[1, string]
discard "/02.html".find(regexp, matches)
echo matches[0]

View file

@ -1,3 +1,10 @@
discard """
output: '''[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0]
5050'''
"""
template mathPerComponent(op: untyped): untyped = template mathPerComponent(op: untyped): untyped =
proc op*[N,T](v,u: array[N,T]): array[N,T] {.inline.} = proc op*[N,T](v,u: array[N,T]): array[N,T] {.inline.} =
@ -19,3 +26,24 @@ proc foo(): void =
echo repr(v1 *** v2) echo repr(v1 *** v2)
foo() foo()
# bug #5383
import sequtils
proc zipWithIndex[A](ts: seq[A]): seq[(int, A)] =
toSeq(pairs(ts))
proc main =
discard zipWithIndex(@["foo", "bar"])
discard zipWithIndex(@[1, 2])
discard zipWithIndex(@[true, false])
main()
# bug #5405
proc main2() =
let s = toSeq(1..100).foldL(a + b)
echo s
main2()

View file

@ -5,8 +5,8 @@ import macros
# Test that parameters are properly gensym'ed finally: # Test that parameters are properly gensym'ed finally:
template genNodeKind(kind, name: expr): stmt = template genNodeKind(kind, name: untyped) =
proc name*(children: varargs[PNimrodNode]): PNimrodNode {.compiletime.}= proc name*(children: varargs[NimNode]): NimNode {.compiletime.}=
result = newNimNode(kind) result = newNimNode(kind)
for c in children: for c in children:
result.add(c) result.add(c)
@ -22,7 +22,7 @@ type Something = object
proc testA(x: Something) = discard proc testA(x: Something) = discard
template def(name: expr) {.immediate.} = template def(name: untyped) =
proc testB[T](reallyUniqueName: T) = proc testB[T](reallyUniqueName: T) =
`test name`(reallyUniqueName) `test name`(reallyUniqueName)
def A def A
@ -35,8 +35,7 @@ testB(x)
# Test that templates in generics still work (regression to fix the # Test that templates in generics still work (regression to fix the
# regression...) # regression...)
template forStatic(index: expr, slice: Slice[int], predicate: stmt): template forStatic(index, slice, predicate: untyped) =
stmt {.immediate.} =
const a = slice.a const a = slice.a
const b = slice.b const b = slice.b
when a <= b: when a <= b:

View file

@ -147,6 +147,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
testSpec r, makeTest("tests/gc" / filename, options & testSpec r, makeTest("tests/gc" / filename, options &
" -d:release --gc:boehm", cat, actionRun) " -d:release --gc:boehm", cat, actionRun)
testWithoutBoehm "foreign_thr"
test "gcemscripten" test "gcemscripten"
test "growobjcrash" test "growobjcrash"
test "gcbench" test "gcbench"

View file

@ -77,6 +77,235 @@ for i in 1..10:
discard db.getRow( discard db.getRow(
SqlQuery("INSERT INTO tags(name) VALUES(\'$1\') RETURNING id" % [name])) SqlQuery("INSERT INTO tags(name) VALUES(\'$1\') RETURNING id" % [name]))
# get column details
db.exec(SqlQuery("DROP TABLE IF EXISTS dbtypes;"))
db.exec(SqlQuery("DROP TYPE IF EXISTS custom_enum;"))
db.exec(SqlQuery("CREATE TYPE custom_enum AS ENUM ('1', '2', '3');"))
db.exec(SqlQuery("DROP TYPE IF EXISTS custom_composite;"))
db.exec(SqlQuery("CREATE TYPE custom_composite AS (r double precision, i double precision);"))
db.exec(SqlQuery("""CREATE TABLE dbtypes(
id serial UNIQUE,
bytea_col bytea,
smallint_col smallint,
integer_col integer,
bigint_col bigint,
decimal_col decimal,
numeric_col numeric,
real_col real,
double_precision_col double precision,
smallserial_col smallserial,
serial_col serial,
bigserial_col bigserial,
money_col money,
varchar_col varchar(10),
character_col character(1),
text_col text,
timestamp_col timestamp,
date_col date,
time_col time,
interval_col interval,
bool_col boolean,
custom_enum_col custom_enum,
point_col point,
line_col line,
lseg_col lseg,
box_col box,
path_col path,
polygon_col polygon,
circle_col circle,
cidr_col cidr,
inet_col inet,
macaddr_col macaddr,
bit_col bit,
varbit_col bit(3),
tsvector_col tsvector,
tsquery_col tsquery,
uuid_col uuid,
xml_col xml,
json_col json,
array_col integer[],
custom_composite_col custom_composite,
range_col int4range
);"""))
db.exec(SqlQuery("INSERT INTO dbtypes (id) VALUES(0);"))
var dbCols : DbColumns = @[]
for row in db.instantRows(dbCols, sql"SELECT * FROM dbtypes"):
doAssert len(dbCols) == 42
doAssert dbCols[0].name == "id"
doAssert dbCols[0].typ.kind == DbTypeKind.dbInt
doAssert dbCols[0].typ.name == "int4"
doAssert dbCols[0].typ.size == 4
doAssert dbCols[1].name == "bytea_col"
doAssert dbCols[1].typ.kind == DbTypeKind.dbBlob
doAssert dbCols[1].typ.name == "bytea"
doAssert dbCols[2].name == "smallint_col"
doAssert dbCols[2].typ.kind == DbTypeKind.dbInt
doAssert dbCols[2].typ.name == "int2"
doAssert dbCols[2].typ.size == 2
doAssert dbCols[3].name == "integer_col"
doAssert dbCols[3].typ.kind == DbTypeKind.dbInt
doAssert dbCols[3].typ.name == "int4"
doAssert dbCols[3].typ.size == 4
doAssert dbCols[4].name == "bigint_col"
doAssert dbCols[4].typ.kind == DbTypeKind.dbInt
doAssert dbCols[4].typ.name == "int8"
doAssert dbCols[4].typ.size == 8
doAssert dbCols[5].name == "decimal_col"
doAssert dbCols[5].typ.kind == DbTypeKind.dbDecimal
doAssert dbCols[5].typ.name == "numeric"
doAssert dbCols[6].name == "numeric_col"
doAssert dbCols[6].typ.kind == DbTypeKind.dbDecimal
doAssert dbCols[6].typ.name == "numeric"
doAssert dbCols[7].name == "real_col"
doAssert dbCols[7].typ.kind == DbTypeKind.dbFloat
doAssert dbCols[7].typ.name == "float4"
doAssert dbCols[8].name == "double_precision_col"
doAssert dbCols[8].typ.kind == DbTypeKind.dbFloat
doAssert dbCols[8].typ.name == "float8"
doAssert dbCols[9].name == "smallserial_col"
doAssert dbCols[9].typ.kind == DbTypeKind.dbInt
doAssert dbCols[9].typ.name == "int2"
doAssert dbCols[10].name == "serial_col"
doAssert dbCols[10].typ.kind == DbTypeKind.dbInt
doAssert dbCols[10].typ.name == "int4"
doAssert dbCols[11].name == "bigserial_col"
doAssert dbCols[11].typ.kind == DbTypeKind.dbInt
doAssert dbCols[11].typ.name == "int8"
doAssert dbCols[12].name == "money_col"
doAssert dbCols[12].typ.kind == DbTypeKind.dbDecimal
doAssert dbCols[12].typ.name == "money"
doAssert dbCols[13].name == "varchar_col"
doAssert dbCols[13].typ.kind == DbTypeKind.dbVarchar
doAssert dbCols[13].typ.name == "varchar"
doAssert dbCols[14].name == "character_col"
doAssert dbCols[14].typ.kind == DbTypeKind.dbFixedChar
doAssert dbCols[14].typ.name == "bpchar"
doAssert dbCols[15].name == "text_col"
doAssert dbCols[15].typ.kind == DbTypeKind.dbVarchar
doAssert dbCols[15].typ.name == "text"
doAssert dbCols[16].name == "timestamp_col"
doAssert dbCols[16].typ.kind == DbTypeKind.dbTimestamp
doAssert dbCols[16].typ.name == "timestamp"
doAssert dbCols[17].name == "date_col"
doAssert dbCols[17].typ.kind == DbTypeKind.dbDate
doAssert dbCols[17].typ.name == "date"
doAssert dbCols[18].name == "time_col"
doAssert dbCols[18].typ.kind == DbTypeKind.dbTime
doAssert dbCols[18].typ.name == "time"
doAssert dbCols[19].name == "interval_col"
doAssert dbCols[19].typ.kind == DbTypeKind.dbTimeInterval
doAssert dbCols[19].typ.name == "interval"
doAssert dbCols[20].name == "bool_col"
doAssert dbCols[20].typ.kind == DbTypeKind.dbBool
doAssert dbCols[20].typ.name == "bool"
doAssert dbCols[21].name == "custom_enum_col"
doAssert dbCols[21].typ.kind == DbTypeKind.dbUnknown
doAssert parseInt(dbCols[21].typ.name) > 0
doAssert dbCols[22].name == "point_col"
doAssert dbCols[22].typ.kind == DbTypeKind.dbPoint
doAssert dbCols[22].typ.name == "point"
doAssert dbCols[23].name == "line_col"
doAssert dbCols[23].typ.kind == DbTypeKind.dbLine
doAssert dbCols[23].typ.name == "line"
doAssert dbCols[24].name == "lseg_col"
doAssert dbCols[24].typ.kind == DbTypeKind.dbLseg
doAssert dbCols[24].typ.name == "lseg"
doAssert dbCols[25].name == "box_col"
doAssert dbCols[25].typ.kind == DbTypeKind.dbBox
doAssert dbCols[25].typ.name == "box"
doAssert dbCols[26].name == "path_col"
doAssert dbCols[26].typ.kind == DbTypeKind.dbPath
doAssert dbCols[26].typ.name == "path"
doAssert dbCols[27].name == "polygon_col"
doAssert dbCols[27].typ.kind == DbTypeKind.dbPolygon
doAssert dbCols[27].typ.name == "polygon"
doAssert dbCols[28].name == "circle_col"
doAssert dbCols[28].typ.kind == DbTypeKind.dbCircle
doAssert dbCols[28].typ.name == "circle"
doAssert dbCols[29].name == "cidr_col"
doAssert dbCols[29].typ.kind == DbTypeKind.dbInet
doAssert dbCols[29].typ.name == "cidr"
doAssert dbCols[30].name == "inet_col"
doAssert dbCols[30].typ.kind == DbTypeKind.dbInet
doAssert dbCols[30].typ.name == "inet"
doAssert dbCols[31].name == "macaddr_col"
doAssert dbCols[31].typ.kind == DbTypeKind.dbMacAddress
doAssert dbCols[31].typ.name == "macaddr"
doAssert dbCols[32].name == "bit_col"
doAssert dbCols[32].typ.kind == DbTypeKind.dbBit
doAssert dbCols[32].typ.name == "bit"
doAssert dbCols[33].name == "varbit_col"
doAssert dbCols[33].typ.kind == DbTypeKind.dbBit
doAssert dbCols[33].typ.name == "bit"
doAssert dbCols[34].name == "tsvector_col"
doAssert dbCols[34].typ.kind == DbTypeKind.dbVarchar
doAssert dbCols[34].typ.name == "tsvector"
doAssert dbCols[35].name == "tsquery_col"
doAssert dbCols[35].typ.kind == DbTypeKind.dbVarchar
doAssert dbCols[35].typ.name == "tsquery"
doAssert dbCols[36].name == "uuid_col"
doAssert dbCols[36].typ.kind == DbTypeKind.dbVarchar
doAssert dbCols[36].typ.name == "uuid"
doAssert dbCols[37].name == "xml_col"
doAssert dbCols[37].typ.kind == DbTypeKind.dbXml
doAssert dbCols[37].typ.name == "xml"
doAssert dbCols[38].name == "json_col"
doAssert dbCols[38].typ.kind == DbTypeKind.dbJson
doAssert dbCols[38].typ.name == "json"
doAssert dbCols[39].name == "array_col"
doAssert dbCols[39].typ.kind == DbTypeKind.dbArray
doAssert dbCols[39].typ.name == "int4[]"
doAssert dbCols[40].name == "custom_composite_col"
doAssert dbCols[40].typ.kind == DbTypeKind.dbUnknown
doAssert parseInt(dbCols[40].typ.name) > 0
doAssert dbCols[41].name == "range_col"
doAssert dbCols[41].typ.kind == DbTypeKind.dbComposite
doAssert dbCols[41].typ.name == "int4range"
echo("All tests succeeded!") echo("All tests succeeded!")
db.close() db.close()

View file

@ -209,6 +209,9 @@ proc main() =
of Manual: of Manual:
echo "After download, move it to: ", dest echo "After download, move it to: ", dest
if askBool("Download successful? (y/n) "): if askBool("Download successful? (y/n) "):
while not fileExists("dist" / mingw):
echo "could not find: ", "dist" / mingw
if not askBool("Try again? (y/n) "): break
if unzip(): retry = true if unzip(): retry = true
of Failure: discard of Failure: discard
of Success: of Success:

1
web/bountysource.nim.cfg Normal file
View file

@ -0,0 +1 @@
-d:ssl

View file

@ -1,26 +1,40 @@
logo, name, url, this_month, all_time, since, level logo, name, url, this_month, all_time, since, level
,bogen,,0,1010,"Jul 23, 2016",1 ,bogen,,0,1010,"Jul 23, 2016",1
,mikra,,0,400,"Apr 28, 2016",1 ,mikra,,0,400,"Apr 28, 2016",1
,linkmonitor,,0,180,"Jan 28, 2016",1 ,shkolnick-kun,,0,375,"Jul 6, 2016",1
,"Chris Heller",,0,350,"May 19, 2016",1
,linkmonitor,,0,280,"Jan 28, 2016",1
,avsej,,0,110,"Jun 10, 2016",1 ,avsej,,0,110,"Jun 10, 2016",1
,WilRubin,,0,100,"Aug 11, 2015",1 ,WilRubin,,0,100,"Aug 11, 2015",1
,"Benny Luypaert",,0,100,"Apr 10, 2016",1 ,"Benny Luypaert",,0,100,"Apr 10, 2016",1
,"Chris Heller",,0,100,"May 19, 2016",1
,PhilipWitte,,0,100,"Aug 5, 2016",1 ,PhilipWitte,,0,100,"Aug 5, 2016",1
,skunkiferous,,0,100,"Oct 2, 2016",1
,"Jonathan Arnett",,0,90,"May 20, 2016",1
,Boxifier,,0,75,"Apr 12, 2016",1 ,Boxifier,,0,75,"Apr 12, 2016",1
,iolloyd,,0,75,"Apr 29, 2016",1 ,iolloyd,,0,75,"Apr 29, 2016",1
,btbytes,,0,70,"Apr 6, 2016",1
,rb01,,0,50,"May 4, 2016",1 ,rb01,,0,50,"May 4, 2016",1
,barcharcraz,,0,50,"Jun 2, 2016",1
,zachaysan,,0,50,"Jun 7, 2016",1
,kunev,,0,50,"Dec 26, 2016",1
,iboB,,0,50,"Jan 28, 2017",1
,TedSinger,,0,45,"Apr 9, 2016",1 ,TedSinger,,0,45,"Apr 9, 2016",1
,johnnovak,,0,45,"Apr 30, 2016",1
,"Matthew Baulch",,0,40,"Jun 7, 2016",1
,"Matthew Newton",,0,35,"Apr 20, 2016",1
,martinbbjerregaard,,0,35,"Jun 9, 2016",1 ,martinbbjerregaard,,0,35,"Jun 9, 2016",1
,RationalG,,0,30,"Jun 17, 2016",1 ,RationalG,,0,30,"Jun 17, 2016",1
,benbve,,0,30,"Jul 12, 2016",1 ,benbve,,0,30,"Jul 12, 2016",1
,barcharcraz,,0,25,"Jun 2, 2016",1 ,multikatt,,0,30,"Nov 2, 2016",1
,"Landon Bass",,0,25,"Jun 7, 2016",1 ,"Landon Bass",,0,25,"Jun 7, 2016",1
,jimrichards,,0,25,"Jun 8, 2016",1 ,jimrichards,,0,25,"Jun 8, 2016",1
,jjzazuet,,0,25,"Jul 10, 2016",1 ,jjzazuet,,0,25,"Jul 10, 2016",1
,moigagoo,,0,20,"May 13, 2016",1
,kteza1,,0,20,"Jun 10, 2016",1 ,kteza1,,0,20,"Jun 10, 2016",1
,tomkeus,,0,20,"Sep 4, 2016",1 ,tomkeus,,0,20,"Sep 4, 2016",1
,csoriano89,,0,20,"Sep 7, 2016",1
,juanjux,,0,20,"Oct 29, 2016",1
,zagfai,,0,20,"Nov 3, 2016",1
,hellcoderz,,0,20,"Jan 24, 2017",1
,mirek,,0,15,"Apr 9, 2016",1 ,mirek,,0,15,"Apr 9, 2016",1
,DateinAsia,,0,15,"Jul 30, 2016",1 ,DateinAsia,,0,15,"Jul 30, 2016",1
,rickc,,0,15,"Jul 31, 2016",1 ,rickc,,0,15,"Jul 31, 2016",1
@ -38,13 +52,6 @@ logo, name, url, this_month, all_time, since, level
,Blumenversand,,0,10,"Jul 21, 2016",1 ,Blumenversand,,0,10,"Jul 21, 2016",1
,cinnabardk,,0,10,"Aug 6, 2016",1 ,cinnabardk,,0,10,"Aug 6, 2016",1
,reddec,,0,10,"Aug 31, 2016",1 ,reddec,,0,10,"Aug 31, 2016",1
,cupen,,0,10,"Nov 21, 2016",1
,yay,,0,10,"Jan 25, 2017",1
,niv,,0,5,"Apr 6, 2016",1 ,niv,,0,5,"Apr 6, 2016",1
,goniz,,0,5,"Apr 7, 2016",1
,genunix,,0,5,"Apr 12, 2016",1
,CynepHy6,,0,5,"Apr 14, 2016",1
,ivanflorentin,,0,5,"May 3, 2016",1
,stevenyhw,,0,5,"May 20, 2016",1
,"Sanjay Singh",,0,5,"Jun 6, 2016",1
,yuttie,,0,5,"Jun 7, 2016",1
,hron,,0,5,"Jun 11, 2016",1
,laszlowaty,,0,5,"Jun 17, 2016",1

1 logo name url this_month all_time since level
2 bogen 0 1010 Jul 23, 2016 1
3 mikra 0 400 Apr 28, 2016 1
4 linkmonitor shkolnick-kun 0 180 375 Jan 28, 2016 Jul 6, 2016 1
5 Chris Heller 0 350 May 19, 2016 1
6 linkmonitor 0 280 Jan 28, 2016 1
7 avsej 0 110 Jun 10, 2016 1
8 WilRubin 0 100 Aug 11, 2015 1
9 Benny Luypaert 0 100 Apr 10, 2016 1
Chris Heller 0 100 May 19, 2016 1
10 PhilipWitte 0 100 Aug 5, 2016 1
11 skunkiferous 0 100 Oct 2, 2016 1
12 Jonathan Arnett 0 90 May 20, 2016 1
13 Boxifier 0 75 Apr 12, 2016 1
14 iolloyd 0 75 Apr 29, 2016 1
15 btbytes 0 70 Apr 6, 2016 1
16 rb01 0 50 May 4, 2016 1
17 barcharcraz 0 50 Jun 2, 2016 1
18 zachaysan 0 50 Jun 7, 2016 1
19 kunev 0 50 Dec 26, 2016 1
20 iboB 0 50 Jan 28, 2017 1
21 TedSinger 0 45 Apr 9, 2016 1
22 johnnovak 0 45 Apr 30, 2016 1
23 Matthew Baulch 0 40 Jun 7, 2016 1
24 Matthew Newton 0 35 Apr 20, 2016 1
25 martinbbjerregaard 0 35 Jun 9, 2016 1
26 RationalG 0 30 Jun 17, 2016 1
27 benbve 0 30 Jul 12, 2016 1
28 barcharcraz multikatt 0 25 30 Jun 2, 2016 Nov 2, 2016 1
29 Landon Bass 0 25 Jun 7, 2016 1
30 jimrichards 0 25 Jun 8, 2016 1
31 jjzazuet 0 25 Jul 10, 2016 1
moigagoo 0 20 May 13, 2016 1
32 kteza1 0 20 Jun 10, 2016 1
33 tomkeus 0 20 Sep 4, 2016 1
34 csoriano89 0 20 Sep 7, 2016 1
35 juanjux 0 20 Oct 29, 2016 1
36 zagfai 0 20 Nov 3, 2016 1
37 hellcoderz 0 20 Jan 24, 2017 1
38 mirek 0 15 Apr 9, 2016 1
39 DateinAsia 0 15 Jul 30, 2016 1
40 rickc 0 15 Jul 31, 2016 1
52 Blumenversand 0 10 Jul 21, 2016 1
53 cinnabardk 0 10 Aug 6, 2016 1
54 reddec 0 10 Aug 31, 2016 1
55 cupen 0 10 Nov 21, 2016 1
56 yay 0 10 Jan 25, 2017 1
57 niv 0 5 Apr 6, 2016 1
goniz 0 5 Apr 7, 2016 1
genunix 0 5 Apr 12, 2016 1
CynepHy6 0 5 Apr 14, 2016 1
ivanflorentin 0 5 May 3, 2016 1
stevenyhw 0 5 May 20, 2016 1
Sanjay Singh 0 5 Jun 6, 2016 1
yuttie 0 5 Jun 7, 2016 1
hron 0 5 Jun 11, 2016 1
laszlowaty 0 5 Jun 17, 2016 1

View file

@ -18,7 +18,11 @@ Changes affecting backwards compatibility
- The IO routines now raise ``EOFError`` for the "end of file" condition. - The IO routines now raise ``EOFError`` for the "end of file" condition.
``EOFError`` is a subtype of ``IOError`` and so it's easier to distinguish ``EOFError`` is a subtype of ``IOError`` and so it's easier to distinguish
between "error during read" and "error due to EOF". between "error during read" and "error due to EOF".
- A hash procedure has been added for ``cstring`` type in ``hashes`` module.
Previously, hash of a ``cstring`` would be calculated as a hash of the
pointer. Now the hash is calculated from the contents of the string, assuming
``cstring`` is a null-terminated string. Equal ``string`` and ``cstring``
values produce an equal hash value.
Library Additions Library Additions
----------------- -----------------

View file

@ -1,34 +1,40 @@
logo, name, url, this_month, all_time, since, level logo, name, url, this_month, all_time, since, level
assets/bountysource/secondspectrum.png,Second Spectrum,http://www.secondspectrum.com/,250,1250,"May 5, 2016",250 assets/bountysource/secondspectrum.png,Second Spectrum,http://www.secondspectrum.com/,250,2250,"May 5, 2016",250
assets/bountysource/xored.svg,"Xored Software, Inc.",http://xored.com/,250,1000,"Jun 20, 2016",250 assets/bountysource/xored.svg,"Xored Software, Inc.",http://xored.com/,250,1000,250,2000,"Jun 20, 2016",250
,shkolnick-kun,https://github.com/shkolnick-kun,75,225,"Jul 6, 2016",75 ,Varriount,https://github.com/Varriount,250,750,"Nov 18, 2016",250
,flyx,http://flyx.org,35,210,"Apr 7, 2016",75 ,flyx,http://flyx.org,35,350,"Apr 7, 2016",75
,"Yuriy Glukhov",,25,150,"Apr 6, 2016",25 ,"Yuriy Glukhov",,25,250,"Apr 6, 2016",25
,endragor,https://github.com/endragor,25,150,"Apr 7, 2016",25 ,endragor,https://github.com/endragor,25,250,"Apr 7, 2016",25
,FedericoCeratto,http://firelet.net,25,150,"Apr 7, 2016",25 ,FedericoCeratto,http://firelet.net,25,250,"Apr 7, 2016",25
,"Adrian Veith",,25,150,"Apr 20, 2016",25 ,"Adrian Veith",,25,250,"Apr 20, 2016",25
,skunkiferous,https://github.com/skunkiferous,100,100,"Oct 2, 2016",150 ,euantorano,http://euantorano.co.uk,25,200,"Jun 7, 2016",25
,euantorano,http://euantorano.co.uk,25,100,"Jun 7, 2016",25 ,xxlabaza,https://github.com/xxlabaza,25,170,"Jun 17, 2016",25
,xxlabaza,https://github.com/xxlabaza,25,95,"Jun 17, 2016",25 ,devted,https://github.com/devted,25,100,"Oct 19, 2016",25
,btbytes,https://www.btbytes.com/,10,60,"Apr 6, 2016",10 ,"pyloor ",https://schwarz-weiss.cc/,10,95,"May 16, 2016",10
,niebaopeng,https://github.com/niebaopeng,10,50,"Apr 15, 2016",10 ,niebaopeng,https://github.com/niebaopeng,10,90,"Apr 15, 2016",10
,"Jonathan Arnett",,10,50,"May 20, 2016",10 ,zolern,https://github.com/zolern,10,80,"Apr 15, 2016",10
,swalf,https://github.com/swalf,5,45,"May 9, 2016",5 ,"Oskari Timperi",,10,80,"Jun 8, 2016",10
,zolern,https://github.com/zolern,10,40,"Apr 15, 2016",10 ,jcosborn,https://github.com/jcosborn,25,75,"Nov 21, 2016",25
,"pyloor ",https://schwarz-weiss.cc/,10,40,"May 16, 2016",10 ,swalf,https://github.com/swalf,5,65,"May 9, 2016",5
,zachaysan,http://venn.lc,10,40,"Jun 7, 2016",10 ,"Handojo Goenadi",,5,55,"Apr 19, 2016",5
,"Matthew Baulch",,10,40,"Jun 7, 2016",10 ,cpunion,https://github.com/cpunion,10,50,"Sep 9, 2016",10
,"Oskari Timperi",,10,40,"Jun 8, 2016",10 ,D-L,https://github.com/D-L,5,50,"Apr 7, 2016",5
,"Handojo Goenadi",,5,35,"Apr 19, 2016",5 ,moigagoo,http://sloth-ci.com,10,40,"May 13, 2016",10
,"Matthew Newton",,5,30,"Apr 20, 2016",5 ,enthus1ast,http://code0.xyz/,10,40,"Oct 28, 2016",10
,johnnovak,http://www.johnnovak.net/,5,30,"Apr 29, 2016",5 ,RyanMarcus,http://rmarcus.info,5,35,"Jul 19, 2016",5
,RyanMarcus,http://rmarcus.info,5,15,"Jul 19, 2016",5 ,lenzenmi,https://github.com/lenzenmi,5,35,"Jul 28, 2016",5
,lenzenmi,https://github.com/lenzenmi,5,15,"Jul 28, 2016",5 ,"Christian Bagley",,10,30,"Oct 11, 2016",10
,cpunion,https://github.com/cpunion,10,10,"Sep 9, 2016",10 ,pandada8,https://github.com/pandada8,5,30,"Aug 12, 2016",5
,pandada8,https://github.com/pandada8,5,10,"Aug 12, 2016",5 ,abeaumont,http://alfredobeaumont.org/blog,5,30,"Aug 12, 2016",5
,abeaumont,http://alfredobeaumont.org/blog,5,10,"Aug 12, 2016",5 ,opendragon,http://www.opendragon.com,25,25,"Jan 18, 2017",25
,"Svend Knudsen",,1,6,"Apr 11, 2016",1 ,"Eric Raible",,10,20,"Dec 23, 2016",10
,"Michael D. Sklaroff",,1,6,"Apr 27, 2016",1 ,zefciu,http://pythonista.net,10,20,"Dec 29, 2016",10
,csoriano89,https://github.com/csoriano89,5,5,"Sep 7, 2016",5 ,"Andrey ",https://github.com/Andrey,5,20,"Oct 10, 2016",5
,nicck,,1,2,"Aug 9, 2016",1 ,syrol,https://github.com/syrol,5,10,"Dec 12, 2016",5
,campbellr,,1,1,"Sep 4, 2016",1 ,"Svend Knudsen",,1,10,"Apr 11, 2016",1
,"Michael D. Sklaroff",,1,10,"Apr 27, 2016",1
,nicck,,1,6,"Aug 9, 2016",1
,cnygaard,,5,5,"Jan 17, 2017",5
,Aldrog,,5,5,"Feb 11, 2017",5
,mpachecofaulk55,,5,5,"Feb 11, 2017",5
,campbellr,,1,5,"Sep 4, 2016",1

Can't render this file because it has a wrong number of fields in line 3.