# Mu - exception1.mu

     1 # Example program showing exceptions built out of delimited continuations.
     2
     3 # Since Mu is statically typed, we can't build an all-purpose higher-order
     4 # function called 'try'; it wouldn't know how many arguments the function
     5 # passed to it needs to take, what their types are, etc. Instead, until Mu
     6 # gets macros we'll directly use the continuation primitives.
     7
     8 def main [
     9   local-scope
    10   foo false/no-exception
    11   foo true/raise-exception
    12 ]
    13
    14 # example showing exception handling
    15 def foo raise-exception?:bool [
    16   local-scope
    17   load-inputs
    18   # To run an instruction of the form:
    19   #   try f ...
    20   # write this:
    21   #   call-with-continuation-mark 999/exception-tag, f, ...
    22   # By convention we reserve tag 999 for exceptions.
    23   #
    24   # 'f' above may terminate at either a regular 'return' or a 'return-with-continuation-mark'.
    25   # We never re-call the continuation returned in the latter case;
    26   # its existence merely signals that an exception was raised.
    27   # So just treat it as a boolean.
    28   # The other inputs and outputs to 'call-with-continuation-mark' depend on
    29   # the function it is called with.
    30   exception-raised?:bool, err:text, result:num <- call-with-continuation-mark 999/exception-tag, f, raise-exception?
    31   {
    32     break-if exception-raised?
    33     $print [normal exit; result ] result 10/newline
    34   }
    35   {
    36     break-unless exception-raised?
    37     $print [error caught: ] err 10/newline
    38   }
    39 ]
    40
    41 # A callee function that can raise an exception has some weird constraints at
    42 # the moment.
    43 #
    44 # The caller's 'call-with-continuation-mark' instruction may return with
    45 # either a regular 'return' or a 'return-continuation-until-mark'.
    46 # To handle both cases, regular 'return' instructions in the callee must
    47 # prepend an extra 0 result, in place of the continuation that may have been
    48 # returned.
    49 # This change to number of outputs violates our type system, so the call has
    50 # to be dynamically typed. The callee can't have a header.
    51 def f [
    52   local-scope
    53   raise-exception?:bool <- next-input
    54   {
    55     break-unless raise-exception?
    56     # throw/raise: 2 results + implicit continuation (ignoring the continuation tag)
    57     return-continuation-until-mark 999/exception-tag, [error will robinson!], 0/unused
    58   }
    59   # normal return: 3 results including 0 continuation placeholder at start
    60   return 0/continuation-placeholder, null/no-error, 34/regular-result
    61 ]