mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 01:44:37 +00:00
Merge branch 'master' of github.com:Araq/Nimrod into upstream
This commit is contained in:
@@ -227,9 +227,6 @@ type
|
||||
sfInnerProc, # proc is an inner proc
|
||||
sfThread, # proc will run as a thread
|
||||
# variable is a thread variable
|
||||
sfInline # forced-inline procs
|
||||
sfImmediate, # macro or template is immediately expanded without
|
||||
# considering any possible overloads
|
||||
sfCompileTime, # proc can be evaluated at compile time
|
||||
sfMerge, # proc can be merged with itself
|
||||
sfDeadCodeElim, # dead code elimination for the module is turned on
|
||||
@@ -246,6 +243,8 @@ const
|
||||
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
|
||||
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
||||
sfNoInit* = sfMainModule # don't generate code to init the variable
|
||||
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
|
||||
# without considering any possible overloads
|
||||
|
||||
type
|
||||
TTypeKind* = enum # order is important!
|
||||
|
||||
@@ -146,6 +146,14 @@ proc IITablePut*(t: var TIITable, key, val: int)
|
||||
|
||||
# implementation
|
||||
|
||||
proc skipConv*(n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
result = n.sons[0]
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = n.sons[1]
|
||||
else: result = n
|
||||
|
||||
proc SameValue*(a, b: PNode): bool =
|
||||
result = false
|
||||
case a.kind
|
||||
|
||||
@@ -139,9 +139,9 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
case n.sym.kind
|
||||
of skParam, skForVar, skTemp:
|
||||
of skParam, skTemp:
|
||||
result = OnStack
|
||||
of skVar, skResult, skLet:
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in n.sym.flags: result = OnHeap
|
||||
else: result = OnStack
|
||||
of skConst:
|
||||
@@ -1652,7 +1652,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
|
||||
genComplexConst(p, sym, d)
|
||||
of skEnumField:
|
||||
putIntoDest(p, d, e.typ, toRope(sym.position))
|
||||
of skVar, skResult, skLet:
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
InternalError(e.info, "expr: var not init " & sym.name.s)
|
||||
@@ -1664,7 +1664,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
else:
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skForVar, skTemp:
|
||||
of skTemp:
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
InternalError(e.info, "expr: temp not init " & sym.name.s)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
|
||||
@@ -23,7 +23,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
for i in countup(0, L-3):
|
||||
var v = n.sons[i].sym
|
||||
if sfCompileTime in v.flags: continue
|
||||
if sfGlobal in v.flags and v.kind != skForVar:
|
||||
if sfGlobal in v.flags:
|
||||
assignGlobalVar(p, v)
|
||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
||||
else:
|
||||
@@ -49,7 +49,7 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if sfCompileTime in v.flags: return
|
||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
||||
if sfGlobal in v.flags and v.kind != skForVar:
|
||||
if sfGlobal in v.flags:
|
||||
assignGlobalVar(p, v)
|
||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
||||
else:
|
||||
@@ -725,7 +725,10 @@ proc genStmts(p: BProc, t: PNode) =
|
||||
genLineDir(p, t)
|
||||
initLocExpr(p, t, a)
|
||||
of nkAsgn: genAsgn(p, t, fastAsgn=false)
|
||||
of nkFastAsgn: genAsgn(p, t, fastAsgn=true)
|
||||
of nkFastAsgn:
|
||||
# transf is overly aggressive with 'nkFastAsgn', so we work around here.
|
||||
# See tests/run/tcnstseq3 for an example that would fail otherwise.
|
||||
genAsgn(p, t, fastAsgn=p.prc != nil)
|
||||
of nkDiscardStmt:
|
||||
genLineDir(p, t)
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
|
||||
@@ -70,6 +70,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
genTraverseProc(c, accessor.parentObj, typ.sons[i])
|
||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
||||
of tyTuple:
|
||||
let typ = GetUniqueType(typ)
|
||||
if typ.n != nil:
|
||||
genTraverseProc(c, accessor, typ.n)
|
||||
else:
|
||||
@@ -110,7 +111,11 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
|
||||
if typ.kind == tySequence:
|
||||
genTraverseProcSeq(c, "a".toRope, typ)
|
||||
else:
|
||||
genTraverseProc(c, "(*a)".toRope, typ.sons[0])
|
||||
if skipTypes(typ.sons[0], abstractInst).kind in {tyArrayConstr, tyArray}:
|
||||
# C's arrays are broken beyond repair:
|
||||
genTraverseProc(c, "a".toRope, typ.sons[0])
|
||||
else:
|
||||
genTraverseProc(c, "(*a)".toRope, typ.sons[0])
|
||||
|
||||
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
||||
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
|
||||
|
||||
@@ -39,10 +39,10 @@ proc mangleName(s: PSym): PRope =
|
||||
case s.kind
|
||||
of skProc, skMethod, skConverter, skConst:
|
||||
result = toRope("@")
|
||||
of skVar, skResult, skLet:
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in s.flags: result = toRope("@")
|
||||
else: result = toRope("%")
|
||||
of skForVar, skTemp, skParam, skType, skEnumField, skModule:
|
||||
of skTemp, skParam, skType, skEnumField, skModule:
|
||||
result = toRope("%")
|
||||
else: InternalError(s.info, "mangleName")
|
||||
app(result, toRope(mangle(s.name.s)))
|
||||
|
||||
@@ -779,6 +779,9 @@ proc genMainProc(m: BModule) =
|
||||
PosixCMain = "int main(int argc, char** args, char** env) {$n" &
|
||||
" cmdLine = args;$n" & " cmdCount = argc;$n" & " gEnv = env;$n" &
|
||||
" NimMain();$n" & " return nim_program_result;$n" & "}$n"
|
||||
StandaloneCMain = "int main(void) {$n" &
|
||||
" NimMain();$n" &
|
||||
" return 0;$n" & "}$n"
|
||||
WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
|
||||
CommonMainBody & "}$n"
|
||||
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
|
||||
@@ -808,7 +811,10 @@ proc genMainProc(m: BModule) =
|
||||
elif optGenDynLib in gGlobalOptions:
|
||||
nimMain = posixNimDllMain
|
||||
otherMain = posixCDllMain
|
||||
else:
|
||||
elif platform.targetOS == osStandalone:
|
||||
nimMain = PosixNimMain
|
||||
otherMain = StandaloneCMain
|
||||
else:
|
||||
nimMain = PosixNimMain
|
||||
otherMain = PosixCMain
|
||||
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
|
||||
|
||||
@@ -36,7 +36,7 @@ type
|
||||
cfsDynLibInit, # section for init of dynamic library binding
|
||||
cfsDynLibDeinit # section for deinitialization of dynamic
|
||||
# libraries
|
||||
TCTypeKind* = enum # describes the type kind of a C type
|
||||
TCTypeKind* = enum # describes the type kind of a C type
|
||||
ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64,
|
||||
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
# included from transf.nim
|
||||
|
||||
const
|
||||
declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef,
|
||||
nkConverterDef}
|
||||
declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||
procDefs = nkLambdaKinds + declarativeDefs
|
||||
|
||||
proc indirectAccess(a, b: PSym, info: TLineInfo): PNode =
|
||||
|
||||
@@ -21,7 +21,8 @@ type
|
||||
# conditionals to condsyms (end of module).
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
|
||||
osAtari, osNetware, osMacos, osMacosx, osEcmaScript, osNimrodVM
|
||||
osAtari, osNetware, osMacos, osMacosx, osEcmaScript, osNimrodVM,
|
||||
osStandalone
|
||||
|
||||
type
|
||||
TInfoOSProp* = enum
|
||||
@@ -139,14 +140,18 @@ const
|
||||
exeExt: "", extSep: ".", props: {}),
|
||||
(name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {})]
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
|
||||
(name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
|
||||
props: {})]
|
||||
|
||||
type
|
||||
TSystemCPU* = enum # Also add CPU for in initialization section and
|
||||
# alias conditionals to condsyms (end of module).
|
||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
|
||||
cpuEcmaScript, cpuNimrodVM
|
||||
cpuEcmaScript, cpuNimrodVM, cpuAVR
|
||||
|
||||
type
|
||||
TEndian* = enum
|
||||
@@ -169,7 +174,8 @@ const
|
||||
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "ecmascript", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
|
||||
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32)]
|
||||
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
|
||||
|
||||
var
|
||||
targetCPU*, hostCPU*: TSystemCPU
|
||||
|
||||
@@ -535,7 +535,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
|
||||
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
var
|
||||
w: string
|
||||
d, L, inclCrc: int
|
||||
d, inclCrc: int
|
||||
while r.s[r.pos] != '\0':
|
||||
var section = rdWord(r)
|
||||
if r.reason != rrNone:
|
||||
@@ -573,20 +573,17 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
of "FILES":
|
||||
inc(r.pos, 2) # skip "(\10"
|
||||
inc(r.line)
|
||||
L = 0
|
||||
while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')':
|
||||
setlen(r.files, L + 1)
|
||||
while r.s[r.pos] != ')':
|
||||
var relativePath = decodeStr(r.s, r.pos)
|
||||
var resolvedPath = relativePath.findModule
|
||||
r.files[L] = if resolvedPath.len > 0: resolvedPath else: relativePath
|
||||
r.files.add(if resolvedPath.len > 0: resolvedPath else: relativePath)
|
||||
inc(r.pos) # skip #10
|
||||
inc(r.line)
|
||||
inc(L)
|
||||
if r.s[r.pos] == ')': inc(r.pos)
|
||||
of "INCLUDES":
|
||||
inc(r.pos, 2) # skip "(\10"
|
||||
inc(r.line)
|
||||
while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')':
|
||||
while r.s[r.pos] != ')':
|
||||
w = r.files[decodeVInt(r.s, r.pos)]
|
||||
inc(r.pos) # skip ' '
|
||||
inclCrc = decodeVInt(r.s, r.pos)
|
||||
@@ -597,13 +594,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
inc(r.pos)
|
||||
inc(r.line)
|
||||
if r.s[r.pos] == ')': inc(r.pos)
|
||||
of "DEPS":
|
||||
of "DEPS":
|
||||
inc(r.pos) # skip ':'
|
||||
L = 0
|
||||
while r.s[r.pos] > '\x0A':
|
||||
setlen(r.modDeps, L + 1)
|
||||
r.modDeps[L] = r.files[decodeVInt(r.s, r.pos)]
|
||||
inc(L)
|
||||
r.modDeps.add r.files[decodeVInt(r.s, r.pos)]
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
of "INTERF":
|
||||
r.interfIdx = r.pos + 2
|
||||
@@ -629,9 +623,11 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
of "INIT":
|
||||
r.initIdx = r.pos + 2 # "(\10"
|
||||
skipSection(r)
|
||||
else:
|
||||
MsgWriteln("skipping section: " & section &
|
||||
" at " & $r.pos & " in " & r.filename)
|
||||
else:
|
||||
InternalError("invalid section: '" & section &
|
||||
"' at " & $r.line & " in " & r.filename)
|
||||
#MsgWriteln("skipping section: " & section &
|
||||
# " at " & $r.line & " in " & r.filename)
|
||||
skipSection(r)
|
||||
if r.s[r.pos] == '\x0A':
|
||||
inc(r.pos)
|
||||
|
||||
@@ -22,7 +22,7 @@ proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = newStrNode(nkStrLit, content)
|
||||
result.typ = getSysType(tyString)
|
||||
result.info = n.info
|
||||
c.slurpedFiles.add(filename)
|
||||
c.slurpedFiles.add(a.strVal)
|
||||
except EIO:
|
||||
GlobalError(a.info, errCannotOpenFile, a.strVal)
|
||||
|
||||
|
||||
@@ -107,14 +107,14 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
|
||||
result = c.mapping[v.id]
|
||||
if result != toUndefined: return
|
||||
case v.kind
|
||||
of skVar, skLet, skResult:
|
||||
of skVar, skForVar, skLet, skResult:
|
||||
result = toNil
|
||||
if sfGlobal in v.flags:
|
||||
if sfThread in v.flags:
|
||||
result = toMine
|
||||
elif containsGarbageCollectedRef(v.typ):
|
||||
result = toTheirs
|
||||
of skTemp, skForVar: result = toNil
|
||||
of skTemp: result = toNil
|
||||
of skConst: result = toMine
|
||||
of skParam:
|
||||
result = c.mapping[v.id]
|
||||
|
||||
@@ -251,43 +251,38 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
result = semIdentVis(c, kind, n, allowed)
|
||||
|
||||
proc checkForOverlap(c: PContext, t, ex: PNode, branchIndex: int) =
|
||||
let ex = ex.skipConv
|
||||
for i in countup(1, branchIndex - 1):
|
||||
for j in countup(0, sonsLen(t.sons[i]) - 2):
|
||||
if overlap(t.sons[i].sons[j], ex):
|
||||
if overlap(t.sons[i].sons[j].skipConv, ex):
|
||||
LocalError(ex.info, errDuplicateCaseLabel)
|
||||
|
||||
proc semBranchExpr(c: PContext, t, e: PNode): PNode =
|
||||
result = semConstExpr(c, e)
|
||||
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var biggestInt): PNode =
|
||||
checkMinSonsLen(t, 1)
|
||||
result = fitNode(c, t.sons[0].typ, result)
|
||||
#if cmpTypes(t.sons[0].typ, result.typ) <= isConvertible:
|
||||
# typeMismatch(result, t.sons[0].typ, result.typ)
|
||||
let ac = semConstExpr(c, a)
|
||||
let bc = semConstExpr(c, b)
|
||||
let at = fitNode(c, t.sons[0].typ, ac)
|
||||
let bt = fitNode(c, t.sons[0].typ, bc)
|
||||
|
||||
result = newNodeI(nkRange, a.info)
|
||||
result.add(at)
|
||||
result.add(bt)
|
||||
if emptyRange(ac, bc): GlobalError(b.info, errRangeIsEmpty)
|
||||
covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
|
||||
|
||||
proc SemCaseBranchRange(c: PContext, t, b: PNode,
|
||||
covered: var biggestInt): PNode =
|
||||
checkSonsLen(b, 3)
|
||||
result = newNodeI(nkRange, b.info)
|
||||
result.add(semBranchExpr(c, t, b.sons[1]))
|
||||
result.add(semBranchExpr(c, t, b.sons[2]))
|
||||
if emptyRange(result[0], result[1]): GlobalError(b.info, errRangeIsEmpty)
|
||||
covered = covered + getOrdValue(result[1]) - getOrdValue(result[0]) + 1
|
||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||
|
||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||
covered: var biggestInt): PNode =
|
||||
if isRange(b):
|
||||
checkSonsLen(b, 3)
|
||||
result = newNodeI(nkRange, b.info)
|
||||
result.add(semBranchExpr(c, t, b.sons[1]))
|
||||
result.add(semBranchExpr(c, t, b.sons[2]))
|
||||
if emptyRange(result[0], result[1]): GlobalError(b.info, errRangeIsEmpty)
|
||||
covered = covered + getOrdValue(result[1]) - getOrdValue(result[0]) + 1
|
||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||
elif b.kind == nkRange:
|
||||
checkSonsLen(b, 2)
|
||||
result = newNodeI(nkRange, b.info)
|
||||
result.add(semBranchExpr(c, t, b.sons[0]))
|
||||
result.add(semBranchExpr(c, t, b.sons[1]))
|
||||
if emptyRange(result[0], result[1]): GlobalError(b.info, errRangeIsEmpty)
|
||||
covered = covered + getOrdValue(result[1]) - getOrdValue(result[0]) + 1
|
||||
result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
|
||||
else:
|
||||
result = fitNode(c, t.sons[0].typ, b)
|
||||
inc(covered)
|
||||
|
||||
@@ -267,14 +267,6 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||
discard c.blockSyms.pop()
|
||||
else:
|
||||
result = transform(c, n)
|
||||
|
||||
proc skipConv(n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
result = n.sons[0]
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = n.sons[1]
|
||||
else: result = n
|
||||
|
||||
proc newTupleAccess(tup: PNode, i: int): PNode =
|
||||
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i])
|
||||
|
||||
@@ -869,9 +869,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||
of tyArray:
|
||||
result = t.sons[1].kind == tyEmpty or
|
||||
typeAllowedAux(marker, t.sons[1], skVar)
|
||||
of tyPtr, tyRef:
|
||||
of tyRef:
|
||||
if kind == skConst: return false
|
||||
result = typeAllowedAux(marker, t.sons[0], skVar)
|
||||
of tyPtr:
|
||||
result = typeAllowedAux(marker, t.sons[0], skVar)
|
||||
of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter, tyProxy:
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
result = typeAllowedAux(marker, t.sons[i], kind)
|
||||
|
||||
@@ -255,6 +255,10 @@ XML Processing
|
||||
* `htmlparser <htmlparser.html>`_
|
||||
This module parses an HTML document and creates its XML tree representation.
|
||||
|
||||
* `htmlgen <htmlgen.html>`_
|
||||
This module implements a simple XML and HTML code
|
||||
generator. Each commonly used HTML tag has a corresponding macro
|
||||
that generates a string with its HTML representation.
|
||||
|
||||
Cryptography and Hashing
|
||||
------------------------
|
||||
|
||||
2
koch.nim
2
koch.nim
@@ -141,7 +141,7 @@ proc boot(args: string) =
|
||||
return
|
||||
copyExe(output, (i+1).thVersion)
|
||||
copyExe(output, finalDest)
|
||||
echo "[Warning] executables are still not equal"
|
||||
when not defined(windows): echo "[Warning] executables are still not equal"
|
||||
|
||||
# -------------- clean --------------------------------------------------------
|
||||
|
||||
|
||||
@@ -142,6 +142,8 @@ proc parseMessage(msg: string): TIRCEvent =
|
||||
inc(i) # Skip `:`
|
||||
var nick = ""
|
||||
i.inc msg.parseUntil(nick, {'!', ' '}, i)
|
||||
result.nick = ""
|
||||
result.serverName = ""
|
||||
if msg[i] == '!':
|
||||
result.nick = nick
|
||||
inc(i) # Skip `!`
|
||||
@@ -237,7 +239,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent =
|
||||
result = parseMessage(line)
|
||||
# Get the origin
|
||||
result.origin = result.params[0]
|
||||
if result.origin == irc.nick: result.origin = result.nick
|
||||
if result.origin == irc.nick and
|
||||
result.nick != "": result.origin = result.nick
|
||||
|
||||
if result.cmd == MError:
|
||||
irc.close()
|
||||
@@ -386,6 +389,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
|
||||
result.messageBuffer = @[]
|
||||
result.handleEvent = ircEvent
|
||||
result.userArg = userArg
|
||||
result.lineBuffer = ""
|
||||
|
||||
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
||||
## Registers ``irc`` with dispatcher ``d``.
|
||||
|
||||
@@ -8,8 +8,12 @@
|
||||
#
|
||||
|
||||
## This module implements a simple portable type-safe sockets layer.
|
||||
##
|
||||
## Most procedures raise EOS on error.
|
||||
|
||||
|
||||
import os, parseutils
|
||||
from times import epochTime
|
||||
|
||||
when defined(Windows):
|
||||
import winlean
|
||||
@@ -59,6 +63,8 @@ type
|
||||
TRecvLineResult* = enum ## result for recvLineAsync
|
||||
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
||||
|
||||
ETimeout* = object of ESynch
|
||||
|
||||
const
|
||||
InvalidSocket* = TSocket(-1'i32) ## invalid socket number
|
||||
|
||||
@@ -377,12 +383,14 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||
## host name. If ``name`` is a host name, this function will try each IP
|
||||
## of that host name. ``htons`` is already performed on ``port`` so you must
|
||||
## not do it.
|
||||
|
||||
var hints: TAddrInfo
|
||||
var aiList: ptr TAddrInfo = nil
|
||||
hints.ai_family = toInt(af)
|
||||
hints.ai_socktype = toInt(SOCK_STREAM)
|
||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||
gaiNim(name, port, hints, aiList)
|
||||
|
||||
# try all possibilities:
|
||||
var success = false
|
||||
var it = aiList
|
||||
@@ -445,7 +453,6 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||
freeaddrinfo(aiList)
|
||||
if not success: OSError()
|
||||
|
||||
|
||||
proc timeValFromMilliseconds(timeout = 500): TTimeVal =
|
||||
if timeout != -1:
|
||||
var seconds = timeout div 1000
|
||||
@@ -545,7 +552,33 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
|
||||
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
|
||||
|
||||
pruneSocketSet(readfds, (rd))
|
||||
|
||||
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||
## receives data from a socket
|
||||
result = recv(cint(socket), data, size, 0'i32)
|
||||
|
||||
template waitFor(): stmt =
|
||||
if timeout - int(waited * 1000.0) < 1:
|
||||
raise newException(ETimeout, "Call to recv() timed out.")
|
||||
var s = @[socket]
|
||||
var startTime = epochTime()
|
||||
if select(s, timeout - int(waited * 1000.0)) != 1:
|
||||
raise newException(ETimeout, "Call to recv() timed out.")
|
||||
waited += (epochTime() - startTime)
|
||||
|
||||
proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int =
|
||||
## overload with a ``timeout`` parameter in miliseconds.
|
||||
var waited = 0.0 # number of seconds already waited
|
||||
|
||||
var read = 0
|
||||
while read < size:
|
||||
waitFor()
|
||||
result = recv(cint(socket), addr(data[read]), 1, 0'i32)
|
||||
if result < 0:
|
||||
return
|
||||
inc(read)
|
||||
|
||||
result = read
|
||||
|
||||
proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||
## returns false if no further data is available. `Line` must be initialized
|
||||
@@ -567,6 +600,29 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||
elif c == '\L': return true
|
||||
add(line.string, c)
|
||||
|
||||
proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
|
||||
## variant with a ``timeout`` parameter, the timeout parameter specifies
|
||||
## how many miliseconds to wait for data.
|
||||
|
||||
var waited = 0.0 # number of seconds already waited
|
||||
|
||||
setLen(line.string, 0)
|
||||
while true:
|
||||
var c: char
|
||||
waitFor()
|
||||
var n = recv(cint(socket), addr(c), 1, 0'i32)
|
||||
if n < 0: return
|
||||
elif n == 0: return true
|
||||
if c == '\r':
|
||||
waitFor()
|
||||
n = recv(cint(socket), addr(c), 1, MSG_PEEK)
|
||||
if n > 0 and c == '\L':
|
||||
discard recv(cint(socket), addr(c), 1, 0'i32)
|
||||
elif n <= 0: return false
|
||||
return true
|
||||
elif c == '\L': return true
|
||||
add(line.string, c)
|
||||
|
||||
proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||
## similar to ``recvLine`` but for non-blocking sockets.
|
||||
## The values of the returned enum should be pretty self explanatory:
|
||||
@@ -592,10 +648,6 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||
elif c == '\L': return RecvFullLine
|
||||
add(line.string, c)
|
||||
|
||||
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||
## receives data from a socket
|
||||
result = recv(cint(socket), data, size, 0'i32)
|
||||
|
||||
proc recv*(socket: TSocket): TaintedString =
|
||||
## receives all the data from the socket.
|
||||
## Socket errors will result in an ``EOS`` error.
|
||||
@@ -625,6 +677,16 @@ proc recv*(socket: TSocket): TaintedString =
|
||||
add(result.string, buf)
|
||||
if bytesRead != bufSize-1: break
|
||||
|
||||
proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
|
||||
## overloaded variant to support a ``timeout`` parameter, the ``timeout``
|
||||
## parameter specifies the amount of miliseconds to wait for data on the
|
||||
## socket.
|
||||
var s = @[socket]
|
||||
if s.select(timeout) != 1:
|
||||
raise newException(ETimeout, "Call to recv() timed out.")
|
||||
|
||||
return socket.recv
|
||||
|
||||
proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
|
||||
## receives all the data from a non-blocking socket. If socket is non-blocking
|
||||
## and there are no messages available, `False` will be returned.
|
||||
@@ -723,6 +785,21 @@ proc setBlocking*(s: TSocket, blocking: bool) =
|
||||
if fcntl(cint(s), F_SETFL, mode) == -1:
|
||||
OSError()
|
||||
|
||||
proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),
|
||||
af: TDomain = AF_INET) =
|
||||
## Overload for ``connect`` to support timeouts. The ``timeout`` parameter
|
||||
## specifies the time in miliseconds of how long to wait for a connection
|
||||
## to be made.
|
||||
##
|
||||
## **Warning:** If ``socket`` is non-blocking and timeout is not ``-1`` then
|
||||
## this function may set blocking mode on ``socket`` to true.
|
||||
socket.setBlocking(true)
|
||||
|
||||
socket.connectAsync(name, port, af)
|
||||
var s: seq[TSocket] = @[socket]
|
||||
if selectWrite(s, timeout) != 1:
|
||||
raise newException(ETimeout, "Call to connect() timed out.")
|
||||
|
||||
when defined(Windows):
|
||||
var wsa: TWSADATA
|
||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
||||
|
||||
@@ -851,7 +851,7 @@ template sysAssert(cond: bool, msg: string) =
|
||||
|
||||
include "system/inclrtl"
|
||||
|
||||
when not defined(ecmascript) and not defined(nimrodVm):
|
||||
when not defined(ecmascript) and not defined(nimrodVm) and not defined(avr):
|
||||
include "system/cgprocs"
|
||||
|
||||
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
||||
@@ -1604,16 +1604,17 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
{.push stack_trace: off.}
|
||||
|
||||
proc initGC()
|
||||
when not defined(boehmgc):
|
||||
when not defined(boehmgc) and not defined(useMalloc):
|
||||
proc initAllocator() {.inline.}
|
||||
|
||||
proc initStackBottom() {.inline.} =
|
||||
# WARNING: This is very fragile! An array size of 8 does not work on my
|
||||
# Linux 64bit system. Very strange, but we are at the will of GCC's
|
||||
# optimizer...
|
||||
var locals {.volatile.}: pointer
|
||||
locals = addr(locals)
|
||||
setStackBottom(locals)
|
||||
when not defined(nogc):
|
||||
proc initStackBottom() {.inline.} =
|
||||
# WARNING: This is very fragile! An array size of 8 does not work on my
|
||||
# Linux 64bit system. Very strange, but we are at the will of GCC's
|
||||
# optimizer...
|
||||
var locals {.volatile.}: pointer
|
||||
locals = addr(locals)
|
||||
setStackBottom(locals)
|
||||
|
||||
var
|
||||
strDesc: TNimType
|
||||
@@ -1868,7 +1869,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
when hasThreadSupport:
|
||||
include "system/syslocks"
|
||||
include "system/threads"
|
||||
else:
|
||||
elif not defined(nogc):
|
||||
initStackBottom()
|
||||
initGC()
|
||||
|
||||
@@ -1881,21 +1882,23 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
## for debug builds.
|
||||
|
||||
{.push stack_trace: off.}
|
||||
include "system/excpt"
|
||||
when hostCPU == "avr":
|
||||
include "system/embedded"
|
||||
else:
|
||||
include "system/excpt"
|
||||
|
||||
# we cannot compile this with stack tracing on
|
||||
# as it would recurse endlessly!
|
||||
include "system/arithm"
|
||||
{.pop.} # stack trace
|
||||
{.pop.} # stack trace
|
||||
|
||||
include "system/dyncalls"
|
||||
when hostOS != "standalone": include "system/dyncalls"
|
||||
include "system/sets"
|
||||
|
||||
const
|
||||
GenericSeqSize = (2 * sizeof(int))
|
||||
|
||||
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
|
||||
|
||||
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
|
||||
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
||||
var d: int
|
||||
@@ -1918,7 +1921,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
|
||||
include "system/mmdisp"
|
||||
{.push stack_trace: off.}
|
||||
include "system/sysstr"
|
||||
when hostCPU != "avr": include "system/sysstr"
|
||||
{.pop.}
|
||||
|
||||
include "system/sysio"
|
||||
@@ -1938,18 +1941,19 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
var res = TaintedString(newStringOfCap(80))
|
||||
while f.readLine(res): yield TaintedString(res)
|
||||
|
||||
include "system/assign"
|
||||
include "system/repr"
|
||||
when hostCPU != "avr":
|
||||
include "system/assign"
|
||||
include "system/repr"
|
||||
|
||||
proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
|
||||
## retrieves the current exception; if there is none, nil is returned.
|
||||
result = currException
|
||||
proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
|
||||
## retrieves the current exception; if there is none, nil is returned.
|
||||
result = currException
|
||||
|
||||
proc getCurrentExceptionMsg*(): string {.inline.} =
|
||||
## retrieves the error message that was attached to the current
|
||||
## exception; if there is none, "" is returned.
|
||||
var e = getCurrentException()
|
||||
return if e == nil: "" else: e.msg
|
||||
proc getCurrentExceptionMsg*(): string {.inline.} =
|
||||
## retrieves the error message that was attached to the current
|
||||
## exception; if there is none, "" is returned.
|
||||
var e = getCurrentException()
|
||||
return if e == nil: "" else: e.msg
|
||||
|
||||
{.push stack_trace: off.}
|
||||
when defined(endb):
|
||||
|
||||
@@ -103,4 +103,3 @@ proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.}
|
||||
proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.}
|
||||
|
||||
{.pop}
|
||||
|
||||
|
||||
106
lib/system/embedded.nim
Normal file
106
lib/system/embedded.nim
Normal file
@@ -0,0 +1,106 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
|
||||
# Bare-bones implementation of some things for embedded targets.
|
||||
|
||||
proc writeToStdErr(msg: CString) = write(stdout, msg)
|
||||
|
||||
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||
proc chckRange(i, a, b: int): int {.inline, compilerproc.}
|
||||
proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
|
||||
proc chckNil(p: pointer) {.inline, compilerproc.}
|
||||
|
||||
proc pushFrame(s: PFrame) {.compilerRtl, inl.} = nil
|
||||
proc popFrame {.compilerRtl, inl.} = nil
|
||||
|
||||
proc setFrame(s: PFrame) {.compilerRtl, inl.} = nil
|
||||
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = nil
|
||||
proc popSafePoint {.compilerRtl, inl.} = nil
|
||||
proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = nil
|
||||
proc popCurrentException {.compilerRtl, inl.} = nil
|
||||
|
||||
# some platforms have native support for stack traces:
|
||||
const
|
||||
nativeStackTraceSupported = false
|
||||
hasSomeStackTrace = false
|
||||
|
||||
proc quitOrDebug() {.inline.} =
|
||||
quit(1)
|
||||
|
||||
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||
writeToStdErr(ename)
|
||||
|
||||
proc reraiseException() {.compilerRtl.} =
|
||||
writeToStdErr("reraise not supported")
|
||||
|
||||
proc WriteStackTrace() = nil
|
||||
|
||||
proc setControlCHook(hook: proc () {.noconv.}) =
|
||||
# ugly cast, but should work on all architectures:
|
||||
type TSignalHandler = proc (sig: cint) {.noconv.}
|
||||
c_signal(SIGINT, cast[TSignalHandler](hook))
|
||||
|
||||
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
|
||||
writeToStdErr("value out of range")
|
||||
|
||||
proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
|
||||
writeToStdErr("index out of bounds")
|
||||
|
||||
proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
|
||||
writeToStdErr("field is not accessible")
|
||||
|
||||
proc chckIndx(i, a, b: int): int =
|
||||
if i >= a and i <= b:
|
||||
return i
|
||||
else:
|
||||
raiseIndexError()
|
||||
|
||||
proc chckRange(i, a, b: int): int =
|
||||
if i >= a and i <= b:
|
||||
return i
|
||||
else:
|
||||
raiseRangeError(i)
|
||||
|
||||
proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
|
||||
if i >= a and i <= b:
|
||||
return i
|
||||
else:
|
||||
raiseRangeError(i)
|
||||
|
||||
proc chckRangeF(x, a, b: float): float =
|
||||
if x >= a and x <= b:
|
||||
return x
|
||||
else:
|
||||
raise newException(EOutOfRange, "value " & $x & " out of range")
|
||||
|
||||
proc chckNil(p: pointer) =
|
||||
if p == nil: c_raise(SIGSEGV)
|
||||
|
||||
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
|
||||
# checks if obj is of type subclass:
|
||||
var x = obj
|
||||
if x == subclass: return # optimized fast path
|
||||
while x != subclass:
|
||||
if x == nil:
|
||||
raise newException(EInvalidObjectConversion, "invalid object conversion")
|
||||
x = x.base
|
||||
|
||||
proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
|
||||
if a != b:
|
||||
raise newException(EInvalidObjectAssignment, "invalid object assignment")
|
||||
|
||||
proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
|
||||
# checks if obj is of type subclass:
|
||||
var x = obj
|
||||
if x == subclass: return true # optimized fast path
|
||||
while x != subclass:
|
||||
if x == nil: return false
|
||||
x = x.base
|
||||
return true
|
||||
@@ -27,7 +27,7 @@ else:
|
||||
proc writeToStdErr(msg: CString) =
|
||||
discard MessageBoxA(0, msg, nil, 0)
|
||||
|
||||
proc registerSignalHandler() {.compilerproc.}
|
||||
proc registerSignalHandler()
|
||||
|
||||
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||
proc chckRange(i, a, b: int): int {.inline, compilerproc.}
|
||||
|
||||
@@ -181,6 +181,78 @@ when defined(boehmgc):
|
||||
proc deallocOsPages() {.inline.} = nil
|
||||
|
||||
include "system/cellsets"
|
||||
elif defined(nogc) and defined(useMalloc):
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc alloc(size: int): pointer =
|
||||
result = cmalloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc alloc0(size: int): pointer =
|
||||
result = alloc(size)
|
||||
zeroMem(result, size)
|
||||
proc realloc(p: Pointer, newsize: int): pointer =
|
||||
result = crealloc(p, newsize)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc dealloc(p: Pointer) = cfree(p)
|
||||
|
||||
proc allocShared(size: int): pointer =
|
||||
result = cmalloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc allocShared0(size: int): pointer =
|
||||
result = alloc(size)
|
||||
zeroMem(result, size)
|
||||
proc reallocShared(p: Pointer, newsize: int): pointer =
|
||||
result = crealloc(p, newsize)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc deallocShared(p: Pointer) = cfree(p)
|
||||
|
||||
proc GC_disable() = nil
|
||||
proc GC_enable() = nil
|
||||
proc GC_fullCollect() = nil
|
||||
proc GC_setStrategy(strategy: TGC_Strategy) = nil
|
||||
proc GC_enableMarkAndSweep() = nil
|
||||
proc GC_disableMarkAndSweep() = nil
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
||||
proc getOccupiedMem(): int = nil
|
||||
proc getFreeMem(): int = nil
|
||||
proc getTotalMem(): int = nil
|
||||
|
||||
proc setStackBottom(theStackBottom: pointer) = nil
|
||||
|
||||
proc initGC() = nil
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
result = alloc(size)
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer =
|
||||
result = realloc(old, newsize)
|
||||
|
||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
|
||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
|
||||
|
||||
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
||||
dest[] = src
|
||||
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
||||
dest[] = src
|
||||
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
||||
dest[] = src
|
||||
|
||||
type
|
||||
TMemRegion = object {.final, pure.}
|
||||
|
||||
proc Alloc(r: var TMemRegion, size: int): pointer =
|
||||
result = alloc(size)
|
||||
proc Alloc0(r: var TMemRegion, size: int): pointer =
|
||||
result = alloc0(size)
|
||||
proc Dealloc(r: var TMemRegion, p: Pointer) = Dealloc(p)
|
||||
proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
|
||||
proc deallocOsPages() {.inline.} = nil
|
||||
|
||||
elif defined(nogc):
|
||||
# Even though we don't want the GC, we cannot simply use C's memory manager
|
||||
# because Nimrod's runtime wants ``realloc`` to zero out the additional
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
# The generic ``repr`` procedure. It is an invaluable debugging tool.
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
|
||||
|
||||
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
||||
proc reprFloat(x: float): string {.compilerproc.} = return $x
|
||||
|
||||
|
||||
47
tests/benchmark.nim
Normal file
47
tests/benchmark.nim
Normal file
@@ -0,0 +1,47 @@
|
||||
#
|
||||
#
|
||||
# Nimrod Benchmark tool
|
||||
# (c) Copyright 2012 Dominik Picheta
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This program runs benchmarks
|
||||
import osproc, os, times, json
|
||||
|
||||
type
|
||||
TBenchResult = tuple[file: string, success: bool, time: float]
|
||||
|
||||
proc compileBench(file: string) =
|
||||
## Compiles ``file``.
|
||||
doAssert(execCmdEx("nimrod c -d:release " & file).exitCode == QuitSuccess)
|
||||
|
||||
proc runBench(file: string): TBenchResult =
|
||||
## Runs ``file`` and returns info on how long it took to run.
|
||||
var start = epochTime()
|
||||
if execCmdEx(file.addFileExt(ExeExt)).exitCode == QuitSuccess:
|
||||
var t = epochTime() - start
|
||||
result = (file, true, t)
|
||||
else: result = (file, false, -1.0)
|
||||
|
||||
proc genOutput(benches: seq[TBenchResult]): PJsonNode =
|
||||
result = newJObject()
|
||||
for i in benches:
|
||||
if i.success:
|
||||
result[i.file.extractFilename] = newJFloat(i.time)
|
||||
else:
|
||||
result[i.file.extractFilename] = newJNull()
|
||||
|
||||
proc doBench(): seq[TBenchResult] =
|
||||
result = @[]
|
||||
for i in walkFiles("tests/benchmarks/*.nim"):
|
||||
echo(i.extractFilename)
|
||||
compileBench(i)
|
||||
result.add(runBench(i))
|
||||
|
||||
when isMainModule:
|
||||
var b = doBench()
|
||||
var output = genOutput(b)
|
||||
writeFile("benchmarkResults.json", pretty(output))
|
||||
|
||||
69
tests/benchmarks/fannkuch.nim
Normal file
69
tests/benchmarks/fannkuch.nim
Normal file
@@ -0,0 +1,69 @@
|
||||
import os
|
||||
import strutils
|
||||
|
||||
proc fannkuch (n: int): int =
|
||||
var
|
||||
count: seq[int]
|
||||
maxFlips = 0
|
||||
m = n-1
|
||||
r = n
|
||||
check = 0
|
||||
perm1: seq[int]
|
||||
perm: seq[int]
|
||||
|
||||
newSeq (count, n+1)
|
||||
newSeq (perm1, n)
|
||||
newSeq (perm, n)
|
||||
for i in 0 .. n-1:
|
||||
count[i] = i+1
|
||||
perm1[i] = i
|
||||
perm[i] = i
|
||||
count[n] = n+1
|
||||
|
||||
while True:
|
||||
if check < 30:
|
||||
for i in items (perm1):
|
||||
write (stdout, $(i+1))
|
||||
echo ("")
|
||||
inc (check)
|
||||
|
||||
while r != 1:
|
||||
count[r-1] = r
|
||||
dec (r)
|
||||
|
||||
if perm1[0] != 0 and perm1[m] != m:
|
||||
# perm = perm1
|
||||
# The above line is between 3 and 4 times slower than the loop below!
|
||||
for i in 0 .. n-1:
|
||||
perm[i] = perm1[i]
|
||||
var flipsCount = 0
|
||||
var k = perm[0]
|
||||
while k != 0:
|
||||
for i in 0 .. (k div 2):
|
||||
swap (perm[i], perm[k-i])
|
||||
inc (flipsCount)
|
||||
k = perm[0]
|
||||
|
||||
if flipsCount > maxFlips:
|
||||
maxFlips = flipsCount
|
||||
|
||||
block makePerm:
|
||||
while r != n:
|
||||
var tmp = perm1[0]
|
||||
# # perm1.delete (0)
|
||||
# # perm1.insert (tmp, r)
|
||||
# # The above is about twice as slow as the following:
|
||||
# moveMem (addr (perm1[0]), addr (perm1[1]), r * sizeof (int))
|
||||
# The call to moveMem is about 50% slower than the loop below!
|
||||
for i in 0 .. r-1:
|
||||
perm1[i] = perm1[i+1]
|
||||
perm1[r] = tmp
|
||||
|
||||
dec (count[r])
|
||||
if count[r] > 0:
|
||||
break makePerm
|
||||
inc (r)
|
||||
return maxFlips
|
||||
|
||||
var n = 10
|
||||
echo ("Pfannkuchen(" & $n & ") = " & $fannkuch (n))
|
||||
54
tests/benchmarks/quicksort.nim
Normal file
54
tests/benchmarks/quicksort.nim
Normal file
@@ -0,0 +1,54 @@
|
||||
import os
|
||||
import strutils
|
||||
|
||||
# Generate some pseudo-random data
|
||||
var seed: tuple[s1, s2, s3: int32] = (2'i32, 8'i32, 16'i32)
|
||||
|
||||
proc random(): int32 =
|
||||
seed = (((((((seed[0] and 0x0007_FFFF'i32) shl 13'i32) xor seed[0]) shr
|
||||
19'i32) and 0x0000_1FFF'i32) xor
|
||||
((seed[0] and 0x000F_FFFE'i32) shl 12'i32)),
|
||||
|
||||
((((((seed[1] and 0x3FFF_FFFF'i32) shl 2'i32) xor seed[1]) shr
|
||||
25'i32) and 0x0000_007F'i32) xor
|
||||
((seed[1] and 0x0FFF_FFF8'i32) shl 4'i32)),
|
||||
|
||||
((((((seed[2] and 0x1FFF_FFFF'i32) shl 3'i32) xor seed[2]) shr
|
||||
11'i32) and 0x001F_FFFF'i32) xor
|
||||
((seed[2] and 0x0000_7FF0'i32) shl 17'i32)))
|
||||
return seed[0] xor seed[1] xor seed[2]
|
||||
|
||||
var n = 9999999
|
||||
|
||||
var data: seq[int32]
|
||||
newSeq (data, n)
|
||||
for i in 0 .. data.high():
|
||||
data[i] = random()
|
||||
|
||||
|
||||
proc `$` (d: seq[int32]): string =
|
||||
result = "[ "
|
||||
for i in items (d):
|
||||
result.addSep (", ", 2)
|
||||
result.add ($(i and 0xFFFF_FFFF'i64))
|
||||
result.add (" ]")
|
||||
|
||||
# Sort the data
|
||||
proc sort (start, stop: int) =
|
||||
if stop <= start+1:
|
||||
return
|
||||
|
||||
var j = start
|
||||
for i in start..stop-2:
|
||||
if data[i] <% data[stop-1]:
|
||||
swap (data[i], data[j])
|
||||
inc (j)
|
||||
swap (data[j], data[stop-1])
|
||||
|
||||
sort (start, j)
|
||||
sort (j+1, stop)
|
||||
|
||||
sort (0, data.len)
|
||||
echo (data[n div 2 - 1] and 0xFFFF_FFFF'i64, ", ",
|
||||
data[n div 2] and 0xFFFF_FFFF'i64, ", ",
|
||||
data[n div 2 + 1] and 0xFFFF_FFFF'i64)
|
||||
7
tests/compile/tglobalforvar.nim
Normal file
7
tests/compile/tglobalforvar.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
var funcs: seq[proc (): int] = @[]
|
||||
for i in 0..10:
|
||||
funcs.add((proc (): int = return i * i))
|
||||
|
||||
echo(funcs[3]())
|
||||
|
||||
447
tests/compile/tircbot.nim
Normal file
447
tests/compile/tircbot.nim
Normal file
@@ -0,0 +1,447 @@
|
||||
import irc, sockets, asyncio, json, os, strutils, times, redis
|
||||
|
||||
type
|
||||
TDb* = object
|
||||
r*: TRedis
|
||||
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*: TTime
|
||||
|
||||
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: TPort): TDb =
|
||||
result.r = redis.open(host, port)
|
||||
result.lastPing = epochTime()
|
||||
|
||||
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 = TTime(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(EInvalidValue, 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 TObject
|
||||
dispatcher: PDispatcher
|
||||
sock: PAsyncSocket
|
||||
ircClient: PAsyncIRC
|
||||
hubPort: TPort
|
||||
database: TDb
|
||||
dbConnected: bool
|
||||
|
||||
TSeenType = enum
|
||||
PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
|
||||
|
||||
TSeen = object
|
||||
nick: string
|
||||
channel: string
|
||||
timestamp: TTime
|
||||
case kind*: TSeenType
|
||||
of PSeenJoin: nil
|
||||
of PSeenPart, PSeenQuit, PSeenMsg:
|
||||
msg: string
|
||||
of PSeenNick:
|
||||
newNick: string
|
||||
|
||||
const
|
||||
ircServer = "irc.freenode.net"
|
||||
joinChans = @["#nimrod"]
|
||||
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: nil
|
||||
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":
|
||||
#s.kind = value.parseInt.TSeenType
|
||||
of "channel":
|
||||
s.channel = value
|
||||
of "timestamp":
|
||||
s.timestamp = TTime(value.parseInt)
|
||||
of "msg":
|
||||
s.msg = value
|
||||
of "newnick":
|
||||
s.newNick = value
|
||||
|
||||
template createSeen(typ: TSeenType, n, c: string): stmt =
|
||||
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.existsKey("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 #nimrod.
|
||||
state.ircClient[].privmsg(joinChans[0], message)
|
||||
elif json.existsKey("redisinfo"):
|
||||
assert json["redisinfo"].existsKey("port")
|
||||
let redisPort = json["redisinfo"]["port"].num
|
||||
state.dbConnected = true
|
||||
|
||||
proc hubConnect(state: PState)
|
||||
proc handleConnect(s: PAsyncSocket, userArg: PObject) =
|
||||
let state = PState(userArg)
|
||||
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(EInvalidValue,
|
||||
"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 EOS:
|
||||
echo(getCurrentExceptionMsg())
|
||||
s.close()
|
||||
echo("Waiting 5 seconds...")
|
||||
sleep(5000)
|
||||
state.hubConnect()
|
||||
|
||||
proc handleRead(s: PAsyncSocket, userArg: PObject) =
|
||||
let state = PState(userArg)
|
||||
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.userArg = state
|
||||
state.sock.handleConnect = handleConnect
|
||||
state.sock.handleRead = handleRead
|
||||
|
||||
state.dispatcher.register(state.sock)
|
||||
|
||||
proc handleIrc(irc: var TAsyncIRC, event: TIRCEvent, userArg: PObject) =
|
||||
let state = PState(userArg)
|
||||
case event.typ
|
||||
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, "#nimrod")
|
||||
seenNick.newNick = event.params[0]
|
||||
state.database.setSeen(seenNick)
|
||||
else:
|
||||
nil # TODO: ?
|
||||
|
||||
proc open(port: TPort = TPort(5123)): PState =
|
||||
new(result)
|
||||
result.dispatcher = newDispatcher()
|
||||
|
||||
result.hubPort = port
|
||||
result.hubConnect()
|
||||
|
||||
# Connect to the irc server.
|
||||
result.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
|
||||
joinChans = joinChans, ircEvent = handleIrc, userArg = result)
|
||||
result.ircClient.connect()
|
||||
result.dispatcher.register(result.ircClient)
|
||||
|
||||
result.dbConnected = false
|
||||
|
||||
var state = tircbot.open() # Connect to the website and the IRC server.
|
||||
|
||||
while state.dispatcher.poll():
|
||||
if state.dbConnected:
|
||||
state.database.keepAlive()
|
||||
@@ -1,7 +1,7 @@
|
||||
discard """
|
||||
file: "t99bott.nim"
|
||||
line: 26
|
||||
errormsg: "cannot evaluate 'GetBottleNumber(bn)'"
|
||||
errormsg: "constant expression expected"
|
||||
disabled: false
|
||||
"""
|
||||
## 99 Bottles of Beer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
line: 7
|
||||
errormsg: "a type has no value"
|
||||
errormsg: "type mismatch"
|
||||
"""
|
||||
|
||||
type a = enum b,c,d
|
||||
|
||||
5
todo.txt
5
todo.txt
@@ -1,7 +1,7 @@
|
||||
version 0.9.0
|
||||
=============
|
||||
|
||||
- bootstrapping fails with --symbolFiles:on again!
|
||||
- make GC realtime capable: GC_step(ms: int)
|
||||
- ``=`` should be overloadable; requires specialization for ``=``
|
||||
- fix remaining generics bugs
|
||||
- fix remaining closure bugs:
|
||||
@@ -49,6 +49,8 @@ Bugs
|
||||
without ``-d:release`` leaks memory?
|
||||
- bug: object {.pure, final.} does not work again!
|
||||
- bug: tsortdev does not run with native GC?
|
||||
- bug: pragma statements in combination with symbol files are evaluated twice
|
||||
but this can lead to compilation errors
|
||||
|
||||
|
||||
version 0.9.XX
|
||||
@@ -98,6 +100,7 @@ version 0.9.XX
|
||||
Library
|
||||
-------
|
||||
|
||||
- provide more up to date OpenGL headers
|
||||
- wrappers for mongodb; poppler; libharu
|
||||
- suffix trees
|
||||
- locale support; i18n module
|
||||
|
||||
@@ -42,11 +42,11 @@ priority).
|
||||
Nimrod is efficient
|
||||
===================
|
||||
|
||||
* Native code generation (currently via compilation to C), not dependant on a
|
||||
* Native code generation (currently via compilation to C), not dependent on a
|
||||
virtual machine: **Nimrod produces small executables without dependencies
|
||||
for easy redistribution.**
|
||||
* A fast non-recursive incremental and generational garbage collector that
|
||||
should be well suited for soft real-time systems (like games).
|
||||
* A fast **non-tracing** garbage collector that should be well suited for soft
|
||||
real-time systems (like games).
|
||||
* System programming features: Ability to manage your own memory and access the
|
||||
hardware directly. Pointers to garbage collected memory are distinguished
|
||||
from pointers to manually managed memory.
|
||||
|
||||
@@ -17,6 +17,7 @@ Bugfixes
|
||||
Library Additions
|
||||
-----------------
|
||||
|
||||
- Added the (already existing) module ``htmlgen`` to the documentation.
|
||||
- Added ``system.shallow`` that can be used to speed up string and sequence
|
||||
assignments.
|
||||
- Added ``system.eval`` that can execute an anonymous block of code at
|
||||
|
||||
Reference in New Issue
Block a user