/// <summary> /// Works like throwException(), except we search for the right try clause. /// </summary> public static void ThrowException( State state, object thrown ) { Step tryStep = state.findAction( step => IsTryMarker( step ) ); if( tryStep == null ) { // Make sure we have a CoralException. if( !(thrown is CoralException) ) thrown = new CoralException( thrown ); CoralException cex = (CoralException)thrown; if( cex.trace == null ) cex.setStackTrace( state ); // Unwind everything else off the stack. There is an implicit "except" at the top anyway. state.clearActions(); // Push on a thrower. We do this in a separate step so that the same try/catch can deal // with it at the Runner level. state.pushAction( new Step( null, a => { throw new UnhandledException( (CoralException)thrown ); }, "re-thrower" ) ); return; } AstTry node = (AstTry)tryStep.node; node.throwException( state, thrown ); }
/// <summary> /// Throws an exception. /// </summary> /// <param name="thrown"> /// The object to throw. It's recommended that this be a dictionary with a /// "name" parameter at the least. /// </param> public void throwException( State state, object thrown ) { // We want to have stack traces, so this is necessary... but we also want to // throw data objects and not C# objects. So we have to convert back and forth. if( !(thrown is CoralException) ) thrown = new CoralException( thrown ); var cex = (CoralException)thrown; if( cex.trace == null ) cex.setStackTrace( state ); thrown = cex.data; state.pushAction( new Step( this, st => { // We'll want to hold on to the finally runner if there is one. This will // let us properly handle nested exceptions. Step finallyStep = null; st.unwindActions( step => IsTryMarker( step ), this.finallyBlock != null ); if( this.finallyBlock != null ) finallyStep = st.popAction(); // The except block may have a parameter. if( this.exceptIdentifer != null ) { IScope exceptScope = new ParameterScope( st.scope, new string[] { this.exceptIdentifer } ); exceptScope.set( this.exceptIdentifer, thrown ); state.pushActionAndScope( new Step( this, a => {}, "except: scope" ), exceptScope ); } this.exceptBlock.run( st ); if( finallyStep != null ) { finallyStep.description = "finally block"; st.pushAction( finallyStep ); } }, "throw" ) ); }