Aztec® Programming Language
Version 1.1 Alpha 2

Copyright © 2010-2017, Aztec Development Group, All Rights Reserved

Download Aztec

Search        Contact Us

I didn't get a lot in class...

But I know it don't come in a shot glass.

- Amy Winehouse

 

Exception Event Handling

An Exception is a special Aztec Event that is created when a run-time error occurs. An Exception object is created automatically by the Aztec Virtual Machine or Class Framework when a critical error occurs, and then the Exception is "Fired". The framework also allows an Exception to be created and fired by user code when appropriate. When an exception is fired, it causes execution in the Virtual Machine thread to immediately stop. It then searches for an appropriate 'handle' block as described below which can perform fixup code and allow the application to continue executing, albeit at a different location.

If the system does not find a match after looking at all applicable exceptions/handle constructs, the script/application terminates and writes an error message to the Virtual Machine log. If the Aztec Engine is running in "-menu" mode, a dialog is also displayed indicating that the exception was not properly handled.

The syntax for the exceptions statement is shown in the following diagram. The square braces ([ ]) are used to indicate optional parts of the syntax, as described in more detail below.

Aztec Exception Handling Construct

 

As an Aztec script/application is executed, the VM keeps track of all exceptions/handle constructs that the code executes, together with the method in which they were executed. When an exception is fired, the VM searches the list of exceptions/handle constructs in a backwards fashion. The most recent one is visited first, and the exception object is compared to each of the handle statements to see if there is a match.

♦ If there is an object oriented "is a" match between the object and the handle class type, then transfer of control is passed to the Aztec statement block associated with that handle statement. When the VM transfers control to the handle block, it unwinds the VM stack for that thread to match the location of the code. If the matching exceptions/handle block is not in the same method where the exception is fired, the VM unwinds the stack and performs all cleanup of objects for each of the methods that is unwound.

♦ If there is not an object oriented "is a" match between the object and any of the handle statements, the VM moves to the next most recent exceptions/handle construct, and performs the same check there. As mentioned above, if there are no exceptions/handle statements that match the fired exception object, an "unhandled exception" error is written to the VM log and the script/application is terminated.

The following rules define how to use the exceptions statement.

♦ The 'ExceptionEvent.Fire()' method is used to "fire off an exception event" and initiate exception handling within the Virtual Machine.

♦ The exception class list on the “exceptions” statement is optional. Any number of separate classes can be listed, and each class must be derived from the ExceptionEvent class, directly or indirectly. This list provides a set of class filters for all exceptions being handled.

♦ If the list is empty, the handle statements in the construct can be used for any type of exception object.
♦ If the exception class list contains one or more classes, those exception classes are used as filters for this exceptions/handle construct. Only an exception object that matches one of the exception filter classes will be processed by the handle statements in the construct.

♦ Each "handle" statement will typically have a single argument, enclosed in triangular braces (< >), and the argument type must be derived from ExceptionEvent. An empty argument list is also allowed if there are one or more classes in the exception list.

♦ At least one “handle” block is required if there is no exception class list on the “exceptions” statement.

♦ Each handle statement must contain a single exception argument as described above.

♦ If an exception class list is used, then the “handle” block is optional.

♦ If no handle block is used, and the fired exception object matches one of the classes in the exception class list, the exception is already considered "handled". Nothing else needs to be done. Execution will flow to the "cleanup" block if one exists, and to the statement after the entire exceptions/handle construct if no cleanup block.
♦ A handle statement with no exception argument is allowed with an exception class list. The block will be executed as long as the fired exception matches one of the classes in the exception list.
♦ A handle statement can use the exception argument, and will get invoked if it is the first handle block to match the fired exception object.

♦ If multiple “handle” blocks are used, execution will flow to the first handle block which has an exception argument which matches the exception which was fired (using an OO "is a" comparison).

♦ If none is found, the VM continues searching other “outer” exception blocks.
♦ If the end of the method is reached while searching for a match, the method is exited and the stack is automatically cleaned up for the method, including the execution of deterministic destructors if applicable.
♦ The previous method is searched from the point where the method was called. This entire process is repeated for all methods in the call stack until an exception match is found. If a match isn't found, an "unhandled exception" error is displayed by the VM and the script is terminated.

♦ The “cleanup” block is executed if no exception was fired within the exceptions block, AND it is also executed if an exception was fired that matches one of the “handle” statements. It will also be executed for an automatic match using class filters as described above.

♦ The only time that the cleanup block does not get executed is if an exception does occur, and the exception object does not match any of the handle statements or classes from the exceptions list.

