improvements to get code size down for programs that don't use GC
This commit is contained in:
parent
c9d21164be
commit
e25384db89
18 changed files with 642 additions and 181 deletions
|
|
@ -1451,6 +1451,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
mInSet:
|
mInSet:
|
||||||
genSetOp(p, e, d, op)
|
genSetOp(p, e, d, op)
|
||||||
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, mCreateThread:
|
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, mCreateThread:
|
||||||
|
var opr = e.sons[0].sym
|
||||||
|
if lfNoDecl notin opr.loc.flags:
|
||||||
|
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
||||||
genCall(p, e, d)
|
genCall(p, e, d)
|
||||||
of mReset: genReset(p, e)
|
of mReset: genReset(p, e)
|
||||||
of mEcho: genEcho(p, e)
|
of mEcho: genEcho(p, e)
|
||||||
|
|
|
||||||
|
|
@ -203,8 +203,6 @@ if [ $# -eq 1 ] ; then
|
||||||
chmod 644 $libdir/system/threads.nim
|
chmod 644 $libdir/system/threads.nim
|
||||||
cp lib/core/macros.nim $libdir/core/macros.nim || exit 1
|
cp lib/core/macros.nim $libdir/core/macros.nim || exit 1
|
||||||
chmod 644 $libdir/core/macros.nim
|
chmod 644 $libdir/core/macros.nim
|
||||||
cp lib/core/marshal.nim $libdir/core/marshal.nim || exit 1
|
|
||||||
chmod 644 $libdir/core/marshal.nim
|
|
||||||
cp lib/core/typeinfo.nim $libdir/core/typeinfo.nim || exit 1
|
cp lib/core/typeinfo.nim $libdir/core/typeinfo.nim || exit 1
|
||||||
chmod 644 $libdir/core/typeinfo.nim
|
chmod 644 $libdir/core/typeinfo.nim
|
||||||
cp lib/pure/algorithm.nim $libdir/pure/algorithm.nim || exit 1
|
cp lib/pure/algorithm.nim $libdir/pure/algorithm.nim || exit 1
|
||||||
|
|
@ -241,6 +239,8 @@ if [ $# -eq 1 ] ; then
|
||||||
chmod 644 $libdir/pure/lexbase.nim
|
chmod 644 $libdir/pure/lexbase.nim
|
||||||
cp lib/pure/logging.nim $libdir/pure/logging.nim || exit 1
|
cp lib/pure/logging.nim $libdir/pure/logging.nim || exit 1
|
||||||
chmod 644 $libdir/pure/logging.nim
|
chmod 644 $libdir/pure/logging.nim
|
||||||
|
cp lib/pure/marshal.nim $libdir/pure/marshal.nim || exit 1
|
||||||
|
chmod 644 $libdir/pure/marshal.nim
|
||||||
cp lib/pure/math.nim $libdir/pure/math.nim || exit 1
|
cp lib/pure/math.nim $libdir/pure/math.nim || exit 1
|
||||||
chmod 644 $libdir/pure/math.nim
|
chmod 644 $libdir/pure/math.nim
|
||||||
cp lib/pure/md5.nim $libdir/pure/md5.nim || exit 1
|
cp lib/pure/md5.nim $libdir/pure/md5.nim || exit 1
|
||||||
|
|
|
||||||
|
|
@ -1387,7 +1387,7 @@ const nimrodStackTrace = compileOption("stacktrace")
|
||||||
# of the code
|
# of the code
|
||||||
|
|
||||||
var
|
var
|
||||||
dbgLineHook*: proc = nil
|
dbgLineHook*: proc
|
||||||
## set this variable to provide a procedure that should be called before
|
## set this variable to provide a procedure that should be called before
|
||||||
## each executed instruction. This should only be used by debuggers!
|
## each executed instruction. This should only be used by debuggers!
|
||||||
## Only code compiled with the ``debugger:on`` switch calls this hook.
|
## Only code compiled with the ``debugger:on`` switch calls this hook.
|
||||||
|
|
@ -1397,6 +1397,25 @@ var
|
||||||
## application code should never set this hook! You better know what you
|
## application code should never set this hook! You better know what you
|
||||||
## do when setting this. If ``raiseHook`` returns false, the exception
|
## do when setting this. If ``raiseHook`` returns false, the exception
|
||||||
## is caught and does not propagate further through the call stack.
|
## is caught and does not propagate further through the call stack.
|
||||||
|
|
||||||
|
outOfMemHook*: proc
|
||||||
|
## set this variable to provide a procedure that should be called
|
||||||
|
## in case of an `out of memory`:idx: event. The standard handler
|
||||||
|
## writes an error message and terminates the program. `outOfMemHook` can
|
||||||
|
## be used to raise an exception in case of OOM like so:
|
||||||
|
##
|
||||||
|
## code-block:: nimrod
|
||||||
|
## var gOutOfMem: ref EOutOfMemory
|
||||||
|
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
|
||||||
|
## gOutOfMem.msg = "out of memory"
|
||||||
|
##
|
||||||
|
## proc handleOOM() =
|
||||||
|
## raise gOutOfMem
|
||||||
|
##
|
||||||
|
## system.outOfMemHook = handleOOM
|
||||||
|
##
|
||||||
|
## If the handler does not raise an exception, ordinary control flow
|
||||||
|
## continues and the program is terminated.
|
||||||
|
|
||||||
type
|
type
|
||||||
PFrame = ptr TFrame
|
PFrame = ptr TFrame
|
||||||
|
|
@ -1710,25 +1729,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
# as it would recurse endlessly!
|
# as it would recurse endlessly!
|
||||||
include "system/arithm"
|
include "system/arithm"
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
|
|
||||||
include "system/sysio"
|
|
||||||
|
|
||||||
iterator lines*(filename: string): string =
|
|
||||||
## Iterate over any line in the file named `filename`.
|
|
||||||
## If the file does not exist `EIO` is raised.
|
|
||||||
var f = open(filename)
|
|
||||||
var res = ""
|
|
||||||
while not endOfFile(f):
|
|
||||||
rawReadLine(f, res)
|
|
||||||
yield res
|
|
||||||
Close(f)
|
|
||||||
|
|
||||||
iterator lines*(f: TFile): string =
|
|
||||||
## Iterate over any line in the file `f`.
|
|
||||||
var res = ""
|
|
||||||
while not endOfFile(f):
|
|
||||||
rawReadLine(f, res)
|
|
||||||
yield res
|
|
||||||
|
|
||||||
include "system/dyncalls"
|
include "system/dyncalls"
|
||||||
include "system/sets"
|
include "system/sets"
|
||||||
|
|
@ -1763,6 +1763,25 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
include "system/sysstr"
|
include "system/sysstr"
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
include "system/sysio"
|
||||||
|
|
||||||
|
iterator lines*(filename: string): string =
|
||||||
|
## Iterate over any line in the file named `filename`.
|
||||||
|
## If the file does not exist `EIO` is raised.
|
||||||
|
var f = open(filename)
|
||||||
|
var res = ""
|
||||||
|
while not endOfFile(f):
|
||||||
|
rawReadLine(f, res)
|
||||||
|
yield res
|
||||||
|
Close(f)
|
||||||
|
|
||||||
|
iterator lines*(f: TFile): string =
|
||||||
|
## Iterate over any line in the file `f`.
|
||||||
|
var res = ""
|
||||||
|
while not endOfFile(f):
|
||||||
|
rawReadLine(f, res)
|
||||||
|
yield res
|
||||||
|
|
||||||
include "system/assign"
|
include "system/assign"
|
||||||
include "system/repr"
|
include "system/repr"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2009 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -138,10 +138,8 @@ proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
|
||||||
write(stdout, "*** endb| (procedure name not available) ***\n")
|
write(stdout, "*** endb| (procedure name not available) ***\n")
|
||||||
|
|
||||||
proc dbgShowExecutionPoint() =
|
proc dbgShowExecutionPoint() =
|
||||||
ThreadGlobals()
|
write(stdout, "*** endb| " & $framePtr.filename &
|
||||||
write(stdout, "*** endb| " & $(||framePtr).filename &
|
"(" & $framePtr.line & ") " & $framePtr.procname & " ***\n")
|
||||||
"(" & $(||framePtr).line & ") " &
|
|
||||||
$(||framePtr).procname & " ***\n")
|
|
||||||
|
|
||||||
when defined(windows) or defined(dos) or defined(os2):
|
when defined(windows) or defined(dos) or defined(os2):
|
||||||
{.define: FileSystemCaseInsensitive.}
|
{.define: FileSystemCaseInsensitive.}
|
||||||
|
|
@ -172,10 +170,9 @@ proc fileMatches(c, bp: cstring): bool =
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc dbgBreakpointReached(line: int): int =
|
proc dbgBreakpointReached(line: int): int =
|
||||||
ThreadGlobals()
|
|
||||||
for i in 0..dbgBPlen-1:
|
for i in 0..dbgBPlen-1:
|
||||||
if line >= dbgBP[i].low and line <= dbgBP[i].high and
|
if line >= dbgBP[i].low and line <= dbgBP[i].high and
|
||||||
fileMatches((||framePtr).filename, dbgBP[i].filename): return i
|
fileMatches(framePtr.filename, dbgBP[i].filename): return i
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
proc scanAndAppendWord(src: string, a: var string, start: int): int =
|
proc scanAndAppendWord(src: string, a: var string, start: int): int =
|
||||||
|
|
@ -257,7 +254,6 @@ proc hasExt(s: string): bool =
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc setBreakPoint(s: string, start: int) =
|
proc setBreakPoint(s: string, start: int) =
|
||||||
ThreadGlobals()
|
|
||||||
var dbgTemp: string
|
var dbgTemp: string
|
||||||
var i = scanWord(s, dbgTemp, start)
|
var i = scanWord(s, dbgTemp, start)
|
||||||
if i <= start:
|
if i <= start:
|
||||||
|
|
@ -272,7 +268,7 @@ proc setBreakPoint(s: string, start: int) =
|
||||||
i = scanNumber(s, dbgBP[x].low, i)
|
i = scanNumber(s, dbgBP[x].low, i)
|
||||||
if dbgBP[x].low == 0:
|
if dbgBP[x].low == 0:
|
||||||
# set to current line:
|
# set to current line:
|
||||||
dbgBP[x].low = (||framePtr).line
|
dbgBP[x].low = framePtr.line
|
||||||
i = scanNumber(s, dbgBP[x].high, i)
|
i = scanNumber(s, dbgBP[x].high, i)
|
||||||
if dbgBP[x].high == 0: # set to low:
|
if dbgBP[x].high == 0: # set to low:
|
||||||
dbgBP[x].high = dbgBP[x].low
|
dbgBP[x].high = dbgBP[x].low
|
||||||
|
|
@ -281,7 +277,7 @@ proc setBreakPoint(s: string, start: int) =
|
||||||
if not hasExt(dbgTemp): add(dbgTemp, ".nim")
|
if not hasExt(dbgTemp): add(dbgTemp, ".nim")
|
||||||
dbgBP[x].filename = dbgTemp
|
dbgBP[x].filename = dbgTemp
|
||||||
else: # use current filename
|
else: # use current filename
|
||||||
dbgBP[x].filename = $(||framePtr).filename
|
dbgBP[x].filename = $framePtr.filename
|
||||||
# skip whitespace:
|
# skip whitespace:
|
||||||
while s[i] in {' ', '\t'}: inc(i)
|
while s[i] in {' ', '\t'}: inc(i)
|
||||||
if s[i] != '\0':
|
if s[i] != '\0':
|
||||||
|
|
@ -350,10 +346,9 @@ proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
|
||||||
|
|
||||||
proc CommandPrompt() =
|
proc CommandPrompt() =
|
||||||
# if we return from this routine, user code executes again
|
# if we return from this routine, user code executes again
|
||||||
ThreadGlobals()
|
|
||||||
var
|
var
|
||||||
again = True
|
again = True
|
||||||
dbgFramePtr = ||framePtr # for going down and up the stack
|
dbgFramePtr = framePtr # for going down and up the stack
|
||||||
dbgDown = 0 # how often we did go down
|
dbgDown = 0 # how often we did go down
|
||||||
|
|
||||||
while again:
|
while again:
|
||||||
|
|
@ -370,11 +365,11 @@ proc CommandPrompt() =
|
||||||
again = false
|
again = false
|
||||||
of "n", "next":
|
of "n", "next":
|
||||||
dbgState = dbStepOver
|
dbgState = dbStepOver
|
||||||
dbgSkipToFrame = ||framePtr
|
dbgSkipToFrame = framePtr
|
||||||
again = false
|
again = false
|
||||||
of "f", "skipcurrent":
|
of "f", "skipcurrent":
|
||||||
dbgState = dbSkipCurrent
|
dbgState = dbSkipCurrent
|
||||||
dbgSkipToFrame = (||framePtr).prev
|
dbgSkipToFrame = framePtr.prev
|
||||||
again = false
|
again = false
|
||||||
of "c", "continue":
|
of "c", "continue":
|
||||||
dbgState = dbBreakpoints
|
dbgState = dbBreakpoints
|
||||||
|
|
@ -405,7 +400,7 @@ proc CommandPrompt() =
|
||||||
if dbgDown <= 0:
|
if dbgDown <= 0:
|
||||||
debugOut("[Warning] cannot go up any further ")
|
debugOut("[Warning] cannot go up any further ")
|
||||||
else:
|
else:
|
||||||
dbgFramePtr = ||framePtr
|
dbgFramePtr = framePtr
|
||||||
for j in 0 .. dbgDown-2: # BUGFIX
|
for j in 0 .. dbgDown-2: # BUGFIX
|
||||||
dbgFramePtr = dbgFramePtr.prev
|
dbgFramePtr = dbgFramePtr.prev
|
||||||
dec(dbgDown)
|
dec(dbgDown)
|
||||||
|
|
@ -446,17 +441,16 @@ proc endbStep() =
|
||||||
CommandPrompt()
|
CommandPrompt()
|
||||||
|
|
||||||
proc checkForBreakpoint() =
|
proc checkForBreakpoint() =
|
||||||
ThreadGlobals()
|
var i = dbgBreakpointReached(framePtr.line)
|
||||||
var i = dbgBreakpointReached((||framePtr).line)
|
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
write(stdout, "*** endb| reached ")
|
write(stdout, "*** endb| reached ")
|
||||||
write(stdout, dbgBP[i].name)
|
write(stdout, dbgBP[i].name)
|
||||||
write(stdout, " in ")
|
write(stdout, " in ")
|
||||||
write(stdout, (||framePtr).filename)
|
write(stdout, framePtr.filename)
|
||||||
write(stdout, "(")
|
write(stdout, "(")
|
||||||
write(stdout, (||framePtr).line)
|
write(stdout, framePtr.line)
|
||||||
write(stdout, ") ")
|
write(stdout, ") ")
|
||||||
write(stdout, (||framePtr).procname)
|
write(stdout, framePtr.procname)
|
||||||
write(stdout, " ***\n")
|
write(stdout, " ***\n")
|
||||||
CommandPrompt()
|
CommandPrompt()
|
||||||
|
|
||||||
|
|
@ -487,8 +481,7 @@ proc endb(line: int) {.compilerproc.} =
|
||||||
# Thus, it must have as few parameters as possible to keep the
|
# Thus, it must have as few parameters as possible to keep the
|
||||||
# code size small!
|
# code size small!
|
||||||
# Check if we are at an enabled breakpoint or "in the mood"
|
# Check if we are at an enabled breakpoint or "in the mood"
|
||||||
ThreadGlobals()
|
framePtr.line = line # this is done here for smaller code size!
|
||||||
(||framePtr).line = line # this is done here for smaller code size!
|
|
||||||
if dbgLineHook != nil: dbgLineHook()
|
if dbgLineHook != nil: dbgLineHook()
|
||||||
case dbgState
|
case dbgState
|
||||||
of dbStepInto:
|
of dbStepInto:
|
||||||
|
|
@ -496,7 +489,7 @@ proc endb(line: int) {.compilerproc.} =
|
||||||
dbgShowExecutionPoint()
|
dbgShowExecutionPoint()
|
||||||
CommandPrompt()
|
CommandPrompt()
|
||||||
of dbSkipCurrent, dbStepOver: # skip current routine
|
of dbSkipCurrent, dbStepOver: # skip current routine
|
||||||
if ||framePtr == dbgSkipToFrame:
|
if framePtr == dbgSkipToFrame:
|
||||||
dbgShowExecutionPoint()
|
dbgShowExecutionPoint()
|
||||||
CommandPrompt()
|
CommandPrompt()
|
||||||
else: # breakpoints are wanted though (I guess)
|
else: # breakpoints are wanted though (I guess)
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,15 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# Exception handling code. This is difficult because it has
|
# Exception handling code. Carefully coded so that tiny programs which do not
|
||||||
# to work if there is no more memory (but it doesn't yet!).
|
# use the heap (and nor exceptions) do not include the GC or memory allocator.
|
||||||
|
|
||||||
# XXX assertions are unnecessarily complex; system should use their own
|
|
||||||
# assertion mechanism instead!
|
|
||||||
|
|
||||||
var
|
var
|
||||||
stackTraceNewLine* = "\n" ## undocumented feature; it is replaced by ``<br>``
|
stackTraceNewLine*: string ## undocumented feature; it is replaced by ``<br>``
|
||||||
## for CGI applications
|
## for CGI applications
|
||||||
isMultiThreaded: bool # true when prog created at least 1 thread
|
|
||||||
|
template stackTraceNL: expr =
|
||||||
|
(if IsNil(stackTraceNewLine): "\n" else: stackTraceNewLine)
|
||||||
|
|
||||||
when not defined(windows) or not defined(guiapp):
|
when not defined(windows) or not defined(guiapp):
|
||||||
proc writeToStdErr(msg: CString) = write(stdout, msg)
|
proc writeToStdErr(msg: CString) = write(stdout, msg)
|
||||||
|
|
@ -42,21 +41,6 @@ var
|
||||||
# a global variable for the root of all try blocks
|
# a global variable for the root of all try blocks
|
||||||
currException {.rtlThreadVar.}: ref E_Base
|
currException {.rtlThreadVar.}: ref E_Base
|
||||||
|
|
||||||
buf {.rtlThreadVar.}: string # cannot be allocated on the stack!
|
|
||||||
assertBuf {.rtlThreadVar.}: string
|
|
||||||
# we need a different buffer for
|
|
||||||
# assert, as it raises an exception and
|
|
||||||
# exception handler needs the buffer too
|
|
||||||
gAssertionFailed {.rtlThreadVar.}: ref EAssertionFailed
|
|
||||||
|
|
||||||
proc initGlobals() =
|
|
||||||
new(gAssertionFailed)
|
|
||||||
buf = newStringOfCap(2000)
|
|
||||||
assertBuf = newStringOfCap(2000)
|
|
||||||
|
|
||||||
when not hasThreadSupport:
|
|
||||||
initGlobals()
|
|
||||||
|
|
||||||
proc pushFrame(s: PFrame) {.compilerRtl, inl.} =
|
proc pushFrame(s: PFrame) {.compilerRtl, inl.} =
|
||||||
s.prev = framePtr
|
s.prev = framePtr
|
||||||
framePtr = s
|
framePtr = s
|
||||||
|
|
@ -83,8 +67,10 @@ proc popCurrentException {.compilerRtl, inl.} =
|
||||||
|
|
||||||
# some platforms have native support for stack traces:
|
# some platforms have native support for stack traces:
|
||||||
const
|
const
|
||||||
nativeStackTraceSupported = (defined(macosx) or defined(linux)) and
|
nativeStackTraceSupported = (defined(macosx) or defined(linux)) and
|
||||||
not nimrodStackTrace
|
not nimrodStackTrace
|
||||||
|
hasSomeStackTrace = nimrodStackTrace or
|
||||||
|
defined(nativeStackTrace) and nativeStackTraceSupported
|
||||||
|
|
||||||
when defined(nativeStacktrace) and nativeStackTraceSupported:
|
when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||||
type
|
type
|
||||||
|
|
@ -126,7 +112,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||||
add(s, tempDlInfo.dli_sname)
|
add(s, tempDlInfo.dli_sname)
|
||||||
else:
|
else:
|
||||||
add(s, '?')
|
add(s, '?')
|
||||||
add(s, stackTraceNewLine)
|
add(s, stackTraceNL)
|
||||||
else:
|
else:
|
||||||
if dlresult != 0 and tempDlInfo.dli_sname != nil and
|
if dlresult != 0 and tempDlInfo.dli_sname != nil and
|
||||||
c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
|
c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
|
||||||
|
|
@ -181,24 +167,24 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||||
add(s, ')')
|
add(s, ')')
|
||||||
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
|
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
|
||||||
add(s, tempFrames[j].procname)
|
add(s, tempFrames[j].procname)
|
||||||
add(s, stackTraceNewLine)
|
add(s, stackTraceNL)
|
||||||
|
|
||||||
proc rawWriteStackTrace(s: var string) =
|
when hasSomeStackTrace:
|
||||||
when nimrodStackTrace:
|
proc rawWriteStackTrace(s: var string) =
|
||||||
if framePtr == nil:
|
when nimrodStackTrace:
|
||||||
add(s, "No stack traceback available")
|
if framePtr == nil:
|
||||||
add(s, stackTraceNewLine)
|
add(s, "No stack traceback available")
|
||||||
|
add(s, stackTraceNL)
|
||||||
|
else:
|
||||||
|
add(s, "Traceback (most recent call last)")
|
||||||
|
add(s, stackTraceNL)
|
||||||
|
auxWriteStackTrace(framePtr, s)
|
||||||
|
elif defined(nativeStackTrace) and nativeStackTraceSupported:
|
||||||
|
add(s, "Traceback from system (most recent call last)")
|
||||||
|
add(s, stackTraceNL)
|
||||||
|
auxWriteStackTraceWithBacktrace(s)
|
||||||
else:
|
else:
|
||||||
add(s, "Traceback (most recent call last)")
|
add(s, "No stack traceback available\n")
|
||||||
add(s, stackTraceNewLine)
|
|
||||||
auxWriteStackTrace(framePtr, s)
|
|
||||||
elif defined(nativeStackTrace) and nativeStackTraceSupported:
|
|
||||||
add(s, "Traceback from system (most recent call last)")
|
|
||||||
add(s, stackTraceNewLine)
|
|
||||||
auxWriteStackTraceWithBacktrace(s)
|
|
||||||
else:
|
|
||||||
add(s, "No stack traceback available")
|
|
||||||
add(s, stackTraceNewLine)
|
|
||||||
|
|
||||||
proc quitOrDebug() {.inline.} =
|
proc quitOrDebug() {.inline.} =
|
||||||
when not defined(endb):
|
when not defined(endb):
|
||||||
|
|
@ -214,13 +200,16 @@ proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||||
if excHandler != nil:
|
if excHandler != nil:
|
||||||
pushCurrentException(e)
|
pushCurrentException(e)
|
||||||
c_longjmp(excHandler.context, 1)
|
c_longjmp(excHandler.context, 1)
|
||||||
|
elif e[] is EOutOfMemory:
|
||||||
|
writeToStdErr(ename)
|
||||||
|
quitOrDebug()
|
||||||
else:
|
else:
|
||||||
if not isNil(buf):
|
when hasSomeStackTrace:
|
||||||
setLen(buf, 0)
|
var buf = newStringOfCap(2000)
|
||||||
rawWriteStackTrace(buf)
|
rawWriteStackTrace(buf)
|
||||||
if e.msg != nil and e.msg[0] != '\0':
|
if not isNil(e.msg):
|
||||||
add(buf, "Error: unhandled exception: ")
|
add(buf, "Error: unhandled exception: ")
|
||||||
add(buf, $e.msg)
|
add(buf, e.msg)
|
||||||
else:
|
else:
|
||||||
add(buf, "Error: unhandled exception")
|
add(buf, "Error: unhandled exception")
|
||||||
add(buf, " [")
|
add(buf, " [")
|
||||||
|
|
@ -228,7 +217,21 @@ proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||||
add(buf, "]\n")
|
add(buf, "]\n")
|
||||||
writeToStdErr(buf)
|
writeToStdErr(buf)
|
||||||
else:
|
else:
|
||||||
writeToStdErr(ename)
|
# ugly, but avoids heap allocations :-)
|
||||||
|
template xadd(buf, s, slen: expr) =
|
||||||
|
if L + slen < high(buf):
|
||||||
|
copyMem(addr(buf[L]), cstring(s), slen)
|
||||||
|
inc L, slen
|
||||||
|
template add(buf, s: expr) =
|
||||||
|
xadd(buf, s, s.len)
|
||||||
|
var buf: array [0..2000, char]
|
||||||
|
var L = 0
|
||||||
|
add(buf, "Error: unhandled exception: ")
|
||||||
|
if not isNil(e.msg): add(buf, e.msg)
|
||||||
|
add(buf, " [")
|
||||||
|
xadd(buf, ename, c_strlen(ename))
|
||||||
|
add(buf, "]\n")
|
||||||
|
writeToStdErr(buf)
|
||||||
quitOrDebug()
|
quitOrDebug()
|
||||||
GC_enable()
|
GC_enable()
|
||||||
|
|
||||||
|
|
@ -240,54 +243,57 @@ proc reraiseException() {.compilerRtl.} =
|
||||||
|
|
||||||
proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
|
proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
|
||||||
if not cond:
|
if not cond:
|
||||||
#c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
|
var gAssertionFailed: ref EAssertionFailed
|
||||||
#quit(1)
|
new(gAssertionFailed)
|
||||||
GC_disable() # BUGFIX: `$` allocates a new string object!
|
gAssertionFailed.msg = newStringOfCap(200)
|
||||||
if not isNil(assertBuf):
|
add(gAssertionFailed.msg, "[Assertion failure] file: ")
|
||||||
# BUGFIX: when debugging the GC, assertBuf may be nil
|
add(gAssertionFailed.msg, file)
|
||||||
setLen(assertBuf, 0)
|
add(gAssertionFailed.msg, " line: ")
|
||||||
add(assertBuf, "[Assertion failure] file: ")
|
add(gAssertionFailed.msg, $line)
|
||||||
add(assertBuf, file)
|
add(gAssertionFailed.msg, "\n")
|
||||||
add(assertBuf, " line: ")
|
raise gAssertionFailed
|
||||||
add(assertBuf, $line)
|
|
||||||
add(assertBuf, "\n")
|
|
||||||
gAssertionFailed.msg = assertBuf
|
|
||||||
GC_enable()
|
|
||||||
if gAssertionFailed != nil:
|
|
||||||
raise gAssertionFailed
|
|
||||||
else:
|
|
||||||
c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
|
|
||||||
quit(1)
|
|
||||||
|
|
||||||
proc WriteStackTrace() =
|
proc WriteStackTrace() =
|
||||||
var s = ""
|
when hasSomeStackTrace:
|
||||||
rawWriteStackTrace(s)
|
var s = ""
|
||||||
writeToStdErr(s)
|
rawWriteStackTrace(s)
|
||||||
|
writeToStdErr(s)
|
||||||
|
else:
|
||||||
|
writeToStdErr("No stack traceback available\n")
|
||||||
|
|
||||||
var
|
when defined(endb):
|
||||||
dbgAborting: bool # whether the debugger wants to abort
|
var
|
||||||
|
dbgAborting: bool # whether the debugger wants to abort
|
||||||
|
|
||||||
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
|
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
|
||||||
# print stack trace and quit
|
template processSignal(s, action: expr) =
|
||||||
var s = sig
|
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
|
||||||
GC_disable()
|
elif s == SIGSEGV:
|
||||||
setLen(buf, 0)
|
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
|
||||||
rawWriteStackTrace(buf)
|
elif s == SIGABRT:
|
||||||
|
when defined(endb):
|
||||||
|
if dbgAborting: return # the debugger wants to abort
|
||||||
|
action("SIGABRT: Abnormal termination.\n")
|
||||||
|
elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n")
|
||||||
|
elif s == SIGILL: action("SIGILL: Illegal operation.\n")
|
||||||
|
elif s == SIGBUS:
|
||||||
|
action("SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
|
||||||
|
else: action("unknown signal\n")
|
||||||
|
|
||||||
if s == SIGINT: add(buf, "SIGINT: Interrupted by Ctrl-C.\n")
|
# print stack trace and quit
|
||||||
elif s == SIGSEGV:
|
when hasSomeStackTrace:
|
||||||
add(buf, "SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
|
GC_disable()
|
||||||
elif s == SIGABRT:
|
var buf = newStringOfCap(2000)
|
||||||
if dbgAborting: return # the debugger wants to abort
|
rawWriteStackTrace(buf)
|
||||||
add(buf, "SIGABRT: Abnormal termination.\n")
|
processSignal(sig, buf.add) # nice hu? currying a la nimrod :-)
|
||||||
elif s == SIGFPE: add(buf, "SIGFPE: Arithmetic error.\n")
|
writeToStdErr(buf)
|
||||||
elif s == SIGILL: add(buf, "SIGILL: Illegal operation.\n")
|
GC_enable()
|
||||||
elif s == SIGBUS:
|
else:
|
||||||
add(buf, "SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
|
var msg: cstring
|
||||||
else: add(buf, "unknown signal\n")
|
template asgn(y: expr) = msg = y
|
||||||
writeToStdErr(buf)
|
processSignal(sig, asgn)
|
||||||
dbgAborting = True # play safe here...
|
writeToStdErr(msg)
|
||||||
GC_enable()
|
when defined(endb): dbgAborting = True
|
||||||
quit(1) # always quit when SIGABRT
|
quit(1) # always quit when SIGABRT
|
||||||
|
|
||||||
proc registerSignalHandler() =
|
proc registerSignalHandler() =
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,6 @@ proc initGC() =
|
||||||
init(gch.tempStack)
|
init(gch.tempStack)
|
||||||
Init(gch.cycleRoots)
|
Init(gch.cycleRoots)
|
||||||
Init(gch.decStack)
|
Init(gch.decStack)
|
||||||
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
|
|
||||||
|
|
||||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
var d = cast[TAddress](dest)
|
var d = cast[TAddress](dest)
|
||||||
|
|
|
||||||
|
|
@ -52,15 +52,10 @@ const
|
||||||
IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
|
IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
|
||||||
IntMask = 1 shl IntShift - 1
|
IntMask = 1 shl IntShift - 1
|
||||||
|
|
||||||
var
|
proc raiseOutOfMem() {.noinline.} =
|
||||||
gOutOfMem: ref EOutOfMemory
|
if outOfMemHook != nil: outOfMemHook()
|
||||||
|
echo("out of memory")
|
||||||
proc raiseOutOfMem() {.noreturn.} =
|
quit(1)
|
||||||
if gOutOfMem == nil:
|
|
||||||
echo("out of memory; cannot even throw an exception")
|
|
||||||
quit(1)
|
|
||||||
gOutOfMem.msg = "out of memory"
|
|
||||||
raise gOutOfMem
|
|
||||||
|
|
||||||
when defined(boehmgc):
|
when defined(boehmgc):
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,24 @@ proc rawNewString(space: int): NimString {.compilerProc.} =
|
||||||
(s+1) * sizeof(char)))
|
(s+1) * sizeof(char)))
|
||||||
result.space = s
|
result.space = s
|
||||||
|
|
||||||
proc mnewString(len: int): NimString {.exportc.} =
|
proc mnewString(len: int): NimString {.compilerProc.} =
|
||||||
#c_fprintf(c_stdout, "[NEWSTRING] len: %ld\n", len)
|
|
||||||
result = rawNewString(len)
|
result = rawNewString(len)
|
||||||
result.len = len
|
result.len = len
|
||||||
|
|
||||||
|
proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
|
||||||
|
var start = max(start, 0)
|
||||||
|
var len = min(last, s.len-1) - start + 1
|
||||||
|
if len > 0:
|
||||||
|
result = rawNewString(len)
|
||||||
|
result.len = len
|
||||||
|
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
|
||||||
|
result.data[len] = '\0'
|
||||||
|
else:
|
||||||
|
result = mnewString(0)
|
||||||
|
|
||||||
|
proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
|
||||||
|
result = copyStrLast(s, start, s.len-1)
|
||||||
|
|
||||||
proc toNimStr(str: CString, len: int): NimString {.compilerProc.} =
|
proc toNimStr(str: CString, len: int): NimString {.compilerProc.} =
|
||||||
result = rawNewString(len)
|
result = rawNewString(len)
|
||||||
result.len = len
|
result.len = len
|
||||||
|
|
@ -72,20 +85,6 @@ proc hashString(s: string): int {.compilerproc.} =
|
||||||
h = h +% h shl 15
|
h = h +% h shl 15
|
||||||
result = h
|
result = h
|
||||||
|
|
||||||
proc copyStrLast(s: NimString, start, last: int): NimString {.exportc.} =
|
|
||||||
var start = max(start, 0)
|
|
||||||
var len = min(last, s.len-1) - start + 1
|
|
||||||
if len > 0:
|
|
||||||
result = rawNewString(len)
|
|
||||||
result.len = len
|
|
||||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
|
|
||||||
result.data[len] = '\0'
|
|
||||||
else:
|
|
||||||
result = mnewString(0)
|
|
||||||
|
|
||||||
proc copyStr(s: NimString, start: int): NimString {.exportc.} =
|
|
||||||
result = copyStrLast(s, start, s.len-1)
|
|
||||||
|
|
||||||
proc addChar(s: NimString, c: char): NimString =
|
proc addChar(s: NimString, c: char): NimString =
|
||||||
# is compilerproc!
|
# is compilerproc!
|
||||||
result = s
|
result = s
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,6 @@ proc ThreadVarsAlloc(size: int): pointer =
|
||||||
result = c_malloc(size)
|
result = c_malloc(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
proc ThreadVarsDealloc(p: pointer) {.importc: "free", nodecl.}
|
proc ThreadVarsDealloc(p: pointer) {.importc: "free", nodecl.}
|
||||||
proc initGlobals()
|
|
||||||
|
|
||||||
type
|
type
|
||||||
PGcThread = ptr TGcThread
|
PGcThread = ptr TGcThread
|
||||||
|
|
@ -239,8 +238,7 @@ when not defined(useNimRtl):
|
||||||
|
|
||||||
initStackBottom()
|
initStackBottom()
|
||||||
initGC()
|
initGC()
|
||||||
initGlobals()
|
|
||||||
|
|
||||||
var heapLock: TSysLock
|
var heapLock: TSysLock
|
||||||
InitSysLock(HeapLock)
|
InitSysLock(HeapLock)
|
||||||
|
|
||||||
|
|
@ -301,7 +299,6 @@ template ThreadProcWrapperBody(closure: expr) =
|
||||||
setStackBottom(addr(t))
|
setStackBottom(addr(t))
|
||||||
initGC()
|
initGC()
|
||||||
t.stackBottom = addr(t)
|
t.stackBottom = addr(t)
|
||||||
initGlobals()
|
|
||||||
registerThread(t)
|
registerThread(t)
|
||||||
try:
|
try:
|
||||||
t.fn(t.data)
|
t.fn(t.data)
|
||||||
|
|
|
||||||
55
tests/accept/compile/tcodegenbug1.nim
Normal file
55
tests/accept/compile/tcodegenbug1.nim
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import os
|
||||||
|
# TODO: Rename this module to ``utils``
|
||||||
|
type
|
||||||
|
TStatusEnum* = enum
|
||||||
|
sUnknown = -1, sBuildFailure, sBuildInProgress, sBuildSuccess,
|
||||||
|
sTestFailure, sTestInProgress, sTestSuccess, # ORDER MATTERS!
|
||||||
|
sDocGenFailure, sDocGenInProgress, sDocGenSuccess,
|
||||||
|
sCSrcGenFailure, sCSrcGenInProgress, sCSrcGenSuccess
|
||||||
|
|
||||||
|
TStatus* = object
|
||||||
|
status*: TStatusEnum
|
||||||
|
desc*: string
|
||||||
|
hash*: string
|
||||||
|
|
||||||
|
proc initStatus*(): TStatus =
|
||||||
|
result.status = sUnknown
|
||||||
|
result.desc = ""
|
||||||
|
result.hash = ""
|
||||||
|
|
||||||
|
proc isInProgress*(status: TStatusEnum): bool =
|
||||||
|
return status in {sBuildInProgress, sTestInProgress, sDocGenInProgress,
|
||||||
|
sCSrcGenInProgress}
|
||||||
|
|
||||||
|
proc `$`*(status: TStatusEnum): string =
|
||||||
|
case status
|
||||||
|
of sBuildFailure:
|
||||||
|
return "build failure"
|
||||||
|
of sBuildInProgress:
|
||||||
|
return "build in progress"
|
||||||
|
of sBuildSuccess:
|
||||||
|
return "build finished"
|
||||||
|
of sTestFailure:
|
||||||
|
return "testing failure"
|
||||||
|
of sTestInProgress:
|
||||||
|
return "testing in progress"
|
||||||
|
of sTestSuccess:
|
||||||
|
return "testing finished"
|
||||||
|
of sDocGenFailure:
|
||||||
|
return "documentation generation failed"
|
||||||
|
of sDocGenInProgress:
|
||||||
|
return "generating documentation"
|
||||||
|
of sDocGenSuccess:
|
||||||
|
return "documentation generation succeeded"
|
||||||
|
of sCSrcGenFailure:
|
||||||
|
return "csource generation failed"
|
||||||
|
of sCSrcGenInProgress:
|
||||||
|
return "csource generation in progress"
|
||||||
|
of sCSrcGenSuccess:
|
||||||
|
return "csource generation succeeded"
|
||||||
|
of sUnknown:
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
proc makeCommitPath*(platform, hash: string): string =
|
||||||
|
return platform / "nimrod_" & hash.copy(0, 11) # 11 Chars.
|
||||||
|
|
||||||
13
tests/accept/compile/tnimrodnode_for_runtime.nim
Normal file
13
tests/accept/compile/tnimrodnode_for_runtime.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
output: "bla"
|
||||||
|
disabled: true
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
proc makeMacro: PNimrodNode =
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
var p = makeMacro()
|
||||||
|
|
||||||
|
echo "bla"
|
||||||
|
|
||||||
16
tests/accept/run/tgenericassigntuples.nim
Normal file
16
tests/accept/run/tgenericassigntuples.nim
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
discard """
|
||||||
|
output: '''abc232'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
var t, s: tuple[x: string, c: int]
|
||||||
|
|
||||||
|
proc ugh: seq[tuple[x: string, c: int]] =
|
||||||
|
result = @[("abc", 232)]
|
||||||
|
|
||||||
|
t = ugh()[0]
|
||||||
|
s = t
|
||||||
|
s = ugh()[0]
|
||||||
|
|
||||||
|
echo s[0], t[1]
|
||||||
|
|
||||||
|
|
||||||
346
tests/accept/run/tsimplesort.nim
Normal file
346
tests/accept/run/tsimplesort.nim
Normal file
|
|
@ -0,0 +1,346 @@
|
||||||
|
discard """
|
||||||
|
output: '''true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashes, math
|
||||||
|
|
||||||
|
|
||||||
|
when defined(shallowADT):
|
||||||
|
{.pragma: myShallow, shallow.}
|
||||||
|
else:
|
||||||
|
{.pragma: myShallow.}
|
||||||
|
|
||||||
|
type
|
||||||
|
TSlotEnum = enum seEmpty, seFilled, seDeleted
|
||||||
|
TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
|
||||||
|
TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
|
||||||
|
TTable* {.final, myShallow.}[A, B] = object
|
||||||
|
data: TKeyValuePairSeq[A, B]
|
||||||
|
counter: int
|
||||||
|
|
||||||
|
proc len*[A, B](t: TTable[A, B]): int =
|
||||||
|
## returns the number of keys in `t`.
|
||||||
|
result = t.counter
|
||||||
|
|
||||||
|
iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
|
||||||
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
|
for h in 0..high(t.data):
|
||||||
|
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
|
iterator keys*[A, B](t: TTable[A, B]): A =
|
||||||
|
## iterates over any key in the table `t`.
|
||||||
|
for h in 0..high(t.data):
|
||||||
|
if t.data[h].slot == seFilled: yield t.data[h].key
|
||||||
|
|
||||||
|
iterator values*[A, B](t: TTable[A, B]): B =
|
||||||
|
## iterates over any value in the table `t`.
|
||||||
|
for h in 0..high(t.data):
|
||||||
|
if t.data[h].slot == seFilled: yield t.data[h].val
|
||||||
|
|
||||||
|
const
|
||||||
|
growthFactor = 2
|
||||||
|
|
||||||
|
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||||
|
assert(length > counter)
|
||||||
|
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||||
|
|
||||||
|
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||||
|
result = ((5 * h) + 1) and maxHash
|
||||||
|
|
||||||
|
template rawGetImpl() =
|
||||||
|
var h: THash = hash(key) and high(t.data) # start with real hash value
|
||||||
|
while t.data[h].slot != seEmpty:
|
||||||
|
if t.data[h].key == key and t.data[h].slot == seFilled:
|
||||||
|
return h
|
||||||
|
h = nextTry(h, high(t.data))
|
||||||
|
result = -1
|
||||||
|
|
||||||
|
template rawInsertImpl() =
|
||||||
|
var h: THash = hash(key) and high(data)
|
||||||
|
while data[h].slot == seFilled:
|
||||||
|
h = nextTry(h, high(data))
|
||||||
|
data[h].key = key
|
||||||
|
data[h].val = val
|
||||||
|
data[h].slot = seFilled
|
||||||
|
|
||||||
|
proc RawGet[A, B](t: TTable[A, B], key: A): int =
|
||||||
|
rawGetImpl()
|
||||||
|
|
||||||
|
proc `[]`*[A, B](t: TTable[A, B], key: A): B =
|
||||||
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
|
## default empty value for the type `B` is returned
|
||||||
|
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||||
|
## exists.
|
||||||
|
var index = RawGet(t, key)
|
||||||
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
||||||
|
proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
|
||||||
|
## returns true iff `key` is in the table `t`.
|
||||||
|
result = rawGet(t, key) >= 0
|
||||||
|
|
||||||
|
proc RawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
|
||||||
|
key: A, val: B) =
|
||||||
|
rawInsertImpl()
|
||||||
|
|
||||||
|
proc Enlarge[A, B](t: var TTable[A, B]) =
|
||||||
|
var n: TKeyValuePairSeq[A, B]
|
||||||
|
newSeq(n, len(t.data) * growthFactor)
|
||||||
|
for i in countup(0, high(t.data)):
|
||||||
|
if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||||
|
swap(t.data, n)
|
||||||
|
|
||||||
|
template PutImpl() =
|
||||||
|
var index = RawGet(t, key)
|
||||||
|
if index >= 0:
|
||||||
|
t.data[index].val = val
|
||||||
|
else:
|
||||||
|
if mustRehash(len(t.data), t.counter): Enlarge(t)
|
||||||
|
RawInsert(t, t.data, key, val)
|
||||||
|
inc(t.counter)
|
||||||
|
|
||||||
|
proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) =
|
||||||
|
## puts a (key, value)-pair into `t`.
|
||||||
|
putImpl()
|
||||||
|
|
||||||
|
proc del*[A, B](t: var TTable[A, B], key: A) =
|
||||||
|
## deletes `key` from hash table `t`.
|
||||||
|
var index = RawGet(t, key)
|
||||||
|
if index >= 0:
|
||||||
|
t.data[index].slot = seDeleted
|
||||||
|
dec(t.counter)
|
||||||
|
|
||||||
|
proc initTable*[A, B](initialSize=64): TTable[A, B] =
|
||||||
|
## creates a new hash table that is empty. `initialSize` needs to be
|
||||||
|
## a power of two.
|
||||||
|
assert isPowerOfTwo(initialSize)
|
||||||
|
result.counter = 0
|
||||||
|
newSeq(result.data, initialSize)
|
||||||
|
|
||||||
|
proc toTable*[A, B](pairs: openarray[tuple[key: A,
|
||||||
|
val: B]]): TTable[A, B] =
|
||||||
|
## creates a new hash table that contains the given `pairs`.
|
||||||
|
result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
|
||||||
|
for key, val in items(pairs): result[key] = val
|
||||||
|
|
||||||
|
template dollarImpl(): stmt =
|
||||||
|
if t.len == 0:
|
||||||
|
result = "{:}"
|
||||||
|
else:
|
||||||
|
result = "{"
|
||||||
|
for key, val in pairs(t):
|
||||||
|
if result.len > 1: result.add(", ")
|
||||||
|
result.add($key)
|
||||||
|
result.add(": ")
|
||||||
|
result.add($val)
|
||||||
|
result.add("}")
|
||||||
|
|
||||||
|
proc `$`*[A, B](t: TTable[A, B]): string =
|
||||||
|
## The `$` operator for hash tables.
|
||||||
|
dollarImpl()
|
||||||
|
|
||||||
|
# ------------------------------ count tables -------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
TCountTable* {.final, myShallow.}[
|
||||||
|
A] = object ## table that counts the number of each key
|
||||||
|
data: seq[tuple[key: A, val: int]]
|
||||||
|
counter: int
|
||||||
|
|
||||||
|
proc len*[A](t: TCountTable[A]): int =
|
||||||
|
## returns the number of keys in `t`.
|
||||||
|
result = t.counter
|
||||||
|
|
||||||
|
iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
||||||
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
|
for h in 0..high(t.data):
|
||||||
|
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
|
iterator keys*[A](t: TCountTable[A]): A =
|
||||||
|
## iterates over any key in the table `t`.
|
||||||
|
for h in 0..high(t.data):
|
||||||
|
if t.data[h].val != 0: yield t.data[h].key
|
||||||
|
|
||||||
|
iterator values*[A](t: TCountTable[A]): int =
|
||||||
|
## iterates over any value in the table `t`.
|
||||||
|
for h in 0..high(t.data):
|
||||||
|
if t.data[h].val != 0: yield t.data[h].val
|
||||||
|
|
||||||
|
proc RawGet[A](t: TCountTable[A], key: A): int =
|
||||||
|
var h: THash = hash(key) and high(t.data) # start with real hash value
|
||||||
|
while t.data[h].val != 0:
|
||||||
|
if t.data[h].key == key: return h
|
||||||
|
h = nextTry(h, high(t.data))
|
||||||
|
result = -1
|
||||||
|
|
||||||
|
proc `[]`*[A](t: TCountTable[A], key: A): int =
|
||||||
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
|
## 0 is returned. One can check with ``hasKey`` whether the key
|
||||||
|
## exists.
|
||||||
|
var index = RawGet(t, key)
|
||||||
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
||||||
|
proc hasKey*[A](t: TCountTable[A], key: A): bool =
|
||||||
|
## returns true iff `key` is in the table `t`.
|
||||||
|
result = rawGet(t, key) >= 0
|
||||||
|
|
||||||
|
proc RawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
|
||||||
|
key: A, val: int) =
|
||||||
|
var h: THash = hash(key) and high(data)
|
||||||
|
while data[h].val != 0: h = nextTry(h, high(data))
|
||||||
|
data[h].key = key
|
||||||
|
data[h].val = val
|
||||||
|
|
||||||
|
proc Enlarge[A](t: var TCountTable[A]) =
|
||||||
|
var n: seq[tuple[key: A, val: int]]
|
||||||
|
newSeq(n, len(t.data) * growthFactor)
|
||||||
|
for i in countup(0, high(t.data)):
|
||||||
|
if t.data[i].val != 0: RawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||||
|
swap(t.data, n)
|
||||||
|
|
||||||
|
proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) =
|
||||||
|
## puts a (key, value)-pair into `t`. `val` has to be positive.
|
||||||
|
assert val > 0
|
||||||
|
PutImpl()
|
||||||
|
|
||||||
|
proc initCountTable*[A](initialSize=64): TCountTable[A] =
|
||||||
|
## creates a new count table that is empty. `initialSize` needs to be
|
||||||
|
## a power of two.
|
||||||
|
assert isPowerOfTwo(initialSize)
|
||||||
|
result.counter = 0
|
||||||
|
newSeq(result.data, initialSize)
|
||||||
|
|
||||||
|
proc toCountTable*[A](keys: openArray[A]): TCountTable[A] =
|
||||||
|
## creates a new count table with every key in `keys` having a count of 1.
|
||||||
|
result = initCountTable[A](nextPowerOfTwo(keys.len+10))
|
||||||
|
for key in items(keys): result[key] = 1
|
||||||
|
|
||||||
|
proc `$`*[A](t: TCountTable[A]): string =
|
||||||
|
## The `$` operator for count tables.
|
||||||
|
dollarImpl()
|
||||||
|
|
||||||
|
proc inc*[A](t: var TCountTable[A], key: A, val = 1) =
|
||||||
|
## increments `t[key]` by `val`.
|
||||||
|
var index = RawGet(t, key)
|
||||||
|
if index >= 0:
|
||||||
|
inc(t.data[index].val, val)
|
||||||
|
else:
|
||||||
|
if mustRehash(len(t.data), t.counter): Enlarge(t)
|
||||||
|
RawInsert(t, t.data, key, val)
|
||||||
|
inc(t.counter)
|
||||||
|
|
||||||
|
proc Smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
||||||
|
## returns the largest (key,val)-pair. Efficiency: O(n)
|
||||||
|
assert t.len > 0
|
||||||
|
var minIdx = 0
|
||||||
|
for h in 1..high(t.data):
|
||||||
|
if t.data[h].val > 0 and t.data[minIdx].val > t.data[h].val: minIdx = h
|
||||||
|
result.key = t.data[minIdx].key
|
||||||
|
result.val = t.data[minIdx].val
|
||||||
|
|
||||||
|
proc Largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
||||||
|
## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
|
||||||
|
assert t.len > 0
|
||||||
|
var maxIdx = 0
|
||||||
|
for h in 1..high(t.data):
|
||||||
|
if t.data[maxIdx].val < t.data[h].val: maxIdx = h
|
||||||
|
result.key = t.data[maxIdx].key
|
||||||
|
result.val = t.data[maxIdx].val
|
||||||
|
|
||||||
|
proc sort*[A](t: var TCountTable[A]) =
|
||||||
|
## sorts the count table so that the entry with the highest counter comes
|
||||||
|
## first. This is destructive! You must not modify `t` afterwards!
|
||||||
|
## You can use the iterators `pairs`, `keys`, and `values` to iterate over
|
||||||
|
## `t` in the sorted order.
|
||||||
|
var w: type(t.data[0])
|
||||||
|
checkTypeInfo(addr(w), 10, GetTypeInfo(w))
|
||||||
|
|
||||||
|
# we use shellsort here; fast enough and simple
|
||||||
|
var h = 1
|
||||||
|
while true:
|
||||||
|
h = 3 * h + 1
|
||||||
|
if h >= high(t.data): break
|
||||||
|
while true:
|
||||||
|
h = h div 3
|
||||||
|
for i in countup(h, high(t.data)):
|
||||||
|
var j = i
|
||||||
|
checkTypeInfo(addr(w), 11, GetTypeInfo(w))
|
||||||
|
while t.data[j-h].val <= t.data[j].val:
|
||||||
|
checkTypeInfo(addr(w), 12, GetTypeInfo(w))
|
||||||
|
var xyz = t.data[j]
|
||||||
|
checkTypeInfo(addr(w), 13, GetTypeInfo(w))
|
||||||
|
t.data[j] = xyz
|
||||||
|
checkTypeInfo(addr(w), 14, GetTypeInfo(w))
|
||||||
|
t.data[j-h] = t.data[j]
|
||||||
|
#swap(t.data[j], t.data[j-h])
|
||||||
|
checkTypeInfo(addr(w), 15, GetTypeInfo(w))
|
||||||
|
j = j-h
|
||||||
|
checkTypeInfo(addr(w), 16, GetTypeInfo(w))
|
||||||
|
if j < h: break
|
||||||
|
if h == 1: break
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
data = {
|
||||||
|
"34": 123456, "12": 789,
|
||||||
|
"90": 343, "0": 34404,
|
||||||
|
"1": 344004, "2": 344774,
|
||||||
|
"3": 342244, "4": 3412344,
|
||||||
|
"5": 341232144, "6": 34214544,
|
||||||
|
"7": 3434544, "8": 344544,
|
||||||
|
"9": 34435644, "---00": 346677844,
|
||||||
|
"10": 34484, "11": 34474, "19": 34464,
|
||||||
|
"20": 34454, "30": 34141244, "40": 344114,
|
||||||
|
"50": 344490, "60": 344491, "70": 344492,
|
||||||
|
"80": 344497}
|
||||||
|
|
||||||
|
proc fake() =
|
||||||
|
#var s: TTable[string, int]
|
||||||
|
#var otherCountTable: TCountTable[string]
|
||||||
|
#var w: type(otherCountTable.data[0])
|
||||||
|
#checkTypeInfo(addr(w), nil, GetTypeInfo(w))
|
||||||
|
|
||||||
|
proc countTableTest1 =
|
||||||
|
#fake()
|
||||||
|
var s = initTable[string, int](64)
|
||||||
|
for key, val in items(data): s[key] = val
|
||||||
|
var w: tuple[key: string, val: int] #type(otherCountTable.data[0])
|
||||||
|
checkTypeInfo(addr(w), 0, GetTypeInfo(w))
|
||||||
|
|
||||||
|
#var s = data.toTable
|
||||||
|
#var otherCountTable: TCountTable[string]
|
||||||
|
#var w: tuple[key: string, val: int] #type(otherCountTable.data[0])
|
||||||
|
checkTypeInfo(addr(w), 1, GetTypeInfo(w))
|
||||||
|
|
||||||
|
var t = initCountTable[string]()
|
||||||
|
checkTypeInfo(addr(w), 2, GetTypeInfo(w))
|
||||||
|
for k, v in items(data): t.inc(k)
|
||||||
|
checkTypeInfo(addr(w), 3, GetTypeInfo(w))
|
||||||
|
for k in t.keys: assert t[k] == 1
|
||||||
|
checkTypeInfo(addr(w), 4, GetTypeInfo(w))
|
||||||
|
t.inc("90", 3)
|
||||||
|
checkTypeInfo(addr(w), 5, GetTypeInfo(w))
|
||||||
|
t.inc("12", 2)
|
||||||
|
checkTypeInfo(addr(w), 6, GetTypeInfo(w))
|
||||||
|
t.inc("34", 1)
|
||||||
|
checkTypeInfo(addr(w), 7, GetTypeInfo(w))
|
||||||
|
assert t.largest()[0] == "90"
|
||||||
|
checkTypeInfo(addr(w), 8, GetTypeInfo(w))
|
||||||
|
t.sort()
|
||||||
|
checkTypeInfo(addr(w), 9, GetTypeInfo(w))
|
||||||
|
when false:
|
||||||
|
for k, v in t.pairs:
|
||||||
|
echo k, ": ", v
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
for k, v in t.pairs:
|
||||||
|
case i
|
||||||
|
of 0: assert k == "90" and v == 4
|
||||||
|
of 1: assert k == "12" and v == 3
|
||||||
|
of 2: assert k == "34" and v == 2
|
||||||
|
else: break
|
||||||
|
inc i
|
||||||
|
|
||||||
|
countTableTest1()
|
||||||
|
echo true
|
||||||
|
|
||||||
|
|
||||||
14
tests/reject/temptycaseobj.nim
Normal file
14
tests/reject/temptycaseobj.nim
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
discard """
|
||||||
|
line: 11
|
||||||
|
errormsg: "identifier expected, but found '[same indentation]'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyEnum = enum enA, enU, enO
|
||||||
|
TMyCase = object
|
||||||
|
case e: TMyEnum
|
||||||
|
of enA:
|
||||||
|
of enU: x, y: int
|
||||||
|
of enO: a, b: string
|
||||||
|
|
||||||
|
|
||||||
18
tests/reject/tprocvar.nim
Normal file
18
tests/reject/tprocvar.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "type mismatch"
|
||||||
|
line: 17
|
||||||
|
file: "tprocvar.nim"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TCallback = proc (a, b: int)
|
||||||
|
|
||||||
|
proc huh(x, y: var int) =
|
||||||
|
x = 0
|
||||||
|
y = x+1
|
||||||
|
|
||||||
|
proc so(c: TCallback) =
|
||||||
|
c(2, 4)
|
||||||
|
|
||||||
|
so(huh)
|
||||||
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
# To test stack overflow message
|
# To test stack overflow message
|
||||||
|
|
||||||
proc over(a: int): int =
|
proc over(a: int): int =
|
||||||
if a == high(int): return
|
if a >= 400:
|
||||||
|
assert false
|
||||||
|
return
|
||||||
result = over(a+1)+5
|
result = over(a+1)+5
|
||||||
|
|
||||||
Echo($over(0))
|
Echo($over(0))
|
||||||
|
|
|
||||||
16
todo.txt
16
todo.txt
|
|
@ -2,7 +2,6 @@ High priority (version 0.8.12)
|
||||||
==============================
|
==============================
|
||||||
* test threads on windows; thread analysis needs to be even more restrictive!
|
* test threads on windows; thread analysis needs to be even more restrictive!
|
||||||
* implement message passing built-ins: channels/queues
|
* implement message passing built-ins: channels/queues
|
||||||
* outOfMem hook; 0 over-head for hello world program :-)
|
|
||||||
* bug: {:}.toTable[int, string]()
|
* bug: {:}.toTable[int, string]()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -20,18 +19,6 @@ version 0.9.0
|
||||||
- fix overloading resolution
|
- fix overloading resolution
|
||||||
- make ^ available as operator
|
- make ^ available as operator
|
||||||
- implement closures; implement proper coroutines
|
- implement closures; implement proper coroutines
|
||||||
- rethink comment syntax; people want::
|
|
||||||
|
|
||||||
type
|
|
||||||
TConfig* = object
|
|
||||||
limit*: int
|
|
||||||
outFile*: string
|
|
||||||
# Regex patterns to ignore. TLogEntry field -> regex pattern
|
|
||||||
# If this matches, the request will NOT be shown.
|
|
||||||
ignoreRe*: TTable[string, string]
|
|
||||||
|
|
||||||
I think a good compromise is to define positions for the docgen in the
|
|
||||||
grammar and ignore other comments everywhere.
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
----
|
----
|
||||||
|
|
@ -45,8 +32,7 @@ version 0.9.XX
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- distinct types for array/seq indexes
|
- distinct types for array/seq indexes
|
||||||
- GC: marker procs for native Nimrod GC and Boehm GC
|
- GC: marker procs for native Nimrod GC and Boehm GC; precise stack marking
|
||||||
- code concerning 'assert' is wasteful and unnecessarily complex
|
|
||||||
- implicit ref/ptr->var conversion; the compiler may store an object
|
- implicit ref/ptr->var conversion; the compiler may store an object
|
||||||
implicitly on the heap for write barrier efficiency
|
implicitly on the heap for write barrier efficiency
|
||||||
- resizing of strings/sequences could take into account the memory that
|
- resizing of strings/sequences could take into account the memory that
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ Additions
|
||||||
- Added a wrapper for ``sphinx``.
|
- Added a wrapper for ``sphinx``.
|
||||||
- The compiler now supports array, sequence and string slicing.
|
- The compiler now supports array, sequence and string slicing.
|
||||||
- Added ``system.newStringOfCap``.
|
- Added ``system.newStringOfCap``.
|
||||||
- Added ``system.raiseHook`` and ``system.outOfMemoryHook``.
|
- Added ``system.raiseHook`` and ``system.outOfMemHook``.
|
||||||
- Added ``system.writeFile``.
|
- Added ``system.writeFile``.
|
||||||
- Added ``system.shallowCopy``.
|
- Added ``system.shallowCopy``.
|
||||||
- ``system.echo`` is guaranteed to be thread-safe.
|
- ``system.echo`` is guaranteed to be thread-safe.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue