void MCKeywordsExecTry(MCExecContext& ctxt, MCStatement *trystatements, MCStatement *catchstatements, MCStatement *finallystatements, MCVarref *errorvar, uint2 line, uint2 pos) { Try_state state = TS_TRY; MCStatement *tspr = trystatements; Exec_stat stat; Exec_stat retcode = ES_NORMAL; MCtrylock++; while (tspr != NULL) { if (MCtrace || MCnbreakpoints) { MCB_trace(ctxt, tspr->getline(), tspr->getpos()); if (MCexitall) break; } ctxt . SetLineAndPos(tspr->getline(), tspr->getpos()); //stat = tspr->exec(ctxt . GetEP()); tspr->exec_ctxt(ctxt); stat = ctxt . GetExecStat(); ctxt . IgnoreLastError(); MCActionsRunAll(); switch(stat) { case ES_NORMAL: tspr = tspr->getnext(); if (MCexitall) { retcode = ES_NORMAL; tspr = NULL; } if (tspr == NULL && state != TS_FINALLY) { // Everything has executed normally but there may have been an // error added on another event. The trylock needs refactoring to // ensure a trylock on one event can't cause issues in another // event. MCeerror->clear(); tspr = finallystatements; state = TS_FINALLY; } break; case ES_ERROR: if ((MCtrace || MCnbreakpoints) && state != TS_TRY) do { if (MCB_error(ctxt, tspr->getline(), tspr->getpos(), EE_TRY_BADSTATEMENT)) break; ctxt.IgnoreLastError(); tspr->exec_ctxt(ctxt); } while(MCtrace && (stat = ctxt . GetExecStat()) != ES_NORMAL); if (stat == ES_ERROR) { if (MCexitall) { retcode = ES_NORMAL; tspr = NULL; } else if (state != TS_TRY) { MCtrylock--; return; } else { if (errorvar != NULL) { MCAutoStringRef t_error; MCeerror -> copyasstringref(&t_error); errorvar->set(ctxt, *t_error); } // MW-2007-09-04: At this point we need to clear the execution error // stack so that errors inside the catch statements are reported // correctly. MCeerror->clear(); MCperror->clear(); tspr = catchstatements; state = TS_CATCH; // MW-2007-07-03: [[ Bug 3029 ]] - If there is no catch clause // we end up skipping the finally as the loop terminates // before a state transition is made, thus we force it here. if (catchstatements == NULL) { MCeerror -> clear(); tspr = finallystatements; state = TS_FINALLY; } } } else tspr = tspr->getnext(); break; case ES_PASS: if (state == TS_CATCH) { MCAutoValueRef t_value; MCAutoStringRef t_string; if ((errorvar->eval(ctxt, &t_value), !ctxt.HasError()) && ctxt . ConvertToString(*t_value, &t_string)) { MCeerror->copystringref(*t_string, False); } MCeerror->add(EE_TRY_BADSTATEMENT, line, pos); stat = ES_ERROR; } default: if (state == TS_FINALLY) { MCeerror->clear(); retcode = ES_NORMAL; tspr = NULL; } else { retcode = stat; tspr = finallystatements; state = TS_FINALLY; } } } if (state == TS_CATCH) MCeerror->clear(); MCtrylock--; ctxt . SetExecStat(retcode); }
static Exec_stat MCKeywordsExecuteStatements(MCExecContext& ctxt, MCStatement *p_statements, Exec_errors p_error) { Exec_stat stat = ES_NORMAL; MCStatement *tspr = p_statements; while (tspr != NULL) { if (MCtrace || MCnbreakpoints) { MCB_trace(ctxt, tspr->getline(), tspr->getpos()); if (MCexitall) break; } ctxt . SetLineAndPos(tspr->getline(), tspr->getpos()); // stat = tspr->exec(ctxt . GetEP()); tspr->exec_ctxt(ctxt); stat = ctxt . GetExecStat(); ctxt . IgnoreLastError(); MCActionsRunAll(); switch(stat) { case ES_NORMAL: if (MCexitall) return ES_NORMAL; tspr = tspr->getnext(); break; case ES_NEXT_REPEAT: tspr = NULL; break; // SN-2014-08-06: [[ Bug 13122 ]] We want to know that we got an EXIT_SWITCH, // since we might be inside an IF statement case ES_EXIT_REPEAT: case ES_EXIT_SWITCH: return stat; case ES_ERROR: if ((MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors) do { if (!MCB_error(ctxt, tspr->getline(), tspr->getpos(), p_error)) break; ctxt . IgnoreLastError(); tspr->exec_ctxt(ctxt); } while (MCtrace && (stat = ctxt . GetExecStat()) != ES_NORMAL); if (stat == ES_ERROR) { if (MCexitall) return ES_NORMAL; ctxt . LegacyThrow(p_error); return stat; } else tspr = tspr->getnext(); break; default: return stat; } } return stat; }