Note that Aztec Exceptions (classes derived from “ExceptionEvent”) are also Aztec Events. It is therefore possible to register an event handler to get invoked when a particular type of exception occurs.

♦ If an exception handler is registered from a different thread than where the exception occurs, then the registered handler can be executed in parallel with the thread which is processing the exception itself.

♦ This allows a script to monitor and track exceptions automatically, independent of the code that actually handles the exception inside the thread where it occurred.

♦ The “Thread.AddExceptionHandler()” method is used to register event handlers for any specific type of exception.

The following diagrams show the class hierarchy for some common system level exception classes, along with several tables showing some of the key methods in those classes.

ExceptionClass Hierarchy Sample           MathException Class Hierarchy

Key Methods in MathException Class Hierarchy

 

The ExceptionEvent.ModuleLine() method tries to return the line number where the exception occurred, but the system does not normally track this to the individual statement, for performance reasons. It only tracks it to the start of the method where it occcurred. The "-debug" command line option is used to track this number directly to the offending line of source code. The compiler inserts special VM instructions in the binary code to allow this number to be tracked directly to the offending source code line. It increases the size of the executable slightly, and marginally decreases performance.

Exception Handler Data Types

To be consistent with other Event "Handler" data types, the Exception family of classes each provide an associated Handler data type. This data type is likely not useful for traditional in-line exception handling using the exceptions/handle construct. It becomes useful when defining a separate event handler to execute in parallel when a particular exception is fired. The following list shows the Handler data types for each ExceptionEvent in the framework.

Aztec Exception Event Handlers

 

The Aztec source code showing simple exception event handling is shown below.

#===================================================================================================
# Example Script: Aztec Simple Exception Script
# Demonstrates the use of exception handling in the thread where the exception occurred.
#===================================================================================================

# Main run-time entry point for the script.
method Main
{
data<bool> Error
data<bool> ForceMathException
data<bool> ForceNullException
data<float> FinalResult
data<SampleAnalysis> MyDataAnalysis

# Look at 1st command line arg and set "force exception" flags if 1 or 2.
if ( GetScript().GetArg(1) == '1' )
ForceMathException = true
else if ( GetScript().GetArg(1) == '2' )
ForceNullException = true

#--------------------------------------------------------------
# Wrap all script processing in a catch-all exception handler
# and also look specifically for 'NullRefException'.
#--------------------------------------------------------------
exceptions
{
# Create sample class and call the calculate method to possibly cause an exception.
MyDataAnalysis = new<SampleAnalysis(25.0,ForceMathException,ForceNullException)>
FinalResult = MyDataAnalysis.CalculateResult(2.5)
}
handle<NullRefException Exception>
{
Error = true
StdIO.Write("Handled a NullRef exception in 'Main()' that came from 'CalculateResult()'.")
}
handle<ExceptionEvent Exception>
{
# All as-of-yet unhandled exceptions will come this way before script exits.
Error = true
StdIO.Write(Exception.ObjectClass().Name() + " occurred at line " + Exception.ModuleLine().Str())
}
cleanup
{
if ( !Error )
{
StdIO.Write("No exceptions handled in Main. Final result is " + FinalResult.Str())
}
}
}

# Simple class used for exception demonstration.
class SampleAnalysis
{
method SampleAnalysis(float InitValue, bool ForceMathException = false, bool ForceNullException = false)
{
InitialValue = InitValue
self.ForceMathException = ForceMathException
self.ForceNullException = ForceNullException
}

method<float> CalculateResult(float Input)
{
data<float> Output
data<Thread> ThisThread

#--------------------------------------------------------------------------------
# Wrap the processing for this method in an exceptions/handle construct. For
# demonstration purposes, we'll handle Math here and let Null go back to caller.
#--------------------------------------------------------------------------------
exceptions<MathException>
{
# Calculate a dummy result. If flag is set to cause exception, initiate it by dividing by zero.
if ( ForceMathException )
{
Input = 0
}

Output = InitialValue / Input

# Initiate a "Null" exception if flag is set by calling a method with a null reference.
if ( !ForceNullException )
{
ThisThread = GetThread()
}

StdIO.Write("Thread id is " + ThisThread.ThreadId().Str())
}
handle
{
# We know this is a Math exception since that's the only thing we filtered on above.
StdIO.Write("Handled a math exception in the 'CalculateResult()' method.")
}

return(Output)
}

data<bool> ForceMathException
data<bool> ForceNullException
data<float> InitialValue
}

Page UpPage DownCopyright © 2010-2017
Aztec Development Group
All Rights Reserved

Download Aztec