codegen for C++ exceptions
This commit is contained in:
parent
3ce400bb00
commit
bb850aafec
3 changed files with 80 additions and 65 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue