Exceptions
This is a basic overview of how to deal with exceptions from PIR. There are two main topics: throwing exceptions and catching exceptions. We'll start with the first.
Throwing exceptions
If you're going to be using exceptions, you probably want to start by including two pasm files that define constants for exception type and severity.
.include 'include/except_types.pasm' .include 'include/except_severity.pasm'
You create exceptions just like you create any other object, with new
.
.local pmc ex ex = new 'Exception'
You usually want to at least set a descriptive message about what went wrong.
ex = "Everything is horrible, dood."
You also usually want to set a severity and sometimes a type. You can find these in "parrot/include/except_severity.pasm" in runtime.
ex['severity'] = .EXCEPT_DOOMED ex['type'] = .CONTROL_ERROR
You actually throw the exception by using the throw
op.
throw ex
Put all together, it looks like this:
Throw Example
.include 'include/except_types.pasm' .include 'include/except_severity.pasm' .local pmc ex ex = new 'Exception' ex = "Everything is horrible, dood." ex['severity'] = .EXCEPT_DOOMED ex['type'] = .CONTROL_ERROR throw ex
Catching exceptions
Parrot maintains a stack of exception handlers. When an exception is thrown, Parrot iterates through the stack looking for a handler that can handle the exception. When it finds a valid exception handler, the exception handler is invoked with the exception as an argument. Exception handlers run in the context of the throw
that they're handling.
You create exception handlers just like you create any other object, with new
.
.local pmc eh eh = new 'ExceptionHandler'
You set the target of the exception handler (the code that will be invoked) with the set_attr
opcode. Usually this will be a label. You manipulate the exception handler stack with the push_eh
and pop_eh
opcodes. This is a fairly standard use of exception handlers:
.local pmc eh eh = new 'ExceptionHandler' set_addr eh, handler push_eh eh ... # code that might throw an exception pop_eh .return (1) # Success! handler: .local pmc ex .get_results (ex) ... # code that prints a warning, logs an error, whatever .return (0) # Failure!
Sometimes you want to be more specific in what you catch. You can set filters on the exception handler based on exception type and severity. The methods you use include .min_severity()
, .max_severity()
, .handle_types()
, and .handle_types_except()
.
Here's an example of a sub that catches only error exceptions and prints an appropriate log message before exiting.
.include 'include/except_severity.pasm' .sub 'dostuff' .local pmc eh eh = new 'ExceptionHandler' set_addr eh, handler eh.'min_severity'(.EXCEPT_ERROR) push_eh eh # ... stuff that might throw an error pop_eh .return (1) handler: .local pmc ex .local string msg .get_results (ex) print "There was a fatal error in dostuff: " msg = ex say ex exit 1 .end