(⬑Table of Contents) (data types)
Exceptions
Like most not-entirely-low-level languages, whcl offers support for
so-called "exceptions" for reporting errors from script
code. Exceptions change the flow of a script, propagating an error up
until the next instance of the catch builtin command, which stops
propagation of the exception. If no catch is in place, the
"uncaught" exceptions bubbles up out of the script and is passed to
the C-level caller, who may deal with it as they please.
An exception contains information about where it was thrown and the call stack leading up to that point, making it easy to track the location of an exception.
Exceptions in whcl are relatively limited, namely in that a catch
statement cannot distinguish between different types of exceptions.
For the vast majority of cases, all exceptions are equal in
whcl's eyes.
Using Exceptions
There are several distinct ways to use exceptions:
- The builtin
exceptionand thewhcl[Exception]are two functionally equivalent ways of creating exceptions. The latter is provided primarily so that its prototype may be extended by clients. - The
throwbuiltin command will create a new exception if the value given to it is not already one. If given an exception object, it re-throws it as-is without modification.
An exception by itself does not trigger an error. The triggering
happens via the throw builtin (or equivalent C-level code).
Exceptions have three significant key/value pairs:
codeis an integer code associated with the error. The whcl library always uses codes from thecwal_rc_eenum but client code is not required to.messageis an arbitrary value but typically a string.stackTracegets injected by the interpreter when an exception is created so that the developer may trace which commands leds up to the throwing of an exception.
As alluded to above, "activating" an exceptional error case requires
the throw keyword or equivalent C code. The most common usage is
simply:
throw exception "This is my message!"
# Equivalent to:
throw new whcl[Exception] "This is my message!"
If passed a single argument, the code defaults to
CWAL_RC_EXCEPTION, but it may optionally be passed as the first of
two arguments:
throw exception RANGE "Number out of range."
# Equivalent to:
throw new whcl[Exception] RANGE "Number out of range."
The name RANGE there is the suffix of a cwal_rc_e enum code (the
One True set of result codes used by the library). The exception
constructor accepts three different forms of code value:
- An arbitrary non-0 integer.
- A string in the form
CWAL_RC_...which matches the name of acwal_rc_eenum entry. - A string in the form
XXXwhereXXXmatches theXXXpart of aCWAL_RC_XXXenum entry. e.g.CWAL_RC_RANGEandRANGEare equivalent.
If passed a value of 0, or a value which is not in one of the above
forms, the value CWAL_RC_EXCEPTION is used. Note, however, that none
of the values from the cwal_rc_e have well-defined values except for
CWAL_RC_OK, which is always 0. All others are guaranteed only to be
non-0.
The code-string Method
The exception prototype has a method called code-string which has
the following distinct uses:
- If passed no argument, it returns the string form of the exception's
codevalue, if it can find one, in the form"CWAL_RC_xxx"(without the quotes). It returnsundefinedif the code does not match any known C-levelcwal_rc_evalue. - If passed an integer argument which lies in the
cwal_rc_erange, it return the name of that code, as described above, orundefinedif the integer is out of that range. - If passed a string argument, it expects it to be in the form
CWAL_RC_...orXXX, whereXXXis the suffix of aCWAL_RC_XXXentry. If a match is found, it returns the integer code (noting the caveat above about the instability of those codes), else it returnsundefined.
This method primarily exists to facilitate testing of C-level code which uses the cwal result code range (e.g. whcl itself). For example:
catch x { ... }
assert CWAL_RC_RANGE == [x code-string]
Or, more succinctly:
assert CWAL_RC_RANGE == [[catch {...}].code-string]