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 0/no-exception
11   foo 1/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, 0/no-error, 34/regular-result
61 ]