Merge branch 'master' of github.com:Araq/Nimrod into upstream
This commit is contained in:
commit
88f7b7bc50
31 changed files with 459 additions and 114 deletions
|
|
@ -36,7 +36,7 @@ type
|
|||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
|
||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||
nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
||||
nnkConstDef, nnkTypeDef,
|
||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||
|
|
@ -217,10 +217,19 @@ template emit*(s: expr): stmt =
|
|||
## Example:
|
||||
##
|
||||
## emit("echo " & '"' & "hello world".toUpper & '"')
|
||||
##
|
||||
block:
|
||||
const evaluated = s
|
||||
eval: result = evaluated.parseStmt
|
||||
##
|
||||
block:
|
||||
const evaluated = s
|
||||
eval: result = evaluated.parseStmt
|
||||
when false:
|
||||
template once(x: expr): expr =
|
||||
block:
|
||||
const y = x
|
||||
y
|
||||
|
||||
macro `payload`(x: stmt): stmt = result = once(s).parseStmt
|
||||
`payload`()
|
||||
|
||||
|
||||
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
||||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
|
|
@ -323,7 +332,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
|
|||
|
||||
macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
|
||||
## Accepts a block of nimrod code and prints the parsed abstract syntax
|
||||
## tree using the `toTree` function.
|
||||
## tree using the `toTree` function. Printing is done *at compile time*.
|
||||
##
|
||||
## You can use this as a tool to explore the Nimrod's abstract syntax
|
||||
## tree and to discover what kind of nodes must be created to represent
|
||||
|
|
@ -331,7 +340,7 @@ macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
|
|||
|
||||
macro dumpLisp*(s: stmt): stmt = echo s[1].lispRepr
|
||||
## Accepts a block of nimrod code and prints the parsed abstract syntax
|
||||
## tree using the `toLisp` function.
|
||||
## tree using the `toLisp` function. Printing is done *at compile time*.
|
||||
##
|
||||
## See `dumpTree`.
|
||||
|
||||
|
|
|
|||
|
|
@ -479,7 +479,8 @@ proc setBiggestFloat*(x: TAny, y: biggestFloat) =
|
|||
proc getString*(x: TAny): string =
|
||||
## retrieve the string value out of `x`. `x` needs to represent a string.
|
||||
assert x.rawtype.kind == tyString
|
||||
result = cast[ptr string](x.value)[]
|
||||
if not isNil(cast[ptr pointer](x.value)[]):
|
||||
result = cast[ptr string](x.value)[]
|
||||
|
||||
proc setString*(x: TAny, y: string) =
|
||||
## sets the string value of `x`. `x` needs to represent a string.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,11 @@ type
|
|||
mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
|
||||
TWeekDay* = enum ## represents a weekday
|
||||
dMon, dTue, dWed, dThu, dFri, dSat, dSun
|
||||
|
||||
|
||||
var
|
||||
timezone {.importc, header: "<time.h>".}: int
|
||||
tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
|
||||
|
||||
when defined(posix):
|
||||
type
|
||||
TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
|
||||
|
|
@ -112,6 +116,20 @@ type
|
|||
yearday*: range[0..365] ## The number of days since January 1,
|
||||
## in the range 0 to 365.
|
||||
## Always 0 if the target is ECMAScript.
|
||||
isDST*: bool ## Determines whether DST is in effect. Always
|
||||
## ``False`` if time is UTC.
|
||||
tzname*: string ## The timezone this time is in. E.g. GMT
|
||||
timezone*: int ## The offset of the (non-DST) timezone in seconds
|
||||
## west of UTC.
|
||||
|
||||
TTimeInterval* = object
|
||||
miliseconds*: int ## The number of miliseconds
|
||||
seconds*: int ## The number of seconds
|
||||
minutes*: int ## The number of minutes
|
||||
hours*: int ## The number of hours
|
||||
days*: int ## The number of days
|
||||
months*: int ## The number of months
|
||||
years*: int ## The number of years
|
||||
|
||||
proc getTime*(): TTime ## gets the current calendar time
|
||||
proc getLocalTime*(t: TTime): TTimeInfo
|
||||
|
|
@ -122,7 +140,7 @@ proc getGMTime*(t: TTime): TTimeInfo
|
|||
## expressed in Coordinated Universal Time (UTC).
|
||||
|
||||
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
|
||||
## converts a broken-down time structure, expressed as local time, to
|
||||
## converts a broken-down time structure to
|
||||
## calendar time representation. The function ignores the specified
|
||||
## contents of the structure members `weekday` and `yearday` and recomputes
|
||||
## them from the other information in the broken-down time structure.
|
||||
|
|
@ -146,10 +164,90 @@ proc `<=` * (a, b: TTime): bool {.
|
|||
## returns true iff ``a <= b``.
|
||||
result = a - b <= 0
|
||||
|
||||
proc getTzname*(): tuple[nonDST, DST: string]
|
||||
## returns the local timezone; ``nonDST`` is the name of the local non-DST
|
||||
## timezone, ``DST`` is the name of the local DST timezone.
|
||||
|
||||
proc getTimezone*(): int
|
||||
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
|
||||
|
||||
proc getStartMilsecs*(): int {.deprecated.}
|
||||
## get the miliseconds from the start of the program. **Deprecated since
|
||||
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
|
||||
|
||||
proc newInterval*(miliseconds, seconds, minutes, hours, days, months,
|
||||
years: int = 0): TTimeInterval =
|
||||
## creates a new ``TTimeInterval``.
|
||||
result.miliseconds = miliseconds
|
||||
result.seconds = seconds
|
||||
result.minutes = minutes
|
||||
result.hours = hours
|
||||
result.days = days
|
||||
result.months = months
|
||||
result.years = years
|
||||
|
||||
proc isLeapYear(year: int): bool =
|
||||
if year mod 400 == 0:
|
||||
return true
|
||||
elif year mod 100 == 0:
|
||||
return false
|
||||
elif year mod 4 == 0:
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
proc getDaysInMonth(month: TMonth, year: int): int =
|
||||
# http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
|
||||
if month == mFeb: # Feb
|
||||
if isLeapYear(year):
|
||||
result = 29
|
||||
else:
|
||||
result = 28
|
||||
elif month in [mApr, mJun, mSep, mNov]: result = 30
|
||||
else: result = 31
|
||||
|
||||
proc calculateSeconds(a: TTimeInfo, interval: TTimeInterval): float =
|
||||
var anew = a
|
||||
var newinterv = interval
|
||||
result = 0.0
|
||||
|
||||
newinterv.months += interval.years * 12
|
||||
var curMonth = anew.month
|
||||
for mth in 1 .. newinterv.months:
|
||||
result += float(getDaysInMonth(curMonth, anew.year) * 24 * 60 * 60)
|
||||
if curMonth == mDec:
|
||||
curMonth = mJan
|
||||
anew.year.inc()
|
||||
else:
|
||||
curMonth.inc()
|
||||
result += float(newinterv.days * 24 * 60 * 60)
|
||||
result += float(newinterv.minutes * 60 * 60)
|
||||
result += newinterv.seconds.float
|
||||
result += newinterv.miliseconds / 1000
|
||||
|
||||
proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
|
||||
## adds ``interval`` time.
|
||||
##
|
||||
## **Note:** This has been only briefly tested and it may not be very accurate.
|
||||
let t = timeInfoToTime(a)
|
||||
var secs = calculateSeconds(a, interval)
|
||||
if a.tzname == "UTC":
|
||||
result = getGMTime(TTime(float(t) + secs))
|
||||
else:
|
||||
result = getLocalTime(TTime(float(t) + secs))
|
||||
|
||||
proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
|
||||
## subtracts ``interval`` time.
|
||||
##
|
||||
## **Note:** This has been only briefly tested, it is inaccurate especially
|
||||
## when you subtract so much that you reach the Julian calendar.
|
||||
let t = timeInfoToTime(a)
|
||||
var secs = calculateSeconds(a, interval)
|
||||
if a.tzname == "UTC":
|
||||
result = getGMTime(TTime(float(t) - secs))
|
||||
else:
|
||||
result = getLocalTime(TTime(float(t) - secs))
|
||||
|
||||
when not defined(ECMAScript):
|
||||
proc epochTime*(): float {.rtl, extern: "nt$1".}
|
||||
## gets time after the UNIX epoch (1970) in seconds. It is a float
|
||||
|
|
@ -169,7 +267,8 @@ when not defined(ECMAScript):
|
|||
## doWork()
|
||||
## echo "CPU time [s] ", cpuTime() - t0
|
||||
|
||||
when not defined(ECMAScript):
|
||||
when not defined(ECMAScript):
|
||||
|
||||
# C wrapper:
|
||||
type
|
||||
structTM {.importc: "struct tm", final.} = object
|
||||
|
|
@ -205,7 +304,7 @@ when not defined(ECMAScript):
|
|||
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
|
||||
|
||||
# our own procs on top of that:
|
||||
proc tmToTimeInfo(tm: structTM): TTimeInfo =
|
||||
proc tmToTimeInfo(tm: structTM, local: bool): TTimeInfo =
|
||||
const
|
||||
weekDays: array [0..6, TWeekDay] = [
|
||||
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
|
||||
|
|
@ -217,6 +316,18 @@ when not defined(ECMAScript):
|
|||
result.year = tm.year + 1900'i32
|
||||
result.weekday = weekDays[int(tm.weekDay)]
|
||||
result.yearday = int(tm.yearday)
|
||||
result.isDST = tm.isDST > 0
|
||||
#result.tzname = if local: getTzname()[if result.isDST: 0 else: 1] else: "UTC"
|
||||
# TODO: ^^^ Crashes the compiler.
|
||||
if local:
|
||||
if result.isDST:
|
||||
result.tzname = getTzname()[0]
|
||||
if not result.isDST:
|
||||
result.tzname = getTzname()[1]
|
||||
else:
|
||||
result.tzname = "UTC"
|
||||
|
||||
result.timezone = if local: getTimezone() else: 0
|
||||
|
||||
proc timeInfoToTM(t: TTimeInfo): structTM =
|
||||
const
|
||||
|
|
@ -229,7 +340,7 @@ when not defined(ECMAScript):
|
|||
result.year = t.year - 1900
|
||||
result.weekday = weekDays[t.weekDay]
|
||||
result.yearday = t.yearday
|
||||
result.isdst = -1
|
||||
result.isdst = if t.isDST: 1 else: 0
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc `-` (a, b: TTime): int64 =
|
||||
|
|
@ -251,13 +362,13 @@ when not defined(ECMAScript):
|
|||
proc getTime(): TTime = return timec(nil)
|
||||
proc getLocalTime(t: TTime): TTimeInfo =
|
||||
var a = t
|
||||
result = tmToTimeInfo(localtime(addr(a))[])
|
||||
result = tmToTimeInfo(localtime(addr(a))[], true)
|
||||
# copying is needed anyway to provide reentrancity; thus
|
||||
# the convertion is not expensive
|
||||
|
||||
proc getGMTime(t: TTime): TTimeInfo =
|
||||
var a = t
|
||||
result = tmToTimeInfo(gmtime(addr(a))[])
|
||||
result = tmToTimeInfo(gmtime(addr(a))[], false)
|
||||
# copying is needed anyway to provide reentrancity; thus
|
||||
# the convertion is not expensive
|
||||
|
||||
|
|
@ -294,7 +405,13 @@ when not defined(ECMAScript):
|
|||
proc winTimeToUnixTime*(t: int64): TTime =
|
||||
## converts a Windows time to a UNIX `TTime` (``time_t``)
|
||||
result = TTime((t - epochDiff) div rateDiff)
|
||||
|
||||
|
||||
proc getTzname(): tuple[nonDST, DST: string] =
|
||||
return ($tzname[0], $tzname[1])
|
||||
|
||||
proc getTimezone(): int =
|
||||
return timezone
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc epochTime(): float =
|
||||
when defined(posix):
|
||||
|
|
@ -417,18 +534,21 @@ proc format*(info: TTimeInfo, f: string): string =
|
|||
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
|
||||
## y(yyyy) This displays the year to different digits. You most likely only want 2 or 4 'y's
|
||||
## yy Displays the year to two digits. ``2012 -> 12``
|
||||
## yyyy Displays the year to four digits. ``2012 -> 2012``
|
||||
## yyyy Displays the year to four digits. ``2012 -> 2012``
|
||||
## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5``
|
||||
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
|
||||
## zzz Same as above but with ``:00``. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
|
||||
## ZZZ Displays the name of the timezone. ``GMT -> GMT``, ``EST -> EST``
|
||||
## ========== ================================================================================= ================================================
|
||||
|
||||
##
|
||||
## Other strings can be inserted by putting them in ``''``. For example ``hh'->'mm`` will give ``01->56``.
|
||||
|
||||
result = ""
|
||||
var i = 0
|
||||
var currentF = ""
|
||||
while True:
|
||||
case f[i]
|
||||
of '\0':
|
||||
break
|
||||
of ' ', '-', '/', ':', '\'':
|
||||
of ' ', '-', '/', ':', '\'', '\0':
|
||||
case currentF
|
||||
of "d":
|
||||
result.add($info.monthday)
|
||||
|
|
@ -437,9 +557,9 @@ proc format*(info: TTimeInfo, f: string): string =
|
|||
result.add("0")
|
||||
result.add($info.monthday)
|
||||
of "ddd":
|
||||
result.add(($info.month)[0 .. 2])
|
||||
result.add(($info.monthday)[0 .. 2])
|
||||
of "dddd":
|
||||
result.add($info.month)
|
||||
result.add($info.monthday)
|
||||
of "h":
|
||||
result.add($(info.hour - 12))
|
||||
of "hh":
|
||||
|
|
@ -460,11 +580,11 @@ proc format*(info: TTimeInfo, f: string): string =
|
|||
result.add('0')
|
||||
result.add($info.minute)
|
||||
of "M":
|
||||
result.add($(int(info.month)))
|
||||
result.add($(int(info.month)+1))
|
||||
of "MM":
|
||||
if int(info.month) < 10:
|
||||
result.add('0')
|
||||
result.add($(int(info.month)))
|
||||
result.add($(int(info.month)+1))
|
||||
of "MMM":
|
||||
result.add(($info.month)[0..2])
|
||||
of "MMMM":
|
||||
|
|
@ -500,12 +620,32 @@ proc format*(info: TTimeInfo, f: string): string =
|
|||
of "yyyyy":
|
||||
result.add('0')
|
||||
result.add($info.year)
|
||||
of "z":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
result.add($hrs)
|
||||
of "zz":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
||||
result.add($hrs)
|
||||
if hrs.abs < 10:
|
||||
var atIndex = result.len-(($hrs).len-(if hrs < 0: 1 else: 0))
|
||||
result.insert("0", atIndex)
|
||||
of "zzz":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
||||
result.add($hrs & ":00")
|
||||
if hrs.abs < 10:
|
||||
var atIndex = result.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
|
||||
result.insert("0", atIndex)
|
||||
of "ZZZ":
|
||||
result.add(info.tzname)
|
||||
of "":
|
||||
nil # Do nothing.
|
||||
else:
|
||||
raise newException(EInvalidValue, "Invalid format string: " & currentF)
|
||||
|
||||
currentF = ""
|
||||
if f[i] == '\0': break
|
||||
|
||||
if f[i] == '\'':
|
||||
inc(i) # Skip '
|
||||
|
|
|
|||
|
|
@ -49,9 +49,13 @@ type
|
|||
## a type description (for templates)
|
||||
void* {.magic: "VoidType".} ## meta type to denote the absense of any type
|
||||
|
||||
TInteger* = int|char|int8|int16|int32|int64|bool|enum
|
||||
TInteger* = int|int8|int16|int32|int64
|
||||
## type class matching all integer types
|
||||
|
||||
TOrdinal* = TInteger|bool|enum
|
||||
## type class matching all ordinal types; however this includes enums with
|
||||
## holes.
|
||||
|
||||
TNumber* = TInteger|float|float32|float64
|
||||
## type class matching all number types
|
||||
|
||||
|
|
@ -190,6 +194,7 @@ type
|
|||
msg* {.exportc: "message".}: string ## the exception's message. Not
|
||||
## providing an exception message
|
||||
## is bad style.
|
||||
trace: string
|
||||
|
||||
EAsynch* = object of E_Base ## Abstract exception class for
|
||||
## *asynchronous exceptions* (interrupts).
|
||||
|
|
@ -1195,6 +1200,15 @@ iterator `..`*[S, T](a: S, b: T): T {.inline.} =
|
|||
yield res
|
||||
inc res
|
||||
|
||||
iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
|
||||
inline, magic: "OmpParFor", sideEffect.} =
|
||||
## parallel loop iterator. Same as `..` but the loop may run in parallel.
|
||||
## `annotation` is an additional annotation for the code generator to use.
|
||||
## Note that the compiler maps that to
|
||||
## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as
|
||||
## such isn't aware of the parallelism in your code. Be careful.
|
||||
nil
|
||||
|
||||
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.}
|
||||
proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.}
|
||||
proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.}
|
||||
|
|
@ -1900,6 +1914,10 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
|||
when hostOS != "standalone":
|
||||
proc getStackTrace*(): string
|
||||
## gets the current stack trace. This is only works for debug builds.
|
||||
|
||||
proc getStackTrace*(e: ref E_Base): string
|
||||
## gets the stack trace associated with `e`, which is the stack that
|
||||
## lead to the ``raise`` statement. This is only works for debug builds.
|
||||
|
||||
{.push stack_trace: off.}
|
||||
when hostOS == "standalone":
|
||||
|
|
@ -2177,19 +2195,19 @@ proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline, noSideEffect.} =
|
|||
## Binary `*=` operator for ordinals
|
||||
x = x * y
|
||||
|
||||
proc `+=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||
proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
|
||||
## Increments in placee a floating point number
|
||||
x = x + y
|
||||
|
||||
proc `-=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||
proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
|
||||
## Decrements in place a floating point number
|
||||
x = x - y
|
||||
|
||||
proc `*=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||
proc `*=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
|
||||
## Multiplies in place a floating point number
|
||||
x = x * y
|
||||
|
||||
proc `/=` *(x: var float, y:float) {.inline, noSideEffect.} =
|
||||
proc `/=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
|
||||
## Divides in place a floating point number
|
||||
x = x / y
|
||||
|
||||
|
|
@ -2283,5 +2301,18 @@ template eval*(blk: stmt): stmt =
|
|||
macro payload(x: stmt): stmt = blk
|
||||
payload()
|
||||
|
||||
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
|
||||
## inserts `item` into `x` at position `i`.
|
||||
var xl = x.len
|
||||
setLen(x, xl+item.len)
|
||||
var j = xl-1
|
||||
while j >= i:
|
||||
shallowCopy(x[j+item.len], x[j])
|
||||
dec(j)
|
||||
j = 0
|
||||
while j < item.len:
|
||||
x[j+i] = item[j]
|
||||
inc(j)
|
||||
|
||||
when defined(initDebugger):
|
||||
initDebugger()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
proc genericResetAux(dest: Pointer, n: ptr TNimNode)
|
||||
|
||||
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool)
|
||||
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
|
||||
var
|
||||
|
|
@ -20,10 +22,16 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
|
|||
for i in 0..n.len-1:
|
||||
genericAssignAux(dest, src, n.sons[i], shallow)
|
||||
of nkCase:
|
||||
var dd = selectBranch(dest, n)
|
||||
var m = selectBranch(src, n)
|
||||
# reset if different branches are in use; note different branches also
|
||||
# imply that's not self-assignment (``x = x``)!
|
||||
if m != dd and dd != nil:
|
||||
genericResetAux(dest, dd)
|
||||
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||
n.typ.size)
|
||||
var m = selectBranch(src, n)
|
||||
if m != nil: genericAssignAux(dest, src, m, shallow)
|
||||
if m != nil:
|
||||
genericAssignAux(dest, src, m, shallow)
|
||||
of nkNone: sysAssert(false, "genericAssignAux")
|
||||
#else:
|
||||
# echo "ugh memory corruption! ", n.kind
|
||||
|
|
|
|||
|
|
@ -194,6 +194,9 @@ proc quitOrDebug() {.inline.} =
|
|||
|
||||
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||
e.name = ename
|
||||
when hasSomeStackTrace:
|
||||
e.trace = ""
|
||||
rawWriteStackTrace(e.trace)
|
||||
if localRaiseHook != nil:
|
||||
if not localRaiseHook(e): return
|
||||
if globalRaiseHook != nil:
|
||||
|
|
@ -253,6 +256,12 @@ proc getStackTrace(): string =
|
|||
else:
|
||||
result = "No stack traceback available\n"
|
||||
|
||||
proc getStackTrace(e: ref E_Base): string =
|
||||
if not isNil(e) and not isNil(e.trace):
|
||||
result = e.trace
|
||||
else:
|
||||
result = ""
|
||||
|
||||
when defined(endb):
|
||||
var
|
||||
dbgAborting: bool # whether the debugger wants to abort
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue