Merge remote-tracking branch 'upstream/devel' into devel

This commit is contained in:
PhilipWitte
2015-02-13 11:39:28 -08:00
105 changed files with 1902 additions and 1535 deletions

View File

@@ -130,8 +130,8 @@ proc skipConvAndClosure*(n: PNode): PNode =
proc sameValue*(a, b: PNode): bool =
result = false
case a.kind
of nkCharLit..nkInt64Lit:
if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal
of nkCharLit..nkUInt64Lit:
if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit:
@@ -145,13 +145,13 @@ proc leValue*(a, b: PNode): bool =
# a <= b?
result = false
case a.kind
of nkCharLit..nkInt64Lit:
if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat64Lit:
of nkCharLit..nkUInt32Lit:
if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
of nkStrLit..nkTripleStrLit:
of nkStrLit..nkTripleStrLit:
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
else:
else:
# don't raise an internal error for 'nimrod check':
#InternalError(a.info, "leValue")
discard

View File

@@ -430,15 +430,27 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
assert(typ.kind == tyProc)
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))
if length > 1:
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
app(pl, ~" ")
app(pl, op.r)
if length > 2:
app(pl, ~": ")
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
for i in countup(3, length-1):
# don't call 'ropeToStr' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil
var start = 3
if ' ' in pat:
start = 1
app(pl, op.r)
if length > 1:
app(pl, ~": ")
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
start = 2
else:
if length > 1:
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
app(pl, ~" ")
app(pl, op.r)
if length > 2:
app(pl, ~": ")
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
for i in countup(start, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
internalError(ri.info, "varargs for objective C method?")

View File

@@ -83,7 +83,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
else:
result = toRope("NIM_NIL")
of nkStrLit..nkTripleStrLit:
if skipTypes(ty, abstractVarRange).kind == tyString:
if n.strVal.isNil:
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
elif skipTypes(ty, abstractVarRange).kind == tyString:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
if id == gBackendId:
# string literal not found in the cache:
@@ -950,7 +952,7 @@ proc genEcho(p: BProc, n: PNode) =
var a: TLoc
for i in countup(0, n.len-1):
initLocExpr(p, n.sons[i], a)
appf(args, ", ($1)->data", [rdLoc(a)])
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeatStr(n.len, "%s") & tnl), args)
@@ -2105,17 +2107,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
discard
of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d)
of nkProcDef, nkMethodDef, nkConverterDef:
if (n.sons[genericParamsPos].kind == nkEmpty):
of nkProcDef, nkMethodDef, nkConverterDef:
if n.sons[genericParamsPos].kind == nkEmpty:
var prc = n.sons[namePos].sym
# due to a bug/limitation in the lambda lifting, unused inner procs
# are not transformed correctly. We work around this issue (#411) here
# by ensuring it's no inner proc (owner is a module):
#
# We also check whether the proc captures its environment here to
# prevent issue #1642.
if prc.skipGenericOwner.kind == skModule and
tfCapturesEnv in prc.typ.flags:
if prc.skipGenericOwner.kind == skModule:
if (optDeadCodeElim notin gGlobalOptions and
sfDeadCodeElim notin getModule(prc).flags) or
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
@@ -2173,7 +2171,7 @@ proc genConstExpr(p: BProc, n: PNode): PRope =
var cs: TBitSet
toBitSet(n, cs)
result = genRawSetData(cs, int(getSize(n.typ)))
of nkBracket, nkPar, nkClosure:
of nkBracket, nkPar, nkClosure, nkObjConstr:
var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence:
result = genConstSeq(p, n, t)

View File

@@ -253,15 +253,6 @@ proc genConstStmt(p: BProc, t: PNode) =
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
c.ast.len != 0:
if not emitLazily(c): requestConstImpl(p, c)
when false:
# generate the data:
fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown)
if sfImportc in c.flags:
appf(p.module.s[cfsData], "extern NIM_CONST $1 $2;$n",
[getTypeDesc(p.module, c.typ), c.loc.r])
else:
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, c.typ), c.loc.r, genConstExpr(p, c.ast)])
proc genIf(p: BProc, n: PNode, d: var TLoc) =
#

View File

@@ -141,7 +141,7 @@ proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo) =
info: TLineInfo; orig: string) =
var id = "" # arg = "X]:on|off"
var i = 0
var n = hintMin
@@ -149,17 +149,17 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
add(id, arg[i])
inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i)
else: invalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, orig, info)
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: invalidCmdLineOption(pass, arg, info)
if state == wHint:
else: invalidCmdLineOption(pass, orig, info)
if state == wHint:
var x = findStr(msgs.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin))
else: invalidCmdLineOption(pass, arg, info)
else:
else: localError(info, "unknown hint: " & id)
else:
var x = findStr(msgs.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin))
else: invalidCmdLineOption(pass, arg, info)
else: localError(info, "unknown warning: " & id)
case whichKeyword(substr(arg, i))
of wOn: incl(gNotes, n)
of wOff: excl(gNotes, n)
@@ -368,8 +368,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
defineSymbol("nogc")
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
of "warning": processSpecificNote(arg, wWarning, pass, info)
of "hint": processSpecificNote(arg, wHint, pass, info)
of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
of "hint": processSpecificNote(arg, wHint, pass, info, switch)
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)

View File

@@ -380,7 +380,7 @@ proc setCC*(ccname: string) =
cCompiler = nameToCC(ccname)
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(cCompiler, ".options.always")
linkOptions = getConfigVar(cCompiler, ".options.linker")
linkOptions = ""
ccompilerpath = getConfigVar(cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
@@ -389,8 +389,8 @@ proc addOpt(dest: var string, src: string) =
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
add(dest, src)
proc addLinkOption*(option: string) =
if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option)
proc addLinkOption*(option: string) =
addOpt(linkOptions, option)
proc addCompileOption*(option: string) =
if strutils.find(compileOptions, option, 0) < 0:
@@ -401,7 +401,7 @@ proc initVars*() =
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
addCompileOption(getConfigVar(cCompiler, ".options.always"))
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0:
ccompilerpath = getConfigVar(cCompiler, ".path")
@@ -553,13 +553,13 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
cfile = quoteShell(cfile)
result = quoteShell(compilePattern % [
"file", cfile, "objfile", objfile, "options", options,
"include", includeCmd, "nimrod", getPrefixDir(),
"include", includeCmd, "nim", getPrefixDir(),
"nim", getPrefixDir(), "lib", libpath])
add(result, ' ')
addf(result, CC[c].compileTmpl, [
"file", cfile, "objfile", objfile,
"options", options, "include", includeCmd,
"nimrod", quoteShell(getPrefixDir()),
"nim", quoteShell(getPrefixDir()),
"nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
@@ -626,7 +626,9 @@ proc callCCompiler*(projectfile: string) =
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
if gNumberOfProcessors <= 1:
for i in countup(0, high(cmds)): res = max(execWithEcho(cmds[i]), res)
for i in countup(0, high(cmds)):
res = execWithEcho(cmds[i])
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
elif optListCmd in gGlobalOptions or gVerbosity > 1:
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
gNumberOfProcessors)
@@ -677,15 +679,16 @@ proc callCCompiler*(projectfile: string) =
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
exefile = quoteShell(exefile)
let linkOptions = getLinkOptions()
let linkOptions = getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
"exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
linkCmd.add ' '
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions,
"objfiles", objfiles, "exefile", exefile,
"nimrod", quoteShell(getPrefixDir()),
"nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
if optCompileOnly notin gGlobalOptions:
if gVerbosity == 1:
@@ -714,7 +717,8 @@ proc writeMapping*(gSymbolMapping: PRope) =
app(code, strutils.escape(getCompileOptions()))
app(code, "\n[Linker]\nFlags=")
app(code, strutils.escape(getLinkOptions()))
app(code, strutils.escape(getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")))
app(code, "\n[Environment]\nlibpath=")
app(code, strutils.escape(libpath))

View File

@@ -30,47 +30,32 @@ type
PLLStream* = ref TLLStream
proc llStreamOpen*(data: string): PLLStream
proc llStreamOpen*(f: var File): PLLStream
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream
proc llStreamOpen*(): PLLStream
proc llStreamOpenStdIn*(): PLLStream
proc llStreamClose*(s: PLLStream)
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc llStreamReadLine*(s: PLLStream, line: var string): bool
proc llStreamReadAll*(s: PLLStream): string
proc llStreamWrite*(s: PLLStream, data: string)
proc llStreamWrite*(s: PLLStream, data: char)
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc llStreamWriteln*(s: PLLStream, data: string)
# implementation
proc llStreamOpen(data: string): PLLStream =
proc llStreamOpen*(data: string): PLLStream =
new(result)
result.s = data
result.kind = llsString
proc llStreamOpen(f: var File): PLLStream =
proc llStreamOpen*(f: var File): PLLStream =
new(result)
result.f = f
result.kind = llsFile
proc llStreamOpen(filename: string, mode: FileMode): PLLStream =
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
new(result)
result.kind = llsFile
if not open(result.f, filename, mode): result = nil
proc llStreamOpen(): PLLStream =
proc llStreamOpen*(): PLLStream =
new(result)
result.kind = llsNone
proc llStreamOpenStdIn(): PLLStream =
proc llStreamOpenStdIn*(): PLLStream =
new(result)
result.kind = llsStdIn
result.s = ""
result.lineOffset = -1
proc llStreamClose(s: PLLStream) =
proc llStreamClose*(s: PLLStream) =
case s.kind
of llsNone, llsString, llsStdIn:
discard
@@ -130,7 +115,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
copyMem(buf, addr(s.s[s.rd]), result)
inc(s.rd, result)
proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
case s.kind
of llsNone:
result = 0
@@ -144,7 +129,7 @@ proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
of llsStdIn:
result = llReadFromStdin(s, buf, bufLen)
proc llStreamReadLine(s: PLLStream, line: var string): bool =
proc llStreamReadLine*(s: PLLStream, line: var string): bool =
setLen(line, 0)
case s.kind
of llsNone:
@@ -168,7 +153,7 @@ proc llStreamReadLine(s: PLLStream, line: var string): bool =
of llsStdIn:
result = readLine(stdin, line)
proc llStreamWrite(s: PLLStream, data: string) =
proc llStreamWrite*(s: PLLStream, data: string) =
case s.kind
of llsNone, llsStdIn:
discard
@@ -178,11 +163,11 @@ proc llStreamWrite(s: PLLStream, data: string) =
of llsFile:
write(s.f, data)
proc llStreamWriteln(s: PLLStream, data: string) =
proc llStreamWriteln*(s: PLLStream, data: string) =
llStreamWrite(s, data)
llStreamWrite(s, "\n")
proc llStreamWrite(s: PLLStream, data: char) =
proc llStreamWrite*(s: PLLStream, data: char) =
var c: char
case s.kind
of llsNone, llsStdIn:
@@ -194,7 +179,7 @@ proc llStreamWrite(s: PLLStream, data: char) =
c = data
discard writeBuffer(s.f, addr(c), sizeof(c))
proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) =
case s.kind
of llsNone, llsStdIn:
discard
@@ -206,7 +191,7 @@ proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
of llsFile:
discard writeBuffer(s.f, buf, buflen)
proc llStreamReadAll(s: PLLStream): string =
proc llStreamReadAll*(s: PLLStream): string =
const
bufSize = 2048
case s.kind

View File

@@ -113,7 +113,7 @@ type
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnNilStatement, warnAnalysisLoophole,
warnNilStatement, warnTypelessParam,
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
@@ -376,7 +376,7 @@ const
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]",
@@ -418,7 +418,7 @@ const
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored", "NilStmt",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "User"]
@@ -720,7 +720,10 @@ type
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template quit =
if defined(debug) or gVerbosity >= 3 or msg == errInternal:
writeStackTrace()
if stackTraceAvailable():
writeStackTrace()
else:
msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp c <file>")
quit 1
if msg >= fatalMin and msg <= fatalMax:

View File

@@ -198,8 +198,8 @@ proc isSigilLike(tok: TToken): bool {.inline.} =
proc isRightAssociative(tok: TToken): bool {.inline.} =
## Determines whether the token is right assocative.
result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or
(let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
# or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
## Calculates the precedence of the given token.

View File

@@ -138,7 +138,7 @@ const
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
(name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
(name: "JS", parDir: "..",
dllFrmt: "lib$1.so", altDirSep: "/",

View File

@@ -735,11 +735,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
incl(sym.flags, sfProcvar)
if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wGcSafe:
if optThreadAnalysis in gGlobalOptions:
noVal(it)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(it)
noVal(it)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(it)
of wPacked:
noVal(it)
if sym.typ == nil: invalidPragma(it)

View File

@@ -130,9 +130,11 @@ proc commonType*(x, y: PType): PType =
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
var nt: PType
for i in 0.. <a.len:
if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]):
let aEmpty = isEmptyContainer(a.sons[i])
let bEmpty = isEmptyContainer(b.sons[i])
if aEmpty != bEmpty:
if nt.isNil: nt = copyType(a, a.owner, false)
nt.sons[i] = b.sons[i]
nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i]
if not nt.isNil: result = nt
#elif b.sons[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange:

View File

@@ -221,6 +221,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
result = newTypeS(tyFromExpr, c)
assert n != nil
result.n = n
proc newTypeWithSons*(c: PContext, kind: TTypeKind,

View File

@@ -103,28 +103,31 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, n, s, flags)
of skVar, skLet, skResult, skParam, skForVar:
of skParam:
markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
# XXX see the hack in sigmatch.nim ...
return s.typ.n
elif sfGenSym in s.flags:
if c.p.wasForwarded:
# gensym'ed parameters that nevertheless have been forward declared
# need a special fixup:
let realParam = c.p.owner.typ.n[s.position+1]
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
elif c.p.owner.kind == skMacro:
# gensym'ed macro parameters need a similar hack (see bug #1944):
var u = searchInScopes(c, s.name)
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
return newSymNode(u, n.info)
result = newSymNode(s, n.info)
of skVar, skLet, skResult, skForVar:
markUsed(n.info, s)
styleCheckUse(n.info, s)
# if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect)
elif s.kind == skParam:
if s.typ.kind == tyStatic and s.typ.n != nil:
# XXX see the hack in sigmatch.nim ...
return s.typ.n
elif sfGenSym in s.flags:
if c.p.wasForwarded:
# gensym'ed parameters that nevertheless have been forward declared
# need a special fixup:
let realParam = c.p.owner.typ.n[s.position+1]
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
elif c.p.owner.kind == skMacro:
# gensym'ed macro parameters need a similar hack (see bug #1944):
var u = searchInScopes(c, s.name)
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
return newSymNode(u, n.info)
result = newSymNode(s, n.info)
# We cannot check for access to outer vars for example because it's still
# not sure the symbol really ends up being used:
@@ -445,25 +448,30 @@ proc changeType(n: PNode, newType: PType, check: bool) =
let tup = newType.skipTypes({tyGenericInst})
if tup.kind != tyTuple:
internalError(n.info, "changeType: no tuple type for constructor")
elif newType.n == nil: discard
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
for i in countup(0, sonsLen(n) - 1):
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
# named tuple?
for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i].sons[0]
if m.kind != nkSym:
if m.kind != nkSym:
internalError(m.info, "changeType(): invalid tuple constr")
return
var f = getSymFromList(newType.n, m.sym.name)
if f == nil:
internalError(m.info, "changeType(): invalid identifier")
return
changeType(n.sons[i].sons[1], f.typ, check)
if tup.n != nil:
var f = getSymFromList(newType.n, m.sym.name)
if f == nil:
internalError(m.info, "changeType(): invalid identifier")
return
changeType(n.sons[i].sons[1], f.typ, check)
else:
changeType(n.sons[i].sons[1], tup.sons[i], check)
else:
for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m)
changeType(m, tup.sons[i], check)
changeType(n.sons[i], tup.sons[i], check)
when false:
var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m)
changeType(m, tup.sons[i], check)
of nkCharLit..nkUInt64Lit:
if check:
let value = n.intVal
@@ -678,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
# implicit statics.
if n.len > 1:
for i in 1 .. <n.len:
if n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags:
# see bug #2113, it's possible that n[i].typ for errornous code:
if n[i].typ.isNil or n[i].typ.kind != tyStatic or
tfUnresolved notin n[i].typ.flags:
break maybeLabelAsStatic
n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
n.typ.flags.incl tfUnresolved
@@ -1329,7 +1339,12 @@ proc semProcBody(c: PContext, n: PNode): PNode =
if c.p.owner.kind notin {skMacro, skTemplate} and
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
localError(c.p.resultSym.info, errCannotInferReturnType)
if isEmptyType(result.typ):
# we inferred a 'void' return type:
c.p.resultSym.typ = nil
c.p.owner.typ.sons[0] = nil
else:
localError(c.p.resultSym.info, errCannotInferReturnType)
closeScope(c)

View File

@@ -77,11 +77,16 @@ proc removeDefaultParamValues(n: PNode) =
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags:
var x = PSym(idTableGet(symMap, n.sym))
let s = n.sym
var x = PSym(idTableGet(symMap, s))
if x == nil:
x = copySym(n.sym, false)
x.owner = owner
idTablePut(symMap, n.sym, x)
if s.kind == skParam:
x = owner.typ.n[s.position+1].sym
internalAssert x.kind == skParam
else:
x = copySym(s, false)
x.owner = owner
idTablePut(symMap, s, x)
n.sym = x
else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)

View File

@@ -194,6 +194,9 @@ proc warnAboutGcUnsafe(n: PNode) =
#assert false
message(n.info, warnGcUnsafe, renderTree(n))
template markGcUnsafe(a: PEffects) =
a.gcUnsafe = true
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
if isLocalVar(a, s):
@@ -209,7 +212,7 @@ proc useVar(a: PEffects, n: PNode) =
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
tfGcSafe notin s.typ.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
a.gcUnsafe = true
markGcUnsafe(a)
type
TIntersection = seq[tuple[id, count: int]] # a simple count table
@@ -448,7 +451,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
if notGcSafe(s.typ) and sfImportc notin s.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
markGcUnsafe(tracked)
mergeLockLevels(tracked, n, s.getLockLevel)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
@@ -502,13 +505,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
# assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
markGcUnsafe(tracked)
else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
if notGcSafe(op):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
markGcUnsafe(tracked)
notNilCheck(tracked, n, paramType)
proc breaksBlock(n: PNode): bool =
@@ -656,7 +659,7 @@ proc track(tracked: PEffects, n: PNode) =
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
markGcUnsafe(tracked)
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
# may not look like an assignment, but it is:
@@ -825,7 +828,7 @@ proc trackProc*(s: PSym, body: PNode) =
# effects already computed?
if sfForward in s.flags: return
if effects.len == effectListLen: return
var t: TEffects
initEffects(effects, s, t)
track(t, body)
@@ -849,19 +852,20 @@ proc trackProc*(s: PSym, body: PNode) =
# after the check, use the formal spec:
effects.sons[tagEffects] = tagsSpec
if optThreadAnalysis in gGlobalOptions:
if sfThread in s.flags and t.gcUnsafe:
if optThreads in gGlobalOptions:
localError(s.info, "'$1' is not GC-safe" % s.name.s)
else:
localError(s.info, warnGcUnsafe2, s.name.s)
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
if s.typ.lockLevel == UnspecifiedLockLevel:
s.typ.lockLevel = t.maxLockLevel
elif t.maxLockLevel > s.typ.lockLevel:
localError(s.info,
"declared lock level is $1, but real lock level is $2" %
[$s.typ.lockLevel, $t.maxLockLevel])
if sfThread in s.flags and t.gcUnsafe:
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
localError(s.info, "'$1' is not GC-safe" % s.name.s)
else:
localError(s.info, warnGcUnsafe2, s.name.s)
if not t.gcUnsafe:
s.typ.flags.incl tfGcSafe
if s.typ.lockLevel == UnspecifiedLockLevel:
s.typ.lockLevel = t.maxLockLevel
elif t.maxLockLevel > s.typ.lockLevel:
#localError(s.info,
message(s.info, warnLockLevel,
"declared lock level is $1, but real lock level is $2" %
[$s.typ.lockLevel, $t.maxLockLevel])
proc trackTopLevelStmt*(module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,

View File

@@ -359,6 +359,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var def: PNode
if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
# prevent the all too common 'var x = int' bug:
localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
def.typ = errorType(c)
if typ != nil:
if typ.isMetaType:
def = inferWithMetatype(c, typ, def)
@@ -825,9 +829,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
elif efOperand notin flags:
localError(n.info, errGenericLambdaNotAllowed)
@@ -860,9 +864,9 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
addParams(c, n.typ.n, skProc)
pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc)
addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
addResultNode(c, n)
popProcCon(c)
popOwner()
closeScope(c)

View File

@@ -781,9 +781,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result.rawAddSon(paramType)
for i in 0 .. paramType.sonsLen - 2:
let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown
else: tyAnything
result.rawAddSon newTypeS(dummyType, c)
if paramType.sons[i].kind == tyStatic:
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnkown'
else:
result.rawAddSon newTypeS(tyAnything, c)
if paramType.lastSon.kind == tyUserTypeClass:
result.kind = tyUserTypeClassInst
@@ -911,6 +912,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if not hasType and not hasDefault:
if isType: localError(a.info, "':' expected")
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
if tdef == tyAnything:
message(a.info, warnTypelessParam, renderTree(n))
typ = newTypeS(tdef, c)
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue

View File

@@ -418,7 +418,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
return isNone
elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}:
elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
optThreadAnalysis in gGlobalOptions:
# noSideEffect implies ``tfThread``!
return isNone
elif f.flags * {tfIterator} != a.flags * {tfIterator}:
@@ -1056,7 +1057,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyFromExpr:
# fix the expression, so it contains the already instantiated types
if f.n == nil: return isGeneric
if f.n == nil or f.n.kind == nkEmpty: return isGeneric
let reevaluated = tryResolvingStaticExpr(c, f.n)
case reevaluated.typ.kind
of tyTypeDesc:
@@ -1441,13 +1442,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
return
checkConstraint(n.sons[a].sons[1])
if m.baseTypeMatch:
assert(container == nil)
#assert(container == nil)
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
addSon(container, arg)
setSon(m.call, formal.position + 1, container)
if f != formalLen - 1: container = nil
else:
else:
setSon(m.call, formal.position + 1, arg)
inc f
else:
# unnamed param
if f >= formalLen:
@@ -1466,7 +1468,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil):
if arg != nil and m.baseTypeMatch and container != nil:
addSon(container, arg)
incrIndexType(container.typ)
else:
@@ -1480,7 +1482,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
internalError(n.sons[a].info, "matches")
return
formal = m.callee.n.sons[f].sym
if containsOrIncl(marker, formal.position):
if containsOrIncl(marker, formal.position) and container.isNil:
# already in namedParams:
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch
@@ -1493,17 +1495,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch
return
if m.baseTypeMatch:
assert(container == nil)
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
#assert(container == nil)
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
addSon(container, arg)
setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
if f != formalLen - 1: container = nil
#if f != formalLen - 1: container = nil
# pick the formal from the end, so that 'x, y, varargs, z' works:
f = max(f, formalLen - n.len + a + 1)
else:
setSon(m.call, formal.position + 1, arg)
inc(f)
container = nil
checkConstraint(n.sons[a])
inc(a)
inc(f)
proc semFinishOperands*(c: PContext, n: PNode) =
# this needs to be called to ensure that after overloading resolution every

View File

@@ -28,8 +28,9 @@ proc hashTree(n: PNode): THash =
of nkFloatLit..nkFloat64Lit:
if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0):
result = result !& toInt(n.floatVal)
of nkStrLit..nkTripleStrLit:
result = result !& hash(n.strVal)
of nkStrLit..nkTripleStrLit:
if not n.strVal.isNil:
result = result !& hash(n.strVal)
else:
for i in countup(0, sonsLen(n) - 1):
result = result !& hashTree(n.sons[i])

View File

@@ -1029,16 +1029,18 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
flags: TTypeAllowedFlags = {}): PType =
if n != nil:
if n != nil:
result = typeAllowedAux(marker, n.typ, kind, flags)
#if not result: debug(n.typ)
if result == nil:
case n.kind
of nkNone..nkNilLit:
of nkNone..nkNilLit:
discard
else:
for i in countup(0, sonsLen(n) - 1):
result = typeAllowedNode(marker, n.sons[i], kind, flags)
let it = n.sons[i]
if it.kind == nkRecCase and kind == skConst: return n.typ
result = typeAllowedNode(marker, it, kind, flags)
if result != nil: break
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
@@ -1118,7 +1120,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = typeAllowedAux(marker, t.sons[i], kind, flags)
if result != nil: break
of tyObject, tyTuple:
if kind == skConst and t.kind == tyObject: return t
if kind == skConst and t.kind == tyObject and t.sons[0] != nil: return t
let flags = flags+{taField}
for i in countup(0, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], kind, flags)

View File

@@ -1438,7 +1438,9 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
# immediate macros can bypass any type and arity checking so we check the
# arity here too:
if sym.typ.len > n.safeLen and sym.typ.len > 1:
globalError(n.info, "got $#, but expected $# argument(s)" % [$ <n.safeLen, $ <sym.typ.len])
globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
n.renderTree,
$ <n.safeLen, $ <sym.typ.len])
setupGlobalCtx(module)
var c = globalCtx

View File

@@ -604,7 +604,8 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for
# other unsigned types:
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
(t.kind == tyInt and t.size == 4):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =

View File

@@ -10,6 +10,12 @@
cc = gcc
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
# example of how to setup a cross-compiler:
arm.linux.gcc.exe = "arm-linux-gcc"
arm.linux.gcc.linkerexe = "arm-linux-gcc"
@@ -66,12 +72,6 @@ path="$lib/pure/unidecode"
opt:speed
@end
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix:
@if not bsd:
# -fopenmp
@@ -112,6 +112,20 @@ hint[LineTooLong]=off
gcc.cpp.options.always = "-w -fpermissive"
@end
# Configuration for the VxWorks
# This has been tested with VxWorks 6.9 only
@if vxworks:
# For now we only support compiling RTPs applications (i.e. no DKMs)
gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
# The linker config must add the VxWorks common library for the selected
# processor which is usually found in:
# "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common",
# where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks
# compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc)
# For now we only support the PowerPC CPU
gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
@end
gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.size = "-Os"
gcc.options.debug = "-g3 -O0"

View File

@@ -1,7 +1,7 @@
=====================================================
Nim -- a Compiler for Nim. http://nim-lang.org/
Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved.
Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -66,7 +66,6 @@ Advanced options:
--threadanalysis:on|off turn thread analysis on|off
--tlsEmulation:on|off turn thread local storage emulation on|off
--taintMode:on|off turn taint mode on|off
--symbolFiles:on|off turn symbol files on|off (experimental)
--implicitStatic:on|off turn implicit compile time evaluation on|off
--patterns:on|off turn pattern matching on|off
--skipCfg do not read the general configuration file

View File

@@ -14,7 +14,6 @@ Options:
-p, --path:PATH add path to search paths
-d, --define:SYMBOL define a conditional symbol
-u, --undef:SYMBOL undefine a conditional symbol
--symbol:SYMBOL declare a conditional symbol
-f, --forceBuild force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off
--lineTrace:on|off turn line tracing on|off

View File

@@ -12,10 +12,8 @@ Binary operators have 11 different levels of precedence.
Associativity
-------------
Binary operators whose first character is ``^`` or its last character
is ``>`` are right-associative, all other binary operators are left-associative.
Exception: The single "greater than" ``>`` operator is left-associative too.
Binary operators whose first character is ``^`` are right-associative, all
other binary operators are left-associative.
Operators ending in ``>`` but longer than a single character are
called `arrow like`:idx:.

File diff suppressed because it is too large Load Diff

View File

@@ -190,6 +190,6 @@ Real world example
The installers for the Nim compiler itself are generated by niminst. Have a
look at its configuration file:
.. include:: compiler/nim.ini
.. include:: compiler/installer.ini
:literal:

View File

@@ -97,13 +97,13 @@ const
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
proc csource(args: string) =
exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource compiler/nim.ini $1" %
exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource compiler/installer.ini $1" %
[args, VersionAsString, compileNimInst, findNim()])
proc zip(args: string) =
exec("$3 cc -r $2 --var:version=$1 --var:mingw=none scripts compiler/nim.ini" %
exec("$3 cc -r $2 --var:version=$1 --var:mingw=none scripts compiler/installer.ini" %
[VersionAsString, compileNimInst, findNim()])
exec("$# --var:version=$# --var:mingw=none zip compiler/nim.ini" %
exec("$# --var:version=$# --var:mingw=none zip compiler/installer.ini" %
["tools/niminst/niminst".exe, VersionAsString])
proc buildTool(toolname, args: string) =
@@ -121,20 +121,20 @@ proc nsis(args: string) =
" nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)])
proc install(args: string) =
exec("$# cc -r $# --var:version=$# --var:mingw=none scripts compiler/nim.ini" %
exec("$# cc -r $# --var:version=$# --var:mingw=none scripts compiler/installer.ini" %
[findNim(), compileNimInst, VersionAsString])
exec("sh ./install.sh $#" % args)
proc web(args: string) =
exec("$# cc -r tools/nimweb.nim $# web/nim --putenv:nimversion=$#" %
exec("$# cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" %
[findNim(), args, VersionAsString])
proc website(args: string) =
exec("$# cc -r tools/nimweb.nim $# --website web/nim --putenv:nimversion=$#" %
exec("$# cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" %
[findNim(), args, VersionAsString])
proc pdf(args="") =
exec("$# cc -r tools/nimweb.nim $# --pdf web/nim --putenv:nimversion=$#" %
exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" %
[findNim(), args, VersionAsString])
# -------------- boot ---------------------------------------------------------

View File

@@ -136,12 +136,12 @@ proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
## returns the number of children of `n`.
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
noSideEffect.}
noSideEffect, locks: 0.}
## Adds the `child` to the `father` node. Returns the
## father node so that calls can be nested.
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
magic: "NAddMultiple", discardable, noSideEffect.}
magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
## Adds each child of `children` to the `father` node.
## Returns the `father` node so that calls can be nested.
@@ -177,13 +177,13 @@ proc newNimNode*(kind: TNimrodNodeKind,
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.}
proc error*(msg: string) {.magic: "NError", gcsafe.}
proc error*(msg: string) {.magic: "NError", benign.}
## writes an error message at compile time
proc warning*(msg: string) {.magic: "NWarning", gcsafe.}
proc warning*(msg: string) {.magic: "NWarning", benign.}
## writes a warning message at compile time
proc hint*(msg: string) {.magic: "NHint", gcsafe.}
proc hint*(msg: string) {.magic: "NHint", benign.}
## writes a hint message at compile time
proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
@@ -237,7 +237,7 @@ proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
## generates a fresh symbol that is guaranteed to be unique. The symbol
## needs to occur in a declaration context.
proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.}
proc callsite*(): PNimrodNode {.magic: "NCallSite", benign.}
## returns the AST of the invocation expression that invoked this macro.
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
@@ -387,11 +387,11 @@ proc nestList*(theProc: TNimrodIdent,
# This could easily user code and so should be fixed in evals.nim somehow.
result = newCall(theProc, x[i], copyNimTree(result))
proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
proc treeRepr*(n: PNimrodNode): string {.compileTime, benign.} =
## Convert the AST `n` to a human-readable tree-like string.
##
## See also `repr` and `lispRepr`.
proc traverse(res: var string, level: int, n: PNimrodNode) =
proc traverse(res: var string, level: int, n: PNimrodNode) {.benign.} =
for i in 0..level-1: res.add " "
res.add(($n.kind).substr(3))
@@ -412,7 +412,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
result = ""
traverse(result, 0, n)
proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
proc lispRepr*(n: PNimrodNode): string {.compileTime, benign.} =
## Convert the AST `n` to a human-readable lisp-like string,
##
## See also `repr` and `treeRepr`.
@@ -651,7 +651,7 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
else:
badNodeKind someProc.kind, "body="
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.}
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime, benign.}
proc `$`*(node: PNimrodNode): string {.compileTime.} =

View File

@@ -16,11 +16,11 @@ type
TDbConn* = PMySQL ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of EIO ## exception that is raised if a database error occurs
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
FDb* = object of FIO ## effect that denotes a database operation
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation

View File

@@ -1,7 +1,7 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -13,6 +13,8 @@
## is used. This suffices because Windows' console already provides the
## wanted functionality.
{.deadCodeElim: on.}
when defined(Windows):
proc readLineFromStdin*(prompt: string): TaintedString {.
tags: [ReadIOEffect, WriteIOEffect].} =
@@ -31,23 +33,27 @@ when defined(Windows):
stdout.write(prompt)
result = readLine(stdin, line)
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
proc readPasswordFromStdin*(prompt: string, password: var TaintedString) =
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
## Reads a `password` from stdin without printing it. `password` must not
## be ``nil``!
## be ``nil``! Returns ``false`` if the end of the file has been reached,
## ``true`` otherwise.
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
password.setLen(0)
var c: char
echo prompt
stdout.write(prompt)
while true:
c = getch().char
case c
of '\r', chr(0xA):
break
of '\b':
password.setLen(result.len - 1)
else:
password.add(c)
c = getch().char
case c
of '\r', chr(0xA):
break
of '\b':
password.setLen(password.len - 1)
else:
password.add(c)
stdout.write "\n"
# TODO: How to detect EOF on Windows?
else:
import readline, history, termios, unsigned
@@ -78,7 +84,8 @@ else:
discard readline.bind_key('\t'.ord, doNothing)
proc readPasswordFromStdin*(prompt: string, password: var TaintedString) =
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
password.setLen(0)
let fd = stdin.getFileHandle()
var cur, old: Termios
@@ -87,10 +94,11 @@ else:
cur.lflag = cur.lflag and not Tcflag(ECHO)
discard fd.tcsetattr(TCSADRAIN, cur.addr)
stdout.write prompt
discard stdin.readLine(password)
result = stdin.readLine(password)
stdout.write "\n"
discard fd.tcsetattr(TCSADRAIN, old.addr)
proc readPasswordFromStdin*(prompt: string): TaintedString =
## Reads a password from stdin without printing it.
result = TaintedString("")
readPasswordFromStdin(prompt, result)
discard readPasswordFromStdin(prompt, result)

View File

@@ -379,7 +379,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
# define GC_GUARD
#endif
/* Test to see if nimrod and the C compiler agree on the size of a pointer.
/* Test to see if Nim and the C compiler agree on the size of a pointer.
On disagreement, your C compiler will say something like:
"error: 'assert_numbits' declared as an array with a negative size" */
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
@@ -390,3 +390,12 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
#else
# define NIM_EXTERNC
#endif
/* ---------------- platform specific includes ----------------------- */
/* VxWorks related includes */
#if defined(__VXWORKS__)
# include <sys/types.h>
# include <types/vxWind.h>
# include <tool/gnu/toolMacros.h>
#endif

View File

@@ -70,17 +70,10 @@ const
STDIN_FILENO* = 0 ## File number of stdin;
STDOUT_FILENO* = 1 ## File number of stdout;
when defined(endb):
# to not break bootstrapping again ...
type
TDIR* {.importc: "DIR", header: "<dirent.h>",
final, pure, incompleteStruct.} = object
## A type representing a directory stream.
else:
type
TDIR* {.importc: "DIR", header: "<dirent.h>",
final, pure.} = object
## A type representing a directory stream.
type
TDIR* {.importc: "DIR", header: "<dirent.h>",
incompleteStruct.} = object
## A type representing a directory stream.
type
SocketHandle* = distinct cint # The type used to represent socket descriptors

View File

@@ -1064,6 +1064,17 @@ proc accept*(socket: TAsyncFD,
# -- Await Macro
proc skipUntilStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} =
# Skips a nest of StmtList's.
result = node
if node[0].kind == nnkStmtList:
result = skipUntilStmtList(node[0])
proc skipStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} =
result = node
if node[0].kind == nnkStmtList:
result = node[0]
template createCb(retFutureSym, iteratorNameSym,
name: expr): stmt {.immediate.} =
var nameIterVar = iteratorNameSym
@@ -1211,26 +1222,53 @@ proc processBody(node, retFutureSym: PNimrodNode,
of nnkTryStmt:
# try: await x; except: ...
result = newNimNode(nnkStmtList, node)
template wrapInTry(n, tryBody: PNimrodNode) =
var temp = n
n[0] = tryBody
tryBody = temp
# Transform ``except`` body.
# TODO: Could we perform some ``await`` transformation here to get it
# working in ``except``?
tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
proc processForTry(n: PNimrodNode, i: var int,
res: PNimrodNode): bool {.compileTime.} =
## Transforms the body of the tryStmt. Does not transform the
## body in ``except``.
## Returns true if the tryStmt node was transformed into an ifStmt.
result = false
while i < n[0].len:
var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n)
if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
var skipped = n.skipStmtList()
while i < skipped.len:
var processed = processBody(skipped[i], retFutureSym,
subTypeIsVoid, n)
# Check if we transformed the node into an exception check.
# This suggests skipped[i] contains ``await``.
if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
processed = processed.skipUntilStmtList()
expectKind(processed, nnkStmtList)
expectKind(processed[2][1], nnkElse)
i.inc
discard processForTry(n, i, processed[2][1][0])
if not processForTry(n, i, processed[2][1][0]):
# We need to wrap the nnkElse nodes back into a tryStmt.
# As they are executed if an exception does not happen
# inside the awaited future.
# The following code will wrap the nodes inside the
# original tryStmt.
wrapInTry(n, processed[2][1][0])
res.add processed
result = true
else:
res.add n[0][i]
res.add skipped[i]
i.inc
var i = 0
if not processForTry(node, i, result):
var temp = node
temp[0] = result
result = temp
# If the tryStmt hasn't been transformed we can just put the body
# back into it.
wrapInTry(node, result)
return
else: discard
@@ -1329,8 +1367,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
result[6] = outerProcBody
#echo(treeRepr(result))
#if prc[0].getName == "catch":
# echo(toStrLit(result))
if prc[0].getName == "test3":
echo(toStrLit(result))
proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
## Reads a line of data from ``socket``. Returned future will complete once

View File

@@ -24,9 +24,12 @@ import
when not defined(nimhygiene):
{.pragma: dirty.}
# For "integer-like A" that are too big for intsets/bit-vectors to be practical,
# it would be best to shrink hcode to the same size as the integer. Larger
# codes should never be needed, and this can pack more entries per cache-line.
# Losing hcode entirely is also possible - if some element value is forbidden.
type
SlotEnum = enum seEmpty, seFilled, seDeleted
KeyValuePair[A] = tuple[slot: SlotEnum, key: A]
KeyValuePair[A] = tuple[hcode: THash, key: A]
KeyValuePairSeq[A] = seq[KeyValuePair[A]]
HashSet* {.myShallow.}[A] = object ## \
## A generic hash set.
@@ -38,6 +41,14 @@ type
{.deprecated: [TSet: HashSet].}
# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These
# two procs retain clarity of that encoding without the space cost of an enum.
proc isEmpty(hcode: THash): bool {.inline.} =
result = hcode == 0
proc isFilled(hcode: THash): bool {.inline.} =
result = hcode != 0
proc isValid*[A](s: HashSet[A]): bool =
## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
##
@@ -94,7 +105,7 @@ iterator items*[A](s: HashSet[A]): A =
## # --> {(a: 1, b: 3), (a: 0, b: 4)}
assert s.isValid, "The set needs to be initialized."
for h in 0..high(s.data):
if s.data[h].slot == seFilled: yield s.data[h].key
if isFilled(s.data[h].hcode): yield s.data[h].key
const
growthFactor = 2
@@ -103,25 +114,44 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc rightSize*(count: int): int {.inline.} =
## Return the value of `initialSize` to support `count` items.
##
## If more items are expected to be added, simply add that
## expected extra amount to the parameter before calling this.
##
## Internally, we want mustRehash(rightSize(x), x) == false.
result = nextPowerOfTwo(count * 3 div 2 + 4)
template rawGetImpl() {.dirty.} =
var h: THash = hash(key) and high(s.data) # start with real hash value
while s.data[h].slot != seEmpty:
if s.data[h].key == key and s.data[h].slot == seFilled:
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = (h + 1) and maxHash
template rawGetKnownHCImpl() {.dirty.} =
var h: THash = hc and high(s.data) # start with real hash value
while isFilled(s.data[h].hcode):
# Compare hc THEN key with boolean short circuit. This makes the common case
# zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
# It does slow down succeeding lookups by one extra THash cmp&and..usually
# just a few clock cycles, generally worth it for any non-integer-like A.
if s.data[h].hcode == hc and s.data[h].key == key: # compare hc THEN key
return h
h = nextTry(h, high(s.data))
result = -1
result = -1 - h # < 0 => MISSING; insert idx = -1 - result
template rawGetImpl() {.dirty.} =
hc = hash(key)
if hc == 0: # This almost never taken branch should be very predictable.
hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine.
rawGetKnownHCImpl()
template rawInsertImpl() {.dirty.} =
var h: THash = hash(key) and high(data)
while data[h].slot == seFilled:
h = nextTry(h, high(data))
data[h].key = key
data[h].slot = seFilled
data[h].hcode = hc
proc rawGet[A](s: HashSet[A], key: A): int =
proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} =
rawGetImpl()
proc mget*[A](s: var HashSet[A], key: A): var A =
@@ -130,7 +160,8 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
## when one overloaded 'hash' and '==' but still needs reference semantics
## for sharing.
assert s.isValid, "The set needs to be initialized."
var index = rawGet(s, key)
var hc: THash
var index = rawGet(s, key, hc)
if index >= 0: result = s.data[index].key
else: raise newException(KeyError, "key not found: " & $key)
@@ -147,33 +178,43 @@ proc contains*[A](s: HashSet[A], key: A): bool =
## values.excl(2)
## assert(not values.contains(2))
assert s.isValid, "The set needs to be initialized."
var index = rawGet(s, key)
var hc: THash
var index = rawGet(s, key, hc)
result = index >= 0
proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) =
proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
hc: THash, h: THash) =
rawInsertImpl()
proc enlarge[A](s: var HashSet[A]) =
var n: KeyValuePairSeq[A]
newSeq(n, len(s.data) * growthFactor)
for i in countup(0, high(s.data)):
if s.data[i].slot == seFilled: rawInsert(s, n, s.data[i].key)
swap(s.data, n)
swap(s.data, n) # n is now old seq
for i in countup(0, high(n)):
if isFilled(n[i].hcode):
var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode)
rawInsert(s, s.data, n[i].key, n[i].hcode, j)
template inclImpl() {.dirty.} =
var index = rawGet(s, key)
var hc: THash
var index = rawGet(s, key, hc)
if index < 0:
if mustRehash(len(s.data), s.counter): enlarge(s)
rawInsert(s, s.data, key)
if mustRehash(len(s.data), s.counter):
enlarge(s)
index = rawGetKnownHC(s, key, hc)
rawInsert(s, s.data, key, hc, -1 - index)
inc(s.counter)
template containsOrInclImpl() {.dirty.} =
var index = rawGet(s, key)
var hc: THash
var index = rawGet(s, key, hc)
if index >= 0:
result = true
else:
if mustRehash(len(s.data), s.counter): enlarge(s)
rawInsert(s, s.data, key)
if mustRehash(len(s.data), s.counter):
enlarge(s)
index = rawGetKnownHC(s, key, hc)
rawInsert(s, s.data, key, hc, -1 - index)
inc(s.counter)
proc incl*[A](s: var HashSet[A], key: A) =
@@ -204,6 +245,11 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) =
assert other.isValid, "The set `other` needs to be initialized."
for item in other: incl(s, item)
template doWhile(a: expr, b: stmt): stmt =
while true:
b
if not a: break
proc excl*[A](s: var HashSet[A], key: A) =
## Excludes `key` from the set `s`.
##
@@ -215,10 +261,22 @@ proc excl*[A](s: var HashSet[A], key: A) =
## s.excl(2)
## assert s.len == 3
assert s.isValid, "The set needs to be initialized."
var index = rawGet(s, key)
if index >= 0:
s.data[index].slot = seDeleted
var hc: THash
var i = rawGet(s, key, hc)
var msk = high(s.data)
if i >= 0:
s.data[i].hcode = 0
dec(s.counter)
while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
var j = i # The correctness of this depends on (h+1) in nextTry,
var r = j # though may be adaptable to other simple sequences.
s.data[i].hcode = 0 # mark current EMPTY
doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
i = (i + 1) and msk # increment mod table size
if isEmpty(s.data[i].hcode): # end of collision cluster; So all done
return
r = s.data[i].hcode and msk # "home" location of key@i
s.data[j] = s.data[i] # data[j] will be marked EMPTY next loop
proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
## Excludes everything in `other` from `s`.
@@ -295,7 +353,7 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] =
## var numbers = toSet([1, 2, 3, 4, 5])
## assert numbers.contains(2)
## assert numbers.contains(4)
result = initSet[A](nextPowerOfTwo(keys.len+10))
result = initSet[A](rightSize(keys.len))
for key in items(keys): result.incl(key)
template dollarImpl(): stmt {.dirty.} =
@@ -494,7 +552,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
type
OrderedKeyValuePair[A] = tuple[
slot: SlotEnum, next: int, key: A]
hcode: THash, next: int, key: A]
OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
OrderedSet* {.myShallow.}[A] = object ## \
## A generic hash set that remembers insertion order.
@@ -546,7 +604,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
var h = s.first
while h >= 0:
var nxt = s.data[h].next
if s.data[h].slot == seFilled: yieldStmt
if isFilled(s.data[h].hcode): yieldStmt
h = nxt
iterator items*[A](s: OrderedSet[A]): A =
@@ -571,7 +629,10 @@ iterator items*[A](s: OrderedSet[A]): A =
forAllOrderedPairs:
yield s.data[h].key
proc rawGet[A](s: OrderedSet[A], key: A): int =
proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} =
rawGetImpl()
proc contains*[A](s: OrderedSet[A], key: A): bool =
@@ -585,11 +646,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool =
## values.incl(2)
## assert values.contains(2)
assert s.isValid, "The set needs to be initialized."
var index = rawGet(s, key)
var hc: THash
var index = rawGet(s, key, hc)
result = index >= 0
proc rawInsert[A](s: var OrderedSet[A],
data: var OrderedKeyValuePairSeq[A], key: A) =
proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
key: A, hc: THash, h: THash) =
rawInsertImpl()
data[h].next = -1
if s.first < 0: s.first = h
@@ -602,12 +664,13 @@ proc enlarge[A](s: var OrderedSet[A]) =
var h = s.first
s.first = -1
s.last = -1
while h >= 0:
var nxt = s.data[h].next
if s.data[h].slot == seFilled:
rawInsert(s, n, s.data[h].key)
h = nxt
swap(s.data, n)
while h >= 0:
var nxt = n[h].next
if isFilled(n[h].hcode):
var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
rawInsert(s, s.data, n[h].key, n[h].hcode, j)
h = nxt
proc incl*[A](s: var OrderedSet[A], key: A) =
## Includes an element `key` in `s`.
@@ -655,7 +718,7 @@ proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
proc init*[A](s: var OrderedSet[A], initialSize=64) =
## Initializes an ordered hash set.
##
## The `initialSize` parameter needs to be a power of too. You can use
## The `initialSize` parameter needs to be a power of two. You can use
## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at
## runtime. All set variables have to be initialized before you can use them
## with other procs from this module with the exception of `isValid()
@@ -698,7 +761,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
## var numbers = toOrderedSet([1, 2, 3, 4, 5])
## assert numbers.contains(2)
## assert numbers.contains(4)
result = initOrderedSet[A](nextPowerOfTwo(keys.len+10))
result = initOrderedSet[A](rightSize(keys.len))
for key in items(keys): result.incl(key)
proc `$`*[A](s: OrderedSet[A]): string =
@@ -726,7 +789,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
while h >= 0 and g >= 0:
var nxh = s.data[h].next
var nxg = t.data[g].next
if s.data[h].slot == seFilled and s.data[g].slot == seFilled:
if isFilled(s.data[h].hcode) and isFilled(s.data[g].hcode):
if s.data[h].key == s.data[g].key:
inc compared
else:
@@ -901,6 +964,11 @@ proc testModule() =
b.incl(2)
assert b.len == 1
for i in 0 .. 32:
var s = rightSize(i)
if s <= i or mustRehash(s, i):
echo "performance issue: rightSize() will not elide enlarge() at ", i
echo "Micro tests run successfully."
when isMainModule and not defined(release): testModule()

View File

@@ -347,7 +347,7 @@ proc `$`*[A, B](t: TableRef[A, B]): string =
proc `==`*[A, B](s, t: TableRef[A, B]): bool =
if isNil(s): result = isNil(t)
elif isNil(t): result = false
else: result = equalsImpl()
else: equalsImpl()
proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
## Index the collection with the proc provided.

View File

@@ -93,9 +93,9 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
result = x - 1
when defined(cpu64):
result = result or (result shr 32)
when sizeof(int) > 16:
when sizeof(int) > 2:
result = result or (result shr 16)
when sizeof(int) > 8:
when sizeof(int) > 1:
result = result or (result shr 8)
result = result or (result shr 4)
result = result or (result shr 2)
@@ -129,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
result = result + diff*diff
result = result / toFloat(len(x))
proc random*(max: int): int {.gcsafe.}
proc random*(max: int): int {.benign.}
## returns a random number in the range 0..max-1. The sequence of
## random number is always the same, unless `randomize` is called
## which initializes the random number generator with a "random"
## number, i.e. a tickcount.
proc random*(max: float): float {.gcsafe.}
proc random*(max: float): float {.benign.}
## returns a random number in the range 0..<max. The sequence of
## random number is always the same, unless `randomize` is called
## which initializes the random number generator with a "random"
## number, i.e. a tickcount. This has a 16-bit resolution on windows
## and a 48-bit resolution on other platforms.
proc randomize*() {.gcsafe.}
proc randomize*() {.benign.}
## initializes the random number generator with a "random"
## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
## as JavaScript does not support this.
proc randomize*(seed: int) {.gcsafe.}
proc randomize*(seed: int) {.benign.}
## initializes the random number generator with a specific seed.
## Note: Does nothing for the JavaScript target,
## as JavaScript does not support this.

View File

@@ -321,7 +321,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
dealloc(aiList)
proc acceptAddr*(server: Socket, client: var Socket, address: var string,
flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
flags = {SocketFlag.SafeDisconn}) {.
tags: [ReadIOEffect], gcsafe, locks: 0.} =
## Blocks until a connection is being made from a client. When a connection
## is made sets ``client`` to the client socket and ``address`` to the address
## of the connecting client.
@@ -938,8 +939,12 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
doAssert socket.handshake()
socket.fd.setBlocking(true)
proc isSsl*(socket: Socket): bool = return socket.isSSL
proc isSsl*(socket: Socket): bool =
## Determines whether ``socket`` is a SSL socket.
when defined(ssl):
result = socket.isSSL
else:
result = false
proc getFd*(socket: Socket): SocketHandle = return socket.fd
## Returns the socket's file descriptor

View File

@@ -1010,8 +1010,16 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
tags: [ReadIOEffect, WriteIOEffect].} =
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
if c_rename(source, dest) != 0'i32:
raise newException(OSError, $strerror(errno))
when defined(Windows):
when useWinUnicode:
let s = newWideCString(source)
let d = newWideCString(dest)
if moveFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError())
else:
if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError())
else:
if c_rename(source, dest) != 0'i32:
raise newException(OSError, $strerror(errno))
when not declared(ENOENT) and not defined(Windows):
when NoFakeVars:
@@ -1339,7 +1347,7 @@ proc rawRemoveDir(dir: string) =
if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
WriteDirEffect, ReadDirEffect].} =
WriteDirEffect, ReadDirEffect], benign.} =
## Removes the directory `dir` including all subdirectories and files
## in `dir` (recursively).
##
@@ -1385,7 +1393,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
rawCreateDir(dir)
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
tags: [WriteIOEffect, ReadIOEffect].} =
tags: [WriteIOEffect, ReadIOEffect], benign.} =
## Copies a directory from `source` to `dest`.
##
## If this fails, `OSError` is raised. On the Windows platform this proc will
@@ -1558,7 +1566,7 @@ proc copyFileWithPermissions*(source, dest: string,
proc copyDirWithPermissions*(source, dest: string,
ignorePermissionErrors = true) {.rtl, extern: "nos$1",
tags: [WriteIOEffect, ReadIOEffect].} =
tags: [WriteIOEffect, ReadIOEffect], benign.} =
## Copies a directory from `source` to `dest` preserving file permissions.
##
## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()

