Merge ../Nim into devel; track ttables.nim delete.
This commit is contained in:
commit
45a2c1b1d1
35 changed files with 1217 additions and 1273 deletions
|
|
@ -430,15 +430,27 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
var length = sonsLen(ri)
|
var length = sonsLen(ri)
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
|
|
||||||
if length > 1:
|
# don't call 'ropeToStr' here for efficiency:
|
||||||
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
let pat = ri.sons[0].sym.loc.r.data
|
||||||
app(pl, ~" ")
|
internalAssert pat != nil
|
||||||
app(pl, op.r)
|
var start = 3
|
||||||
if length > 2:
|
if ' ' in pat:
|
||||||
app(pl, ~": ")
|
start = 1
|
||||||
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
|
app(pl, op.r)
|
||||||
for i in countup(3, length-1):
|
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))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
if i >= sonsLen(typ):
|
if i >= sonsLen(typ):
|
||||||
internalError(ri.info, "varargs for objective C method?")
|
internalError(ri.info, "varargs for objective C method?")
|
||||||
|
|
|
||||||
|
|
@ -2107,17 +2107,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
discard
|
discard
|
||||||
of nkPragma: genPragma(p, n)
|
of nkPragma: genPragma(p, n)
|
||||||
of nkPragmaBlock: expr(p, n.lastSon, d)
|
of nkPragmaBlock: expr(p, n.lastSon, d)
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||||
if (n.sons[genericParamsPos].kind == nkEmpty):
|
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||||
var prc = n.sons[namePos].sym
|
var prc = n.sons[namePos].sym
|
||||||
# due to a bug/limitation in the lambda lifting, unused inner procs
|
# due to a bug/limitation in the lambda lifting, unused inner procs
|
||||||
# are not transformed correctly. We work around this issue (#411) here
|
# are not transformed correctly. We work around this issue (#411) here
|
||||||
# by ensuring it's no inner proc (owner is a module):
|
# by ensuring it's no inner proc (owner is a module):
|
||||||
#
|
if prc.skipGenericOwner.kind == skModule:
|
||||||
# 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 (optDeadCodeElim notin gGlobalOptions and
|
if (optDeadCodeElim notin gGlobalOptions and
|
||||||
sfDeadCodeElim notin getModule(prc).flags) or
|
sfDeadCodeElim notin getModule(prc).flags) or
|
||||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
||||||
|
|
||||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||||
info: TLineInfo) =
|
info: TLineInfo; orig: string) =
|
||||||
var id = "" # arg = "X]:on|off"
|
var id = "" # arg = "X]:on|off"
|
||||||
var i = 0
|
var i = 0
|
||||||
var n = hintMin
|
var n = hintMin
|
||||||
|
|
@ -149,17 +149,17 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||||
add(id, arg[i])
|
add(id, arg[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
if i < len(arg) and (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)
|
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
||||||
else: invalidCmdLineOption(pass, arg, info)
|
else: invalidCmdLineOption(pass, orig, info)
|
||||||
if state == wHint:
|
if state == wHint:
|
||||||
var x = findStr(msgs.HintsToStr, id)
|
var x = findStr(msgs.HintsToStr, id)
|
||||||
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
||||||
else: invalidCmdLineOption(pass, arg, info)
|
else: localError(info, "unknown hint: " & id)
|
||||||
else:
|
else:
|
||||||
var x = findStr(msgs.WarningsToStr, id)
|
var x = findStr(msgs.WarningsToStr, id)
|
||||||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
||||||
else: invalidCmdLineOption(pass, arg, info)
|
else: localError(info, "unknown warning: " & id)
|
||||||
case whichKeyword(substr(arg, i))
|
case whichKeyword(substr(arg, i))
|
||||||
of wOn: incl(gNotes, n)
|
of wOn: incl(gNotes, n)
|
||||||
of wOff: excl(gNotes, n)
|
of wOff: excl(gNotes, n)
|
||||||
|
|
@ -368,8 +368,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
defineSymbol("nogc")
|
defineSymbol("nogc")
|
||||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||||
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
|
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
|
||||||
of "warning": processSpecificNote(arg, wWarning, pass, info)
|
of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
|
||||||
of "hint": processSpecificNote(arg, wHint, pass, info)
|
of "hint": processSpecificNote(arg, wHint, pass, info, switch)
|
||||||
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
|
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
|
||||||
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
||||||
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
||||||
|
|
|
||||||
|
|
@ -380,7 +380,7 @@ proc setCC*(ccname: string) =
|
||||||
cCompiler = nameToCC(ccname)
|
cCompiler = nameToCC(ccname)
|
||||||
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
||||||
compileOptions = getConfigVar(cCompiler, ".options.always")
|
compileOptions = getConfigVar(cCompiler, ".options.always")
|
||||||
linkOptions = getConfigVar(cCompiler, ".options.linker")
|
linkOptions = ""
|
||||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||||
defineSymbol(CC[cCompiler].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, " ")
|
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
|
||||||
add(dest, src)
|
add(dest, src)
|
||||||
|
|
||||||
proc addLinkOption*(option: string) =
|
proc addLinkOption*(option: string) =
|
||||||
if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option)
|
addOpt(linkOptions, option)
|
||||||
|
|
||||||
proc addCompileOption*(option: string) =
|
proc addCompileOption*(option: string) =
|
||||||
if strutils.find(compileOptions, option, 0) < 0:
|
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)
|
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||||
defineSymbol(CC[cCompiler].name)
|
defineSymbol(CC[cCompiler].name)
|
||||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
||||||
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||||
if len(ccompilerpath) == 0:
|
if len(ccompilerpath) == 0:
|
||||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||||
|
|
||||||
|
|
@ -553,13 +553,13 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||||
cfile = quoteShell(cfile)
|
cfile = quoteShell(cfile)
|
||||||
result = quoteShell(compilePattern % [
|
result = quoteShell(compilePattern % [
|
||||||
"file", cfile, "objfile", objfile, "options", options,
|
"file", cfile, "objfile", objfile, "options", options,
|
||||||
"include", includeCmd, "nimrod", getPrefixDir(),
|
"include", includeCmd, "nim", getPrefixDir(),
|
||||||
"nim", getPrefixDir(), "lib", libpath])
|
"nim", getPrefixDir(), "lib", libpath])
|
||||||
add(result, ' ')
|
add(result, ' ')
|
||||||
addf(result, CC[c].compileTmpl, [
|
addf(result, CC[c].compileTmpl, [
|
||||||
"file", cfile, "objfile", objfile,
|
"file", cfile, "objfile", objfile,
|
||||||
"options", options, "include", includeCmd,
|
"options", options, "include", includeCmd,
|
||||||
"nimrod", quoteShell(getPrefixDir()),
|
"nim", quoteShell(getPrefixDir()),
|
||||||
"nim", quoteShell(getPrefixDir()),
|
"nim", quoteShell(getPrefixDir()),
|
||||||
"lib", quoteShell(libpath)])
|
"lib", quoteShell(libpath)])
|
||||||
|
|
||||||
|
|
@ -679,15 +679,16 @@ proc callCCompiler*(projectfile: string) =
|
||||||
if not exefile.isAbsolute():
|
if not exefile.isAbsolute():
|
||||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||||
exefile = quoteShell(exefile)
|
exefile = quoteShell(exefile)
|
||||||
let linkOptions = getLinkOptions()
|
let linkOptions = getLinkOptions() & " " &
|
||||||
|
getConfigVar(cCompiler, ".options.linker")
|
||||||
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
|
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
|
||||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||||
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
|
"exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
|
||||||
linkCmd.add ' '
|
linkCmd.add ' '
|
||||||
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
|
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
|
||||||
"buildgui", buildgui, "options", linkOptions,
|
"buildgui", buildgui, "options", linkOptions,
|
||||||
"objfiles", objfiles, "exefile", exefile,
|
"objfiles", objfiles, "exefile", exefile,
|
||||||
"nimrod", quoteShell(getPrefixDir()),
|
"nim", quoteShell(getPrefixDir()),
|
||||||
"lib", quoteShell(libpath)])
|
"lib", quoteShell(libpath)])
|
||||||
if optCompileOnly notin gGlobalOptions:
|
if optCompileOnly notin gGlobalOptions:
|
||||||
if gVerbosity == 1:
|
if gVerbosity == 1:
|
||||||
|
|
@ -716,7 +717,8 @@ proc writeMapping*(gSymbolMapping: PRope) =
|
||||||
app(code, strutils.escape(getCompileOptions()))
|
app(code, strutils.escape(getCompileOptions()))
|
||||||
|
|
||||||
app(code, "\n[Linker]\nFlags=")
|
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, "\n[Environment]\nlibpath=")
|
||||||
app(code, strutils.escape(libpath))
|
app(code, strutils.escape(libpath))
|
||||||
|
|
|
||||||
|
|
@ -735,11 +735,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
incl(sym.flags, sfProcvar)
|
incl(sym.flags, sfProcvar)
|
||||||
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
||||||
of wGcSafe:
|
of wGcSafe:
|
||||||
if optThreadAnalysis in gGlobalOptions:
|
noVal(it)
|
||||||
noVal(it)
|
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
else: invalidPragma(it)
|
||||||
else: invalidPragma(it)
|
|
||||||
of wPacked:
|
of wPacked:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
|
|
|
||||||
|
|
@ -686,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
# implicit statics.
|
# implicit statics.
|
||||||
if n.len > 1:
|
if n.len > 1:
|
||||||
for i in 1 .. <n.len:
|
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
|
break maybeLabelAsStatic
|
||||||
n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
|
n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
|
||||||
n.typ.flags.incl tfUnresolved
|
n.typ.flags.incl tfUnresolved
|
||||||
|
|
@ -1337,7 +1339,12 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
if c.p.owner.kind notin {skMacro, skTemplate} and
|
if c.p.owner.kind notin {skMacro, skTemplate} and
|
||||||
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
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)
|
closeScope(c)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,9 @@ proc warnAboutGcUnsafe(n: PNode) =
|
||||||
#assert false
|
#assert false
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
|
|
||||||
|
template markGcUnsafe(a: PEffects) =
|
||||||
|
a.gcUnsafe = true
|
||||||
|
|
||||||
proc useVar(a: PEffects, n: PNode) =
|
proc useVar(a: PEffects, n: PNode) =
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
if isLocalVar(a, s):
|
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
|
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
||||||
tfGcSafe notin s.typ.flags:
|
tfGcSafe notin s.typ.flags:
|
||||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
a.gcUnsafe = true
|
markGcUnsafe(a)
|
||||||
|
|
||||||
type
|
type
|
||||||
TIntersection = seq[tuple[id, count: int]] # a simple count table
|
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 notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
markGcUnsafe(tracked)
|
||||||
mergeLockLevels(tracked, n, s.getLockLevel)
|
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||||
|
|
||||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
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:
|
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||||
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
markGcUnsafe(tracked)
|
||||||
else:
|
else:
|
||||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||||
if notGcSafe(op):
|
if notGcSafe(op):
|
||||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
markGcUnsafe(tracked)
|
||||||
notNilCheck(tracked, n, paramType)
|
notNilCheck(tracked, n, paramType)
|
||||||
|
|
||||||
proc breaksBlock(n: PNode): bool =
|
proc breaksBlock(n: PNode): bool =
|
||||||
|
|
@ -656,7 +659,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
# and it's not a recursive call:
|
# and it's not a recursive call:
|
||||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||||
warnAboutGcUnsafe(n)
|
warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
markGcUnsafe(tracked)
|
||||||
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
|
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}:
|
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||||
# may not look like an assignment, but it is:
|
# may not look like an assignment, but it is:
|
||||||
|
|
@ -825,7 +828,7 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
# effects already computed?
|
# effects already computed?
|
||||||
if sfForward in s.flags: return
|
if sfForward in s.flags: return
|
||||||
if effects.len == effectListLen: return
|
if effects.len == effectListLen: return
|
||||||
|
|
||||||
var t: TEffects
|
var t: TEffects
|
||||||
initEffects(effects, s, t)
|
initEffects(effects, s, t)
|
||||||
track(t, body)
|
track(t, body)
|
||||||
|
|
@ -849,19 +852,20 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
# after the check, use the formal spec:
|
# after the check, use the formal spec:
|
||||||
effects.sons[tagEffects] = tagsSpec
|
effects.sons[tagEffects] = tagsSpec
|
||||||
|
|
||||||
if optThreadAnalysis in gGlobalOptions:
|
if sfThread in s.flags and t.gcUnsafe:
|
||||||
if sfThread in s.flags and t.gcUnsafe:
|
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
|
||||||
if optThreads in gGlobalOptions:
|
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
else:
|
||||||
else:
|
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
if not t.gcUnsafe:
|
||||||
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
s.typ.flags.incl tfGcSafe
|
||||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||||
s.typ.lockLevel = t.maxLockLevel
|
s.typ.lockLevel = t.maxLockLevel
|
||||||
elif t.maxLockLevel > s.typ.lockLevel:
|
elif t.maxLockLevel > s.typ.lockLevel:
|
||||||
localError(s.info,
|
#localError(s.info,
|
||||||
"declared lock level is $1, but real lock level is $2" %
|
message(s.info, warnLockLevel,
|
||||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
"declared lock level is $1, but real lock level is $2" %
|
||||||
|
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||||
|
|
||||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
||||||
|
|
|
||||||
|
|
@ -418,7 +418,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
|
|
||||||
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
|
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
|
||||||
return isNone
|
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``!
|
# noSideEffect implies ``tfThread``!
|
||||||
return isNone
|
return isNone
|
||||||
elif f.flags * {tfIterator} != a.flags * {tfIterator}:
|
elif f.flags * {tfIterator} != a.flags * {tfIterator}:
|
||||||
|
|
@ -1441,13 +1442,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
return
|
return
|
||||||
checkConstraint(n.sons[a].sons[1])
|
checkConstraint(n.sons[a].sons[1])
|
||||||
if m.baseTypeMatch:
|
if m.baseTypeMatch:
|
||||||
assert(container == nil)
|
#assert(container == nil)
|
||||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||||
addSon(container, arg)
|
addSon(container, arg)
|
||||||
setSon(m.call, formal.position + 1, container)
|
setSon(m.call, formal.position + 1, container)
|
||||||
if f != formalLen - 1: container = nil
|
if f != formalLen - 1: container = nil
|
||||||
else:
|
else:
|
||||||
setSon(m.call, formal.position + 1, arg)
|
setSon(m.call, formal.position + 1, arg)
|
||||||
|
inc f
|
||||||
else:
|
else:
|
||||||
# unnamed param
|
# unnamed param
|
||||||
if f >= formalLen:
|
if f >= formalLen:
|
||||||
|
|
@ -1466,7 +1468,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||||
n.sons[a], nOrig.sons[a])
|
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)
|
addSon(container, arg)
|
||||||
incrIndexType(container.typ)
|
incrIndexType(container.typ)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1480,7 +1482,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
internalError(n.sons[a].info, "matches")
|
internalError(n.sons[a].info, "matches")
|
||||||
return
|
return
|
||||||
formal = m.callee.n.sons[f].sym
|
formal = m.callee.n.sons[f].sym
|
||||||
if containsOrIncl(marker, formal.position):
|
if containsOrIncl(marker, formal.position) and container.isNil:
|
||||||
# already in namedParams:
|
# already in namedParams:
|
||||||
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
|
|
@ -1493,17 +1495,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
if m.baseTypeMatch:
|
if m.baseTypeMatch:
|
||||||
assert(container == nil)
|
#assert(container == nil)
|
||||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
if container.isNil:
|
||||||
|
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||||
addSon(container, arg)
|
addSon(container, arg)
|
||||||
setSon(m.call, formal.position + 1,
|
setSon(m.call, formal.position + 1,
|
||||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
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:
|
else:
|
||||||
setSon(m.call, formal.position + 1, arg)
|
setSon(m.call, formal.position + 1, arg)
|
||||||
|
inc(f)
|
||||||
|
container = nil
|
||||||
checkConstraint(n.sons[a])
|
checkConstraint(n.sons[a])
|
||||||
inc(a)
|
inc(a)
|
||||||
inc(f)
|
|
||||||
|
|
||||||
proc semFinishOperands*(c: PContext, n: PNode) =
|
proc semFinishOperands*(c: PContext, n: PNode) =
|
||||||
# this needs to be called to ensure that after overloading resolution every
|
# this needs to be called to ensure that after overloading resolution every
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,12 @@
|
||||||
|
|
||||||
cc = gcc
|
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:
|
# example of how to setup a cross-compiler:
|
||||||
arm.linux.gcc.exe = "arm-linux-gcc"
|
arm.linux.gcc.exe = "arm-linux-gcc"
|
||||||
arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
||||||
|
|
@ -66,12 +72,6 @@ path="$lib/pure/unidecode"
|
||||||
opt:speed
|
opt:speed
|
||||||
@end
|
@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 unix:
|
||||||
@if not bsd:
|
@if not bsd:
|
||||||
# -fopenmp
|
# -fopenmp
|
||||||
|
|
|
||||||
941
doc/nimc.txt
941
doc/nimc.txt
File diff suppressed because it is too large
Load diff
|
|
@ -136,12 +136,12 @@ proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
|
||||||
## returns the number of children of `n`.
|
## returns the number of children of `n`.
|
||||||
|
|
||||||
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
|
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
|
||||||
noSideEffect.}
|
noSideEffect, locks: 0.}
|
||||||
## Adds the `child` to the `father` node. Returns the
|
## Adds the `child` to the `father` node. Returns the
|
||||||
## father node so that calls can be nested.
|
## father node so that calls can be nested.
|
||||||
|
|
||||||
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
|
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.
|
## Adds each child of `children` to the `father` node.
|
||||||
## Returns the `father` node so that calls can be nested.
|
## 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 copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
|
||||||
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", 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
|
## 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
|
## 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
|
## writes a hint message at compile time
|
||||||
|
|
||||||
proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
|
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
|
## generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||||
## needs to occur in a declaration context.
|
## 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.
|
## returns the AST of the invocation expression that invoked this macro.
|
||||||
|
|
||||||
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
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.
|
# This could easily user code and so should be fixed in evals.nim somehow.
|
||||||
result = newCall(theProc, x[i], copyNimTree(result))
|
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.
|
## Convert the AST `n` to a human-readable tree-like string.
|
||||||
##
|
##
|
||||||
## See also `repr` and `lispRepr`.
|
## 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 " "
|
for i in 0..level-1: res.add " "
|
||||||
res.add(($n.kind).substr(3))
|
res.add(($n.kind).substr(3))
|
||||||
|
|
||||||
|
|
@ -412,7 +412,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||||
result = ""
|
result = ""
|
||||||
traverse(result, 0, n)
|
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,
|
## Convert the AST `n` to a human-readable lisp-like string,
|
||||||
##
|
##
|
||||||
## See also `repr` and `treeRepr`.
|
## See also `repr` and `treeRepr`.
|
||||||
|
|
@ -651,7 +651,7 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
|
||||||
else:
|
else:
|
||||||
badNodeKind someProc.kind, "body="
|
badNodeKind someProc.kind, "body="
|
||||||
|
|
||||||
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.}
|
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime, benign.}
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(node: PNimrodNode): string {.compileTime.} =
|
proc `$`*(node: PNimrodNode): string {.compileTime.} =
|
||||||
|
|
|
||||||
|
|
@ -33,14 +33,16 @@ when defined(Windows):
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
result = readLine(stdin, line)
|
result = readLine(stdin, line)
|
||||||
|
|
||||||
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
|
## 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".}
|
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||||
|
|
||||||
password.setLen(0)
|
password.setLen(0)
|
||||||
var c: char
|
var c: char
|
||||||
echo prompt
|
stdout.write(prompt)
|
||||||
while true:
|
while true:
|
||||||
c = getch().char
|
c = getch().char
|
||||||
case c
|
case c
|
||||||
|
|
@ -50,6 +52,8 @@ when defined(Windows):
|
||||||
password.setLen(password.len - 1)
|
password.setLen(password.len - 1)
|
||||||
else:
|
else:
|
||||||
password.add(c)
|
password.add(c)
|
||||||
|
stdout.write "\n"
|
||||||
|
# TODO: How to detect EOF on Windows?
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import readline, history, termios, unsigned
|
import readline, history, termios, unsigned
|
||||||
|
|
@ -80,7 +84,8 @@ else:
|
||||||
|
|
||||||
discard readline.bind_key('\t'.ord, doNothing)
|
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)
|
password.setLen(0)
|
||||||
let fd = stdin.getFileHandle()
|
let fd = stdin.getFileHandle()
|
||||||
var cur, old: Termios
|
var cur, old: Termios
|
||||||
|
|
@ -89,10 +94,11 @@ else:
|
||||||
cur.lflag = cur.lflag and not Tcflag(ECHO)
|
cur.lflag = cur.lflag and not Tcflag(ECHO)
|
||||||
discard fd.tcsetattr(TCSADRAIN, cur.addr)
|
discard fd.tcsetattr(TCSADRAIN, cur.addr)
|
||||||
stdout.write prompt
|
stdout.write prompt
|
||||||
discard stdin.readLine(password)
|
result = stdin.readLine(password)
|
||||||
|
stdout.write "\n"
|
||||||
discard fd.tcsetattr(TCSADRAIN, old.addr)
|
discard fd.tcsetattr(TCSADRAIN, old.addr)
|
||||||
|
|
||||||
proc readPasswordFromStdin*(prompt: string): TaintedString =
|
proc readPasswordFromStdin*(prompt: string): TaintedString =
|
||||||
## Reads a password from stdin without printing it.
|
## Reads a password from stdin without printing it.
|
||||||
result = TaintedString("")
|
result = TaintedString("")
|
||||||
readPasswordFromStdin(prompt, result)
|
discard readPasswordFromStdin(prompt, result)
|
||||||
|
|
|
||||||
|
|
@ -70,17 +70,10 @@ const
|
||||||
STDIN_FILENO* = 0 ## File number of stdin;
|
STDIN_FILENO* = 0 ## File number of stdin;
|
||||||
STDOUT_FILENO* = 1 ## File number of stdout;
|
STDOUT_FILENO* = 1 ## File number of stdout;
|
||||||
|
|
||||||
when defined(endb):
|
type
|
||||||
# to not break bootstrapping again ...
|
TDIR* {.importc: "DIR", header: "<dirent.h>",
|
||||||
type
|
incompleteStruct.} = object
|
||||||
TDIR* {.importc: "DIR", header: "<dirent.h>",
|
## A type representing a directory stream.
|
||||||
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
|
type
|
||||||
SocketHandle* = distinct cint # The type used to represent socket descriptors
|
SocketHandle* = distinct cint # The type used to represent socket descriptors
|
||||||
|
|
|
||||||
|
|
@ -415,7 +415,7 @@ proc `$`*[A, B](t: TableRef[A, B]): string =
|
||||||
proc `==`*[A, B](s, t: TableRef[A, B]): bool =
|
proc `==`*[A, B](s, t: TableRef[A, B]): bool =
|
||||||
if isNil(s): result = isNil(t)
|
if isNil(s): result = isNil(t)
|
||||||
elif isNil(t): result = false
|
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] =
|
proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
|
||||||
## Index the collection with the proc provided.
|
## Index the collection with the proc provided.
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,9 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
|
||||||
result = x - 1
|
result = x - 1
|
||||||
when defined(cpu64):
|
when defined(cpu64):
|
||||||
result = result or (result shr 32)
|
result = result or (result shr 32)
|
||||||
when sizeof(int) > 16:
|
when sizeof(int) > 2:
|
||||||
result = result or (result shr 16)
|
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 8)
|
||||||
result = result or (result shr 4)
|
result = result or (result shr 4)
|
||||||
result = result or (result shr 2)
|
result = result or (result shr 2)
|
||||||
|
|
@ -129,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
|
||||||
result = result + diff*diff
|
result = result + diff*diff
|
||||||
result = result / toFloat(len(x))
|
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
|
## returns a random number in the range 0..max-1. The sequence of
|
||||||
## random number is always the same, unless `randomize` is called
|
## random number is always the same, unless `randomize` is called
|
||||||
## which initializes the random number generator with a "random"
|
## which initializes the random number generator with a "random"
|
||||||
## number, i.e. a tickcount.
|
## 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
|
## returns a random number in the range 0..<max. The sequence of
|
||||||
## random number is always the same, unless `randomize` is called
|
## random number is always the same, unless `randomize` is called
|
||||||
## which initializes the random number generator with a "random"
|
## which initializes the random number generator with a "random"
|
||||||
## number, i.e. a tickcount. This has a 16-bit resolution on windows
|
## number, i.e. a tickcount. This has a 16-bit resolution on windows
|
||||||
## and a 48-bit resolution on other platforms.
|
## and a 48-bit resolution on other platforms.
|
||||||
|
|
||||||
proc randomize*() {.gcsafe.}
|
proc randomize*() {.benign.}
|
||||||
## initializes the random number generator with a "random"
|
## initializes the random number generator with a "random"
|
||||||
## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
|
## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
|
||||||
## as JavaScript does not support this.
|
## 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.
|
## initializes the random number generator with a specific seed.
|
||||||
## Note: Does nothing for the JavaScript target,
|
## Note: Does nothing for the JavaScript target,
|
||||||
## as JavaScript does not support this.
|
## as JavaScript does not support this.
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
|
|
||||||
proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
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
|
## 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
|
## is made sets ``client`` to the client socket and ``address`` to the address
|
||||||
## of the connecting client.
|
## of the connecting client.
|
||||||
|
|
@ -938,8 +939,12 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
|
||||||
doAssert socket.handshake()
|
doAssert socket.handshake()
|
||||||
socket.fd.setBlocking(true)
|
socket.fd.setBlocking(true)
|
||||||
|
|
||||||
proc isSsl*(socket: Socket): bool = return socket.isSSL
|
proc isSsl*(socket: Socket): bool =
|
||||||
## Determines whether ``socket`` is a SSL socket.
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
|
when defined(ssl):
|
||||||
|
result = socket.isSSL
|
||||||
|
else:
|
||||||
|
result = false
|
||||||
|
|
||||||
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||||
## Returns the socket's file descriptor
|
## 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",
|
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
|
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
|
||||||
if c_rename(source, dest) != 0'i32:
|
when defined(Windows):
|
||||||
raise newException(OSError, $strerror(errno))
|
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 not declared(ENOENT) and not defined(Windows):
|
||||||
when NoFakeVars:
|
when NoFakeVars:
|
||||||
|
|
@ -1339,7 +1347,7 @@ proc rawRemoveDir(dir: string) =
|
||||||
if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
|
if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
|
||||||
|
|
||||||
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||||
WriteDirEffect, ReadDirEffect].} =
|
WriteDirEffect, ReadDirEffect], benign.} =
|
||||||
## Removes the directory `dir` including all subdirectories and files
|
## Removes the directory `dir` including all subdirectories and files
|
||||||
## in `dir` (recursively).
|
## in `dir` (recursively).
|
||||||
##
|
##
|
||||||
|
|
@ -1385,7 +1393,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
|
||||||
rawCreateDir(dir)
|
rawCreateDir(dir)
|
||||||
|
|
||||||
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
|
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
tags: [WriteIOEffect, ReadIOEffect].} =
|
tags: [WriteIOEffect, ReadIOEffect], benign.} =
|
||||||
## Copies a directory from `source` to `dest`.
|
## Copies a directory from `source` to `dest`.
|
||||||
##
|
##
|
||||||
## If this fails, `OSError` is raised. On the Windows platform this proc will
|
## 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,
|
proc copyDirWithPermissions*(source, dest: string,
|
||||||
ignorePermissionErrors = true) {.rtl, extern: "nos$1",
|
ignorePermissionErrors = true) {.rtl, extern: "nos$1",
|
||||||
tags: [WriteIOEffect, ReadIOEffect].} =
|
tags: [WriteIOEffect, ReadIOEffect], benign.} =
|
||||||
## Copies a directory from `source` to `dest` preserving file permissions.
|
## Copies a directory from `source` to `dest` preserving file permissions.
|
||||||
##
|
##
|
||||||
## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()
|
## 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
|
sock: Socket
|
||||||
|
|
||||||
var sock = socket()
|
var sock = socket()
|
||||||
if sock == sockets.InvalidSocket: raiseOSError(osLastError())
|
if sock == sockets.invalidSocket: raiseOSError(osLastError())
|
||||||
#sock.setBlocking(false)
|
#sock.setBlocking(false)
|
||||||
sock.connect("irc.freenode.net", Port(6667))
|
sock.connect("irc.freenode.net", Port(6667))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
# of the standard library!
|
# of the standard library!
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils
|
strutils, parseutils
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
||||||
|
|
@ -63,44 +63,44 @@ elif defined(windows):
|
||||||
elif defined(JS):
|
elif defined(JS):
|
||||||
type
|
type
|
||||||
Time* {.importc.} = object
|
Time* {.importc.} = object
|
||||||
getDay: proc (): int {.tags: [], raises: [], gcsafe.}
|
getDay: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
|
getFullYear: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getHours: proc (): int {.tags: [], raises: [], gcsafe.}
|
getHours: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
|
getMinutes: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getMonth: proc (): int {.tags: [], raises: [], gcsafe.}
|
getMonth: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
getSeconds: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getTime: proc (): int {.tags: [], raises: [], gcsafe.}
|
getTime: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getTimezoneOffset: proc (): int {.tags: [], raises: [], gcsafe.}
|
getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getDate: proc (): int {.tags: [], raises: [], gcsafe.}
|
getDate: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCDate: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCDate: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCHours: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCHours: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCMonth: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.}
|
getUTCDay: proc (): int {.tags: [], raises: [], benign.}
|
||||||
getYear: proc (): int {.tags: [], raises: [], gcsafe.}
|
getYear: proc (): int {.tags: [], raises: [], benign.}
|
||||||
parse: proc (s: cstring): Time {.tags: [], raises: [], gcsafe.}
|
parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
|
||||||
setDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setDate: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setHours: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setMonth: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setTime: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setTime: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setUTCSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
setYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
setYear: proc (x: int) {.tags: [], raises: [], benign.}
|
||||||
toGMTString: proc (): cstring {.tags: [], raises: [], gcsafe.}
|
toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
|
||||||
toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.}
|
toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TimeInfo* = object of RootObj ## represents a time in different parts
|
TimeInfo* = object of RootObj ## represents a time in different parts
|
||||||
|
|
@ -139,42 +139,42 @@ type
|
||||||
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
|
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
|
||||||
TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
|
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
|
## gets the current calendar time as a UNIX epoch value (number of seconds
|
||||||
## elapsed since 1970) with integer precission. Use epochTime for higher
|
## elapsed since 1970) with integer precission. Use epochTime for higher
|
||||||
## resolution.
|
## 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,
|
## converts the calendar time `t` to broken-time representation,
|
||||||
## expressed relative to the user's specified time zone.
|
## 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,
|
## converts the calendar time `t` to broken-down time representation,
|
||||||
## expressed in Coordinated Universal Time (UTC).
|
## 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
|
## converts a broken-down time structure to
|
||||||
## calendar time representation. The function ignores the specified
|
## calendar time representation. The function ignores the specified
|
||||||
## contents of the structure members `weekday` and `yearday` and recomputes
|
## contents of the structure members `weekday` and `yearday` and recomputes
|
||||||
## them from the other information in the broken-down time structure.
|
## 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
|
## Takes a float which contains the number of seconds since the unix epoch and
|
||||||
## returns a time object.
|
## 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
|
## Takes an int which contains the number of seconds since the unix epoch and
|
||||||
## returns a time object.
|
## returns a time object.
|
||||||
fromSeconds(float(since1970))
|
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.
|
## 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.
|
## 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.
|
## converts a calendar time to a string representation.
|
||||||
|
|
||||||
proc `-`*(a, b: Time): int64 {.
|
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.
|
## computes the difference of two calendar times. Result is in seconds.
|
||||||
|
|
||||||
proc `<`*(a, b: Time): bool {.
|
proc `<`*(a, b: Time): bool {.
|
||||||
|
|
@ -194,14 +194,14 @@ proc `==`*(a, b: Time): bool {.
|
||||||
|
|
||||||
when not defined(JS):
|
when not defined(JS):
|
||||||
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
|
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
|
||||||
gcsafe.}
|
benign.}
|
||||||
## returns the local timezone; ``nonDST`` is the name of the local non-DST
|
## returns the local timezone; ``nonDST`` is the name of the local non-DST
|
||||||
## timezone, ``DST`` is the name of the local DST timezone.
|
## 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.
|
## 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
|
## get the miliseconds from the start of the program. **Deprecated since
|
||||||
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
|
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
|
||||||
|
|
||||||
|
|
@ -744,6 +744,285 @@ proc format*(info: TimeInfo, f: string): string =
|
||||||
|
|
||||||
{.pop.}
|
{.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:
|
when isMainModule:
|
||||||
# $ date --date='@2147483647'
|
# $ date --date='@2147483647'
|
||||||
# Tue 19 Jan 03:14:07 GMT 2038
|
# Tue 19 Jan 03:14:07 GMT 2038
|
||||||
|
|
@ -778,3 +1057,51 @@ when isMainModule:
|
||||||
# Interval tests
|
# Interval tests
|
||||||
assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
|
assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
|
||||||
assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
|
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
|
## returns an informative string about the GC's activity. This may be useful
|
||||||
## for tweaking.
|
## for tweaking.
|
||||||
|
|
||||||
# XXX mark these as 'locks: 0' once 0.10.0 has been released
|
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.}
|
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.}
|
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*(x: string) {.magic: "GCref", gcsafe.}
|
|
||||||
## marks the object `x` as referenced, so that it will not be freed until
|
## 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`,
|
## 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`.
|
## 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: ref T) {.magic: "GCunref", benign.}
|
||||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.}
|
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
||||||
proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.}
|
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||||
## see the documentation of `GC_ref`.
|
## see the documentation of `GC_ref`.
|
||||||
|
|
||||||
template accumulateResult*(iter: expr) =
|
template accumulateResult*(iter: expr) =
|
||||||
|
|
@ -2248,14 +2247,9 @@ when not declared(sysFatal):
|
||||||
e.msg = message & arg
|
e.msg = message & arg
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
when defined(nimlocks):
|
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
|
||||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.}
|
## get type information for `x`. Ordinary code should not use this, but
|
||||||
## get type information for `x`. Ordinary code should not use this, but
|
## the `typeinfo` module instead.
|
||||||
## 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.
|
|
||||||
|
|
||||||
{.push stackTrace: off.}
|
{.push stackTrace: off.}
|
||||||
proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
|
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``
|
## Returns ``false`` if the end of the file has been reached, ``true``
|
||||||
## otherwise. If ``false`` is returned `line` contains no new data.
|
## otherwise. If ``false`` is returned `line` contains no new data.
|
||||||
|
|
||||||
when not defined(booting):
|
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
tags: [WriteIOEffect], benign.}
|
||||||
tags: [WriteIOEffect], gcsafe, locks: 0.}
|
## writes the values `x` to `f` and then writes "\n".
|
||||||
## writes the values `x` to `f` and then writes "\n".
|
## May throw an IO exception.
|
||||||
## May throw an IO exception.
|
|
||||||
else:
|
|
||||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
|
||||||
tags: [WriteIOEffect].}
|
|
||||||
|
|
||||||
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
|
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
|
||||||
## retrieves the file size (in bytes) of `f`.
|
## retrieves the file size (in bytes) of `f`.
|
||||||
|
|
@ -2576,7 +2566,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
initAllocator()
|
initAllocator()
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
include "system/syslocks"
|
include "system/syslocks"
|
||||||
include "system/threads"
|
when hostOS != "standalone": include "system/threads"
|
||||||
elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
|
elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
|
||||||
when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
|
when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
|
||||||
initGC()
|
initGC()
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||||
type
|
type
|
||||||
PByteArray = ptr array[0.. 0xffff, int8]
|
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
|
case typ.kind
|
||||||
of tyEnum: add result, reprEnum(elem, typ)
|
of tyEnum: add result, reprEnum(elem, typ)
|
||||||
of tyBool: add result, reprBool(bool(elem))
|
of tyBool: add result, reprBool(bool(elem))
|
||||||
|
|
@ -147,7 +147,7 @@ when not defined(useNimRtl):
|
||||||
for i in 0..cl.indent-1: add result, ' '
|
for i in 0..cl.indent-1: add result, ' '
|
||||||
|
|
||||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
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,
|
proc reprArray(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) =
|
cl: var TReprClosure) =
|
||||||
|
|
@ -172,7 +172,7 @@ when not defined(useNimRtl):
|
||||||
add result, "]"
|
add result, "]"
|
||||||
|
|
||||||
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
||||||
cl: var TReprClosure) {.gcsafe.} =
|
cl: var TReprClosure) {.benign.} =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkNone: sysAssert(false, "reprRecordAux")
|
of nkNone: sysAssert(false, "reprRecordAux")
|
||||||
of nkSlot:
|
of nkSlot:
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,10 @@ when useWinUnicode:
|
||||||
bFailIfExists: cint): cint {.
|
bFailIfExists: cint): cint {.
|
||||||
importc: "CopyFileW", stdcall, dynlib: "kernel32".}
|
importc: "CopyFileW", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
|
proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString,
|
||||||
|
bFailIfExists: cint): cint {.
|
||||||
|
importc: "MoveFileW", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
proc getEnvironmentStringsW*(): WideCString {.
|
proc getEnvironmentStringsW*(): WideCString {.
|
||||||
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
|
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
|
||||||
proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
|
proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
|
||||||
|
|
@ -308,6 +312,10 @@ else:
|
||||||
bFailIfExists: cint): cint {.
|
bFailIfExists: cint): cint {.
|
||||||
importc: "CopyFileA", stdcall, dynlib: "kernel32".}
|
importc: "CopyFileA", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
|
proc moveFileA*(lpExistingFileName, lpNewFileName: cstring,
|
||||||
|
bFailIfExists: cint): cint {.
|
||||||
|
importc: "MoveFileA", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
proc getEnvironmentStringsA*(): cstring {.
|
proc getEnvironmentStringsA*(): cstring {.
|
||||||
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
|
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
|
||||||
proc freeEnvironmentStringsA*(para1: cstring): int32 {.
|
proc freeEnvironmentStringsA*(para1: cstring): int32 {.
|
||||||
|
|
|
||||||
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]()
|
const
|
||||||
tbl1.add(1,1)
|
data = {
|
||||||
tbl1.add(2,2)
|
"34": 123456, "12": 789,
|
||||||
doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
|
"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
|
sorteddata = {
|
||||||
TElem = object
|
"---00": 346677844,
|
||||||
foo: int
|
"0": 34404,
|
||||||
bar: string
|
"1": 344004,
|
||||||
|
"10": 34484,
|
||||||
let
|
"11": 34474,
|
||||||
elem1 = TElem(foo: 1, bar: "bar")
|
"12": 789,
|
||||||
elem2 = TElem(foo: 2, bar: "baz")
|
"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]()
|
t["012"] = 67.9
|
||||||
tbl2.add("bar", elem1)
|
t["123"] = 1.5 # test overwriting
|
||||||
tbl2.add("baz", elem2)
|
|
||||||
doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
|
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:
|
block countTableTest1:
|
||||||
var s = data.toTable
|
var s = data.toTable
|
||||||
var t = newCountTable[string]()
|
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
|
for k in t.keys: assert t[k] == 1
|
||||||
t.inc("90", 3)
|
t.inc("90", 3)
|
||||||
t.inc("12", 2)
|
t.inc("12", 2)
|
||||||
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,7 +11,7 @@ fpqeew
|
||||||
[11, 12, 13]
|
[11, 12, 13]
|
||||||
[11, 12, 13]
|
[11, 12, 13]
|
||||||
[11, 12, 13]
|
[11, 12, 13]
|
||||||
{ "key1": 11, "key2": 12, "key3": 13}
|
{"key1": 11, "key2": 12, "key3": 13}
|
||||||
[11, 12, 13]
|
[11, 12, 13]
|
||||||
<Students>
|
<Students>
|
||||||
<Student Name="Aprilfoo" />
|
<Student Name="Aprilfoo" />
|
||||||
|
|
|
||||||
|
|
@ -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: 1): 01, (x: 0, y: 0): 00, (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"
|
|
||||||
|
|
||||||
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))
|
||||||
|
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -1,9 +1,10 @@
|
||||||
version 0.10.4
|
version 0.10.4
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- make 'nil' work for 'add' and 'len'
|
|
||||||
- improve GC-unsafety warnings
|
- improve GC-unsafety warnings
|
||||||
|
- make 'nil' work for 'add' and 'len'
|
||||||
- get rid of 'mget'; aka priority of 'var' needs to be 'var{lvalue}'
|
- get rid of 'mget'; aka priority of 'var' needs to be 'var{lvalue}'
|
||||||
|
- 'result' shadowing warning
|
||||||
|
|
||||||
|
|
||||||
version 1.0
|
version 1.0
|
||||||
|
|
@ -41,7 +42,6 @@ Misc
|
||||||
- make tuple unpacking work in a non-var/let context
|
- make tuple unpacking work in a non-var/let context
|
||||||
- built-in 'getImpl'
|
- built-in 'getImpl'
|
||||||
- prevent 'alloc(TypeWithGCedMemory)'
|
- prevent 'alloc(TypeWithGCedMemory)'
|
||||||
- some table related tests are wrong (memory usage checks)
|
|
||||||
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
|
|
|
||||||
12
web/news.txt
12
web/news.txt
|
|
@ -43,6 +43,18 @@ News
|
||||||
foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
|
foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
|
||||||
|
|
||||||
|
|
||||||
|
- Ordinary parameters can follow after a varargs parameter. This means the
|
||||||
|
following is finally accepted by the compiler:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
|
||||||
|
blck
|
||||||
|
echo a, b
|
||||||
|
|
||||||
|
takesBlock 1, 2, "some", 0.90, "random stuff":
|
||||||
|
echo "yay"
|
||||||
|
|
||||||
|
|
||||||
2014-12-29 Version 0.10.2 released
|
2014-12-29 Version 0.10.2 released
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue