Merge branch 'master' of github.com:Araq/Nimrod into upstream
This commit is contained in:
commit
8d698b2bdd
36 changed files with 1017 additions and 109 deletions
|
|
@ -227,9 +227,6 @@ type
|
||||||
sfInnerProc, # proc is an inner proc
|
sfInnerProc, # proc is an inner proc
|
||||||
sfThread, # proc will run as a thread
|
sfThread, # proc will run as a thread
|
||||||
# variable is a thread variable
|
# 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
|
sfCompileTime, # proc can be evaluated at compile time
|
||||||
sfMerge, # proc can be merged with itself
|
sfMerge, # proc can be merged with itself
|
||||||
sfDeadCodeElim, # dead code elimination for the module is turned on
|
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
|
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
|
||||||
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
||||||
sfNoInit* = sfMainModule # don't generate code to init the variable
|
sfNoInit* = sfMainModule # don't generate code to init the variable
|
||||||
|
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
|
||||||
|
# without considering any possible overloads
|
||||||
|
|
||||||
type
|
type
|
||||||
TTypeKind* = enum # order is important!
|
TTypeKind* = enum # order is important!
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,14 @@ proc IITablePut*(t: var TIITable, key, val: int)
|
||||||
|
|
||||||
# implementation
|
# 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 =
|
proc SameValue*(a, b: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
|
||||||
|
|
@ -139,9 +139,9 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
case n.sym.kind
|
case n.sym.kind
|
||||||
of skParam, skForVar, skTemp:
|
of skParam, skTemp:
|
||||||
result = OnStack
|
result = OnStack
|
||||||
of skVar, skResult, skLet:
|
of skVar, skForVar, skResult, skLet:
|
||||||
if sfGlobal in n.sym.flags: result = OnHeap
|
if sfGlobal in n.sym.flags: result = OnHeap
|
||||||
else: result = OnStack
|
else: result = OnStack
|
||||||
of skConst:
|
of skConst:
|
||||||
|
|
@ -1652,7 +1652,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
genComplexConst(p, sym, d)
|
genComplexConst(p, sym, d)
|
||||||
of skEnumField:
|
of skEnumField:
|
||||||
putIntoDest(p, d, e.typ, toRope(sym.position))
|
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 sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||||
if sym.loc.r == nil or sym.loc.t == nil:
|
if sym.loc.r == nil or sym.loc.t == nil:
|
||||||
InternalError(e.info, "expr: var not init " & sym.name.s)
|
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)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
else:
|
else:
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
of skForVar, skTemp:
|
of skTemp:
|
||||||
if sym.loc.r == nil or sym.loc.t == nil:
|
if sym.loc.r == nil or sym.loc.t == nil:
|
||||||
InternalError(e.info, "expr: temp not init " & sym.name.s)
|
InternalError(e.info, "expr: temp not init " & sym.name.s)
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
for i in countup(0, L-3):
|
for i in countup(0, L-3):
|
||||||
var v = n.sons[i].sym
|
var v = n.sons[i].sym
|
||||||
if sfCompileTime in v.flags: continue
|
if sfCompileTime in v.flags: continue
|
||||||
if sfGlobal in v.flags and v.kind != skForVar:
|
if sfGlobal in v.flags:
|
||||||
assignGlobalVar(p, v)
|
assignGlobalVar(p, v)
|
||||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
||||||
else:
|
else:
|
||||||
|
|
@ -49,7 +49,7 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||||
var v = a.sons[0].sym
|
var v = a.sons[0].sym
|
||||||
if sfCompileTime in v.flags: return
|
if sfCompileTime in v.flags: return
|
||||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
var immediateAsgn = a.sons[2].kind != nkEmpty
|
||||||
if sfGlobal in v.flags and v.kind != skForVar:
|
if sfGlobal in v.flags:
|
||||||
assignGlobalVar(p, v)
|
assignGlobalVar(p, v)
|
||||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
||||||
else:
|
else:
|
||||||
|
|
@ -725,7 +725,10 @@ proc genStmts(p: BProc, t: PNode) =
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
initLocExpr(p, t, a)
|
initLocExpr(p, t, a)
|
||||||
of nkAsgn: genAsgn(p, t, fastAsgn=false)
|
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:
|
of nkDiscardStmt:
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
initLocExpr(p, t.sons[0], a)
|
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])
|
genTraverseProc(c, accessor.parentObj, typ.sons[i])
|
||||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
|
let typ = GetUniqueType(typ)
|
||||||
if typ.n != nil:
|
if typ.n != nil:
|
||||||
genTraverseProc(c, accessor, typ.n)
|
genTraverseProc(c, accessor, typ.n)
|
||||||
else:
|
else:
|
||||||
|
|
@ -110,7 +111,11 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
|
||||||
if typ.kind == tySequence:
|
if typ.kind == tySequence:
|
||||||
genTraverseProcSeq(c, "a".toRope, typ)
|
genTraverseProcSeq(c, "a".toRope, typ)
|
||||||
else:
|
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",
|
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
||||||
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
|
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,10 @@ proc mangleName(s: PSym): PRope =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skMethod, skConverter, skConst:
|
of skProc, skMethod, skConverter, skConst:
|
||||||
result = toRope("@")
|
result = toRope("@")
|
||||||
of skVar, skResult, skLet:
|
of skVar, skForVar, skResult, skLet:
|
||||||
if sfGlobal in s.flags: result = toRope("@")
|
if sfGlobal in s.flags: result = toRope("@")
|
||||||
else: result = toRope("%")
|
else: result = toRope("%")
|
||||||
of skForVar, skTemp, skParam, skType, skEnumField, skModule:
|
of skTemp, skParam, skType, skEnumField, skModule:
|
||||||
result = toRope("%")
|
result = toRope("%")
|
||||||
else: InternalError(s.info, "mangleName")
|
else: InternalError(s.info, "mangleName")
|
||||||
app(result, toRope(mangle(s.name.s)))
|
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" &
|
PosixCMain = "int main(int argc, char** args, char** env) {$n" &
|
||||||
" cmdLine = args;$n" & " cmdCount = argc;$n" & " gEnv = env;$n" &
|
" cmdLine = args;$n" & " cmdCount = argc;$n" & " gEnv = env;$n" &
|
||||||
" NimMain();$n" & " return nim_program_result;$n" & "}$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" &
|
WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
|
||||||
CommonMainBody & "}$n"
|
CommonMainBody & "}$n"
|
||||||
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
|
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
|
||||||
|
|
@ -808,6 +811,9 @@ proc genMainProc(m: BModule) =
|
||||||
elif optGenDynLib in gGlobalOptions:
|
elif optGenDynLib in gGlobalOptions:
|
||||||
nimMain = posixNimDllMain
|
nimMain = posixNimDllMain
|
||||||
otherMain = posixCDllMain
|
otherMain = posixCDllMain
|
||||||
|
elif platform.targetOS == osStandalone:
|
||||||
|
nimMain = PosixNimMain
|
||||||
|
otherMain = StandaloneCMain
|
||||||
else:
|
else:
|
||||||
nimMain = PosixNimMain
|
nimMain = PosixNimMain
|
||||||
otherMain = PosixCMain
|
otherMain = PosixCMain
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ type
|
||||||
cfsDynLibInit, # section for init of dynamic library binding
|
cfsDynLibInit, # section for init of dynamic library binding
|
||||||
cfsDynLibDeinit # section for deinitialization of dynamic
|
cfsDynLibDeinit # section for deinitialization of dynamic
|
||||||
# libraries
|
# 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,
|
ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||||
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64,
|
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64,
|
||||||
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
|
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,7 @@
|
||||||
# included from transf.nim
|
# included from transf.nim
|
||||||
|
|
||||||
const
|
const
|
||||||
declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef,
|
declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||||
nkConverterDef}
|
|
||||||
procDefs = nkLambdaKinds + declarativeDefs
|
procDefs = nkLambdaKinds + declarativeDefs
|
||||||
|
|
||||||
proc indirectAccess(a, b: PSym, info: TLineInfo): PNode =
|
proc indirectAccess(a, b: PSym, info: TLineInfo): PNode =
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ type
|
||||||
# conditionals to condsyms (end of module).
|
# conditionals to condsyms (end of module).
|
||||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
|
osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
|
||||||
osAtari, osNetware, osMacos, osMacosx, osEcmaScript, osNimrodVM
|
osAtari, osNetware, osMacos, osMacosx, osEcmaScript, osNimrodVM,
|
||||||
|
osStandalone
|
||||||
|
|
||||||
type
|
type
|
||||||
TInfoOSProp* = enum
|
TInfoOSProp* = enum
|
||||||
|
|
@ -139,14 +140,18 @@ const
|
||||||
exeExt: "", extSep: ".", props: {}),
|
exeExt: "", extSep: ".", props: {}),
|
||||||
(name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
(name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
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
|
type
|
||||||
TSystemCPU* = enum # Also add CPU for in initialization section and
|
TSystemCPU* = enum # Also add CPU for in initialization section and
|
||||||
# alias conditionals to condsyms (end of module).
|
# alias conditionals to condsyms (end of module).
|
||||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||||
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
|
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
|
||||||
cpuEcmaScript, cpuNimrodVM
|
cpuEcmaScript, cpuNimrodVM, cpuAVR
|
||||||
|
|
||||||
type
|
type
|
||||||
TEndian* = enum
|
TEndian* = enum
|
||||||
|
|
@ -169,7 +174,8 @@ const
|
||||||
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||||
(name: "arm", intSize: 32, endian: littleEndian, 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: "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
|
var
|
||||||
targetCPU*, hostCPU*: TSystemCPU
|
targetCPU*, hostCPU*: TSystemCPU
|
||||||
|
|
|
||||||
|
|
@ -535,7 +535,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
|
||||||
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
var
|
var
|
||||||
w: string
|
w: string
|
||||||
d, L, inclCrc: int
|
d, inclCrc: int
|
||||||
while r.s[r.pos] != '\0':
|
while r.s[r.pos] != '\0':
|
||||||
var section = rdWord(r)
|
var section = rdWord(r)
|
||||||
if r.reason != rrNone:
|
if r.reason != rrNone:
|
||||||
|
|
@ -573,20 +573,17 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
of "FILES":
|
of "FILES":
|
||||||
inc(r.pos, 2) # skip "(\10"
|
inc(r.pos, 2) # skip "(\10"
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
L = 0
|
while r.s[r.pos] != ')':
|
||||||
while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')':
|
|
||||||
setlen(r.files, L + 1)
|
|
||||||
var relativePath = decodeStr(r.s, r.pos)
|
var relativePath = decodeStr(r.s, r.pos)
|
||||||
var resolvedPath = relativePath.findModule
|
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.pos) # skip #10
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
inc(L)
|
|
||||||
if r.s[r.pos] == ')': inc(r.pos)
|
if r.s[r.pos] == ')': inc(r.pos)
|
||||||
of "INCLUDES":
|
of "INCLUDES":
|
||||||
inc(r.pos, 2) # skip "(\10"
|
inc(r.pos, 2) # skip "(\10"
|
||||||
inc(r.line)
|
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)]
|
w = r.files[decodeVInt(r.s, r.pos)]
|
||||||
inc(r.pos) # skip ' '
|
inc(r.pos) # skip ' '
|
||||||
inclCrc = decodeVInt(r.s, r.pos)
|
inclCrc = decodeVInt(r.s, r.pos)
|
||||||
|
|
@ -599,11 +596,8 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
if r.s[r.pos] == ')': inc(r.pos)
|
if r.s[r.pos] == ')': inc(r.pos)
|
||||||
of "DEPS":
|
of "DEPS":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
L = 0
|
|
||||||
while r.s[r.pos] > '\x0A':
|
while r.s[r.pos] > '\x0A':
|
||||||
setlen(r.modDeps, L + 1)
|
r.modDeps.add r.files[decodeVInt(r.s, r.pos)]
|
||||||
r.modDeps[L] = r.files[decodeVInt(r.s, r.pos)]
|
|
||||||
inc(L)
|
|
||||||
if r.s[r.pos] == ' ': inc(r.pos)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
of "INTERF":
|
of "INTERF":
|
||||||
r.interfIdx = r.pos + 2
|
r.interfIdx = r.pos + 2
|
||||||
|
|
@ -630,8 +624,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
r.initIdx = r.pos + 2 # "(\10"
|
r.initIdx = r.pos + 2 # "(\10"
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
else:
|
else:
|
||||||
MsgWriteln("skipping section: " & section &
|
InternalError("invalid section: '" & section &
|
||||||
" at " & $r.pos & " in " & r.filename)
|
"' at " & $r.line & " in " & r.filename)
|
||||||
|
#MsgWriteln("skipping section: " & section &
|
||||||
|
# " at " & $r.line & " in " & r.filename)
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
if r.s[r.pos] == '\x0A':
|
if r.s[r.pos] == '\x0A':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = newStrNode(nkStrLit, content)
|
result = newStrNode(nkStrLit, content)
|
||||||
result.typ = getSysType(tyString)
|
result.typ = getSysType(tyString)
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
c.slurpedFiles.add(filename)
|
c.slurpedFiles.add(a.strVal)
|
||||||
except EIO:
|
except EIO:
|
||||||
GlobalError(a.info, errCannotOpenFile, a.strVal)
|
GlobalError(a.info, errCannotOpenFile, a.strVal)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,14 +107,14 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
|
||||||
result = c.mapping[v.id]
|
result = c.mapping[v.id]
|
||||||
if result != toUndefined: return
|
if result != toUndefined: return
|
||||||
case v.kind
|
case v.kind
|
||||||
of skVar, skLet, skResult:
|
of skVar, skForVar, skLet, skResult:
|
||||||
result = toNil
|
result = toNil
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
if sfThread in v.flags:
|
if sfThread in v.flags:
|
||||||
result = toMine
|
result = toMine
|
||||||
elif containsGarbageCollectedRef(v.typ):
|
elif containsGarbageCollectedRef(v.typ):
|
||||||
result = toTheirs
|
result = toTheirs
|
||||||
of skTemp, skForVar: result = toNil
|
of skTemp: result = toNil
|
||||||
of skConst: result = toMine
|
of skConst: result = toMine
|
||||||
of skParam:
|
of skParam:
|
||||||
result = c.mapping[v.id]
|
result = c.mapping[v.id]
|
||||||
|
|
|
||||||
|
|
@ -251,43 +251,38 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
result = semIdentVis(c, kind, n, allowed)
|
result = semIdentVis(c, kind, n, allowed)
|
||||||
|
|
||||||
proc checkForOverlap(c: PContext, t, ex: PNode, branchIndex: int) =
|
proc checkForOverlap(c: PContext, t, ex: PNode, branchIndex: int) =
|
||||||
|
let ex = ex.skipConv
|
||||||
for i in countup(1, branchIndex - 1):
|
for i in countup(1, branchIndex - 1):
|
||||||
for j in countup(0, sonsLen(t.sons[i]) - 2):
|
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)
|
LocalError(ex.info, errDuplicateCaseLabel)
|
||||||
|
|
||||||
proc semBranchExpr(c: PContext, t, e: PNode): PNode =
|
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var biggestInt): PNode =
|
||||||
result = semConstExpr(c, e)
|
|
||||||
checkMinSonsLen(t, 1)
|
checkMinSonsLen(t, 1)
|
||||||
result = fitNode(c, t.sons[0].typ, result)
|
let ac = semConstExpr(c, a)
|
||||||
#if cmpTypes(t.sons[0].typ, result.typ) <= isConvertible:
|
let bc = semConstExpr(c, b)
|
||||||
# typeMismatch(result, t.sons[0].typ, result.typ)
|
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,
|
proc SemCaseBranchRange(c: PContext, t, b: PNode,
|
||||||
covered: var biggestInt): PNode =
|
covered: var biggestInt): PNode =
|
||||||
checkSonsLen(b, 3)
|
checkSonsLen(b, 3)
|
||||||
result = newNodeI(nkRange, b.info)
|
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||||
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
|
|
||||||
|
|
||||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||||
covered: var biggestInt): PNode =
|
covered: var biggestInt): PNode =
|
||||||
if isRange(b):
|
if isRange(b):
|
||||||
checkSonsLen(b, 3)
|
checkSonsLen(b, 3)
|
||||||
result = newNodeI(nkRange, b.info)
|
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||||
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
|
|
||||||
elif b.kind == nkRange:
|
elif b.kind == nkRange:
|
||||||
checkSonsLen(b, 2)
|
checkSonsLen(b, 2)
|
||||||
result = newNodeI(nkRange, b.info)
|
result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
|
||||||
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
|
|
||||||
else:
|
else:
|
||||||
result = fitNode(c, t.sons[0].typ, b)
|
result = fitNode(c, t.sons[0].typ, b)
|
||||||
inc(covered)
|
inc(covered)
|
||||||
|
|
|
||||||
|
|
@ -268,14 +268,6 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
else:
|
else:
|
||||||
result = transform(c, n)
|
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 =
|
proc newTupleAccess(tup: PNode, i: int): PNode =
|
||||||
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i])
|
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i])
|
||||||
addSon(result, copyTree(tup))
|
addSon(result, copyTree(tup))
|
||||||
|
|
|
||||||
|
|
@ -869,9 +869,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
of tyArray:
|
of tyArray:
|
||||||
result = t.sons[1].kind == tyEmpty or
|
result = t.sons[1].kind == tyEmpty or
|
||||||
typeAllowedAux(marker, t.sons[1], skVar)
|
typeAllowedAux(marker, t.sons[1], skVar)
|
||||||
of tyPtr, tyRef:
|
of tyRef:
|
||||||
if kind == skConst: return false
|
if kind == skConst: return false
|
||||||
result = typeAllowedAux(marker, t.sons[0], skVar)
|
result = typeAllowedAux(marker, t.sons[0], skVar)
|
||||||
|
of tyPtr:
|
||||||
|
result = typeAllowedAux(marker, t.sons[0], skVar)
|
||||||
of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter, tyProxy:
|
of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter, tyProxy:
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], kind)
|
result = typeAllowedAux(marker, t.sons[i], kind)
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,10 @@ XML Processing
|
||||||
* `htmlparser <htmlparser.html>`_
|
* `htmlparser <htmlparser.html>`_
|
||||||
This module parses an HTML document and creates its XML tree representation.
|
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
|
Cryptography and Hashing
|
||||||
------------------------
|
------------------------
|
||||||
|
|
|
||||||
2
koch.nim
2
koch.nim
|
|
@ -141,7 +141,7 @@ proc boot(args: string) =
|
||||||
return
|
return
|
||||||
copyExe(output, (i+1).thVersion)
|
copyExe(output, (i+1).thVersion)
|
||||||
copyExe(output, finalDest)
|
copyExe(output, finalDest)
|
||||||
echo "[Warning] executables are still not equal"
|
when not defined(windows): echo "[Warning] executables are still not equal"
|
||||||
|
|
||||||
# -------------- clean --------------------------------------------------------
|
# -------------- clean --------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,8 @@ proc parseMessage(msg: string): TIRCEvent =
|
||||||
inc(i) # Skip `:`
|
inc(i) # Skip `:`
|
||||||
var nick = ""
|
var nick = ""
|
||||||
i.inc msg.parseUntil(nick, {'!', ' '}, i)
|
i.inc msg.parseUntil(nick, {'!', ' '}, i)
|
||||||
|
result.nick = ""
|
||||||
|
result.serverName = ""
|
||||||
if msg[i] == '!':
|
if msg[i] == '!':
|
||||||
result.nick = nick
|
result.nick = nick
|
||||||
inc(i) # Skip `!`
|
inc(i) # Skip `!`
|
||||||
|
|
@ -237,7 +239,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent =
|
||||||
result = parseMessage(line)
|
result = parseMessage(line)
|
||||||
# Get the origin
|
# Get the origin
|
||||||
result.origin = result.params[0]
|
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:
|
if result.cmd == MError:
|
||||||
irc.close()
|
irc.close()
|
||||||
|
|
@ -386,6 +389,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
|
||||||
result.messageBuffer = @[]
|
result.messageBuffer = @[]
|
||||||
result.handleEvent = ircEvent
|
result.handleEvent = ircEvent
|
||||||
result.userArg = userArg
|
result.userArg = userArg
|
||||||
|
result.lineBuffer = ""
|
||||||
|
|
||||||
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
||||||
## Registers ``irc`` with dispatcher ``d``.
|
## Registers ``irc`` with dispatcher ``d``.
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,12 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a simple portable type-safe sockets layer.
|
## This module implements a simple portable type-safe sockets layer.
|
||||||
|
##
|
||||||
|
## Most procedures raise EOS on error.
|
||||||
|
|
||||||
|
|
||||||
import os, parseutils
|
import os, parseutils
|
||||||
|
from times import epochTime
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
import winlean
|
import winlean
|
||||||
|
|
@ -59,6 +63,8 @@ type
|
||||||
TRecvLineResult* = enum ## result for recvLineAsync
|
TRecvLineResult* = enum ## result for recvLineAsync
|
||||||
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
||||||
|
|
||||||
|
ETimeout* = object of ESynch
|
||||||
|
|
||||||
const
|
const
|
||||||
InvalidSocket* = TSocket(-1'i32) ## invalid socket number
|
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
|
## 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
|
## of that host name. ``htons`` is already performed on ``port`` so you must
|
||||||
## not do it.
|
## not do it.
|
||||||
|
|
||||||
var hints: TAddrInfo
|
var hints: TAddrInfo
|
||||||
var aiList: ptr TAddrInfo = nil
|
var aiList: ptr TAddrInfo = nil
|
||||||
hints.ai_family = toInt(af)
|
hints.ai_family = toInt(af)
|
||||||
hints.ai_socktype = toInt(SOCK_STREAM)
|
hints.ai_socktype = toInt(SOCK_STREAM)
|
||||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||||
gaiNim(name, port, hints, aiList)
|
gaiNim(name, port, hints, aiList)
|
||||||
|
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var it = aiList
|
var it = aiList
|
||||||
|
|
@ -445,7 +453,6 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError()
|
||||||
|
|
||||||
|
|
||||||
proc timeValFromMilliseconds(timeout = 500): TTimeVal =
|
proc timeValFromMilliseconds(timeout = 500): TTimeVal =
|
||||||
if timeout != -1:
|
if timeout != -1:
|
||||||
var seconds = timeout div 1000
|
var seconds = timeout div 1000
|
||||||
|
|
@ -546,6 +553,32 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
|
||||||
|
|
||||||
pruneSocketSet(readfds, (rd))
|
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 =
|
proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||||
## returns false if no further data is available. `Line` must be initialized
|
## 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
|
elif c == '\L': return true
|
||||||
add(line.string, c)
|
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 =
|
proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||||
## similar to ``recvLine`` but for non-blocking sockets.
|
## similar to ``recvLine`` but for non-blocking sockets.
|
||||||
## The values of the returned enum should be pretty self explanatory:
|
## 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
|
elif c == '\L': return RecvFullLine
|
||||||
add(line.string, c)
|
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 =
|
proc recv*(socket: TSocket): TaintedString =
|
||||||
## receives all the data from the socket.
|
## receives all the data from the socket.
|
||||||
## Socket errors will result in an ``EOS`` error.
|
## Socket errors will result in an ``EOS`` error.
|
||||||
|
|
@ -625,6 +677,16 @@ proc recv*(socket: TSocket): TaintedString =
|
||||||
add(result.string, buf)
|
add(result.string, buf)
|
||||||
if bytesRead != bufSize-1: break
|
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 =
|
proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
|
||||||
## receives all the data from a non-blocking socket. If socket is non-blocking
|
## receives all the data from a non-blocking socket. If socket is non-blocking
|
||||||
## and there are no messages available, `False` will be returned.
|
## 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:
|
if fcntl(cint(s), F_SETFL, mode) == -1:
|
||||||
OSError()
|
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):
|
when defined(Windows):
|
||||||
var wsa: TWSADATA
|
var wsa: TWSADATA
|
||||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
||||||
|
|
|
||||||
|
|
@ -851,7 +851,7 @@ template sysAssert(cond: bool, msg: string) =
|
||||||
|
|
||||||
include "system/inclrtl"
|
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"
|
include "system/cgprocs"
|
||||||
|
|
||||||
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
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.}
|
{.push stack_trace: off.}
|
||||||
|
|
||||||
proc initGC()
|
proc initGC()
|
||||||
when not defined(boehmgc):
|
when not defined(boehmgc) and not defined(useMalloc):
|
||||||
proc initAllocator() {.inline.}
|
proc initAllocator() {.inline.}
|
||||||
|
|
||||||
proc initStackBottom() {.inline.} =
|
when not defined(nogc):
|
||||||
# WARNING: This is very fragile! An array size of 8 does not work on my
|
proc initStackBottom() {.inline.} =
|
||||||
# Linux 64bit system. Very strange, but we are at the will of GCC's
|
# WARNING: This is very fragile! An array size of 8 does not work on my
|
||||||
# optimizer...
|
# Linux 64bit system. Very strange, but we are at the will of GCC's
|
||||||
var locals {.volatile.}: pointer
|
# optimizer...
|
||||||
locals = addr(locals)
|
var locals {.volatile.}: pointer
|
||||||
setStackBottom(locals)
|
locals = addr(locals)
|
||||||
|
setStackBottom(locals)
|
||||||
|
|
||||||
var
|
var
|
||||||
strDesc: TNimType
|
strDesc: TNimType
|
||||||
|
|
@ -1868,7 +1869,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
include "system/syslocks"
|
include "system/syslocks"
|
||||||
include "system/threads"
|
include "system/threads"
|
||||||
else:
|
elif not defined(nogc):
|
||||||
initStackBottom()
|
initStackBottom()
|
||||||
initGC()
|
initGC()
|
||||||
|
|
||||||
|
|
@ -1881,21 +1882,23 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
## for debug builds.
|
## for debug builds.
|
||||||
|
|
||||||
{.push stack_trace: off.}
|
{.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
|
# we cannot compile this with stack tracing on
|
||||||
# as it would recurse endlessly!
|
# as it would recurse endlessly!
|
||||||
include "system/arithm"
|
include "system/arithm"
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
|
|
||||||
include "system/dyncalls"
|
when hostOS != "standalone": include "system/dyncalls"
|
||||||
include "system/sets"
|
include "system/sets"
|
||||||
|
|
||||||
const
|
const
|
||||||
GenericSeqSize = (2 * sizeof(int))
|
GenericSeqSize = (2 * sizeof(int))
|
||||||
|
|
||||||
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
|
|
||||||
|
|
||||||
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
|
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
|
||||||
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
||||||
var d: int
|
var d: int
|
||||||
|
|
@ -1918,7 +1921,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
|
|
||||||
include "system/mmdisp"
|
include "system/mmdisp"
|
||||||
{.push stack_trace: off.}
|
{.push stack_trace: off.}
|
||||||
include "system/sysstr"
|
when hostCPU != "avr": include "system/sysstr"
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
include "system/sysio"
|
include "system/sysio"
|
||||||
|
|
@ -1938,18 +1941,19 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
var res = TaintedString(newStringOfCap(80))
|
var res = TaintedString(newStringOfCap(80))
|
||||||
while f.readLine(res): yield TaintedString(res)
|
while f.readLine(res): yield TaintedString(res)
|
||||||
|
|
||||||
include "system/assign"
|
when hostCPU != "avr":
|
||||||
include "system/repr"
|
include "system/assign"
|
||||||
|
include "system/repr"
|
||||||
|
|
||||||
proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
|
proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
|
||||||
## retrieves the current exception; if there is none, nil is returned.
|
## retrieves the current exception; if there is none, nil is returned.
|
||||||
result = currException
|
result = currException
|
||||||
|
|
||||||
proc getCurrentExceptionMsg*(): string {.inline.} =
|
proc getCurrentExceptionMsg*(): string {.inline.} =
|
||||||
## retrieves the error message that was attached to the current
|
## retrieves the error message that was attached to the current
|
||||||
## exception; if there is none, "" is returned.
|
## exception; if there is none, "" is returned.
|
||||||
var e = getCurrentException()
|
var e = getCurrentException()
|
||||||
return if e == nil: "" else: e.msg
|
return if e == nil: "" else: e.msg
|
||||||
|
|
||||||
{.push stack_trace: off.}
|
{.push stack_trace: off.}
|
||||||
when defined(endb):
|
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.}
|
proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.}
|
||||||
|
|
||||||
{.pop}
|
{.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) =
|
proc writeToStdErr(msg: CString) =
|
||||||
discard MessageBoxA(0, msg, nil, 0)
|
discard MessageBoxA(0, msg, nil, 0)
|
||||||
|
|
||||||
proc registerSignalHandler() {.compilerproc.}
|
proc registerSignalHandler()
|
||||||
|
|
||||||
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||||
proc chckRange(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
|
proc deallocOsPages() {.inline.} = nil
|
||||||
|
|
||||||
include "system/cellsets"
|
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):
|
elif defined(nogc):
|
||||||
# Even though we don't want the GC, we cannot simply use C's memory manager
|
# 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
|
# 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.
|
# 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 reprInt(x: int64): string {.compilerproc.} = return $x
|
||||||
proc reprFloat(x: float): 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 """
|
discard """
|
||||||
file: "t99bott.nim"
|
file: "t99bott.nim"
|
||||||
line: 26
|
line: 26
|
||||||
errormsg: "cannot evaluate 'GetBottleNumber(bn)'"
|
errormsg: "constant expression expected"
|
||||||
disabled: false
|
disabled: false
|
||||||
"""
|
"""
|
||||||
## 99 Bottles of Beer
|
## 99 Bottles of Beer
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 7
|
line: 7
|
||||||
errormsg: "a type has no value"
|
errormsg: "type mismatch"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type a = enum b,c,d
|
type a = enum b,c,d
|
||||||
|
|
|
||||||
5
todo.txt
5
todo.txt
|
|
@ -1,7 +1,7 @@
|
||||||
version 0.9.0
|
version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- bootstrapping fails with --symbolFiles:on again!
|
- make GC realtime capable: GC_step(ms: int)
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``
|
- ``=`` should be overloadable; requires specialization for ``=``
|
||||||
- fix remaining generics bugs
|
- fix remaining generics bugs
|
||||||
- fix remaining closure bugs:
|
- fix remaining closure bugs:
|
||||||
|
|
@ -49,6 +49,8 @@ Bugs
|
||||||
without ``-d:release`` leaks memory?
|
without ``-d:release`` leaks memory?
|
||||||
- bug: object {.pure, final.} does not work again!
|
- bug: object {.pure, final.} does not work again!
|
||||||
- bug: tsortdev does not run with native GC?
|
- 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
|
version 0.9.XX
|
||||||
|
|
@ -98,6 +100,7 @@ version 0.9.XX
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- provide more up to date OpenGL headers
|
||||||
- wrappers for mongodb; poppler; libharu
|
- wrappers for mongodb; poppler; libharu
|
||||||
- suffix trees
|
- suffix trees
|
||||||
- locale support; i18n module
|
- locale support; i18n module
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ priority).
|
||||||
Nimrod is efficient
|
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
|
virtual machine: **Nimrod produces small executables without dependencies
|
||||||
for easy redistribution.**
|
for easy redistribution.**
|
||||||
* A fast non-recursive incremental and generational garbage collector that
|
* A fast **non-tracing** garbage collector that should be well suited for soft
|
||||||
should be well suited for soft real-time systems (like games).
|
real-time systems (like games).
|
||||||
* System programming features: Ability to manage your own memory and access the
|
* System programming features: Ability to manage your own memory and access the
|
||||||
hardware directly. Pointers to garbage collected memory are distinguished
|
hardware directly. Pointers to garbage collected memory are distinguished
|
||||||
from pointers to manually managed memory.
|
from pointers to manually managed memory.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ Bugfixes
|
||||||
Library Additions
|
Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Added the (already existing) module ``htmlgen`` to the documentation.
|
||||||
- Added ``system.shallow`` that can be used to speed up string and sequence
|
- Added ``system.shallow`` that can be used to speed up string and sequence
|
||||||
assignments.
|
assignments.
|
||||||
- Added ``system.eval`` that can execute an anonymous block of code at
|
- Added ``system.eval`` that can execute an anonymous block of code at
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue