(*
  Public Domain. Use at your own risk!
  Author: Martin Jambon <martin_jambon@emailuser.net>

  This syntax extension provides a "try ... finally ..." construct
  is used to force the execution of a statement after some computation
  even if that computation raises an exception. For instance, the following
  expression has type "int" and always prints "done" at the end, 
  but propagates the Division_by_zero exception:

  try
    print_string "trying a hard division...";
    0 / 0
  finally
    print_endline " done";
    flush stdout

  In "try e1 finally e2", if e2 raises an exception, it is propagated.
  If this behavior is not wanted, it is the user's responsibility to 
  insert a catch-all statement, i.e. write
  "try e1 finally try e2 with _ -> ()" instead.
*)

let unique = 
  let counter = ref 0 in
  fun () -> incr counter; "__pa_tryfinally" ^ string_of_int !counter

let expand _loc e1 e2 =
  let result = unique () in
  <:expr<
  let $lid:result$ =
    try `Result $e1$
    with [ exn -> `Exn exn ] in
  let () = $e2$ in
  match $lid:result$ with
      [ `Result x -> x
      | `Exn exn -> raise exn ]
  >>

EXTEND
  Pcaml.expr: LEVEL "expr1" [
    [ "try"; e1 = Pcaml.expr; 
      "finally"; e2 = Pcaml.expr LEVEL "top" -> expand _loc e1 e2 ]
  ];
END