mu/archive/1.vm/exception2.mu

63 lines
1.9 KiB
Forth

# Example program showing exceptions built out of delimited continuations.
# Slightly less klunky than exception1.mu.
# 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.
exclusive-container error-or:_elem [
error:text
value:_elem
]
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.
#
# The other inputs and outputs to 'call-with-continuation-mark' depend on
# the function it is called with.
_, result:error-or:num <- call-with-continuation-mark 999/exception-tag, f, raise-exception?
{
val:num, normal-exit?:bool <- maybe-convert result, value:variant
break-unless normal-exit?
$print [normal exit; result ] val 10/newline
}
{
err:text, error-exit?:bool <- maybe-convert result, error:variant
break-unless error-exit?
$print [error caught: ] err 10/newline
}
]
# Callee function that we catch exceptions in must always return using a
# continuation.
def f raise-exception?:bool -> result:error-or:num [
local-scope
load-inputs
{
break-unless raise-exception?
# throw/raise
result <- merge 0/error, [error will robinson!]
return-continuation-until-mark 999/exception-tag, result
}
# 'normal' return; still uses the continuation mark
result <- merge 1/value, 34
return-continuation-until-mark 999/exception-tag, result
# dead code just to avoid errors
result <- merge 1/value, 0
return result
]