There is a construct called try that has the format (try <actions> <onerr> <finally). It always has exactly 3 children. If NIFC encounters this construct, it is always translated into C++'s equivalent. It is the job of the NIFC caller not to emit it when C++ support is disabled. If C++ code is not generated, the new (err) and (onerr) constructs have to be used which can be mapped easily to the current exceptions:goto mode.
raise
(raise value) can be used to produce C++'s throw statement.
onerr .
Calls that can potentially raise an exception must be called with (onerr). When C++'s exception handling mode is used, onerr's first child must always be the dot .:
There is a special magic variable called (err) of type bool that can be set via (asgn) and queried like other locations: (asgn (err) (true)) # set the error bit
onerr
Calls that trigger exception handling control flow must called with (onerr). The format is (onerr <action> <f> <args>). Typically action is a jmp instruction:
Functions can and must (!) be annotated with a (raises) pragma to indicate that they can raise a C++ exception. Likewise they need to use the errs pragma if they use the (err) mechanism. A function can use both annotations at the same time. That would be a C++ function that uses both (raise) and (err).
Benefits of this design
Can leverage C++'s zero-cost exception model.
Can be mapped to LLVM's exception handling model.
Can be mapped to exceptions:goto via:
thread local storage for the error bit
CPU flag for the error bit
Change the function's prototype to add err: var bool to the parameter list or bool to the return type.
Is entirely orthogonal to the used Runtime type information mechanism (RTTI) and also works without RTTI.
Supports the exceptions:quirky mode via an empty node for onerr, onerr . f args signals that f can raise but does not produce any code besides the function call.
try
There is a construct called
try
that has the format(try <actions> <onerr> <finally)
. It always has exactly 3 children. If NIFC encounters this construct, it is always translated into C++'s equivalent. It is the job of the NIFC caller not to emit it when C++ support is disabled. If C++ code is not generated, the new(err)
and(onerr)
constructs have to be used which can be mapped easily to the currentexceptions:goto
mode.raise
(raise value)
can be used to produce C++'sthrow
statement.onerr .
Calls that can potentially raise an exception must be called with
(onerr)
. When C++'s exception handling mode is used,onerr
's first child must always be the dot.
:err
There is a special magic variable called
(err)
of typebool
that can be set via(asgn)
and queried like other locations:(asgn (err) (true)) # set the error bit
onerr
Calls that trigger exception handling control flow must called with
(onerr)
. The format is(onerr <action> <f> <args>)
. Typically action is ajmp
instruction:raises and errs pragma
Functions can and must (!) be annotated with a
(raises)
pragma to indicate that they can raise a C++ exception. Likewise they need to use theerrs
pragma if they use the(err)
mechanism. A function can use both annotations at the same time. That would be a C++ function that uses both(raise)
and(err)
.Benefits of this design
exceptions:goto
via:err: var bool
to the parameter list orbool
to the return type.exceptions:quirky
mode via an empty node foronerr
,onerr . f args
signals thatf
can raise but does not produce any code besides the function call.