mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-06 13:07:48 +00:00
fixes for exception handling; added system.compileOption
This commit is contained in:
@@ -177,10 +177,6 @@ __TINYC__
|
||||
**
|
||||
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
|
||||
** 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
|
||||
|
||||
#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
|
||||
|
||||
@@ -144,6 +144,7 @@ type
|
||||
E_Base* {.compilerproc.} = object of TObject ## base exception class;
|
||||
## each exception has to
|
||||
## 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.
|
||||
## This field is filled automatically in the
|
||||
## ``raise`` statement.
|
||||
@@ -717,6 +718,22 @@ const
|
||||
## a string that describes the application type. Possible values:
|
||||
## "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/cgprocs"
|
||||
|
||||
@@ -961,14 +978,6 @@ proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
|
||||
|
||||
#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:
|
||||
const
|
||||
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`.
|
||||
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 ---------------------------------------------
|
||||
|
||||
proc GC_disable*() {.rtl.}
|
||||
@@ -1577,14 +1577,15 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
include "system/assign"
|
||||
include "system/repr"
|
||||
|
||||
# we have to implement it here after gentostr for the cstrToNimStrDummy proc
|
||||
proc getCurrentExceptionMsg(): string =
|
||||
if excHandler == nil: return ""
|
||||
return $excHandler.exc.msg
|
||||
proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
|
||||
## retrieves the current exception; if there is none, nil is returned.
|
||||
result = currException
|
||||
|
||||
proc getCurrentException(): ref E_Base =
|
||||
if excHandler != nil:
|
||||
result = excHandler.exc
|
||||
proc getCurrentExceptionMsg*(): string {.inline.} =
|
||||
## retrieves the error message that was attached to the current
|
||||
## exception; if there is none, "" is returned.
|
||||
var e = getCurrentException()
|
||||
return if e == nil: "" else: e.msg
|
||||
|
||||
{.push stack_trace: off.}
|
||||
when defined(endb):
|
||||
@@ -1594,6 +1595,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||
include "system/profiler"
|
||||
{.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):
|
||||
include "system/ecmasys"
|
||||
elif defined(NimrodVM):
|
||||
|
||||
@@ -20,9 +20,6 @@ else:
|
||||
proc writeToStdErr(msg: CString) =
|
||||
discard MessageBoxA(0, msg, nil, 0)
|
||||
|
||||
proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.}
|
||||
proc reraiseException() {.compilerproc.}
|
||||
|
||||
proc registerSignalHandler() {.compilerproc.}
|
||||
|
||||
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||
@@ -34,20 +31,29 @@ type
|
||||
PSafePoint = ptr TSafePoint
|
||||
TSafePoint {.compilerproc, final.} = object
|
||||
prev: PSafePoint # points to next safe point ON THE STACK
|
||||
exc: ref E_Base
|
||||
status: int
|
||||
exc: ref E_Base # XXX only needed for bootstrapping
|
||||
context: C_JmpBuf
|
||||
|
||||
var
|
||||
excHandler {.compilerproc.}: PSafePoint = nil
|
||||
# list of exception handlers
|
||||
# a global variable for the root of all try blocks
|
||||
currException: ref E_Base
|
||||
|
||||
proc reraiseException() =
|
||||
if excHandler == nil:
|
||||
raise newException(ENoExceptionToReraise, "no exception to reraise")
|
||||
else:
|
||||
c_longjmp(excHandler.context, 1)
|
||||
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
||||
s.prev = excHandler
|
||||
excHandler = s
|
||||
|
||||
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
|
||||
PFrame = ptr TFrame
|
||||
@@ -114,13 +120,17 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||
add(s, stackTraceNewLine)
|
||||
|
||||
proc rawWriteStackTrace(s: var string) =
|
||||
if framePtr == nil:
|
||||
when compileOption("stacktrace") or compileOption("linetrace"):
|
||||
if framePtr == nil:
|
||||
add(s, "No stack traceback available")
|
||||
add(s, stackTraceNewLine)
|
||||
else:
|
||||
add(s, "Traceback (most recent call last)")
|
||||
add(s, stackTraceNewLine)
|
||||
auxWriteStackTrace(framePtr, s)
|
||||
else:
|
||||
add(s, "No stack traceback available")
|
||||
add(s, stackTraceNewLine)
|
||||
else:
|
||||
add(s, "Traceback (most recent call last)")
|
||||
add(s, stackTraceNewLine)
|
||||
auxWriteStackTrace(framePtr, s)
|
||||
|
||||
proc quitOrDebug() {.inline.} =
|
||||
when not defined(endb):
|
||||
@@ -128,11 +138,11 @@ proc quitOrDebug() {.inline.} =
|
||||
else:
|
||||
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
|
||||
e.name = ename
|
||||
if excHandler != nil:
|
||||
excHandler.exc = e
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
else:
|
||||
if not isNil(buf):
|
||||
@@ -152,6 +162,12 @@ proc raiseException(e: ref E_Base, ename: CString) =
|
||||
quitOrDebug()
|
||||
GC_enable()
|
||||
|
||||
proc reraiseException() {.compilerRtl.} =
|
||||
if currException == nil:
|
||||
raise newException(ENoExceptionToReraise, "no exception to reraise")
|
||||
else:
|
||||
raiseException(currException, currException.name)
|
||||
|
||||
var
|
||||
gAssertionFailed: ref EAssertionFailed
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ type
|
||||
decStack: TCellSeq # cells in the stack that are to decref again
|
||||
cycleRoots: TCellSet
|
||||
tempStack: TCellSeq # temporary stack for recursion elimination
|
||||
cycleRootsLock: TSysLock
|
||||
zctLock: TSysLock
|
||||
stat: TGcStat
|
||||
|
||||
var
|
||||
@@ -68,12 +70,22 @@ var
|
||||
gch: TGcHeap
|
||||
cycleThreshold: int = InitialCycleThreshold
|
||||
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
|
||||
# object allocated by a finalizer will not trigger a garbage collection.
|
||||
# This is wasteful but safe. This is a lock against recursive garbage
|
||||
# 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.} =
|
||||
if (c.refcount and rcZct) == 0:
|
||||
c.refcount = c.refcount and not colorMask or rcZct
|
||||
@@ -159,7 +171,7 @@ when traceGC:
|
||||
for c in elements(states[csAllocated]):
|
||||
inc(e)
|
||||
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)
|
||||
cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
|
||||
e, z, y)
|
||||
@@ -190,25 +202,28 @@ proc prepareDealloc(cell: PCell) =
|
||||
|
||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||
if isMultiThreaded: Lock(gch.cycleRootsLock)
|
||||
incl(gch.cycleRoots, c)
|
||||
if isMultiThreaded: Unlock(gch.cycleRootsLock)
|
||||
|
||||
proc rtlAddZCT(c: PCell) {.rtl, inl.} =
|
||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||
if isMultiThreaded: Lock(gch.zctLock)
|
||||
addZCT(gch.zct, c)
|
||||
if isMultiThreaded: Unlock(gch.zctLock)
|
||||
|
||||
proc decRef(c: PCell) {.inline.} =
|
||||
when stressGC:
|
||||
if c.refcount <% rcIncrement:
|
||||
writeCell("broken cell", c)
|
||||
assert(c.refcount >=% rcIncrement)
|
||||
c.refcount = c.refcount -% rcIncrement
|
||||
if c.refcount <% rcIncrement:
|
||||
if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
|
||||
rtlAddZCT(c)
|
||||
elif canBeCycleRoot(c):
|
||||
rtlAddCycleRoot(c)
|
||||
|
||||
proc incRef(c: PCell) {.inline.} =
|
||||
c.refcount = c.refcount +% rcIncrement
|
||||
discard atomicInc(c.refcount, rcIncrement)
|
||||
if canBeCycleRoot(c):
|
||||
rtlAddCycleRoot(c)
|
||||
|
||||
@@ -228,11 +243,10 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
|
||||
# cycle is possible.
|
||||
if src != nil:
|
||||
var c = usrToCell(src)
|
||||
c.refcount = c.refcount +% rcIncrement
|
||||
discard atomicInc(c.refcount, rcIncrement)
|
||||
if dest^ != nil:
|
||||
var c = usrToCell(dest^)
|
||||
c.refcount = c.refcount -% rcIncrement
|
||||
if c.refcount <% rcIncrement:
|
||||
if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
|
||||
rtlAddZCT(c)
|
||||
dest^ = src
|
||||
|
||||
@@ -260,6 +274,8 @@ proc initGC() =
|
||||
init(gch.tempStack)
|
||||
Init(gch.cycleRoots)
|
||||
Init(gch.decStack)
|
||||
InitLock(gch.cycleRootsLock)
|
||||
InitLock(gch.zctLock)
|
||||
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
|
||||
|
||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||
@@ -310,6 +326,7 @@ proc checkCollection {.inline.} =
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
# generates a new object and sets its reference counter to 0
|
||||
lock(gch)
|
||||
assert(typ.kind in {tyRef, tyString, tySequence})
|
||||
checkCollection()
|
||||
var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell)))
|
||||
@@ -337,15 +354,18 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
break addToZCT
|
||||
add(gch.zct, res)
|
||||
when logGC: writeCell("new cell", res)
|
||||
gcTrace(res, csAllocated)
|
||||
gcTrace(res, csAllocated)
|
||||
unlock(gch)
|
||||
result = cellToUsr(res)
|
||||
|
||||
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))
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).space = len
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||
lock(gch)
|
||||
checkCollection()
|
||||
var ol = usrToCell(old)
|
||||
assert(ol.typ != nil)
|
||||
@@ -383,6 +403,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||
else:
|
||||
assert(ol.typ != nil)
|
||||
zeroMem(ol, sizeof(TCell))
|
||||
unlock(gch)
|
||||
result = cellToUsr(res)
|
||||
|
||||
# ---------------- cycle collector -------------------------------------------
|
||||
@@ -632,9 +653,9 @@ proc collectCT(gch: var TGcHeap) =
|
||||
unmarkStackAndRegisters(gch)
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc GC_disable() = inc(recGcLock)
|
||||
proc GC_disable() = discard atomicInc(recGcLock, 1)
|
||||
proc GC_enable() =
|
||||
if recGcLock > 0: dec(recGcLock)
|
||||
if recGcLock > 0: discard atomicDec(recGcLock, 1)
|
||||
|
||||
proc GC_setStrategy(strategy: TGC_Strategy) =
|
||||
case strategy
|
||||
@@ -651,10 +672,12 @@ when not defined(useNimRtl):
|
||||
# set to the max value to suppress the cycle detector
|
||||
|
||||
proc GC_fullCollect() =
|
||||
lock(gch)
|
||||
var oldThreshold = cycleThreshold
|
||||
cycleThreshold = 0 # forces cycle collection
|
||||
collectCT(gch)
|
||||
cycleThreshold = oldThreshold
|
||||
unlock(gch)
|
||||
|
||||
proc GC_getStatistics(): string =
|
||||
GC_disable()
|
||||
|
||||
@@ -15,6 +15,10 @@ when defined(gcc) or defined(llvm_gcc):
|
||||
elif defined(vcc):
|
||||
proc sync_add_and_fetch(p: var int, val: int): int {.
|
||||
importc: "NimXadd", nodecl.}
|
||||
else:
|
||||
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
|
||||
inc(p, val)
|
||||
result = p
|
||||
|
||||
const
|
||||
isMultiThreaded* = true
|
||||
@@ -37,12 +41,51 @@ proc atomicDec(memLoc: var int, x: int): int =
|
||||
dec(memLoc, x)
|
||||
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
|
||||
TThread* {.final, pure.} = object
|
||||
id: int
|
||||
next: ptr TThread
|
||||
TThreadFunc* = proc (closure: pointer)
|
||||
TThreadFunc* = proc (closure: pointer) {.cdecl.}
|
||||
|
||||
proc createThread*(t: var TThread, fn: TThreadFunc) =
|
||||
|
||||
nil
|
||||
|
||||
proc destroyThread*(t: var TThread) =
|
||||
@@ -50,4 +93,3 @@ proc destroyThread*(t: var TThread) =
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ type
|
||||
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
|
||||
"noconv"]
|
||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
|
||||
"closure", "noconv"]
|
||||
|
||||
type
|
||||
TNodeKind* = enum # order is extremely important, because ranges are used
|
||||
@@ -329,8 +329,9 @@ type
|
||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
||||
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||
mNaN, mInf,
|
||||
mNegInf, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
||||
mNaN, mInf, mNegInf,
|
||||
mCompileOption, mCompileOptionArg,
|
||||
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
||||
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal,
|
||||
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",
|
||||
[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):
|
||||
inc(p.labels, 3)
|
||||
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)])
|
||||
appcg(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
|
||||
proc genReturnStmt(p: BProc, t: PNode) =
|
||||
p.beforeRetNeeded = true
|
||||
genLineDir(p, t)
|
||||
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", [])
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
@@ -202,7 +196,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||
assert(sym.loc.k == locOther)
|
||||
idx = sym.loc.a
|
||||
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)])
|
||||
|
||||
proc genAsmStmt(p: BProc, t: PNode) =
|
||||
@@ -477,7 +471,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||
# {
|
||||
# case DIVIDE_BY_ZERO:
|
||||
# tmpRethrow = false;
|
||||
# printf('Division by Zero\n');
|
||||
# printf("Division by Zero\n");
|
||||
# break;
|
||||
# default: // used for general except!
|
||||
# generalExceptPart();
|
||||
@@ -526,8 +520,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||
inc(i)
|
||||
if t.sons[1].kind == nkExceptBranch:
|
||||
app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement
|
||||
popSafePoints(p, p.nestedTryStmts)
|
||||
dec(p.nestedTryStmts)
|
||||
app(p.s[cpsStmts], "excHandler = excHandler->prev;" & tnl)
|
||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
||||
genStmts(p, t.sons[i].sons[0])
|
||||
if rethrowFlag != nil:
|
||||
@@ -536,38 +530,39 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||
proc genTryStmt(p: BProc, t: PNode) =
|
||||
# code to generate:
|
||||
#
|
||||
# sp.prev = excHandler;
|
||||
# excHandler = &sp;
|
||||
# TSafePoint sp;
|
||||
# pushSafePoint(&sp);
|
||||
# sp.status = setjmp(sp.context);
|
||||
# if (sp.status == 0) {
|
||||
# myDiv(4, 9);
|
||||
# popSafePoint();
|
||||
# } else {
|
||||
# popSafePoint();
|
||||
# /* except DivisionByZero: */
|
||||
# if (sp.status == DivisionByZero) {
|
||||
# printf('Division by Zero\n');
|
||||
#
|
||||
# /* longjmp(excHandler->context, RangeError); /* raise rangeError */
|
||||
# sp.status = RangeError; /* if raise; else 0 */
|
||||
# clearException();
|
||||
# } else {
|
||||
# clearException();
|
||||
# }
|
||||
# }
|
||||
# excHandler = excHandler->prev; /* deactivate this safe point */
|
||||
# /* finally: */
|
||||
# printf('fin!\n');
|
||||
# if (sp.status != 0)
|
||||
# longjmp(excHandler->context, sp.status);
|
||||
# if (exception not cleared)
|
||||
# propagateCurrentException();
|
||||
genLineDir(p, t)
|
||||
var safePoint = getTempName()
|
||||
discard cgsym(p.module, "E_Base")
|
||||
appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
|
||||
appcg(p, cpsStmts, "$1.prev = #excHandler;$n" & "excHandler = &$1;$n" &
|
||||
"$1.status = setjmp($1.context);$n", [safePoint])
|
||||
appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" &
|
||||
"$1.status = setjmp($1.context);$n", [safePoint])
|
||||
if optStackTrace in p.Options:
|
||||
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
||||
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
|
||||
var length = sonsLen(t)
|
||||
inc(p.nestedTryStmts)
|
||||
genStmts(p, t.sons[0])
|
||||
app(p.s[cpsStmts], "} else {" & tnl)
|
||||
appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n")
|
||||
var i = 1
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
var blen = sonsLen(t.sons[i])
|
||||
@@ -575,27 +570,27 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||
# general except section:
|
||||
if i > 1: app(p.s[cpsStmts], "else {" & tnl)
|
||||
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)
|
||||
else:
|
||||
var orExpr: PRope = nil
|
||||
for j in countup(0, blen - 2):
|
||||
assert(t.sons[i].sons[j].kind == nkType)
|
||||
if orExpr != nil: app(orExpr, "||")
|
||||
appf(orExpr, "($1.exc->Sup.m_type == $2)",
|
||||
[safePoint, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
||||
appcg(p.module, orExpr, "#getCurrentException()->Sup.m_type == $1",
|
||||
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
||||
if i > 1: app(p.s[cpsStmts], "else ")
|
||||
appf(p.s[cpsStmts], "if ($1) {$n", [orExpr])
|
||||
genStmts(p, t.sons[i].sons[blen - 1]) # code to clear the exception:
|
||||
appf(p.s[cpsStmts], "$1.status = 0;}$n", [safePoint])
|
||||
genStmts(p, t.sons[i].sons[blen-1])
|
||||
# code to clear the exception:
|
||||
appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();}$n",
|
||||
[safePoint])
|
||||
inc(i)
|
||||
app(p.s[cpsStmts], '}' & tnl) # end of if statement
|
||||
finishTryStmt(p, 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])
|
||||
appcg(p, cpsStmts, "if ($1.status != 0) { " &
|
||||
"#raiseException($1.exc, $1.exc->name); }$n", [safePoint])
|
||||
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
||||
|
||||
var
|
||||
breakPointId: int = 0
|
||||
|
||||
@@ -193,7 +193,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope =
|
||||
while true:
|
||||
j = (j * 10) + Ord(frmt[i]) - ord('0')
|
||||
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
|
||||
if j > high(args) + 1:
|
||||
internalError("ropes: invalid format string $" & $(j))
|
||||
|
||||
@@ -222,6 +222,54 @@ proc processCompile(filename: string) =
|
||||
extccomp.addExternalFileToCompile(found)
|
||||
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) =
|
||||
var
|
||||
theOS: TSystemOS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -10,10 +10,8 @@
|
||||
# This module is responsible for loading of rod files.
|
||||
#
|
||||
# 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.
|
||||
# Thus they are smaller than the source files most of the time. Even if they
|
||||
# are bigger, they are more efficient to process because symbols are only
|
||||
# loaded on demand.
|
||||
# a special text format. ROD-files are more efficient to process because
|
||||
# symbols are only loaded on demand.
|
||||
# It consists of:
|
||||
#
|
||||
# - a header:
|
||||
@@ -149,10 +147,10 @@ proc decodeBInt(r: PRodReader): biggestInt
|
||||
|
||||
proc encode(s: string): PRope =
|
||||
var res = ""
|
||||
for i in countup(0, len(s) + 0 - 1):
|
||||
for i in countup(0, len(s) - 1):
|
||||
case 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)
|
||||
|
||||
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)
|
||||
|
||||
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||
var
|
||||
id: int
|
||||
fl: string
|
||||
result = nil
|
||||
if r.s[r.pos] == '(':
|
||||
inc(r.pos)
|
||||
@@ -207,7 +202,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||
result.flags = cast[TNodeFlags](int32(decodeInt(r)))
|
||||
if r.s[r.pos] == '^':
|
||||
inc(r.pos)
|
||||
id = decodeInt(r)
|
||||
var id = decodeInt(r)
|
||||
result.typ = rrGetType(r, id, result.info)
|
||||
case result.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
@@ -217,7 +212,7 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if r.s[r.pos] == '!':
|
||||
inc(r.pos)
|
||||
fl = decode(r)
|
||||
var fl = decode(r)
|
||||
result.floatVal = parseFloat(fl)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if r.s[r.pos] == '!':
|
||||
@@ -228,14 +223,14 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
|
||||
of nkIdent:
|
||||
if r.s[r.pos] == '!':
|
||||
inc(r.pos)
|
||||
fl = decode(r)
|
||||
var fl = decode(r)
|
||||
result.ident = getIdent(fl)
|
||||
else:
|
||||
internalError(result.info, "decodeNode: nkIdent")
|
||||
of nkSym:
|
||||
if r.s[r.pos] == '!':
|
||||
inc(r.pos)
|
||||
id = decodeInt(r)
|
||||
var id = decodeInt(r)
|
||||
result.sym = rrGetSym(r, id, result.info)
|
||||
else:
|
||||
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])
|
||||
|
||||
proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||
var d: int
|
||||
result = nil
|
||||
if r.s[r.pos] == '[':
|
||||
inc(r.pos)
|
||||
@@ -335,7 +329,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||
else: InternalError(info, "decodeType ^(" & r.s[r.pos])
|
||||
addSon(result, nil)
|
||||
else:
|
||||
d = decodeInt(r)
|
||||
var d = decodeInt(r)
|
||||
addSon(result, rrGetType(r, d, info))
|
||||
|
||||
proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
|
||||
@@ -470,8 +464,8 @@ proc decode(r: PRodReader): string =
|
||||
of '\\':
|
||||
inc(i, 3)
|
||||
var xi = 0
|
||||
hexChar(r.s[i - 2], xi)
|
||||
hexChar(r.s[i - 1], xi)
|
||||
hexChar(r.s[i-2], xi)
|
||||
hexChar(r.s[i-1], xi)
|
||||
add(result, chr(xi))
|
||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_':
|
||||
add(result, r.s[i])
|
||||
@@ -488,7 +482,7 @@ proc skipSection(r: PRodReader) =
|
||||
while true:
|
||||
case r.s[r.pos]
|
||||
of '\x0A': inc(r.line)
|
||||
of '(': inc(c)
|
||||
of '(': inc(c)
|
||||
of ')':
|
||||
if c == 0:
|
||||
inc(r.pos)
|
||||
@@ -499,7 +493,7 @@ proc skipSection(r: PRodReader) =
|
||||
else: nil
|
||||
inc(r.pos)
|
||||
else:
|
||||
InternalError("skipSection " & $(r.line))
|
||||
InternalError("skipSection " & $r.line)
|
||||
|
||||
proc rdWord(r: PRodReader): string =
|
||||
result = ""
|
||||
@@ -530,18 +524,14 @@ proc processInterf(r: PRodReader, module: PSym) =
|
||||
IdTablePut(r.syms, s, s)
|
||||
|
||||
proc processCompilerProcs(r: PRodReader, module: PSym) =
|
||||
var
|
||||
s: PSym
|
||||
w: string
|
||||
key: int
|
||||
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
|
||||
r.pos = r.compilerProcsIdx
|
||||
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
|
||||
w = decode(r)
|
||||
var w = decode(r)
|
||||
inc(r.pos)
|
||||
key = decodeInt(r)
|
||||
var key = decodeInt(r)
|
||||
inc(r.pos) # #10
|
||||
s = PSym(IdTableGet(r.syms, key))
|
||||
var s = PSym(IdTableGet(r.syms, key))
|
||||
if s == nil:
|
||||
s = newStub(r, w, key)
|
||||
s.owner = module
|
||||
@@ -572,24 +562,25 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
|
||||
|
||||
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
var
|
||||
section, w: string
|
||||
w: string
|
||||
d, L, inclCrc: int
|
||||
while r.s[r.pos] != '\0':
|
||||
section = rdWord(r)
|
||||
var section = rdWord(r)
|
||||
if r.reason != rrNone:
|
||||
break # no need to process this file further
|
||||
if section == "CRC":
|
||||
case section
|
||||
of "CRC":
|
||||
inc(r.pos) # skip ':'
|
||||
if int(crc) != decodeInt(r): r.reason = rrCrcChange
|
||||
elif section == "ID":
|
||||
of "ID":
|
||||
inc(r.pos) # skip ':'
|
||||
r.moduleID = decodeInt(r)
|
||||
setID(r.moduleID)
|
||||
elif section == "OPTIONS":
|
||||
of "OPTIONS":
|
||||
inc(r.pos) # skip ':'
|
||||
r.options = cast[TOptions](int32(decodeInt(r)))
|
||||
if options.gOptions != r.options: r.reason = rrOptions
|
||||
elif section == "DEFINES":
|
||||
of "DEFINES":
|
||||
inc(r.pos) # skip ':'
|
||||
d = 0
|
||||
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);
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
if (d != countDefinedSymbols()): r.reason = rrDefines
|
||||
elif section == "FILES":
|
||||
of "FILES":
|
||||
inc(r.pos, 2) # skip "(\10"
|
||||
inc(r.line)
|
||||
L = 0
|
||||
@@ -610,7 +601,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
inc(r.line)
|
||||
inc(L)
|
||||
if r.s[r.pos] == ')': inc(r.pos)
|
||||
elif section == "INCLUDES":
|
||||
of "INCLUDES":
|
||||
inc(r.pos, 2) # skip "(\10"
|
||||
inc(r.line)
|
||||
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.line)
|
||||
if r.s[r.pos] == ')': inc(r.pos)
|
||||
elif section == "DEPS":
|
||||
of "DEPS":
|
||||
inc(r.pos) # skip ':'
|
||||
L = 0
|
||||
while (r.s[r.pos] > '\x0A'):
|
||||
@@ -632,32 +623,32 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
r.modDeps[L] = r.files[decodeInt(r)]
|
||||
inc(L)
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
elif section == "INTERF":
|
||||
of "INTERF":
|
||||
r.interfIdx = r.pos + 2
|
||||
skipSection(r)
|
||||
elif section == "COMPILERPROCS":
|
||||
of "COMPILERPROCS":
|
||||
r.compilerProcsIdx = r.pos + 2
|
||||
skipSection(r)
|
||||
elif section == "INDEX":
|
||||
of "INDEX":
|
||||
processIndex(r, r.index)
|
||||
elif section == "IMPORTS":
|
||||
of "IMPORTS":
|
||||
processIndex(r, r.imports)
|
||||
elif section == "CONVERTERS":
|
||||
of "CONVERTERS":
|
||||
r.convertersIdx = r.pos + 1
|
||||
skipSection(r)
|
||||
elif section == "DATA":
|
||||
of "DATA":
|
||||
r.dataIdx = r.pos + 2 # "(\10"
|
||||
# We do not read the DATA section here! We read the needed objects on
|
||||
# demand.
|
||||
skipSection(r)
|
||||
elif section == "INIT":
|
||||
of "INIT":
|
||||
r.initIdx = r.pos + 2 # "(\10"
|
||||
skipSection(r)
|
||||
elif section == "CGEN":
|
||||
of "CGEN":
|
||||
r.cgenIdx = r.pos + 2
|
||||
skipSection(r)
|
||||
else:
|
||||
MessageOut("skipping section: " & $(r.pos))
|
||||
MessageOut("skipping section: " & $r.pos)
|
||||
skipSection(r)
|
||||
if r.s[r.pos] == '\x0A':
|
||||
inc(r.pos)
|
||||
@@ -686,7 +677,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||
inc(r.pos)
|
||||
if r.s[r.pos] == '\x0A': inc(r.pos)
|
||||
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
|
||||
processRodFile(r, crc)
|
||||
else:
|
||||
@@ -814,7 +805,8 @@ proc checkDep(filename: string): TReasonForRecompile =
|
||||
for i in countup(0, high(r.modDeps)):
|
||||
res = checkDep(r.modDeps[i])
|
||||
if res != rrNone:
|
||||
result = rrModDeps #break // BUGFIX: cannot break here!
|
||||
result = rrModDeps
|
||||
# we cannot break here, because of side-effects of `checkDep`
|
||||
else:
|
||||
result = rrRodDoesNotExist
|
||||
if (result != rrNone) and (gVerbosity > 0):
|
||||
|
||||
@@ -70,8 +70,8 @@ proc fileIdx(w: PRodWriter, filename: string): int =
|
||||
|
||||
proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
|
||||
new(result)
|
||||
result.sstack = @ []
|
||||
result.tstack = @ []
|
||||
result.sstack = @[]
|
||||
result.tstack = @[]
|
||||
InitIITable(result.index.tab)
|
||||
InitIITable(result.imports.tab)
|
||||
result.filename = modfilename
|
||||
@@ -79,7 +79,7 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
|
||||
result.module = module
|
||||
result.defines = getDefines()
|
||||
result.options = options.gOptions
|
||||
result.files = @ []
|
||||
result.files = @[]
|
||||
|
||||
proc addModDep(w: PRodWriter, dep: string) =
|
||||
if w.modDeps != nil: app(w.modDeps, " ")
|
||||
@@ -284,11 +284,10 @@ proc symStack(w: PRodWriter) =
|
||||
setlen(w.sstack, 0)
|
||||
|
||||
proc typeStack(w: PRodWriter) =
|
||||
var i, L: int
|
||||
i = 0
|
||||
var i = 0
|
||||
while i < len(w.tstack):
|
||||
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)
|
||||
app(w.data, encodeType(w, w.tstack[i]))
|
||||
app(w.data, rodNL)
|
||||
@@ -317,9 +316,8 @@ proc addStmt(w: PRodWriter, n: PNode) =
|
||||
processStacks(w)
|
||||
|
||||
proc writeRod(w: PRodWriter) =
|
||||
var content: PRope
|
||||
processStacks(w) # write header:
|
||||
content = toRope("NIM:")
|
||||
var content = toRope("NIM:")
|
||||
app(content, toRope(FileVersion))
|
||||
app(content, rodNL)
|
||||
app(content, toRope("ID:"))
|
||||
@@ -373,43 +371,39 @@ proc writeRod(w: PRodWriter) =
|
||||
writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod")))
|
||||
|
||||
proc process(c: PPassContext, n: PNode): PNode =
|
||||
var
|
||||
w: PRodWriter
|
||||
a: PNode
|
||||
s: PSym
|
||||
result = n
|
||||
if c == nil: return
|
||||
w = PRodWriter(c)
|
||||
var w = PRodWriter(c)
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
|
||||
of nkTemplateDef, nkMacroDef:
|
||||
s = n.sons[namePos].sym
|
||||
var s = n.sons[namePos].sym
|
||||
addInterfaceSym(w, s)
|
||||
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 (n.sons[codePos] != nil) or (s.magic != mNone) or
|
||||
not (sfForward in s.flags):
|
||||
addInterfaceSym(w, s)
|
||||
of nkVarSection:
|
||||
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 != nkIdentDefs: InternalError(a.info, "rodwrite.process")
|
||||
addInterfaceSym(w, a.sons[0].sym)
|
||||
of nkConstSection:
|
||||
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 != nkConstDef: InternalError(a.info, "rodwrite.process")
|
||||
addInterfaceSym(w, a.sons[0].sym)
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
a = n.sons[i]
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
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)
|
||||
# this takes care of enum fields too
|
||||
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
import
|
||||
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
|
||||
# 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:
|
||||
result = copyTree(a)
|
||||
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,
|
||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||
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_I386
|
||||
# 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
|
||||
# define TCC_TARGET_X86_64
|
||||
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
||||
|
||||
4
todo.txt
4
todo.txt
@@ -1,10 +1,8 @@
|
||||
For version 0.8.10
|
||||
==================
|
||||
|
||||
- exception propagation across DLLs
|
||||
- fix exception handling
|
||||
- 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)
|
||||
|
||||
@@ -33,6 +33,9 @@ case $uos in
|
||||
*darwin* )
|
||||
myos="macosx"
|
||||
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
|
||||
if [ `sysctl hw |grep 64bit` = "hw.cpu64bit_capable: 1" ] ; then
|
||||
ucpu="amd64"
|
||||
fi
|
||||
;;
|
||||
*aix* )
|
||||
myos="aix"
|
||||
|
||||
@@ -15,9 +15,10 @@ Bugfixes
|
||||
- Bugfix: ``system.splitChunk`` still contained code for debug output.
|
||||
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
|
||||
``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: ``strutils.endsWith`` lacked range checking.
|
||||
- Bugfix: Better detection for AMD64 on Mac OS X.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
@@ -48,6 +49,7 @@ Additions
|
||||
- Added ``system.reopen``.
|
||||
- Added ``system.getCurrentException``.
|
||||
- Added ``system.appType``.
|
||||
- Added ``system.compileOption``.
|
||||
- Added ``times.epochTime`` and ``times.cpuTime``.
|
||||
- Implemented explicit type arguments for generics.
|
||||
- Implemented implicit type arguments for generics.
|
||||
|
||||
Reference in New Issue
Block a user