fixes for exception handling; added system.compileOption
This commit is contained in:
parent
030d46f218
commit
866572e2e4
18 changed files with 329 additions and 165 deletions
|
|
@ -177,10 +177,6 @@ __TINYC__
|
||||||
**
|
**
|
||||||
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
|
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
|
||||||
** llrint and llrintf which fix this problem as a side effect.
|
** llrint and llrintf which fix this problem as a side effect.
|
||||||
**
|
|
||||||
** On Unix-like systems, the configure process should have detected the
|
|
||||||
** presence of these functions. If they weren't found we have to replace them
|
|
||||||
** here with a standard C cast.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -444,4 +440,12 @@ __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define likely(x) __builtin_expect(x, 1)
|
||||||
|
# define unlikely(x) __builtin_expect(x, 0)
|
||||||
|
#else
|
||||||
|
# define likely(x) (x)
|
||||||
|
# define unlikely(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ type
|
||||||
E_Base* {.compilerproc.} = object of TObject ## base exception class;
|
E_Base* {.compilerproc.} = object of TObject ## base exception class;
|
||||||
## each exception has to
|
## each exception has to
|
||||||
## inherit from `E_Base`.
|
## inherit from `E_Base`.
|
||||||
|
parent: ref E_Base ## parent exception (can be used as a stack)
|
||||||
name: cstring ## The exception's name is its Nimrod identifier.
|
name: cstring ## The exception's name is its Nimrod identifier.
|
||||||
## This field is filled automatically in the
|
## This field is filled automatically in the
|
||||||
## ``raise`` statement.
|
## ``raise`` statement.
|
||||||
|
|
@ -717,6 +718,22 @@ const
|
||||||
## a string that describes the application type. Possible values:
|
## a string that describes the application type. Possible values:
|
||||||
## "console", "gui", "lib".
|
## "console", "gui", "lib".
|
||||||
|
|
||||||
|
proc compileOption*(option: string): bool {.
|
||||||
|
magic: "CompileOption", noSideEffect.}
|
||||||
|
## can be used to determine a on|off compile-time option. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## when compileOption("floatchecks"):
|
||||||
|
## echo "compiled with floating point NaN and Inf checks"
|
||||||
|
|
||||||
|
proc compileOption*(option, arg: string): bool {.
|
||||||
|
magic: "CompileOptionArg", noSideEffect.}
|
||||||
|
## can be used to determine an enum compile-time option. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## when compileOption("opt", "size") and compileOption("gc", "boehm"):
|
||||||
|
## echo "compiled with optimization for size and uses Boehm's GC"
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
include "system/cgprocs"
|
include "system/cgprocs"
|
||||||
|
|
||||||
|
|
@ -961,14 +978,6 @@ proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
|
||||||
|
|
||||||
#proc writeStackTrace() {.export: "writeStackTrace".}
|
#proc writeStackTrace() {.export: "writeStackTrace".}
|
||||||
|
|
||||||
when not defined(NimrodVM):
|
|
||||||
proc getCurrentExceptionMsg*(): string {.exportc.}
|
|
||||||
## retrieves the error message that was attached to the current
|
|
||||||
## exception; if there is none, "" is returned.
|
|
||||||
|
|
||||||
proc getCurrentException*(): ref E_Base
|
|
||||||
## retrieves the current exception; if there is none, nil is returned.
|
|
||||||
|
|
||||||
# new constants:
|
# new constants:
|
||||||
const
|
const
|
||||||
inf* {.magic: "Inf".} = 1.0 / 0.0
|
inf* {.magic: "Inf".} = 1.0 / 0.0
|
||||||
|
|
@ -1168,15 +1177,6 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
|
||||||
## `op` to every item in `data`.
|
## `op` to every item in `data`.
|
||||||
for i in 0..data.len-1: op(data[i])
|
for i in 0..data.len-1: op(data[i])
|
||||||
|
|
||||||
|
|
||||||
# ----------------- FPU ------------------------------------------------------
|
|
||||||
|
|
||||||
#proc disableFPUExceptions*()
|
|
||||||
# disables all floating point unit exceptions
|
|
||||||
|
|
||||||
#proc enableFPUExceptions*()
|
|
||||||
# enables all floating point unit exceptions
|
|
||||||
|
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- GC interface ---------------------------------------------
|
||||||
|
|
||||||
proc GC_disable*() {.rtl.}
|
proc GC_disable*() {.rtl.}
|
||||||
|
|
@ -1577,14 +1577,15 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
include "system/assign"
|
include "system/assign"
|
||||||
include "system/repr"
|
include "system/repr"
|
||||||
|
|
||||||
# we have to implement it here after gentostr for the cstrToNimStrDummy proc
|
proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
|
||||||
proc getCurrentExceptionMsg(): string =
|
## retrieves the current exception; if there is none, nil is returned.
|
||||||
if excHandler == nil: return ""
|
result = currException
|
||||||
return $excHandler.exc.msg
|
|
||||||
|
|
||||||
proc getCurrentException(): ref E_Base =
|
proc getCurrentExceptionMsg*(): string {.inline.} =
|
||||||
if excHandler != nil:
|
## retrieves the error message that was attached to the current
|
||||||
result = excHandler.exc
|
## exception; if there is none, "" is returned.
|
||||||
|
var e = getCurrentException()
|
||||||
|
return if e == nil: "" else: e.msg
|
||||||
|
|
||||||
{.push stack_trace: off.}
|
{.push stack_trace: off.}
|
||||||
when defined(endb):
|
when defined(endb):
|
||||||
|
|
@ -1594,6 +1595,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
include "system/profiler"
|
include "system/profiler"
|
||||||
{.pop.} # stacktrace
|
{.pop.} # stacktrace
|
||||||
|
|
||||||
|
proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
|
||||||
|
## can be used to mark a condition to be likely. This is a hint for the
|
||||||
|
## optimizer.
|
||||||
|
|
||||||
|
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
||||||
|
## can be used to mark a condition to be unlikely. This is a hint for the
|
||||||
|
## optimizer.
|
||||||
|
|
||||||
elif defined(ecmaScript):
|
elif defined(ecmaScript):
|
||||||
include "system/ecmasys"
|
include "system/ecmasys"
|
||||||
elif defined(NimrodVM):
|
elif defined(NimrodVM):
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,6 @@ else:
|
||||||
proc writeToStdErr(msg: CString) =
|
proc writeToStdErr(msg: CString) =
|
||||||
discard MessageBoxA(0, msg, nil, 0)
|
discard MessageBoxA(0, msg, nil, 0)
|
||||||
|
|
||||||
proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.}
|
|
||||||
proc reraiseException() {.compilerproc.}
|
|
||||||
|
|
||||||
proc registerSignalHandler() {.compilerproc.}
|
proc registerSignalHandler() {.compilerproc.}
|
||||||
|
|
||||||
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||||
|
|
@ -34,20 +31,29 @@ type
|
||||||
PSafePoint = ptr TSafePoint
|
PSafePoint = ptr TSafePoint
|
||||||
TSafePoint {.compilerproc, final.} = object
|
TSafePoint {.compilerproc, final.} = object
|
||||||
prev: PSafePoint # points to next safe point ON THE STACK
|
prev: PSafePoint # points to next safe point ON THE STACK
|
||||||
exc: ref E_Base
|
|
||||||
status: int
|
status: int
|
||||||
|
exc: ref E_Base # XXX only needed for bootstrapping
|
||||||
context: C_JmpBuf
|
context: C_JmpBuf
|
||||||
|
|
||||||
var
|
var
|
||||||
excHandler {.compilerproc.}: PSafePoint = nil
|
excHandler {.compilerproc.}: PSafePoint = nil
|
||||||
# list of exception handlers
|
# list of exception handlers
|
||||||
# a global variable for the root of all try blocks
|
# a global variable for the root of all try blocks
|
||||||
|
currException: ref E_Base
|
||||||
|
|
||||||
proc reraiseException() =
|
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
||||||
if excHandler == nil:
|
s.prev = excHandler
|
||||||
raise newException(ENoExceptionToReraise, "no exception to reraise")
|
excHandler = s
|
||||||
else:
|
|
||||||
c_longjmp(excHandler.context, 1)
|
proc popSafePoint {.compilerRtl, inl.} =
|
||||||
|
excHandler = excHandler.prev
|
||||||
|
|
||||||
|
proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} =
|
||||||
|
e.parent = currException
|
||||||
|
currException = e
|
||||||
|
|
||||||
|
proc popCurrentException {.compilerRtl, inl.} =
|
||||||
|
currException = currException.parent
|
||||||
|
|
||||||
type
|
type
|
||||||
PFrame = ptr TFrame
|
PFrame = ptr TFrame
|
||||||
|
|
@ -114,6 +120,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||||
add(s, stackTraceNewLine)
|
add(s, stackTraceNewLine)
|
||||||
|
|
||||||
proc rawWriteStackTrace(s: var string) =
|
proc rawWriteStackTrace(s: var string) =
|
||||||
|
when compileOption("stacktrace") or compileOption("linetrace"):
|
||||||
if framePtr == nil:
|
if framePtr == nil:
|
||||||
add(s, "No stack traceback available")
|
add(s, "No stack traceback available")
|
||||||
add(s, stackTraceNewLine)
|
add(s, stackTraceNewLine)
|
||||||
|
|
@ -121,6 +128,9 @@ proc rawWriteStackTrace(s: var string) =
|
||||||
add(s, "Traceback (most recent call last)")
|
add(s, "Traceback (most recent call last)")
|
||||||
add(s, stackTraceNewLine)
|
add(s, stackTraceNewLine)
|
||||||
auxWriteStackTrace(framePtr, s)
|
auxWriteStackTrace(framePtr, 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):
|
||||||
|
|
@ -128,11 +138,11 @@ proc quitOrDebug() {.inline.} =
|
||||||
else:
|
else:
|
||||||
endbStep() # call the debugger
|
endbStep() # call the debugger
|
||||||
|
|
||||||
proc raiseException(e: ref E_Base, ename: CString) =
|
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||||
GC_disable() # a bad thing is an error in the GC while raising an exception
|
GC_disable() # a bad thing is an error in the GC while raising an exception
|
||||||
e.name = ename
|
e.name = ename
|
||||||
if excHandler != nil:
|
if excHandler != nil:
|
||||||
excHandler.exc = e
|
pushCurrentException(e)
|
||||||
c_longjmp(excHandler.context, 1)
|
c_longjmp(excHandler.context, 1)
|
||||||
else:
|
else:
|
||||||
if not isNil(buf):
|
if not isNil(buf):
|
||||||
|
|
@ -152,6 +162,12 @@ proc raiseException(e: ref E_Base, ename: CString) =
|
||||||
quitOrDebug()
|
quitOrDebug()
|
||||||
GC_enable()
|
GC_enable()
|
||||||
|
|
||||||
|
proc reraiseException() {.compilerRtl.} =
|
||||||
|
if currException == nil:
|
||||||
|
raise newException(ENoExceptionToReraise, "no exception to reraise")
|
||||||
|
else:
|
||||||
|
raiseException(currException, currException.name)
|
||||||
|
|
||||||
var
|
var
|
||||||
gAssertionFailed: ref EAssertionFailed
|
gAssertionFailed: ref EAssertionFailed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ type
|
||||||
decStack: TCellSeq # cells in the stack that are to decref again
|
decStack: TCellSeq # cells in the stack that are to decref again
|
||||||
cycleRoots: TCellSet
|
cycleRoots: TCellSet
|
||||||
tempStack: TCellSeq # temporary stack for recursion elimination
|
tempStack: TCellSeq # temporary stack for recursion elimination
|
||||||
|
cycleRootsLock: TSysLock
|
||||||
|
zctLock: TSysLock
|
||||||
stat: TGcStat
|
stat: TGcStat
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -68,12 +70,22 @@ var
|
||||||
gch: TGcHeap
|
gch: TGcHeap
|
||||||
cycleThreshold: int = InitialCycleThreshold
|
cycleThreshold: int = InitialCycleThreshold
|
||||||
recGcLock: int = 0
|
recGcLock: int = 0
|
||||||
# we use a lock to prevend the garbage collector to be triggered in a
|
# we use a lock to prevent the garbage collector to be triggered in a
|
||||||
# finalizer; the collector should not call itself this way! Thus every
|
# finalizer; the collector should not call itself this way! Thus every
|
||||||
# object allocated by a finalizer will not trigger a garbage collection.
|
# object allocated by a finalizer will not trigger a garbage collection.
|
||||||
# This is wasteful but safe. This is a lock against recursive garbage
|
# This is wasteful but safe. This is a lock against recursive garbage
|
||||||
# collection, not a lock for threads!
|
# collection, not a lock for threads!
|
||||||
|
|
||||||
|
proc lock(gch: var TGcHeap) {.inline.} =
|
||||||
|
if isMultiThreaded:
|
||||||
|
Lock(gch.zctLock)
|
||||||
|
lock(gch.cycleRootsLock)
|
||||||
|
|
||||||
|
proc unlock(gch: var TGcHeap) {.inline.} =
|
||||||
|
if isMultiThreaded:
|
||||||
|
unlock(gch.zctLock)
|
||||||
|
unlock(gch.cycleRootsLock)
|
||||||
|
|
||||||
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
|
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
|
||||||
if (c.refcount and rcZct) == 0:
|
if (c.refcount and rcZct) == 0:
|
||||||
c.refcount = c.refcount and not colorMask or rcZct
|
c.refcount = c.refcount and not colorMask or rcZct
|
||||||
|
|
@ -159,7 +171,7 @@ when traceGC:
|
||||||
for c in elements(states[csAllocated]):
|
for c in elements(states[csAllocated]):
|
||||||
inc(e)
|
inc(e)
|
||||||
if c in states[csZctFreed]: inc(z)
|
if c in states[csZctFreed]: inc(z)
|
||||||
elif c in states[csCycFreed]: inc(z)
|
elif c in states[csCycFreed]: inc(y)
|
||||||
else: writeCell("leak", c)
|
else: writeCell("leak", c)
|
||||||
cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
|
cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
|
||||||
e, z, y)
|
e, z, y)
|
||||||
|
|
@ -190,25 +202,28 @@ proc prepareDealloc(cell: PCell) =
|
||||||
|
|
||||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
|
if isMultiThreaded: Lock(gch.cycleRootsLock)
|
||||||
incl(gch.cycleRoots, c)
|
incl(gch.cycleRoots, c)
|
||||||
|
if isMultiThreaded: Unlock(gch.cycleRootsLock)
|
||||||
|
|
||||||
proc rtlAddZCT(c: PCell) {.rtl, inl.} =
|
proc rtlAddZCT(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
|
if isMultiThreaded: Lock(gch.zctLock)
|
||||||
addZCT(gch.zct, c)
|
addZCT(gch.zct, c)
|
||||||
|
if isMultiThreaded: Unlock(gch.zctLock)
|
||||||
|
|
||||||
proc decRef(c: PCell) {.inline.} =
|
proc decRef(c: PCell) {.inline.} =
|
||||||
when stressGC:
|
when stressGC:
|
||||||
if c.refcount <% rcIncrement:
|
if c.refcount <% rcIncrement:
|
||||||
writeCell("broken cell", c)
|
writeCell("broken cell", c)
|
||||||
assert(c.refcount >=% rcIncrement)
|
assert(c.refcount >=% rcIncrement)
|
||||||
c.refcount = c.refcount -% rcIncrement
|
if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
|
||||||
if c.refcount <% rcIncrement:
|
|
||||||
rtlAddZCT(c)
|
rtlAddZCT(c)
|
||||||
elif canBeCycleRoot(c):
|
elif canBeCycleRoot(c):
|
||||||
rtlAddCycleRoot(c)
|
rtlAddCycleRoot(c)
|
||||||
|
|
||||||
proc incRef(c: PCell) {.inline.} =
|
proc incRef(c: PCell) {.inline.} =
|
||||||
c.refcount = c.refcount +% rcIncrement
|
discard atomicInc(c.refcount, rcIncrement)
|
||||||
if canBeCycleRoot(c):
|
if canBeCycleRoot(c):
|
||||||
rtlAddCycleRoot(c)
|
rtlAddCycleRoot(c)
|
||||||
|
|
||||||
|
|
@ -228,11 +243,10 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
|
||||||
# cycle is possible.
|
# cycle is possible.
|
||||||
if src != nil:
|
if src != nil:
|
||||||
var c = usrToCell(src)
|
var c = usrToCell(src)
|
||||||
c.refcount = c.refcount +% rcIncrement
|
discard atomicInc(c.refcount, rcIncrement)
|
||||||
if dest^ != nil:
|
if dest^ != nil:
|
||||||
var c = usrToCell(dest^)
|
var c = usrToCell(dest^)
|
||||||
c.refcount = c.refcount -% rcIncrement
|
if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
|
||||||
if c.refcount <% rcIncrement:
|
|
||||||
rtlAddZCT(c)
|
rtlAddZCT(c)
|
||||||
dest^ = src
|
dest^ = src
|
||||||
|
|
||||||
|
|
@ -260,6 +274,8 @@ proc initGC() =
|
||||||
init(gch.tempStack)
|
init(gch.tempStack)
|
||||||
Init(gch.cycleRoots)
|
Init(gch.cycleRoots)
|
||||||
Init(gch.decStack)
|
Init(gch.decStack)
|
||||||
|
InitLock(gch.cycleRootsLock)
|
||||||
|
InitLock(gch.zctLock)
|
||||||
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
|
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) =
|
||||||
|
|
@ -310,6 +326,7 @@ proc checkCollection {.inline.} =
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
|
lock(gch)
|
||||||
assert(typ.kind in {tyRef, tyString, tySequence})
|
assert(typ.kind in {tyRef, tyString, tySequence})
|
||||||
checkCollection()
|
checkCollection()
|
||||||
var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell)))
|
||||||
|
|
@ -338,14 +355,17 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
add(gch.zct, res)
|
add(gch.zct, res)
|
||||||
when logGC: writeCell("new cell", res)
|
when logGC: writeCell("new cell", res)
|
||||||
gcTrace(res, csAllocated)
|
gcTrace(res, csAllocated)
|
||||||
|
unlock(gch)
|
||||||
result = cellToUsr(res)
|
result = cellToUsr(res)
|
||||||
|
|
||||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
|
# `newObj` already uses locks, so no need for them here.
|
||||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).space = len
|
cast[PGenericSeq](result).space = len
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||||
|
lock(gch)
|
||||||
checkCollection()
|
checkCollection()
|
||||||
var ol = usrToCell(old)
|
var ol = usrToCell(old)
|
||||||
assert(ol.typ != nil)
|
assert(ol.typ != nil)
|
||||||
|
|
@ -383,6 +403,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||||
else:
|
else:
|
||||||
assert(ol.typ != nil)
|
assert(ol.typ != nil)
|
||||||
zeroMem(ol, sizeof(TCell))
|
zeroMem(ol, sizeof(TCell))
|
||||||
|
unlock(gch)
|
||||||
result = cellToUsr(res)
|
result = cellToUsr(res)
|
||||||
|
|
||||||
# ---------------- cycle collector -------------------------------------------
|
# ---------------- cycle collector -------------------------------------------
|
||||||
|
|
@ -632,9 +653,9 @@ proc collectCT(gch: var TGcHeap) =
|
||||||
unmarkStackAndRegisters(gch)
|
unmarkStackAndRegisters(gch)
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc GC_disable() = inc(recGcLock)
|
proc GC_disable() = discard atomicInc(recGcLock, 1)
|
||||||
proc GC_enable() =
|
proc GC_enable() =
|
||||||
if recGcLock > 0: dec(recGcLock)
|
if recGcLock > 0: discard atomicDec(recGcLock, 1)
|
||||||
|
|
||||||
proc GC_setStrategy(strategy: TGC_Strategy) =
|
proc GC_setStrategy(strategy: TGC_Strategy) =
|
||||||
case strategy
|
case strategy
|
||||||
|
|
@ -651,10 +672,12 @@ when not defined(useNimRtl):
|
||||||
# set to the max value to suppress the cycle detector
|
# set to the max value to suppress the cycle detector
|
||||||
|
|
||||||
proc GC_fullCollect() =
|
proc GC_fullCollect() =
|
||||||
|
lock(gch)
|
||||||
var oldThreshold = cycleThreshold
|
var oldThreshold = cycleThreshold
|
||||||
cycleThreshold = 0 # forces cycle collection
|
cycleThreshold = 0 # forces cycle collection
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
cycleThreshold = oldThreshold
|
cycleThreshold = oldThreshold
|
||||||
|
unlock(gch)
|
||||||
|
|
||||||
proc GC_getStatistics(): string =
|
proc GC_getStatistics(): string =
|
||||||
GC_disable()
|
GC_disable()
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ when defined(gcc) or defined(llvm_gcc):
|
||||||
elif defined(vcc):
|
elif defined(vcc):
|
||||||
proc sync_add_and_fetch(p: var int, val: int): int {.
|
proc sync_add_and_fetch(p: var int, val: int): int {.
|
||||||
importc: "NimXadd", nodecl.}
|
importc: "NimXadd", nodecl.}
|
||||||
|
else:
|
||||||
|
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
|
||||||
|
inc(p, val)
|
||||||
|
result = p
|
||||||
|
|
||||||
const
|
const
|
||||||
isMultiThreaded* = true
|
isMultiThreaded* = true
|
||||||
|
|
@ -37,12 +41,51 @@ proc atomicDec(memLoc: var int, x: int): int =
|
||||||
dec(memLoc, x)
|
dec(memLoc, x)
|
||||||
result = memLoc
|
result = memLoc
|
||||||
|
|
||||||
|
when defined(Windows):
|
||||||
|
type
|
||||||
|
THandle = int
|
||||||
|
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
|
||||||
|
DebugInfo: pointer
|
||||||
|
LockCount: int32
|
||||||
|
RecursionCount: int32
|
||||||
|
OwningThread: int
|
||||||
|
LockSemaphore: int
|
||||||
|
Reserved: int32
|
||||||
|
|
||||||
|
proc InitLock(L: var TSysLock) {.stdcall,
|
||||||
|
dynlib: "kernel32", importc: "InitializeCriticalSection".}
|
||||||
|
proc Lock(L: var TSysLock) {.stdcall,
|
||||||
|
dynlib: "kernel32", importc: "EnterCriticalSection".}
|
||||||
|
proc Unlock(L: var TSysLock) {.stdcall,
|
||||||
|
dynlib: "kernel32", importc: "LeaveCriticalSection".}
|
||||||
|
|
||||||
|
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
|
||||||
|
lpStartAddress: pointer, lpParameter: Pointer,
|
||||||
|
dwCreationFlags: int32, lpThreadId: var int32): THandle {.
|
||||||
|
stdcall, dynlib: "kernel32", importc: "CreateThread".}
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
type
|
||||||
|
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
|
||||||
|
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
|
||||||
|
|
||||||
|
proc InitLock(L: var TSysLock, attr: pointer = nil) {.
|
||||||
|
importc: "pthread_mutex_init", header: "<pthread.h>".}
|
||||||
|
proc Lock(L: var TSysLock) {.
|
||||||
|
importc: "pthread_mutex_lock", header: "<pthread.h>".}
|
||||||
|
proc Unlock(L: var TSysLock) {.
|
||||||
|
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TThread* {.final, pure.} = object
|
TThread* {.final, pure.} = object
|
||||||
|
id: int
|
||||||
next: ptr TThread
|
next: ptr TThread
|
||||||
TThreadFunc* = proc (closure: pointer)
|
TThreadFunc* = proc (closure: pointer) {.cdecl.}
|
||||||
|
|
||||||
proc createThread*(t: var TThread, fn: TThreadFunc) =
|
proc createThread*(t: var TThread, fn: TThreadFunc) =
|
||||||
|
|
||||||
nil
|
nil
|
||||||
|
|
||||||
proc destroyThread*(t: var TThread) =
|
proc destroyThread*(t: var TThread) =
|
||||||
|
|
@ -50,4 +93,3 @@ proc destroyThread*(t: var TThread) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ type
|
||||||
|
|
||||||
const
|
const
|
||||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
|
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
|
||||||
"noconv"]
|
"closure", "noconv"]
|
||||||
|
|
||||||
type
|
type
|
||||||
TNodeKind* = enum # order is extremely important, because ranges are used
|
TNodeKind* = enum # order is extremely important, because ranges are used
|
||||||
|
|
@ -329,8 +329,9 @@ type
|
||||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
||||||
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
||||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||||
mNaN, mInf,
|
mNaN, mInf, mNegInf,
|
||||||
mNegInf, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
mCompileOption, mCompileOptionArg,
|
||||||
|
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
||||||
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
||||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal,
|
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal,
|
||||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
||||||
|
|
|
||||||
|
|
@ -27,21 +27,15 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n",
|
appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n",
|
||||||
[toRope(line), makeCString(toFilename(t.info).extractFilename)])
|
[toRope(line), makeCString(toFilename(t.info).extractFilename)])
|
||||||
|
|
||||||
proc finishTryStmt(p: BProc, howMany: int) =
|
proc popSafePoints(p: BProc, howMany: int) =
|
||||||
for i in countup(1, howMany):
|
for i in countup(1, howMany):
|
||||||
inc(p.labels, 3)
|
appcg(p, cpsStmts, "#popSafePoint();$n", [])
|
||||||
appff(p.s[cpsStmts], "excHandler = excHandler->prev;$n",
|
|
||||||
"%LOC$1 = load %TSafePoint** @excHandler$n" &
|
|
||||||
"%LOC$2 = getelementptr %TSafePoint* %LOC$1, %NI 0$n" &
|
|
||||||
"%LOC$3 = load %TSafePoint** %LOC$2$n" &
|
|
||||||
"store %TSafePoint* %LOC$3, %TSafePoint** @excHandler$n",
|
|
||||||
[toRope(p.labels), toRope(p.labels - 1), toRope(p.labels - 2)])
|
|
||||||
|
|
||||||
proc genReturnStmt(p: BProc, t: PNode) =
|
proc genReturnStmt(p: BProc, t: PNode) =
|
||||||
p.beforeRetNeeded = true
|
p.beforeRetNeeded = true
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
if (t.sons[0] != nil): genStmts(p, t.sons[0])
|
if (t.sons[0] != nil): genStmts(p, t.sons[0])
|
||||||
finishTryStmt(p, p.nestedTryStmts)
|
popSafePoints(p, p.nestedTryStmts)
|
||||||
appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
||||||
|
|
||||||
proc genVarTuple(p: BProc, n: PNode) =
|
proc genVarTuple(p: BProc, n: PNode) =
|
||||||
|
|
@ -202,7 +196,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
assert(sym.loc.k == locOther)
|
assert(sym.loc.k == locOther)
|
||||||
idx = sym.loc.a
|
idx = sym.loc.a
|
||||||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||||
finishTryStmt(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
|
popSafePoints(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
|
||||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)])
|
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)])
|
||||||
|
|
||||||
proc genAsmStmt(p: BProc, t: PNode) =
|
proc genAsmStmt(p: BProc, t: PNode) =
|
||||||
|
|
@ -477,7 +471,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||||
# {
|
# {
|
||||||
# case DIVIDE_BY_ZERO:
|
# case DIVIDE_BY_ZERO:
|
||||||
# tmpRethrow = false;
|
# tmpRethrow = false;
|
||||||
# printf('Division by Zero\n');
|
# printf("Division by Zero\n");
|
||||||
# break;
|
# break;
|
||||||
# default: // used for general except!
|
# default: // used for general except!
|
||||||
# generalExceptPart();
|
# generalExceptPart();
|
||||||
|
|
@ -526,8 +520,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||||
inc(i)
|
inc(i)
|
||||||
if t.sons[1].kind == nkExceptBranch:
|
if t.sons[1].kind == nkExceptBranch:
|
||||||
app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement
|
app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement
|
||||||
|
popSafePoints(p, p.nestedTryStmts)
|
||||||
dec(p.nestedTryStmts)
|
dec(p.nestedTryStmts)
|
||||||
app(p.s[cpsStmts], "excHandler = excHandler->prev;" & tnl)
|
|
||||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
if (i < length) and (t.sons[i].kind == nkFinally):
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
if rethrowFlag != nil:
|
if rethrowFlag != nil:
|
||||||
|
|
@ -536,30 +530,31 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||||
proc genTryStmt(p: BProc, t: PNode) =
|
proc genTryStmt(p: BProc, t: PNode) =
|
||||||
# code to generate:
|
# code to generate:
|
||||||
#
|
#
|
||||||
# sp.prev = excHandler;
|
# TSafePoint sp;
|
||||||
# excHandler = &sp;
|
# pushSafePoint(&sp);
|
||||||
# sp.status = setjmp(sp.context);
|
# sp.status = setjmp(sp.context);
|
||||||
# if (sp.status == 0) {
|
# if (sp.status == 0) {
|
||||||
# myDiv(4, 9);
|
# myDiv(4, 9);
|
||||||
|
# popSafePoint();
|
||||||
# } else {
|
# } else {
|
||||||
|
# popSafePoint();
|
||||||
# /* except DivisionByZero: */
|
# /* except DivisionByZero: */
|
||||||
# if (sp.status == DivisionByZero) {
|
# if (sp.status == DivisionByZero) {
|
||||||
# printf('Division by Zero\n');
|
# printf('Division by Zero\n');
|
||||||
#
|
# clearException();
|
||||||
# /* longjmp(excHandler->context, RangeError); /* raise rangeError */
|
# } else {
|
||||||
# sp.status = RangeError; /* if raise; else 0 */
|
# clearException();
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
# excHandler = excHandler->prev; /* deactivate this safe point */
|
|
||||||
# /* finally: */
|
# /* finally: */
|
||||||
# printf('fin!\n');
|
# printf('fin!\n');
|
||||||
# if (sp.status != 0)
|
# if (exception not cleared)
|
||||||
# longjmp(excHandler->context, sp.status);
|
# propagateCurrentException();
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
var safePoint = getTempName()
|
var safePoint = getTempName()
|
||||||
discard cgsym(p.module, "E_Base")
|
discard cgsym(p.module, "E_Base")
|
||||||
appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
|
appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
|
||||||
appcg(p, cpsStmts, "$1.prev = #excHandler;$n" & "excHandler = &$1;$n" &
|
appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" &
|
||||||
"$1.status = setjmp($1.context);$n", [safePoint])
|
"$1.status = setjmp($1.context);$n", [safePoint])
|
||||||
if optStackTrace in p.Options:
|
if optStackTrace in p.Options:
|
||||||
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
||||||
|
|
@ -567,7 +562,7 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
var length = sonsLen(t)
|
var length = sonsLen(t)
|
||||||
inc(p.nestedTryStmts)
|
inc(p.nestedTryStmts)
|
||||||
genStmts(p, t.sons[0])
|
genStmts(p, t.sons[0])
|
||||||
app(p.s[cpsStmts], "} else {" & tnl)
|
appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n")
|
||||||
var i = 1
|
var i = 1
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||||
var blen = sonsLen(t.sons[i])
|
var blen = sonsLen(t.sons[i])
|
||||||
|
|
@ -575,27 +570,27 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
# general except section:
|
# general except section:
|
||||||
if i > 1: app(p.s[cpsStmts], "else {" & tnl)
|
if i > 1: app(p.s[cpsStmts], "else {" & tnl)
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
appf(p.s[cpsStmts], "$1.status = 0;$n", [safePoint])
|
appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();$n", [safePoint])
|
||||||
if i > 1: app(p.s[cpsStmts], '}' & tnl)
|
if i > 1: app(p.s[cpsStmts], '}' & tnl)
|
||||||
else:
|
else:
|
||||||
var orExpr: PRope = nil
|
var orExpr: PRope = nil
|
||||||
for j in countup(0, blen - 2):
|
for j in countup(0, blen - 2):
|
||||||
assert(t.sons[i].sons[j].kind == nkType)
|
assert(t.sons[i].sons[j].kind == nkType)
|
||||||
if orExpr != nil: app(orExpr, "||")
|
if orExpr != nil: app(orExpr, "||")
|
||||||
appf(orExpr, "($1.exc->Sup.m_type == $2)",
|
appcg(p.module, orExpr, "#getCurrentException()->Sup.m_type == $1",
|
||||||
[safePoint, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
||||||
if i > 1: app(p.s[cpsStmts], "else ")
|
if i > 1: app(p.s[cpsStmts], "else ")
|
||||||
appf(p.s[cpsStmts], "if ($1) {$n", [orExpr])
|
appf(p.s[cpsStmts], "if ($1) {$n", [orExpr])
|
||||||
genStmts(p, t.sons[i].sons[blen - 1]) # code to clear the exception:
|
genStmts(p, t.sons[i].sons[blen-1])
|
||||||
appf(p.s[cpsStmts], "$1.status = 0;}$n", [safePoint])
|
# code to clear the exception:
|
||||||
|
appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();}$n",
|
||||||
|
[safePoint])
|
||||||
inc(i)
|
inc(i)
|
||||||
app(p.s[cpsStmts], '}' & tnl) # end of if statement
|
app(p.s[cpsStmts], '}' & tnl) # end of if statement
|
||||||
finishTryStmt(p, p.nestedTryStmts)
|
|
||||||
dec(p.nestedTryStmts)
|
dec(p.nestedTryStmts)
|
||||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
if i < length and t.sons[i].kind == nkFinally:
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
appcg(p, cpsStmts, "if ($1.status != 0) { " &
|
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
||||||
"#raiseException($1.exc, $1.exc->name); }$n", [safePoint])
|
|
||||||
|
|
||||||
var
|
var
|
||||||
breakPointId: int = 0
|
breakPointId: int = 0
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope =
|
||||||
while true:
|
while true:
|
||||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||||
inc(i)
|
inc(i)
|
||||||
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
if i >= length or not (frmt[i] in {'0'..'9'}): break
|
||||||
num = j
|
num = j
|
||||||
if j > high(args) + 1:
|
if j > high(args) + 1:
|
||||||
internalError("ropes: invalid format string $" & $(j))
|
internalError("ropes: invalid format string $" & $(j))
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,54 @@ proc processCompile(filename: string) =
|
||||||
extccomp.addExternalFileToCompile(found)
|
extccomp.addExternalFileToCompile(found)
|
||||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||||
|
|
||||||
|
proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
||||||
|
case whichKeyword(switch)
|
||||||
|
of wGC:
|
||||||
|
case whichKeyword(arg)
|
||||||
|
of wBoehm: result = contains(gGlobalOptions, optBoehmGC)
|
||||||
|
of wRefc: result = contains(gGlobalOptions, optRefcGC)
|
||||||
|
of wNone: result = gGlobalOptions * {optBoehmGC, optRefcGC} == {}
|
||||||
|
else: liMessage(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||||
|
of wOpt:
|
||||||
|
case whichKeyword(arg)
|
||||||
|
of wSpeed: result = contains(gOptions, optOptimizeSpeed)
|
||||||
|
of wSize: result = contains(gOptions, optOptimizeSize)
|
||||||
|
of wNone: result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
|
||||||
|
else: liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||||
|
else: InvalidCmdLineOption(passCmd1, switch, info)
|
||||||
|
|
||||||
|
proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||||
|
case whichKeyword(switch)
|
||||||
|
of wDebuginfo: result = contains(gGlobalOptions, optCDebug)
|
||||||
|
of wCompileOnly, wC: result = contains(gGlobalOptions, optCompileOnly)
|
||||||
|
of wNoLinking: result = contains(gGlobalOptions, optNoLinking)
|
||||||
|
of wNoMain: result = contains(gGlobalOptions, optNoMain)
|
||||||
|
of wForceBuild, wF: result = contains(gGlobalOptions, optForceFullMake)
|
||||||
|
of wWarnings, wW: result = contains(gOptions, optWarns)
|
||||||
|
of wHints: result = contains(gOptions, optHints)
|
||||||
|
of wCheckpoints: result = contains(gOptions, optCheckpoints)
|
||||||
|
of wStackTrace: result = contains(gOptions, optStackTrace)
|
||||||
|
of wLineTrace: result = contains(gOptions, optLineTrace)
|
||||||
|
of wDebugger: result = contains(gOptions, optEndb)
|
||||||
|
of wProfiler: result = contains(gOptions, optProfiler)
|
||||||
|
of wChecks, wX: result = gOptions * checksOptions == checksOptions
|
||||||
|
of wFloatChecks:
|
||||||
|
result = gOptions * {optNanCheck, optInfCheck} == {optNanCheck, optInfCheck}
|
||||||
|
of wInfChecks: result = contains(gOptions, optInfCheck)
|
||||||
|
of wNanChecks: result = contains(gOptions, optNanCheck)
|
||||||
|
of wObjChecks: result = contains(gOptions, optObjCheck)
|
||||||
|
of wFieldChecks: result = contains(gOptions, optFieldCheck)
|
||||||
|
of wRangeChecks: result = contains(gOptions, optRangeCheck)
|
||||||
|
of wBoundChecks: result = contains(gOptions, optBoundsCheck)
|
||||||
|
of wOverflowChecks: result = contains(gOptions, optOverflowCheck)
|
||||||
|
of wLineDir: result = contains(gOptions, optLineDir)
|
||||||
|
of wAssertions, wA: result = contains(gOptions, optAssert)
|
||||||
|
of wDeadCodeElim: result = contains(gGlobalOptions, optDeadCodeElim)
|
||||||
|
of wRun, wR: result = contains(gGlobalOptions, optRun)
|
||||||
|
of wSymbolFiles: result = contains(gGlobalOptions, optSymbolFiles)
|
||||||
|
of wGenScript: result = contains(gGlobalOptions, optGenScript)
|
||||||
|
else: InvalidCmdLineOption(passCmd1, switch, info)
|
||||||
|
|
||||||
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||||
var
|
var
|
||||||
theOS: TSystemOS
|
theOS: TSystemOS
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2009 Andreas Rumpf
|
# (c) Copyright 2010 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.
|
||||||
|
|
@ -10,10 +10,8 @@
|
||||||
# This module is responsible for loading of rod files.
|
# This module is responsible for loading of rod files.
|
||||||
#
|
#
|
||||||
# Reading and writing binary files are really hard to debug. Therefore we use
|
# Reading and writing binary files are really hard to debug. Therefore we use
|
||||||
# a special text format. ROD-files only describe the interface of a module.
|
# a special text format. ROD-files are more efficient to process because
|
||||||
# Thus they are smaller than the source files most of the time. Even if they
|
# symbols are only loaded on demand.
|
||||||
# are bigger, they are more efficient to process because symbols are only
|
|
||||||
# loaded on demand.
|
|
||||||
# It consists of:
|
# It consists of:
|
||||||
#
|
#
|
||||||
# - a header:
|
# - a header:
|
||||||
|
|
@ -149,10 +147,10 @@ proc decodeBInt(r: PRodReader): biggestInt
|
||||||
|
|
||||||
proc encode(s: string): PRope =
|
proc encode(s: string): PRope =
|
||||||
var res = ""
|
var res = ""
|
||||||
for i in countup(0, len(s) + 0 - 1):
|
for i in countup(0, len(s) - 1):
|
||||||
case s[i]
|
case s[i]
|
||||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(res, s[i])
|
of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(res, s[i])
|
||||||
else: res = res & '\\' & toHex(ord(s[i]), 2)
|
else: add(res, '\\' & toHex(ord(s[i]), 2))
|
||||||
result = toRope(res)
|
result = toRope(res)
|
||||||
|
|
||||||
proc encodeIntAux(str: var string, x: BiggestInt) =
|
proc encodeIntAux(str: var string, x: BiggestInt) =
|
||||||
|
|
@ -191,9 +189,6 @@ proc decodeLineInfo(r: PRodReader, info: var TLineInfo) =
|
||||||
info = newLineInfo(r.files[decodeInt(r)], info.line, info.col)
|
info = newLineInfo(r.files[decodeInt(r)], info.line, info.col)
|
||||||
|
|
||||||
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||||
var
|
|
||||||
id: int
|
|
||||||
fl: string
|
|
||||||
result = nil
|
result = nil
|
||||||
if r.s[r.pos] == '(':
|
if r.s[r.pos] == '(':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
|
|
@ -207,7 +202,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||||
result.flags = cast[TNodeFlags](int32(decodeInt(r)))
|
result.flags = cast[TNodeFlags](int32(decodeInt(r)))
|
||||||
if r.s[r.pos] == '^':
|
if r.s[r.pos] == '^':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
id = decodeInt(r)
|
var id = decodeInt(r)
|
||||||
result.typ = rrGetType(r, id, result.info)
|
result.typ = rrGetType(r, id, result.info)
|
||||||
case result.kind
|
case result.kind
|
||||||
of nkCharLit..nkInt64Lit:
|
of nkCharLit..nkInt64Lit:
|
||||||
|
|
@ -217,7 +212,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||||
of nkFloatLit..nkFloat64Lit:
|
of nkFloatLit..nkFloat64Lit:
|
||||||
if r.s[r.pos] == '!':
|
if r.s[r.pos] == '!':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
fl = decode(r)
|
var fl = decode(r)
|
||||||
result.floatVal = parseFloat(fl)
|
result.floatVal = parseFloat(fl)
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if r.s[r.pos] == '!':
|
if r.s[r.pos] == '!':
|
||||||
|
|
@ -228,14 +223,14 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||||
of nkIdent:
|
of nkIdent:
|
||||||
if r.s[r.pos] == '!':
|
if r.s[r.pos] == '!':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
fl = decode(r)
|
var fl = decode(r)
|
||||||
result.ident = getIdent(fl)
|
result.ident = getIdent(fl)
|
||||||
else:
|
else:
|
||||||
internalError(result.info, "decodeNode: nkIdent")
|
internalError(result.info, "decodeNode: nkIdent")
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if r.s[r.pos] == '!':
|
if r.s[r.pos] == '!':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
id = decodeInt(r)
|
var id = decodeInt(r)
|
||||||
result.sym = rrGetSym(r, id, result.info)
|
result.sym = rrGetSym(r, id, result.info)
|
||||||
else:
|
else:
|
||||||
internalError(result.info, "decodeNode: nkSym")
|
internalError(result.info, "decodeNode: nkSym")
|
||||||
|
|
@ -282,7 +277,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
|
||||||
else: InternalError(info, "decodeLoc " & r.s[r.pos])
|
else: InternalError(info, "decodeLoc " & r.s[r.pos])
|
||||||
|
|
||||||
proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||||
var d: int
|
|
||||||
result = nil
|
result = nil
|
||||||
if r.s[r.pos] == '[':
|
if r.s[r.pos] == '[':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
|
|
@ -335,7 +329,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||||
else: InternalError(info, "decodeType ^(" & r.s[r.pos])
|
else: InternalError(info, "decodeType ^(" & r.s[r.pos])
|
||||||
addSon(result, nil)
|
addSon(result, nil)
|
||||||
else:
|
else:
|
||||||
d = decodeInt(r)
|
var d = decodeInt(r)
|
||||||
addSon(result, rrGetType(r, d, info))
|
addSon(result, rrGetType(r, d, info))
|
||||||
|
|
||||||
proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
|
proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
|
||||||
|
|
@ -499,7 +493,7 @@ proc skipSection(r: PRodReader) =
|
||||||
else: nil
|
else: nil
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
else:
|
else:
|
||||||
InternalError("skipSection " & $(r.line))
|
InternalError("skipSection " & $r.line)
|
||||||
|
|
||||||
proc rdWord(r: PRodReader): string =
|
proc rdWord(r: PRodReader): string =
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -530,18 +524,14 @@ proc processInterf(r: PRodReader, module: PSym) =
|
||||||
IdTablePut(r.syms, s, s)
|
IdTablePut(r.syms, s, s)
|
||||||
|
|
||||||
proc processCompilerProcs(r: PRodReader, module: PSym) =
|
proc processCompilerProcs(r: PRodReader, module: PSym) =
|
||||||
var
|
|
||||||
s: PSym
|
|
||||||
w: string
|
|
||||||
key: int
|
|
||||||
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
|
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
|
||||||
r.pos = r.compilerProcsIdx
|
r.pos = r.compilerProcsIdx
|
||||||
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
|
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
|
||||||
w = decode(r)
|
var w = decode(r)
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
key = decodeInt(r)
|
var key = decodeInt(r)
|
||||||
inc(r.pos) # #10
|
inc(r.pos) # #10
|
||||||
s = PSym(IdTableGet(r.syms, key))
|
var s = PSym(IdTableGet(r.syms, key))
|
||||||
if s == nil:
|
if s == nil:
|
||||||
s = newStub(r, w, key)
|
s = newStub(r, w, key)
|
||||||
s.owner = module
|
s.owner = module
|
||||||
|
|
@ -572,24 +562,25 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
|
||||||
|
|
||||||
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
var
|
var
|
||||||
section, w: string
|
w: string
|
||||||
d, L, inclCrc: int
|
d, L, inclCrc: int
|
||||||
while r.s[r.pos] != '\0':
|
while r.s[r.pos] != '\0':
|
||||||
section = rdWord(r)
|
var section = rdWord(r)
|
||||||
if r.reason != rrNone:
|
if r.reason != rrNone:
|
||||||
break # no need to process this file further
|
break # no need to process this file further
|
||||||
if section == "CRC":
|
case section
|
||||||
|
of "CRC":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
if int(crc) != decodeInt(r): r.reason = rrCrcChange
|
if int(crc) != decodeInt(r): r.reason = rrCrcChange
|
||||||
elif section == "ID":
|
of "ID":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
r.moduleID = decodeInt(r)
|
r.moduleID = decodeInt(r)
|
||||||
setID(r.moduleID)
|
setID(r.moduleID)
|
||||||
elif section == "OPTIONS":
|
of "OPTIONS":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
r.options = cast[TOptions](int32(decodeInt(r)))
|
r.options = cast[TOptions](int32(decodeInt(r)))
|
||||||
if options.gOptions != r.options: r.reason = rrOptions
|
if options.gOptions != r.options: r.reason = rrOptions
|
||||||
elif section == "DEFINES":
|
of "DEFINES":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
d = 0
|
d = 0
|
||||||
while r.s[r.pos] > '\x0A':
|
while r.s[r.pos] > '\x0A':
|
||||||
|
|
@ -599,7 +590,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
|
r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
|
||||||
if r.s[r.pos] == ' ': inc(r.pos)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
if (d != countDefinedSymbols()): r.reason = rrDefines
|
if (d != countDefinedSymbols()): r.reason = rrDefines
|
||||||
elif section == "FILES":
|
of "FILES":
|
||||||
inc(r.pos, 2) # skip "(\10"
|
inc(r.pos, 2) # skip "(\10"
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
L = 0
|
L = 0
|
||||||
|
|
@ -610,7 +601,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
inc(L)
|
inc(L)
|
||||||
if r.s[r.pos] == ')': inc(r.pos)
|
if r.s[r.pos] == ')': inc(r.pos)
|
||||||
elif section == "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] > '\x0A') and (r.s[r.pos] != ')'):
|
||||||
|
|
@ -624,7 +615,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
if r.s[r.pos] == ')': inc(r.pos)
|
if r.s[r.pos] == ')': inc(r.pos)
|
||||||
elif section == "DEPS":
|
of "DEPS":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
L = 0
|
L = 0
|
||||||
while (r.s[r.pos] > '\x0A'):
|
while (r.s[r.pos] > '\x0A'):
|
||||||
|
|
@ -632,32 +623,32 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
r.modDeps[L] = r.files[decodeInt(r)]
|
r.modDeps[L] = r.files[decodeInt(r)]
|
||||||
inc(L)
|
inc(L)
|
||||||
if r.s[r.pos] == ' ': inc(r.pos)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
elif section == "INTERF":
|
of "INTERF":
|
||||||
r.interfIdx = r.pos + 2
|
r.interfIdx = r.pos + 2
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
elif section == "COMPILERPROCS":
|
of "COMPILERPROCS":
|
||||||
r.compilerProcsIdx = r.pos + 2
|
r.compilerProcsIdx = r.pos + 2
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
elif section == "INDEX":
|
of "INDEX":
|
||||||
processIndex(r, r.index)
|
processIndex(r, r.index)
|
||||||
elif section == "IMPORTS":
|
of "IMPORTS":
|
||||||
processIndex(r, r.imports)
|
processIndex(r, r.imports)
|
||||||
elif section == "CONVERTERS":
|
of "CONVERTERS":
|
||||||
r.convertersIdx = r.pos + 1
|
r.convertersIdx = r.pos + 1
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
elif section == "DATA":
|
of "DATA":
|
||||||
r.dataIdx = r.pos + 2 # "(\10"
|
r.dataIdx = r.pos + 2 # "(\10"
|
||||||
# We do not read the DATA section here! We read the needed objects on
|
# We do not read the DATA section here! We read the needed objects on
|
||||||
# demand.
|
# demand.
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
elif section == "INIT":
|
of "INIT":
|
||||||
r.initIdx = r.pos + 2 # "(\10"
|
r.initIdx = r.pos + 2 # "(\10"
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
elif section == "CGEN":
|
of "CGEN":
|
||||||
r.cgenIdx = r.pos + 2
|
r.cgenIdx = r.pos + 2
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
else:
|
else:
|
||||||
MessageOut("skipping section: " & $(r.pos))
|
MessageOut("skipping section: " & $r.pos)
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
if r.s[r.pos] == '\x0A':
|
if r.s[r.pos] == '\x0A':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
|
|
@ -686,7 +677,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
if r.s[r.pos] == '\x0A': inc(r.pos)
|
if r.s[r.pos] == '\x0A': inc(r.pos)
|
||||||
if version == FileVersion:
|
if version == FileVersion:
|
||||||
# since ROD files are only for caching, no backwarts compability is
|
# since ROD files are only for caching, no backwarts compatibility is
|
||||||
# needed
|
# needed
|
||||||
processRodFile(r, crc)
|
processRodFile(r, crc)
|
||||||
else:
|
else:
|
||||||
|
|
@ -814,7 +805,8 @@ proc checkDep(filename: string): TReasonForRecompile =
|
||||||
for i in countup(0, high(r.modDeps)):
|
for i in countup(0, high(r.modDeps)):
|
||||||
res = checkDep(r.modDeps[i])
|
res = checkDep(r.modDeps[i])
|
||||||
if res != rrNone:
|
if res != rrNone:
|
||||||
result = rrModDeps #break // BUGFIX: cannot break here!
|
result = rrModDeps
|
||||||
|
# we cannot break here, because of side-effects of `checkDep`
|
||||||
else:
|
else:
|
||||||
result = rrRodDoesNotExist
|
result = rrRodDoesNotExist
|
||||||
if (result != rrNone) and (gVerbosity > 0):
|
if (result != rrNone) and (gVerbosity > 0):
|
||||||
|
|
|
||||||
|
|
@ -284,11 +284,10 @@ proc symStack(w: PRodWriter) =
|
||||||
setlen(w.sstack, 0)
|
setlen(w.sstack, 0)
|
||||||
|
|
||||||
proc typeStack(w: PRodWriter) =
|
proc typeStack(w: PRodWriter) =
|
||||||
var i, L: int
|
var i = 0
|
||||||
i = 0
|
|
||||||
while i < len(w.tstack):
|
while i < len(w.tstack):
|
||||||
if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey:
|
if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey:
|
||||||
L = ropeLen(w.data)
|
var L = ropeLen(w.data)
|
||||||
addToIndex(w.index, w.tstack[i].id, L)
|
addToIndex(w.index, w.tstack[i].id, L)
|
||||||
app(w.data, encodeType(w, w.tstack[i]))
|
app(w.data, encodeType(w, w.tstack[i]))
|
||||||
app(w.data, rodNL)
|
app(w.data, rodNL)
|
||||||
|
|
@ -317,9 +316,8 @@ proc addStmt(w: PRodWriter, n: PNode) =
|
||||||
processStacks(w)
|
processStacks(w)
|
||||||
|
|
||||||
proc writeRod(w: PRodWriter) =
|
proc writeRod(w: PRodWriter) =
|
||||||
var content: PRope
|
|
||||||
processStacks(w) # write header:
|
processStacks(w) # write header:
|
||||||
content = toRope("NIM:")
|
var content = toRope("NIM:")
|
||||||
app(content, toRope(FileVersion))
|
app(content, toRope(FileVersion))
|
||||||
app(content, rodNL)
|
app(content, rodNL)
|
||||||
app(content, toRope("ID:"))
|
app(content, toRope("ID:"))
|
||||||
|
|
@ -373,43 +371,39 @@ proc writeRod(w: PRodWriter) =
|
||||||
writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod")))
|
writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod")))
|
||||||
|
|
||||||
proc process(c: PPassContext, n: PNode): PNode =
|
proc process(c: PPassContext, n: PNode): PNode =
|
||||||
var
|
|
||||||
w: PRodWriter
|
|
||||||
a: PNode
|
|
||||||
s: PSym
|
|
||||||
result = n
|
result = n
|
||||||
if c == nil: return
|
if c == nil: return
|
||||||
w = PRodWriter(c)
|
var w = PRodWriter(c)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
|
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
|
||||||
of nkTemplateDef, nkMacroDef:
|
of nkTemplateDef, nkMacroDef:
|
||||||
s = n.sons[namePos].sym
|
var s = n.sons[namePos].sym
|
||||||
addInterfaceSym(w, s)
|
addInterfaceSym(w, s)
|
||||||
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef:
|
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef:
|
||||||
s = n.sons[namePos].sym
|
var s = n.sons[namePos].sym
|
||||||
if s == nil: InternalError(n.info, "rodwrite.process")
|
if s == nil: InternalError(n.info, "rodwrite.process")
|
||||||
if (n.sons[codePos] != nil) or (s.magic != mNone) or
|
if (n.sons[codePos] != nil) or (s.magic != mNone) or
|
||||||
not (sfForward in s.flags):
|
not (sfForward in s.flags):
|
||||||
addInterfaceSym(w, s)
|
addInterfaceSym(w, s)
|
||||||
of nkVarSection:
|
of nkVarSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.kind != nkIdentDefs: InternalError(a.info, "rodwrite.process")
|
if a.kind != nkIdentDefs: InternalError(a.info, "rodwrite.process")
|
||||||
addInterfaceSym(w, a.sons[0].sym)
|
addInterfaceSym(w, a.sons[0].sym)
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.kind != nkConstDef: InternalError(a.info, "rodwrite.process")
|
if a.kind != nkConstDef: InternalError(a.info, "rodwrite.process")
|
||||||
addInterfaceSym(w, a.sons[0].sym)
|
addInterfaceSym(w, a.sons[0].sym)
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process")
|
if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process")
|
||||||
s = a.sons[0].sym
|
var s = a.sons[0].sym
|
||||||
addInterfaceSym(w, s)
|
addInterfaceSym(w, s)
|
||||||
# this takes care of enum fields too
|
# this takes care of enum fields too
|
||||||
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
|
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
|
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
|
||||||
nversion, platform, math, msgs, os, condsyms, idents, rnimsyn, types
|
nversion, platform, math, msgs, os, condsyms, idents, rnimsyn, types,
|
||||||
|
commands
|
||||||
|
|
||||||
proc getConstExpr*(m: PSym, n: PNode): PNode
|
proc getConstExpr*(m: PSym, n: PNode): PNode
|
||||||
# evaluates the constant expression or returns nil if it is no constant
|
# evaluates the constant expression or returns nil if it is no constant
|
||||||
|
|
@ -194,6 +195,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of mArrToSeq:
|
of mArrToSeq:
|
||||||
result = copyTree(a)
|
result = copyTree(a)
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
|
of mCompileOption:
|
||||||
|
result = newIntNodeT(Ord(commands.testCompileOption(getStr(a), n.info)), n)
|
||||||
|
of mCompileOptionArg:
|
||||||
|
result = newIntNodeT(Ord(
|
||||||
|
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
|
||||||
of mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh,
|
of mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh,
|
||||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||||
mNLen..mNError, mEqRef:
|
mNLen..mNError, mEqRef:
|
||||||
|
|
|
||||||
21
tests/accept/run/tcontinuexc.nim
Normal file
21
tests/accept/run/tcontinuexc.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
type
|
||||||
|
ESomething = object of E_Base
|
||||||
|
ESomeOtherErr = object of E_Base
|
||||||
|
|
||||||
|
proc genErrors(s: string) =
|
||||||
|
if s == "error!":
|
||||||
|
raise newException(ESomething, "Test")
|
||||||
|
else:
|
||||||
|
raise newException(EsomeotherErr, "bla")
|
||||||
|
|
||||||
|
try:
|
||||||
|
for i in 0..3:
|
||||||
|
try:
|
||||||
|
genErrors("error!")
|
||||||
|
except ESomething:
|
||||||
|
echo("Error happened")
|
||||||
|
echo "came here"
|
||||||
|
raise newException(EsomeotherErr, "bla")
|
||||||
|
finally:
|
||||||
|
echo "caught"
|
||||||
|
|
||||||
5
tests/accept/run/toverflw2.nim
Executable file
5
tests/accept/run/toverflw2.nim
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
var a : int32 = 2147483647
|
||||||
|
var b : int32 = 2147483647
|
||||||
|
var c = a + b
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -6,6 +6,11 @@
|
||||||
# define TCC_TARGET_PE 1
|
# define TCC_TARGET_PE 1
|
||||||
# define TCC_TARGET_I386
|
# define TCC_TARGET_I386
|
||||||
# define CONFIG_TCCDIR "."
|
# define CONFIG_TCCDIR "."
|
||||||
|
#elif defined(__i386__)
|
||||||
|
# define TCC_TARGET_I386
|
||||||
|
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
||||||
|
# define GCC_MAJOR 4
|
||||||
|
# define HOST_I386 1
|
||||||
#else
|
#else
|
||||||
# define TCC_TARGET_X86_64
|
# define TCC_TARGET_X86_64
|
||||||
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
||||||
|
|
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -1,10 +1,8 @@
|
||||||
For version 0.8.10
|
For version 0.8.10
|
||||||
==================
|
==================
|
||||||
|
|
||||||
- exception propagation across DLLs
|
|
||||||
- fix exception handling
|
|
||||||
- fix implicit generic routines
|
- fix implicit generic routines
|
||||||
- fix the streams implementation so that they use methods
|
- fix the streams implementation so that it uses methods
|
||||||
|
|
||||||
|
|
||||||
High priority (version 0.9.0)
|
High priority (version 0.9.0)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ case $uos in
|
||||||
*darwin* )
|
*darwin* )
|
||||||
myos="macosx"
|
myos="macosx"
|
||||||
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
|
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
|
||||||
|
if [ `sysctl hw |grep 64bit` = "hw.cpu64bit_capable: 1" ] ; then
|
||||||
|
ucpu="amd64"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*aix* )
|
*aix* )
|
||||||
myos="aix"
|
myos="aix"
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,10 @@ Bugfixes
|
||||||
- Bugfix: ``system.splitChunk`` still contained code for debug output.
|
- Bugfix: ``system.splitChunk`` still contained code for debug output.
|
||||||
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
|
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
|
||||||
``STOCK_OPEN`` for the GTK backend.
|
``STOCK_OPEN`` for the GTK backend.
|
||||||
- Bugfix: ``raise`` within an exception handler did not work.
|
- Bugfix: Various bugs concerning exception handling fixed.
|
||||||
- Bugfix: ``low(somestring)`` crashed the compiler.
|
- Bugfix: ``low(somestring)`` crashed the compiler.
|
||||||
- Bugfix: ``strutils.endsWith`` lacked range checking.
|
- Bugfix: ``strutils.endsWith`` lacked range checking.
|
||||||
|
- Bugfix: Better detection for AMD64 on Mac OS X.
|
||||||
|
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
|
|
@ -48,6 +49,7 @@ Additions
|
||||||
- Added ``system.reopen``.
|
- Added ``system.reopen``.
|
||||||
- Added ``system.getCurrentException``.
|
- Added ``system.getCurrentException``.
|
||||||
- Added ``system.appType``.
|
- Added ``system.appType``.
|
||||||
|
- Added ``system.compileOption``.
|
||||||
- Added ``times.epochTime`` and ``times.cpuTime``.
|
- Added ``times.epochTime`` and ``times.cpuTime``.
|
||||||
- Implemented explicit type arguments for generics.
|
- Implemented explicit type arguments for generics.
|
||||||
- Implemented implicit type arguments for generics.
|
- Implemented implicit type arguments for generics.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue