mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
Merge remote-tracking branch 'upstream/devel' into devel
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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?")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) =
|
||||
#
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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: "/",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:.
|
||||
|
||||
941
doc/nimc.txt
941
doc/nimc.txt
File diff suppressed because it is too large
Load Diff
@@ -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:
|
||||
|
||||
|
||||
14
koch.nim
14
koch.nim
@@ -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 ---------------------------------------------------------
|
||||
|
||||
@@ -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.} =
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {.
|
||||
|
||||
@@ -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)"
|
||||
|
||||
26
readme.md
26
readme.md
@@ -66,8 +66,24 @@ Copyright (c) 2006-2014 Andreas Rumpf.
|
||||
All rights reserved.
|
||||
|
||||
# Build Status
|
||||
| |Linux|Windows|Mac|
|
||||
|---|---|---|---|
|
||||
| x86 |  |  | 
|
||||
| x86_64 |  |  | 
|
||||
| arm |  |
|
||||
[**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
|
||||
|
||||
@@ -19,7 +19,6 @@ proc processClient(fd: int) {.async.} =
|
||||
var foo = line[0]
|
||||
if foo == 'g':
|
||||
raise newException(EBase, "foobar")
|
||||
|
||||
|
||||
proc serve() {.async.} =
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
15
tests/closure/ttimeinfo.nim
Normal file
15
tests/closure/ttimeinfo.nim
Normal 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)
|
||||
)
|
||||
22
tests/collections/tindexby.nim
Normal file
22
tests/collections/tindexby.nim
Normal 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"
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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
29
tests/gc/growobjcrash.nim
Normal 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"
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
discard """
|
||||
errormsg: "expression 'generate(builder)' has no type (or is ambiguous)"
|
||||
"""
|
||||
|
||||
# bug #898
|
||||
|
||||
proc measureTime(e: auto) =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,6 +14,7 @@ AST b
|
||||
20Test
|
||||
20
|
||||
'''
|
||||
disabled: true
|
||||
"""
|
||||
|
||||
import macros
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got (string) but expected 'ptr'"
|
||||
line: 20
|
||||
disabled: true
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
|
||||
11
tests/metatype/typedesc_as_value.nim
Normal file
11
tests/metatype/typedesc_as_value.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
discard """
|
||||
errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
|
||||
"""
|
||||
|
||||
|
||||
var x = int
|
||||
|
||||
echo x
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
27
tests/objects/trefobjsyntax.nim
Normal file
27
tests/objects/trefobjsyntax.nim
Normal 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))
|
||||
|
||||
27
tests/objvariant/treassign.nim
Normal file
27
tests/objvariant/treassign.nim
Normal 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"
|
||||
17
tests/overload/tparams_after_varargs.nim
Normal file
17
tests/overload/tparams_after_varargs.nim
Normal 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"
|
||||
@@ -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()
|
||||
@@ -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" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
9
tests/types/tauto_canbe_void.nim
Normal file
9
tests/types/tauto_canbe_void.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
import future
|
||||
|
||||
template tempo(s: expr) =
|
||||
s("arg")
|
||||
|
||||
tempo((s: string)->auto => echo(s))
|
||||
tempo((s: string) => echo(s))
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user