codegen for C++ exceptions

This commit is contained in:
Zahary Karadjov 2012-06-03 20:37:56 +03:00
commit bb850aafec
3 changed files with 80 additions and 65 deletions

View file

@ -207,18 +207,20 @@ proc blockLeaveActions(p: BProc, howMany: int) =
var alreadyPoppedCnt = p.inExceptBlock var alreadyPoppedCnt = p.inExceptBlock
for tryStmt in items(stack): for tryStmt in items(stack):
if alreadyPoppedCnt > 0: if gCmd != cmdCompileToCpp:
dec alreadyPoppedCnt if alreadyPoppedCnt > 0:
else: dec alreadyPoppedCnt
appcg(p, cpsStmts, "#popSafePoint();$n", []) else:
appcg(p, cpsStmts, "#popSafePoint();$n", [])
var finallyStmt = lastSon(tryStmt) var finallyStmt = lastSon(tryStmt)
if finallyStmt.kind == nkFinally: if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0]) genStmts(p, finallyStmt.sons[0])
# push old elements again: # push old elements again:
for i in countdown(howMany-1, 0): for i in countdown(howMany-1, 0):
p.nestedTryStmts.add(stack[i]) p.nestedTryStmts.add(stack[i])
for i in countdown(p.inExceptBlock-1, 0): if gCmd != cmdCompileToCpp:
appcg(p, cpsStmts, "#popCurrentException();$n", []) for i in countdown(p.inExceptBlock-1, 0):
appcg(p, cpsStmts, "#popCurrentException();$n", [])
proc genReturnStmt(p: BProc, t: PNode) = proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true p.beforeRetNeeded = true
@ -309,10 +311,10 @@ proc genBreakStmt(p: BProc, t: PNode) =
appf(p.s(cpsStmts), "goto $1;$n", [label]) appf(p.s(cpsStmts), "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string = proc getRaiseFrmt(p: BProc): string =
#if gCmd == cmdCompileToCpp: if gCmd == cmdCompileToCpp:
# result = "throw #nimException($1, $2);$n" result = "throw NimException($1, $2);$n"
#else: else:
result = "#raiseException((#E_Base*)$1, $2);$n" result = "#raiseException((#E_Base*)$1, $2);$n"
proc genRaiseStmt(p: BProc, t: PNode) = proc genRaiseStmt(p: BProc, t: PNode) =
if p.inExceptBlock > 0: if p.inExceptBlock > 0:
@ -320,7 +322,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
# we must execute it before reraising # we must execute it before reraising
var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
if finallyBlock.kind == nkFinally: if finallyBlock.kind == nkFinally:
genStmts(p, finallyBlock.sons[0]) genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty: if t.sons[0].kind != nkEmpty:
var a: TLoc var a: TLoc
InitLocExpr(p, t.sons[0], a) InitLocExpr(p, t.sons[0], a)
@ -331,10 +333,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else: else:
genLineDir(p, t) genLineDir(p, t)
# reraise the last exception: # reraise the last exception:
#if gCmd == cmdCompileToCpp: if gCmd == cmdCompileToCpp:
# appcg(p, cpsStmts, "throw;$n") appcg(p, cpsStmts, "throw;$n")
#else: else:
appcg(p, cpsStmts, "#reraiseException();$n") appcg(p, cpsStmts, "#reraiseException();$n")
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: TFormatStr, labl: TLabel) = rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
@ -528,80 +530,86 @@ proc hasGeneralExceptSection(t: PNode): bool =
inc(i) inc(i)
result = false result = false
proc genTryStmtCpp(p: BProc, t: PNode) = proc genTryStmtCpp(p: BProc, t: PNode) =
# code to generate: # code to generate:
# #
# bool tmpRethrow = false; # XXX: There should be a standard dispatch algorithm
# that's used both here and with multi-methods
#
# try # try
# { # {
# myDiv(4, 9); # myDiv(4, 9);
# } catch (NimException& tmp) { # } catch (NimException& exp) {
# tmpRethrow = true; # if (isObj(exp, EIO) {
# switch (tmp.exc) # ...
# { # } else if (isObj(exp, ESystem) {
# case DIVIDE_BY_ZERO: # ...
# tmpRethrow = false; # finallyPart()
# printf("Division by Zero\n"); # raise;
# break; # } else {
# default: // used for general except! # // general handler
# generalExceptPart();
# tmpRethrow = false;
# } # }
# } # }
# excHandler = excHandler->prev; // we handled the exception
# finallyPart(); # finallyPart();
# if (tmpRethrow) throw; var
#
# XXX: push blocks
var
rethrowFlag: PRope
exc: PRope exc: PRope
i, length, blen: int i, length, blen: int
genLineDir(p, t) genLineDir(p, t)
rethrowFlag = nil
exc = getTempName() exc = getTempName()
if not hasGeneralExceptSection(t): if optStackTrace in p.Options:
rethrowFlag = getTempName()
appf(p.s(cpsLocals), "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag])
if optStackTrace in p.Options:
appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
appf(p.s(cpsStmts), "try {$n")
add(p.nestedTryStmts, t) add(p.nestedTryStmts, t)
startBlock(p, "try {$n")
genStmts(p, t.sons[0]) genStmts(p, t.sons[0])
length = sonsLen(t) length = sonsLen(t)
if t.sons[1].kind == nkExceptBranch: endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
appf(p.s(cpsStmts), "} catch (NimException& $1) {$n", [exc]) inc p.inExceptBlock
if rethrowFlag != nil:
appf(p.s(cpsStmts), "$1 = NIM_TRUE;$n", [rethrowFlag])
appf(p.s(cpsStmts), "if ($1.sp.exc) {$n", [exc])
i = 1 i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch): var catchAllPresent = false
while (i < length) and (t.sons[i].kind == nkExceptBranch):
blen = sonsLen(t.sons[i]) blen = sonsLen(t.sons[i])
if blen == 1: if i > 1: appf(p.s(cpsStmts), "else ")
if blen == 1:
# general except section: # general except section:
appf(p.s(cpsStmts), "default:$n") catchAllPresent = true
genStmts(p, t.sons[i].sons[0]) genSimpleBlock(p, t.sons[i].sons[0])
else: else:
for j in countup(0, blen - 2): var orExpr: PRope = nil
for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
appf(p.s(cpsStmts), "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)]) if orExpr != nil: app(orExpr, "||")
genStmts(p, t.sons[i].sons[blen - 1]) appcg(p.module, orExpr,
if rethrowFlag != nil: "#isObj($1.exp->m_type, $2)",
appf(p.s(cpsStmts), "$1 = NIM_FALSE; ", [rethrowFlag]) [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
appf(p.s(cpsStmts), "break;$n") if i > 1: app(p.s(cpsStmts), "else ")
appf(p.s(cpsStmts), "if ($1) ", [orExpr])
genSimpleBlock(p, t.sons[i].sons[blen-1])
inc(i) inc(i)
if t.sons[1].kind == nkExceptBranch:
appf(p.s(cpsStmts), "}}$n") # end of catch-switch statement # reraise the exception if there was no catch all
appcg(p, cpsStmts, "#popSafePoint();") # and none of the handlers matched
if not catchAllPresent:
if i > 1: appf(p.s(cpsStmts), "else ")
startBlock(p)
var finallyBlock = t.lastSon
if finallyBlock.kind == nkFinally:
genStmts(p, finallyBlock.sons[0])
appcg(p, cpsStmts, "throw;$n")
endBlock(p)
appf(p.s(cpsStmts), "}$n") # end of catch block
dec p.inExceptBlock
discard pop(p.nestedTryStmts) discard pop(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]) genSimpleBlock(p, t.sons[i].sons[0])
if rethrowFlag != nil:
appf(p.s(cpsStmts), "if ($1) { throw; }$n", [rethrowFlag])
proc genTryStmt(p: BProc, t: PNode) = proc genTryStmt(p: BProc, t: PNode) =
# code to generate: # code to generate:
# #
# XXX: There should be a standard dispatch algorithm
# that's used both here and with multi-methods
#
# TSafePoint sp; # TSafePoint sp;
# pushSafePoint(&sp); # pushSafePoint(&sp);
# sp.status = setjmp(sp.context); # sp.status = setjmp(sp.context);

View file

@ -281,6 +281,13 @@ static unsigned long nimInf[2]={0xffffffff, 0x7fffffff};
# endif # endif
# define NIM_BOOL bool # define NIM_BOOL bool
# define NIM_NIL 0 # define NIM_NIL 0
struct NimException
{
NimException(struct E_Base* exp, const char* msg): exp(exp), msg(msg) {}
struct E_Base* exp;
const char* msg;
};
#else #else
# ifdef bool # ifdef bool
# define NIM_BOOL bool # define NIM_BOOL bool

View file

@ -37,7 +37,7 @@ proc reraise_in_except =
echo "BEFORE" echo "BEFORE"
raise newException(EIO, "") raise newException(EIO, "")
except: except EIO:
echo "EXCEPT" echo "EXCEPT"
raise raise