62 lines
2.3 KiB
Forth
62 lines
2.3 KiB
Forth
# Example program showing exceptions built out of delimited continuations.
|
|
|
|
# Since Mu is statically typed, we can't build an all-purpose higher-order
|
|
# function called 'try'; it wouldn't know how many arguments the function
|
|
# passed to it needs to take, what their types are, etc. Instead, until Mu
|
|
# gets macros we'll directly use the continuation primitives.
|
|
|
|
def main [
|
|
local-scope
|
|
foo false/no-exception
|
|
foo true/raise-exception
|
|
]
|
|
|
|
# example showing exception handling
|
|
def foo raise-exception?:bool [
|
|
local-scope
|
|
load-inputs
|
|
# To run an instruction of the form:
|
|
# try f ...
|
|
# write this:
|
|
# call-with-continuation-mark 999/exception-tag, f, ...
|
|
# By convention we reserve tag 999 for exceptions.
|
|
#
|
|
# 'f' above may terminate at either a regular 'return' or a 'return-with-continuation-mark'.
|
|
# We never re-call the continuation returned in the latter case;
|
|
# its existence merely signals that an exception was raised.
|
|
# So just treat it as a boolean.
|
|
# The other inputs and outputs to 'call-with-continuation-mark' depend on
|
|
# the function it is called with.
|
|
exception-raised?:bool, err:text, result:num <- call-with-continuation-mark 999/exception-tag, f, raise-exception?
|
|
{
|
|
break-if exception-raised?
|
|
$print [normal exit; result ] result 10/newline
|
|
}
|
|
{
|
|
break-unless exception-raised?
|
|
$print [error caught: ] err 10/newline
|
|
}
|
|
]
|
|
|
|
# A callee function that can raise an exception has some weird constraints at
|
|
# the moment.
|
|
#
|
|
# The caller's 'call-with-continuation-mark' instruction may return with
|
|
# either a regular 'return' or a 'return-continuation-until-mark'.
|
|
# To handle both cases, regular 'return' instructions in the callee must
|
|
# prepend an extra 0 result, in place of the continuation that may have been
|
|
# returned.
|
|
# This change to number of outputs violates our type system, so the call has
|
|
# to be dynamically typed. The callee can't have a header.
|
|
def f [
|
|
local-scope
|
|
raise-exception?:bool <- next-input
|
|
{
|
|
break-unless raise-exception?
|
|
# throw/raise: 2 results + implicit continuation (ignoring the continuation tag)
|
|
return-continuation-until-mark 999/exception-tag, [error will robinson!], 0/unused
|
|
}
|
|
# normal return: 3 results including 0 continuation placeholder at start
|
|
return 0/continuation-placeholder, null/no-error, 34/regular-result
|
|
]
|