View File

@@ -299,7 +299,7 @@ when isMainModule and not defined(nimdoc):
sock: Socket
var sock = socket()
if sock == sockets.InvalidSocket: raiseOSError(osLastError())
if sock == sockets.invalidSocket: raiseOSError(osLastError())
#sock.setBlocking(false)
sock.connect("irc.freenode.net", Port(6667))

View File

@@ -45,6 +45,21 @@ when defined(windows):
var
oldAttr = getAttributes()
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
else:
import termios, unsigned
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
var mode: Termios
discard fd.tcgetattr(addr mode)
mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON)
mode.oflag = mode.oflag and not Tcflag(OPOST)
mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8
mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
mode.cc[VMIN] = 1.cuchar
mode.cc[VTIME] = 0.cuchar
discard fd.tcsetattr(time, addr mode)
proc setCursorPos*(x, y: int) =
## sets the terminal's cursor to the (x,y) position. (0,0) is the
## upper left of the screen.
@@ -349,6 +364,19 @@ macro styledEcho*(m: varargs[expr]): stmt =
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
result.add(newCall(bindSym"resetAttributes"))
proc getch*(): char =
## Read a single character from the terminal, blocking until it is entered.
## The character is not printed to the terminal.
when defined(windows):
result = winGetch().char
else:
let fd = getFileHandle(stdin)
var oldMode: Termios
discard fd.tcgetattr(addr oldMode)
fd.setRaw()
result = stdin.readChar()
discard fd.tcsetattr(TCSADRAIN, addr oldMode)
when isMainModule:
system.addQuitProc(resetAttributes)
write(stdout, "never mind")

View File

@@ -16,7 +16,7 @@
# of the standard library!
import
strutils
strutils, parseutils
include "system/inclrtl"
@@ -63,44 +63,44 @@ elif defined(windows):
elif defined(JS):
type
Time* {.importc.} = object
getDay: proc (): int {.tags: [], raises: [], gcsafe.}
getFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
getHours: proc (): int {.tags: [], raises: [], gcsafe.}
getMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
getMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
getMonth: proc (): int {.tags: [], raises: [], gcsafe.}
getSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
getTime: proc (): int {.tags: [], raises: [], gcsafe.}
getTimezoneOffset: proc (): int {.tags: [], raises: [], gcsafe.}
getDate: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCDate: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCHours: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCMonth: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.}
getYear: proc (): int {.tags: [], raises: [], gcsafe.}
parse: proc (s: cstring): Time {.tags: [], raises: [], gcsafe.}
setDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
setFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
setHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
setMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
setMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
setMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
setSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
setTime: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
setUTCSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
setYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
toGMTString: proc (): cstring {.tags: [], raises: [], gcsafe.}
toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.}
getDay: proc (): int {.tags: [], raises: [], benign.}
getFullYear: proc (): int {.tags: [], raises: [], benign.}
getHours: proc (): int {.tags: [], raises: [], benign.}
getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
getMinutes: proc (): int {.tags: [], raises: [], benign.}
getMonth: proc (): int {.tags: [], raises: [], benign.}
getSeconds: proc (): int {.tags: [], raises: [], benign.}
getTime: proc (): int {.tags: [], raises: [], benign.}
getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
getDate: proc (): int {.tags: [], raises: [], benign.}
getUTCDate: proc (): int {.tags: [], raises: [], benign.}
getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
getUTCHours: proc (): int {.tags: [], raises: [], benign.}
getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
getUTCDay: proc (): int {.tags: [], raises: [], benign.}
getYear: proc (): int {.tags: [], raises: [], benign.}
parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
setDate: proc (x: int) {.tags: [], raises: [], benign.}
setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
setHours: proc (x: int) {.tags: [], raises: [], benign.}
setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
setMonth: proc (x: int) {.tags: [], raises: [], benign.}
setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
setTime: proc (x: int) {.tags: [], raises: [], benign.}
setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
setYear: proc (x: int) {.tags: [], raises: [], benign.}
toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
type
TimeInfo* = object of RootObj ## represents a time in different parts
@@ -139,42 +139,42 @@ type
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
proc getTime*(): Time {.tags: [TimeEffect], gcsafe.}
proc getTime*(): Time {.tags: [TimeEffect], benign.}
## gets the current calendar time as a UNIX epoch value (number of seconds
## elapsed since 1970) with integer precission. Use epochTime for higher
## resolution.
proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
## converts the calendar time `t` to broken-time representation,
## expressed relative to the user's specified time zone.
proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
## converts the calendar time `t` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.}
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
## them from the other information in the broken-down time structure.
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.}
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.}
## Takes a float which contains the number of seconds since the unix epoch and
## returns a time object.
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} =
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} =
## Takes an int which contains the number of seconds since the unix epoch and
## returns a time object.
fromSeconds(float(since1970))
proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.}
proc toSeconds*(time: Time): float {.tags: [], raises: [], benign.}
## Returns the time in seconds since the unix epoch.
proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.}
proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], benign.}
## converts a `TimeInfo` object to a string representation.
proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.}
proc `$` *(time: Time): string {.tags: [], raises: [], benign.}
## converts a calendar time to a string representation.
proc `-`*(a, b: Time): int64 {.
rtl, extern: "ntDiffTime", tags: [], raises: [].}
rtl, extern: "ntDiffTime", tags: [], raises: [], benign.}
## computes the difference of two calendar times. Result is in seconds.
proc `<`*(a, b: Time): bool {.
@@ -194,14 +194,14 @@ proc `==`*(a, b: Time): bool {.
when not defined(JS):
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
gcsafe.}
benign.}
## returns the local timezone; ``nonDST`` is the name of the local non-DST
## timezone, ``DST`` is the name of the local DST timezone.
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], gcsafe.}
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.}
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
## get the miliseconds from the start of the program. **Deprecated since
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
@@ -744,6 +744,285 @@ proc format*(info: TimeInfo, f: string): string =
{.pop.}
proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
## Helper of the parse proc to parse individual tokens.
var sv: int
case token
of "d":
var pd = parseInt(value[j..j+1], sv)
info.monthday = sv
j += pd
of "dd":
info.monthday = value[j..j+1].parseInt()
j += 2
of "ddd":
case value[j..j+2].toLower():
of "sun":
info.weekday = dSun
of "mon":
info.weekday = dMon
of "tue":
info.weekday = dTue
of "wed":
info.weekday = dWed
of "thu":
info.weekday = dThu
of "fri":
info.weekday = dFri
of "sat":
info.weekday = dSat
else:
raise newException(ValueError, "invalid day of week ")
j += 3
of "dddd":
if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
info.weekday = dSun
j += 6
elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("monday") == 0:
info.weekday = dMon
j += 6
elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("tuesday") == 0:
info.weekday = dTue
j += 7
elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("wednesday") == 0:
info.weekday = dWed
j += 9
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("thursday") == 0:
info.weekday = dThu
j += 8
elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("friday") == 0:
info.weekday = dFri
j += 6
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("saturday") == 0:
info.weekday = dSat
j += 8
else:
raise newException(ValueError, "invalid day of week ")
of "h", "H":
var pd = parseInt(value[j..j+1], sv)
info.hour = sv
j += pd
of "hh", "HH":
info.hour = value[j..j+1].parseInt()
j += 2
of "m":
var pd = parseInt(value[j..j+1], sv)
info.minute = sv
j += pd
of "mm":
info.minute = value[j..j+1].parseInt()
j += 2
of "M":
var pd = parseInt(value[j..j+1], sv)
info.month = Month(sv-1)
info.monthday = sv
j += pd
of "MM":
var month = value[j..j+1].parseInt()
j += 2
info.month = Month(month-1)
of "MMM":
case value[j..j+2].toLower():
of "jan":
info.month = mJan
of "feb":
info.month = mFeb
of "mar":
info.month = mMar
of "apr":
info.month = mApr
of "may":
info.month = mMay
of "jun":
info.month = mJun
of "jul":
info.month = mJul
of "aug":
info.month = mAug
of "sep":
info.month = mSep
of "oct":
info.month = mOct
of "nov":
info.month = mNov
of "dec":
info.month = mDec
else:
raise newException(ValueError, "invalid month")
j += 3
of "MMMM":
if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
info.month = mJan
j += 7
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0:
info.month = mFeb
j += 8
elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0:
info.month = mMar
j += 5
elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0:
info.month = mApr
j += 5
elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0:
info.month = mMay
j += 3
elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0:
info.month = mJun
j += 4
elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0:
info.month = mJul
j += 4
elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0:
info.month = mAug
j += 6
elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0:
info.month = mSep
j += 9
elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0:
info.month = mOct
j += 7
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0:
info.month = mNov
j += 8
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0:
info.month = mDec
j += 8
else:
raise newException(ValueError, "invalid month")
of "s":
var pd = parseInt(value[j..j+1], sv)
info.second = sv
j += pd
of "ss":
info.second = value[j..j+1].parseInt()
j += 2
of "t":
if value[j] == 'P' and info.hour > 0 and info.hour < 12:
info.hour += 12
j += 1
of "tt":
if value[j..j+1] == "PM" and info.hour > 0 and info.hour < 12:
info.hour += 12
j += 2
of "yy":
# Assumes current century
var year = value[j..j+1].parseInt()
var thisCen = getLocalTime(getTime()).year div 100
info.year = thisCen*100 + year
j += 2
of "yyyy":
info.year = value[j..j+3].parseInt()
j += 4
of "z":
if value[j] == '+':
info.timezone = parseInt($value[j+1])
elif value[j] == '-':
info.timezone = 0-parseInt($value[j+1])
else:
raise newException(ValueError, "Sign for timezone " & value[j])
j += 2
of "zz":
if value[j] == '+':
info.timezone = value[j+1..j+2].parseInt()
elif value[j] == '-':
info.timezone = 0-value[j+1..j+2].parseInt()
else:
raise newException(ValueError, "Sign for timezone " & value[j])
j += 3
of "zzz":
if value[j] == '+':
info.timezone = value[j+1..j+2].parseInt()
elif value[j] == '-':
info.timezone = 0-value[j+1..j+2].parseInt()
else:
raise newException(ValueError, "Sign for timezone " & value[j])
j += 6
of "ZZZ":
info.tzname = value[j..j+2].toUpper()
j += 3
else:
# Ignore the token and move forward in the value string by the same length
j += token.len
proc parse*(value, layout: string): TimeInfo =
## This function parses a date/time string using the standard format identifiers (below)
## The function defaults information not provided in the format string from the running program (timezone, month, year, etc)
##
## ========== ================================================================================= ================================================
## Specifier Description Example
## ========== ================================================================================= ================================================
## d Numeric value of the day of the month, it will be one or two digits long. ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
## dd Same as above, but always two digits. ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
## ddd Three letter string which indicates the day of the week. ``Saturday -> Sat``, ``Monday -> Mon``
## dddd Full string for the day of the week. ``Saturday -> Saturday``, ``Monday -> Monday``
## h The hours in one digit if possible. Ranging from 0-12. ``5pm -> 5``, ``2am -> 2``
## hh The hours in two digits always. If the hour is one digit 0 is prepended. ``5pm -> 05``, ``11am -> 11``
## H The hours in one digit if possible, randing from 0-24. ``5pm -> 17``, ``2am -> 2``
## HH The hours in two digits always. 0 is prepended if the hour is one digit. ``5pm -> 17``, ``2am -> 02``
## m The minutes in 1 digit if possible. ``5:30 -> 30``, ``2:01 -> 1``
## mm Same as above but always 2 digits, 0 is prepended if the minute is one digit. ``5:30 -> 30``, ``2:01 -> 01``
## M The month in one digit if possible. ``September -> 9``, ``December -> 12``
## MM The month in two digits always. 0 is prepended. ``September -> 09``, ``December -> 12``
## MMM Abbreviated three-letter form of the month. ``September -> Sep``, ``December -> Dec``
## MMMM Full month string, properly capitalized. ``September -> September``
## s Seconds as one digit if possible. ``00:00:06 -> 6``
## ss Same as above but always two digits. 0 is prepended. ``00:00:06 -> 06``
## t ``A`` when time is in the AM. ``P`` when time is in the PM.
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
## yy Displays the year to two digits. ``2012 -> 12``
## yyyy Displays the year to four digits. ``2012 -> 2012``
## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5``
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
## zzz Same as above but with ``:00``. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
## ZZZ Displays the name of the timezone. ``GMT -> GMT``, ``EST -> EST``
## ========== ================================================================================= ================================================
##
## Other strings can be inserted by putting them in ``''``. For example
## ``hh'->'mm`` will give ``01->56``. The following characters can be
## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
## ``,``. However you don't need to necessarily separate format specifiers, a
## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
var i = 0 # pointer for format string
var j = 0 # pointer for value string
var token = ""
# Assumes current day of month, month and year, but time is reset to 00:00:00. Weekday will be reset after parsing.
var info = getLocalTime(getTime())
info.hour = 0
info.minute = 0
info.second = 0
while true:
case layout[i]
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
if token.len > 0:
parseToken(info, token, value, j)
# Reset token
token = ""
# Break if at end of line
if layout[i] == '\0': break
# Skip separator and everything between single quotes
# These are literals in both the layout and the value string
if layout[i] == '\'':
inc(i)
inc(j)
while layout[i] != '\'' and layout.len-1 > i:
inc(i)
inc(j)
else:
inc(i)
inc(j)
else:
# Check if the letter being added matches previous accumulated buffer.
if token.len < 1 or token[high(token)] == layout[i]:
token.add(layout[i])
inc(i)
else:
parseToken(info, token, value, j)
token = ""
# Reset weekday as it might not have been provided and the default may be wrong
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
return info
when isMainModule:
# $ date --date='@2147483647'
# Tue 19 Jan 03:14:07 GMT 2038
@@ -778,3 +1057,51 @@ when isMainModule:
# Interval tests
assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
var s = "Tuesday at 09:04am on Dec 15, 2015"
var f = "dddd at hh:mmtt on MMM d, yyyy"
assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
# ANSIC = "Mon Jan _2 15:04:05 2006"
s = "Mon Jan 2 15:04:05 2006"
f = "ddd MMM d HH:mm:ss yyyy"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# UnixDate = "Mon Jan _2 15:04:05 MST 2006"
s = "Mon Jan 2 15:04:05 MST 2006"
f = "ddd MMM d HH:mm:ss ZZZ yyyy"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
s = "Mon Jan 02 15:04:05 -07:00 2006"
f = "ddd MMM dd HH:mm:ss zzz yyyy"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# RFC822 = "02 Jan 06 15:04 MST"
s = "02 Jan 06 15:04 MST"
f = "dd MMM yy HH:mm ZZZ"
assert($s.parse(f) == "Mon Jan 2 15:04:00 2006")
# RFC822Z = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
s = "02 Jan 06 15:04 -07:00"
f = "dd MMM yy HH:mm zzz"
assert($s.parse(f) == "Mon Jan 2 15:04:00 2006")
# RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
s = "Monday, 02-Jan-06 15:04:05 MST"
f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
s = "Mon, 02 Jan 2006 15:04:05 MST"
f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
s = "Mon, 02 Jan 2006 15:04:05 -07:00"
f = "ddd, dd MMM yyyy HH:mm:ss zzz"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# RFC3339 = "2006-01-02T15:04:05Z07:00"
s = "2006-01-02T15:04:05Z-07:00"
f = "yyyy-MM-ddTHH:mm:ssZzzz"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
s = "2006-01-02T15:04:05.999999999Z-07:00"
f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
# Kitchen = "3:04PM"
s = "3:04PM"
f = "h:mmtt"
echo "Kitchen: " & $s.parse(f)

View File

@@ -2098,17 +2098,16 @@ when not defined(nimrodVM) and hostOS != "standalone":
## returns an informative string about the GC's activity. This may be useful
## for tweaking.
# XXX mark these as 'locks: 0' once 0.10.0 has been released
proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.}
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.}
proc GC_ref*(x: string) {.magic: "GCref", gcsafe.}
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
proc GC_ref*(x: string) {.magic: "GCref", benign.}
## marks the object `x` as referenced, so that it will not be freed until
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
## n calls to `GC_unref` are needed to unmark `x`.
proc GC_unref*[T](x: ref T) {.magic: "GCunref", gcsafe.}
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.}
proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.}
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
## see the documentation of `GC_ref`.
template accumulateResult*(iter: expr) =
@@ -2248,14 +2247,9 @@ when not declared(sysFatal):
e.msg = message & arg
raise e
when defined(nimlocks):
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.}
## get type information for `x`. Ordinary code should not use this, but
## the `typeinfo` module instead.
else:
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.}
## get type information for `x`. Ordinary code should not use this, but
## the `typeinfo` module instead.
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
## get type information for `x`. Ordinary code should not use this, but
## the `typeinfo` module instead.
{.push stackTrace: off.}
proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
@@ -2455,14 +2449,10 @@ when not defined(JS): #and not defined(NimrodVM):
## Returns ``false`` if the end of the file has been reached, ``true``
## otherwise. If ``false`` is returned `line` contains no new data.
when not defined(booting):
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
tags: [WriteIOEffect], gcsafe, locks: 0.}
## writes the values `x` to `f` and then writes "\n".
## May throw an IO exception.
else:
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
tags: [WriteIOEffect].}
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
tags: [WriteIOEffect], benign.}
## writes the values `x` to `f` and then writes "\n".
## May throw an IO exception.
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
## retrieves the file size (in bytes) of `f`.
@@ -2576,7 +2566,7 @@ when not defined(JS): #and not defined(NimrodVM):
initAllocator()
when hasThreadSupport:
include "system/syslocks"
include "system/threads"
when hostOS != "standalone": include "system/threads"
elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
initGC()
@@ -3161,7 +3151,7 @@ when hostOS != "standalone":
x[j+i] = item[j]
inc(j)
proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} =
proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
## Special compile-time procedure that checks whether `x` can be compiled
## without any semantic error.
## This can be used to check whether a type supports some operation:

View File

@@ -27,7 +27,7 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
var m = selectBranch(src, n)
# reset if different branches are in use; note different branches also
# imply that's not self-assignment (``x = x``)!
if m != dd and dd != nil:
if m != dd and dd != nil:
genericResetAux(dest, dd)
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ.size)
@@ -205,9 +205,13 @@ proc genericReset(dest: pointer, mt: PNimType) =
case mt.kind
of tyString, tyRef, tySequence:
unsureAsgnRef(cast[PPointer](dest), nil)
of tyObject, tyTuple:
# we don't need to reset m_type field for tyObject
of tyTuple:
genericResetAux(dest, mt.node)
of tyObject:
genericResetAux(dest, mt.node)
# also reset the type field for tyObject, for correct branch switching!
var pint = cast[ptr PNimType](dest)
pint[] = nil
of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1:
genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)

View File

@@ -175,6 +175,8 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
add(s, tempFrames[j].procname)
add(s, "\n")
proc stackTraceAvailable*(): bool
when hasSomeStackTrace:
proc rawWriteStackTrace(s: var string) =
when NimStackTrace:
@@ -188,6 +190,18 @@ when hasSomeStackTrace:
auxWriteStackTraceWithBacktrace(s)
else:
add(s, "No stack traceback available\n")
proc stackTraceAvailable(): bool =
when NimStackTrace:
if framePtr == nil:
result = false
else:
result = true
elif defined(nativeStackTrace) and nativeStackTraceSupported:
result = true
else:
result = false
else:
proc stackTraceAvailable*(): bool = result = false
proc quitOrDebug() {.inline.} =
when not defined(endb):

View File

@@ -528,20 +528,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
#if res.refcount <% rcIncrement:
# add(gch.zct, res)
#else: # XXX: what to do here?
# decRef(ol)
if (ol.refcount and ZctFlag) != 0:
var j = gch.zct.len-1
var d = gch.zct.d
while j >= 0:
if d[j] == ol:
d[j] = res
break
dec(j)
if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
# This can be wrong for intermediate temps that are nevertheless on the
# heap because of lambda lifting:
#gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
when logGC:
writeCell("growObj old cell", ol)
writeCell("growObj new cell", res)
@@ -549,7 +538,26 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
gcTrace(res, csAllocated)
when reallyDealloc:
sysAssert(allocInv(gch.region), "growObj before dealloc")
rawDealloc(gch.region, ol)
if ol.refcount shr rcShift <=% 1:
# free immediately to save space:
if (ol.refcount and ZctFlag) != 0:
var j = gch.zct.len-1
var d = gch.zct.d
while j >= 0:
if d[j] == ol:
d[j] = res
break
dec(j)
if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
rawDealloc(gch.region, ol)
else:
# we split the old refcount in 2 parts. XXX This is still not entirely
# correct if the pointer that receives growObj's result is on the stack.
# A better fix would be to emit the location specific write barrier for
# 'growObj', but this is lost of more work and who knows what new problems
# this would create.
res.refcount = rcIncrement
decRef(ol)
else:
sysAssert(ol.typ != nil, "growObj: 5")
zeroMem(ol, sizeof(TCell))

View File

@@ -297,10 +297,12 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
when withBitvectors: excl(gch.allocated, ol)
when reallyDealloc: rawDealloc(gch.region, ol)
else:
zeroMem(ol, sizeof(TCell))
when false:
# this is wrong since seqs can be shared via 'shallow':
when withBitvectors: excl(gch.allocated, ol)
when reallyDealloc: rawDealloc(gch.region, ol)
else:
zeroMem(ol, sizeof(TCell))
when withBitvectors: incl(gch.allocated, res)
when useCellIds:
inc gch.idGenerator

View File

@@ -78,7 +78,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
type
PByteArray = ptr array[0.. 0xffff, int8]
proc addSetElem(result: var string, elem: int, typ: PNimType) {.gcsafe.} =
proc addSetElem(result: var string, elem: int, typ: PNimType) {.benign.} =
case typ.kind
of tyEnum: add result, reprEnum(elem, typ)
of tyBool: add result, reprBool(bool(elem))
@@ -147,7 +147,7 @@ when not defined(useNimRtl):
for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) {.gcsafe.}
cl: var TReprClosure) {.benign.}
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
@@ -172,7 +172,7 @@ when not defined(useNimRtl):
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) {.gcsafe.} =
cl: var TReprClosure) {.benign.} =
case n.kind
of nkNone: sysAssert(false, "reprRecordAux")
of nkSlot:

View File

@@ -284,6 +284,10 @@ when useWinUnicode:
bFailIfExists: cint): cint {.
importc: "CopyFileW", stdcall, dynlib: "kernel32".}
proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString,
bFailIfExists: cint): cint {.
importc: "MoveFileW", stdcall, dynlib: "kernel32".}
proc getEnvironmentStringsW*(): WideCString {.
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
@@ -308,6 +312,10 @@ else:
bFailIfExists: cint): cint {.
importc: "CopyFileA", stdcall, dynlib: "kernel32".}
proc moveFileA*(lpExistingFileName, lpNewFileName: cstring,
bFailIfExists: cint): cint {.
importc: "MoveFileA", stdcall, dynlib: "kernel32".}
proc getEnvironmentStringsA*(): cstring {.
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
proc freeEnvironmentStringsA*(para1: cstring): int32 {.

View File

@@ -13,7 +13,7 @@
when defined(Unix):
when defined(macosx):
const
lib = "libmysqlclient.(15|16|17[18).dylib"
lib = "libmysqlclient.(15|16|17|18).dylib"
else:
const
lib = "libmysqlclient.so.(15|16|17|18)"

View File

@@ -66,8 +66,24 @@ Copyright (c) 2006-2014 Andreas Rumpf.
All rights reserved.
# Build Status
| |Linux|Windows|Mac|
|---|---|---|---|
| x86 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x32-builder)
| x86_64 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x64-builder)
| arm | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-arm5-builder) |
[**Build Waterfall**][waterfall]
| | Linux | Windows | Mac |
| ------ | ----- | ------- | --- |
| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | ![mac-x86][mac-x86-img] |
| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] |
| arm | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] | | |
[linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
[linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
[linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
[linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
[linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
[windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
[mac-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder
[mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
[waterfall]: http://buildbot.nim-lang.org/waterfall

View File

@@ -19,7 +19,6 @@ proc processClient(fd: int) {.async.} =
var foo = line[0]
if foo == 'g':
raise newException(EBase, "foobar")
proc serve() {.async.} =

View File

@@ -49,3 +49,44 @@ proc catch() {.async.} =
assert false
asyncCheck catch()
proc test(): Future[bool] {.async.} =
result = false
try:
raise newException(OSError, "Foobar")
except:
result = true
return
proc foo(): Future[bool] {.async.} = discard
proc test2(): Future[bool] {.async.} =
result = false
try:
discard await foo()
raise newException(OSError, "Foobar")
except:
result = true
return
proc test3(): Future[int] {.async.} =
result = 0
try:
try:
discard await foo()
raise newException(OSError, "Hello")
except:
result = 1
raise
except:
result = 2
return
var x = test()
assert x.read
x = test2()
assert x.read
var y = test3()
assert y.read == 2

View File

@@ -0,0 +1,15 @@
# bug #2073
import sequtils
import times
# 1
proc f(n: int): TimeInfo =
TimeInfo(year: n, month: mJan, monthday: 1)
echo toSeq(2000 || 2015).map(f)
# 2
echo toSeq(2000 || 2015).map(proc (n: int): TimeInfo =
TimeInfo(year: n, month: mJan, monthday: 1)
)

View File

@@ -0,0 +1,22 @@
import tables
doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
var tbl1 = initTable[int, int]()
tbl1.add(1,1)
tbl1.add(2,2)
doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
type
TElem = object
foo: int
bar: string
let
elem1 = TElem(foo: 1, bar: "bar")
elem2 = TElem(foo: 2, bar: "baz")
var tbl2 = initTable[string, TElem]()
tbl2.add("bar", elem1)
tbl2.add("baz", elem2)
doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"

View File

@@ -1,22 +1,128 @@
import tables
discard """
output: '''true'''
"""
doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
import hashes, tables
var tbl1 = initTable[int, int]()
tbl1.add(1,1)
tbl1.add(2,2)
doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
const
data = {
"34": 123456, "12": 789,
"90": 343, "0": 34404,
"1": 344004, "2": 344774,
"3": 342244, "4": 3412344,
"5": 341232144, "6": 34214544,
"7": 3434544, "8": 344544,
"9": 34435644, "---00": 346677844,
"10": 34484, "11": 34474, "19": 34464,
"20": 34454, "30": 34141244, "40": 344114,
"50": 344490, "60": 344491, "70": 344492,
"80": 344497}
type
TElem = object
foo: int
bar: string
let
elem1 = TElem(foo: 1, bar: "bar")
elem2 = TElem(foo: 2, bar: "baz")
sorteddata = {
"---00": 346677844,
"0": 34404,
"1": 344004,
"10": 34484,
"11": 34474,
"12": 789,
"19": 34464,
"2": 344774, "20": 34454,
"3": 342244, "30": 34141244,
"34": 123456,
"4": 3412344, "40": 344114,
"5": 341232144, "50": 344490,
"6": 34214544, "60": 344491,
"7": 3434544, "70": 344492,
"8": 344544, "80": 344497,
"9": 34435644,
"90": 343}
block tableTest1:
var t = initTable[tuple[x, y: int], string]()
t[(0,0)] = "00"
t[(1,0)] = "10"
t[(0,1)] = "01"
t[(1,1)] = "11"
for x in 0..1:
for y in 0..1:
assert t[(x,y)] == $x & $y
assert($t ==
"{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2:
var t = initTable[string, float]()
t["test"] = 1.2345
t["111"] = 1.000043
t["123"] = 1.23
t.del("111")
var tbl2 = initTable[string, TElem]()
tbl2.add("bar", elem1)
tbl2.add("baz", elem2)
doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
t["012"] = 67.9
t["123"] = 1.5 # test overwriting
assert t["123"] == 1.5
assert t["111"] == 0.0 # deleted
assert(not hasKey(t, "111"))
for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat
block orderedTableTest1:
var t = initOrderedTable[string, int](2)
for key, val in items(data): t[key] = val
for key, val in items(data): assert t[key] == val
var i = 0
# `pairs` needs to yield in insertion order:
for key, val in pairs(t):
assert key == data[i][0]
assert val == data[i][1]
inc(i)
for key, val in mpairs(t): val = 99
for val in mvalues(t): assert val == 99
block countTableTest1:
var s = data.toTable
var t = initCountTable[string]()
for k in s.keys: t.inc(k)
for k in t.keys: assert t[k] == 1
t.inc("90", 3)
t.inc("12", 2)
t.inc("34", 1)
assert t.largest()[0] == "90"
t.sort()
var i = 0
for k, v in t.pairs:
case i
of 0: assert k == "90" and v == 4
of 1: assert k == "12" and v == 3
of 2: assert k == "34" and v == 2
else: break
inc i
block SyntaxTest:
var x = toTable[int, string]({:})
proc orderedTableSortTest() =
var t = initOrderedTable[string, int](2)
for key, val in items(data): t[key] = val
for key, val in items(data): assert t[key] == val
t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
var i = 0
# `pairs` needs to yield in sorted order:
for key, val in pairs(t):
doAssert key == sorteddata[i][0]
doAssert val == sorteddata[i][1]
inc(i)
# check that lookup still works:
for key, val in pairs(t):
doAssert val == t[key]
# check that insert still works:
t["newKeyHere"] = 80
orderedTableSortTest()
echo "true"

View File

@@ -84,7 +84,7 @@ block orderedTableTest1:
block countTableTest1:
var s = data.toTable
var t = newCountTable[string]()
for k in s.Keys: t.inc(k)
for k in s.keys: t.inc(k)
for k in t.keys: assert t[k] == 1
t.inc("90", 3)
t.inc("12", 2)

View File

@@ -38,12 +38,14 @@ proc newPlus(a, b: ref TExpr): ref TPlusExpr =
result.b = b
result.op2 = $getOccupiedMem()
const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 500_000
for i in 0..100_000:
var s: array[0..11, ref TExpr]
for j in 0..high(s):
s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4))
if eval(s[j]) != j+6:
quit "error: wrong result"
if getOccupiedMem() > 500_000: quit("still a leak!")
if getOccupiedMem() > Limit: quit("still a leak!")
echo "no leak: ", getOccupiedMem()

29
tests/gc/growobjcrash.nim Normal file
View File

@@ -0,0 +1,29 @@
discard """
output: "works"
"""
import cgi, strtabs
proc handleRequest(query: string): StringTableRef =
iterator foo(): StringTableRef {.closure.} =
var params = {:}.newStringTable()
for key, val in cgi.decodeData(query):
params[key] = val
yield params
let x = foo
result = x()
const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000
proc main =
var counter = 0
for i in 0 .. 100_000:
for k, v in handleRequest("nick=Elina2&type=activate"):
inc counter
if counter mod 100 == 0:
if getOccupiedMem() > Limit:
quit "but now a leak"
main()
echo "works"

View File

@@ -1,6 +1,5 @@
discard """
output: '''TMatrix[3, 3, system.int]
3
3'''
"""
@@ -22,5 +21,5 @@ proc echoMat2(a: TMat2) =
var m = TMatrix[3,3,int](data: [1,2,3,4,5,6,7,8,9])
echoMatrix m
echoMat2 m
#echoMat2 m

View File

@@ -1,9 +1,10 @@
discard """
output: "2"
output: '''2
88'''
"""
type
TValue* {.pure, final.} = object of TObject
TValue* {.pure, final.} = object of RootObj
a: int
PValue = ref TValue
PPValue = ptr PValue
@@ -16,3 +17,19 @@ var sp: PPValue = addr x
sp.a = 2
if sp.a == 2: echo 2 # with sp[].a the error is gone
# Test the new auto-deref a little
{.experimental.}
proc p(x: var int; y: int) = x += y
block:
var x: ref int
new(x)
x.p(44)
var indirect = p
x.indirect(44)
echo x[]

View File

@@ -1,3 +1,7 @@
discard """
errormsg: "expression 'generate(builder)' has no type (or is ambiguous)"
"""
# bug #898
proc measureTime(e: auto) =

View File

@@ -30,7 +30,7 @@ accept bar(vbar)
accept baz(vbar)
accept baz(vbaz)
reject baz(vnotbaz)
#reject baz(vnotbaz) # XXX this really shouldn't compile
reject bar(vfoo)
# https://github.com/Araq/Nim/issues/517

View File

@@ -14,6 +14,7 @@ AST b
20Test
20
'''
disabled: true
"""
import macros

View File

@@ -1,6 +1,7 @@
discard """
msg: "int\nstring\nTBar[int]"
output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
disabled: true
"""
import typetraits

View File

@@ -1,6 +1,7 @@
discard """
errormsg: "type mismatch: got (string) but expected 'ptr'"
line: 20
disabled: true
"""
import typetraits

View File

@@ -0,0 +1,11 @@
discard """
errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
"""
var x = int
echo x

View File

@@ -1,7 +1,7 @@
discard """
file: "tests/reject/trecincb.nim"
line: 9
errormsg: "recursive dependency: 'tests/module/trecincb.nim'"
errormsg: "recursive dependency: 'trecincb.nim'"
"""
# Test recursive includes

View File

@@ -1,7 +1,7 @@
discard """
file: "trecincb.nim"
line: 9
errormsg: "recursive dependency: 'tests/module/trecincb.nim'"
errormsg: "recursive dependency: 'trecincb.nim'"
"""
# Test recursive includes

View File

@@ -0,0 +1,27 @@
discard """
output: '''wohoo
baz'''
"""
# Test to ensure the popular 'ref T' syntax works everywhere
type
Foo = object
a, b: int
s: string
FooBar = object of RootObj
n, m: string
Baz = object of FooBar
proc invoke(a: ref Baz) =
echo "baz"
# check object construction:
let x = (ref Foo)(a: 0, b: 45, s: "wohoo")
echo x.s
var y: ref FooBar = (ref Baz)(n: "n", m: "m")
invoke((ref Baz)(y))

View File

@@ -0,0 +1,27 @@
discard """
output: "SUCCESS"
"""
type
BasicNumber = object of RootObj
value: float32
RefChild* = ref object
curr*: TokenObject
Token* {.pure.} = enum
foo,
bar,
TokenObject = object
case kind*: Token
of Token.foo:
foo*: string
of Token.bar:
bar*: BasicNumber
var t = RefChild()
t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34))
t.curr = TokenObject(kind: Token.foo, foo: "foo")
echo "SUCCESS"

View File

@@ -0,0 +1,17 @@
discard """
output: '''a 1 b 2 x @[3, 4, 5] y 6 z 7
yay
12'''
"""
proc test(a, b: int, x: varargs[int]; y, z: int) =
echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z
test 1, 2, 3, 4, 5, 6, 7
template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
blck
echo a, b
takesBlock 1, 2, "some", 0.90, "random stuff":
echo "yay"

View File

@@ -1,453 +0,0 @@
import irc, sockets, asyncio, json, os, strutils, times, redis
type
TDb* = object
r*: Redis
lastPing: float
TBuildResult* = enum
bUnknown, bFail, bSuccess
TTestResult* = enum
tUnknown, tFail, tSuccess
TEntry* = tuple[c: TCommit, p: seq[TPlatform]]
TCommit* = object
commitMsg*, username*, hash*: string
date*: Time
TPlatform* = object
buildResult*: TBuildResult
testResult*: TTestResult
failReason*, platform*: string
total*, passed*, skipped*, failed*: BiggestInt
csources*: bool
const
listName = "commits"
failOnExisting = false
proc open*(host = "localhost", port: Port): TDb =
result.r = redis.open(host, port)
result.lastPing = epochTime()
discard """proc customHSet(database: TDb, name, field, value: string) =
if database.r.hSet(name, field, value).int == 0:
if failOnExisting:
assert(false)
else:
echo("[Warning:REDIS] ", field, " already exists in ", name)"""
proc updateProperty*(database: TDb, commitHash, platform, property,
value: string) =
var name = platform & ":" & commitHash
if database.r.hSet(name, property, value).int == 0:
echo("[INFO:REDIS] '$1' field updated in hash" % [property])
else:
echo("[INFO:REDIS] '$1' new field added to hash" % [property])
proc globalProperty*(database: TDb, commitHash, property, value: string) =
if database.r.hSet(commitHash, property, value).int == 0:
echo("[INFO:REDIS] '$1' field updated in hash" % [property])
else:
echo("[INFO:REDIS] '$1' new field added to hash" % [property])
proc addCommit*(database: TDb, commitHash, commitMsg, user: string) =
# Add the commit hash to the `commits` list.
discard database.r.lPush(listName, commitHash)
# Add the commit message, current date and username as a property
globalProperty(database, commitHash, "commitMsg", commitMsg)
globalProperty(database, commitHash, "date", $int(getTime()))
globalProperty(database, commitHash, "username", user)
proc keepAlive*(database: var TDb) =
## Keep the connection alive. Ping redis in this case. This functions does
## not guarantee that redis will be pinged.
var t = epochTime()
if t - database.lastPing >= 60.0:
echo("PING -> redis")
assert(database.r.ping() == "PONG")
database.lastPing = t
proc getCommits*(database: TDb,
plStr: var seq[string]): seq[TEntry] =
result = @[]
var commitsRaw = database.r.lrange("commits", 0, -1)
for c in items(commitsRaw):
var commit: TCommit
commit.hash = c
for key, value in database.r.hPairs(c):
case normalize(key)
of "commitmsg": commit.commitMsg = value
of "date": commit.date = Time(parseInt(value))
of "username": commit.username = value
else:
echo(key)
assert(false)
var platformsRaw = database.r.lrange(c & ":platforms", 0, -1)
var platforms: seq[TPlatform] = @[]
for p in items(platformsRaw):
var platform: TPlatform
for key, value in database.r.hPairs(p & ":" & c):
case normalize(key)
of "buildresult":
platform.buildResult = parseInt(value).TBuildResult
of "testresult":
platform.testResult = parseInt(value).TTestResult
of "failreason":
platform.failReason = value
of "total":
platform.total = parseBiggestInt(value)
of "passed":
platform.passed = parseBiggestInt(value)
of "skipped":
platform.skipped = parseBiggestInt(value)
of "failed":
platform.failed = parseBiggestInt(value)
of "csources":
platform.csources = if value == "t": true else: false
else:
echo(normalize(key))
assert(false)
platform.platform = p
platforms.add(platform)
if p notin plStr:
plStr.add(p)
result.add((commit, platforms))
proc commitExists*(database: TDb, commit: string, starts = false): bool =
# TODO: Consider making the 'commits' list a set.
for c in items(database.r.lrange("commits", 0, -1)):
if starts:
if c.startsWith(commit): return true
else:
if c == commit: return true
return false
proc platformExists*(database: TDb, commit: string, platform: string): bool =
for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)):
if p == platform: return true
proc expandHash*(database: TDb, commit: string): string =
for c in items(database.r.lrange("commits", 0, -1)):
if c.startsWith(commit): return c
assert false
proc isNewest*(database: TDb, commit: string): bool =
return database.r.lIndex("commits", 0) == commit
proc getNewest*(database: TDb): string =
return database.r.lIndex("commits", 0)
proc addPlatform*(database: TDb, commit: string, platform: string) =
assert database.commitExists(commit)
assert (not database.platformExists(commit, platform))
var name = platform & ":" & commit
if database.r.exists(name):
if failOnExisting: quit("[FAIL] " & name & " already exists!", 1)
else: echo("[Warning] " & name & " already exists!")
discard database.r.lPush(commit & ":" & "platforms", platform)
proc `[]`*(p: seq[TPlatform], name: string): TPlatform =
for platform in items(p):
if platform.platform == name:
return platform
raise newException(ValueError, name & " platforms not found in commits.")
proc contains*(p: seq[TPlatform], s: string): bool =
for i in items(p):
if i.platform == s:
return true
type
PState = ref TState
TState = object of RootObj
dispatcher: Dispatcher
sock: AsyncSocket
ircClient: PAsyncIRC
hubPort: Port
database: TDb
dbConnected: bool
TSeenType = enum
PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
TSeen = object
nick: string
channel: string
timestamp: Time
case kind*: TSeenType
of PSeenJoin: nil
of PSeenPart, PSeenQuit, PSeenMsg:
msg: string
of PSeenNick:
newNick: string
const
ircServer = "irc.freenode.net"
joinChans = @["#nim"]
botNickname = "NimBot"
proc setSeen(d: TDb, s: TSeen) =
discard d.r.del("seen:" & s.nick)
var hashToSet = @[("type", $s.kind.int), ("channel", s.channel),
("timestamp", $s.timestamp.int)]
case s.kind
of PSeenJoin: discard
of PSeenPart, PSeenMsg, PSeenQuit:
hashToSet.add(("msg", s.msg))
of PSeenNick:
hashToSet.add(("newnick", s.newNick))
d.r.hMSet("seen:" & s.nick, hashToSet)
proc getSeen(d: TDb, nick: string, s: var TSeen): bool =
if d.r.exists("seen:" & nick):
result = true
s.nick = nick
# Get the type first
s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType
for key, value in d.r.hPairs("seen:" & nick):
case normalize(key)
of "type":
discard
#s.kind = value.parseInt.TSeenType
of "channel":
s.channel = value
of "timestamp":
s.timestamp = Time(value.parseInt)
of "msg":
s.msg = value
of "newnick":
s.newNick = value
template createSeen(typ: TSeenType, n, c: string): stmt {.immediate, dirty.} =
var seenNick: TSeen
seenNick.kind = typ
seenNick.nick = n
seenNick.channel = c
seenNick.timestamp = getTime()
proc parseReply(line: string, expect: string): bool =
var jsonDoc = parseJson(line)
return jsonDoc["reply"].str == expect
proc limitCommitMsg(m: string): string =
## Limits the message to 300 chars and adds ellipsis.
var m1 = m
if NewLines in m1:
m1 = m1.splitLines()[0]
if m1.len >= 300:
m1 = m1[0..300]
if m1.len >= 300 or NewLines in m: m1.add("... ")
if NewLines in m: m1.add($m.splitLines().len & " more lines")
return m1
proc handleWebMessage(state: PState, line: string) =
echo("Got message from hub: " & line)
var json = parseJson(line)
if json.hasKey("payload"):
for i in 0..min(4, json["payload"]["commits"].len-1):
var commit = json["payload"]["commits"][i]
# Create the message
var message = ""
message.add(json["payload"]["repository"]["owner"]["name"].str & "/" &
json["payload"]["repository"]["name"].str & " ")
message.add(commit["id"].str[0..6] & " ")
message.add(commit["author"]["name"].str & " ")
message.add("[+" & $commit["added"].len & " ")
message.add("±" & $commit["modified"].len & " ")
message.add("-" & $commit["removed"].len & "]: ")
message.add(limitCommitMsg(commit["message"].str))
# Send message to #nim.
discard state.ircClient.privmsg(joinChans[0], message)
elif json.hasKey("redisinfo"):
assert json["redisinfo"].hasKey("port")
#let redisPort = json["redisinfo"]["port"].num
state.dbConnected = true
proc hubConnect(state: PState)
proc handleConnect(s: AsyncSocket, state: PState) =
try:
# Send greeting
var obj = newJObject()
obj["name"] = newJString("irc")
obj["platform"] = newJString("?")
state.sock.send($obj & "\c\L")
# Wait for reply.
var line = ""
sleep(1500)
if state.sock.recvLine(line):
assert(line != "")
doAssert parseReply(line, "OK")
echo("The hub accepted me!")
else:
raise newException(ValueError,
"Hub didn't accept me. Waited 1.5 seconds.")
# ask for the redis info
var riobj = newJObject()
riobj["do"] = newJString("redisinfo")
state.sock.send($riobj & "\c\L")
except OsError:
echo(getCurrentExceptionMsg())
s.close()
echo("Waiting 5 seconds...")
sleep(5000)
state.hubConnect()
proc handleRead(s: AsyncSocket, state: PState) =
var line = ""
if state.sock.recvLine(line):
if line != "":
# Handle the message
state.handleWebMessage(line)
else:
echo("Disconnected from hub: ", osErrorMsg())
s.close()
echo("Reconnecting...")
state.hubConnect()
else:
echo(osErrorMsg())
proc hubConnect(state: PState) =
state.sock = asyncSocket()
state.sock.connect("127.0.0.1", state.hubPort)
state.sock.handleConnect =
proc (s: AsyncSocket) =
handleConnect(s, state)
state.sock.handleRead =
proc (s: AsyncSocket) =
handleRead(s, state)
state.dispatcher.register(state.sock)
proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) =
case event.typ
of EvConnected: discard
of EvDisconnected:
while not state.ircClient.isConnected:
try:
state.ircClient.connect()
except:
echo("Error reconnecting: ", getCurrentExceptionMsg())
echo("Waiting 5 seconds...")
sleep(5000)
echo("Reconnected successfully!")
of EvMsg:
echo("< ", event.raw)
case event.cmd
of MPrivMsg:
let msg = event.params[event.params.len-1]
let words = msg.split(' ')
template pm(msg: string): stmt =
state.ircClient.privmsg(event.origin, msg)
case words[0]
of "!ping": pm("pong")
of "!lag":
if state.ircClient.getLag != -1.0:
var lag = state.ircClient.getLag
lag = lag * 1000.0
pm($int(lag) & "ms between me and the server.")
else:
pm("Unknown.")
of "!seen":
if words.len > 1:
let nick = words[1]
if nick == botNickname:
pm("Yes, I see myself.")
echo(nick)
var seenInfo: TSeen
if state.database.getSeen(nick, seenInfo):
#var mSend = ""
case seenInfo.kind
of PSeenMsg:
pm("$1 was last seen on $2 in $3 saying: $4" %
[seenInfo.nick, $seenInfo.timestamp,
seenInfo.channel, seenInfo.msg])
of PSeenJoin:
pm("$1 was last seen on $2 joining $3" %
[seenInfo.nick, $seenInfo.timestamp, seenInfo.channel])
of PSeenPart:
pm("$1 was last seen on $2 leaving $3 with message: $4" %
[seenInfo.nick, $seenInfo.timestamp, seenInfo.channel,
seenInfo.msg])
of PSeenQuit:
pm("$1 was last seen on $2 quitting with message: $3" %
[seenInfo.nick, $seenInfo.timestamp, seenInfo.msg])
of PSeenNick:
pm("$1 was last seen on $2 changing nick to $3" %
[seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick])
else:
pm("I have not seen " & nick)
else:
pm("Syntax: !seen <nick>")
# TODO: ... commands
# -- Seen
# Log this as activity.
createSeen(PSeenMsg, event.nick, event.origin)
seenNick.msg = msg
state.database.setSeen(seenNick)
of MJoin:
createSeen(PSeenJoin, event.nick, event.origin)
state.database.setSeen(seenNick)
of MPart:
createSeen(PSeenPart, event.nick, event.origin)
let msg = event.params[event.params.high]
seenNick.msg = msg
state.database.setSeen(seenNick)
of MQuit:
createSeen(PSeenQuit, event.nick, event.origin)
let msg = event.params[event.params.high]
seenNick.msg = msg
state.database.setSeen(seenNick)
of MNick:
createSeen(PSeenNick, event.nick, "#nim")
seenNick.newNick = event.params[0]
state.database.setSeen(seenNick)
else:
discard # TODO: ?
proc open(port: Port = Port(5123)): PState =
var res: PState
new(res)
res.dispatcher = newDispatcher()
res.hubPort = port
res.hubConnect()
let hirc =
proc (a: PAsyncIRC, ev: TIRCEvent) =
handleIrc(a, ev, res)
# Connect to the irc server.
res.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
joinChans = joinChans, ircEvent = hirc)
res.ircClient.connect()
res.dispatcher.register(res.ircClient)
res.dbConnected = false
result = res
var state = tircbot.open() # Connect to the website and the IRC server.
while state.dispatcher.poll():
if state.dbConnected:
state.database.keepAlive()

View File

@@ -11,8 +11,8 @@ fpqeew
[11, 12, 13]
[11, 12, 13]
[11, 12, 13]
{ "key1": 11, "key2": 12, "key3": 13}
[ 11, 12, 13]
{"key1": 11, "key2": 12, "key3": 13}
[11, 12, 13]
<Students>
<Student Name="Aprilfoo" />
<Student Name="bar" />

View File

@@ -1,128 +0,0 @@
discard """
output: '''true'''
"""
import hashes, tables
const
data = {
"34": 123456, "12": 789,
"90": 343, "0": 34404,
"1": 344004, "2": 344774,
"3": 342244, "4": 3412344,
"5": 341232144, "6": 34214544,
"7": 3434544, "8": 344544,
"9": 34435644, "---00": 346677844,
"10": 34484, "11": 34474, "19": 34464,
"20": 34454, "30": 34141244, "40": 344114,
"50": 344490, "60": 344491, "70": 344492,
"80": 344497}
sorteddata = {
"---00": 346677844,
"0": 34404,
"1": 344004,
"10": 34484,
"11": 34474,
"12": 789,
"19": 34464,
"2": 344774, "20": 34454,
"3": 342244, "30": 34141244,
"34": 123456,
"4": 3412344, "40": 344114,
"5": 341232144, "50": 344490,
"6": 34214544, "60": 344491,
"7": 3434544, "70": 344492,
"8": 344544, "80": 344497,
"9": 34435644,
"90": 343}
block tableTest1:
var t = initTable[tuple[x, y: int], string]()
t[(0,0)] = "00"
t[(1,0)] = "10"
t[(0,1)] = "01"
t[(1,1)] = "11"
for x in 0..1:
for y in 0..1:
assert t[(x,y)] == $x & $y
assert($t ==
"{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2:
var t = initTable[string, float]()
t["test"] = 1.2345
t["111"] = 1.000043
t["123"] = 1.23
t.del("111")
t["012"] = 67.9
t["123"] = 1.5 # test overwriting
assert t["123"] == 1.5
assert t["111"] == 0.0 # deleted
assert(not hasKey(t, "111"))
for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat
block orderedTableTest1:
var t = initOrderedTable[string, int](2)
for key, val in items(data): t[key] = val
for key, val in items(data): assert t[key] == val
var i = 0
# `pairs` needs to yield in insertion order:
for key, val in pairs(t):
assert key == data[i][0]
assert val == data[i][1]
inc(i)
for key, val in mpairs(t): val = 99
for val in mvalues(t): assert val == 99
block countTableTest1:
var s = data.toTable
var t = initCountTable[string]()
for k in s.keys: t.inc(k)
for k in t.keys: assert t[k] == 1
t.inc("90", 3)
t.inc("12", 2)
t.inc("34", 1)
assert t.largest()[0] == "90"
t.sort()
var i = 0
for k, v in t.pairs:
case i
of 0: assert k == "90" and v == 4
of 1: assert k == "12" and v == 3
of 2: assert k == "34" and v == 2
else: break
inc i
block SyntaxTest:
var x = toTable[int, string]({:})
proc orderedTableSortTest() =
var t = initOrderedTable[string, int](2)
for key, val in items(data): t[key] = val
for key, val in items(data): assert t[key] == val
t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
var i = 0
# `pairs` needs to yield in sorted order:
for key, val in pairs(t):
doAssert key == sorteddata[i][0]
doAssert val == sorteddata[i][1]
inc(i)
# check that lookup still works:
for key, val in pairs(t):
doAssert val == t[key]
# check that insert still works:
t["newKeyHere"] = 80
orderedTableSortTest()
echo "true"

View File

@@ -12,3 +12,22 @@ template genNodeKind(kind, name: expr): stmt =
result.add(c)
genNodeKind(nnkNone, None)
# Test that generics in templates still work (regression to fix #1915)
# bug #2004
type Something = object
proc testA(x: Something) = discard
template def(name: expr) {.immediate.} =
proc testB[T](reallyUniqueName: T) =
`test name`(reallyUniqueName)
def A
var x: Something
testB(x)

View File

@@ -120,7 +120,8 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
" --gc:markAndSweep", cat, actionRun)
testSpec r, makeTest("tests/gc" / filename, options &
" -d:release --gc:markAndSweep", cat, actionRun)
test "growobjcrash"
test "gcbench"
test "gcleak"
test "gcleak2"

View File

@@ -0,0 +1,9 @@
import future
template tempo(s: expr) =
s("arg")
tempo((s: string)->auto => echo(s))
tempo((s: string) => echo(s))

View File

@@ -5,7 +5,7 @@ discard """
# bug #1708
let foo = {
"1" : (bar: @["1"]),
"2" : (baz: @[])
"2" : (bar: @[])
}
# bug #871

Some files were not shown because too many files have changed in this diff Show More