let print_template = fun chan ->
  let rec print = fun formatter -> function
    | Tmpl_Text text -> begin
        match List.rev (Str.split_delim (Str.regexp "\013?\n") text) with
          | hd :: tl ->
              List.iter
                (fun s -> Format.fprintf formatter
                   "Pervasives.output_string tmpl__channel \"%s\\n\";@ "
                   (String.escaped s))
                (List.rev tl);
              if hd <> "" then
                Format.fprintf formatter
                  "Pervasives.output_string tmpl__channel \"%s\";@ "
                  (String.escaped hd)
          | _ ->
              ()
      end

    | Tmpl_Block (caml, ts) ->
        Format.fprintf formatter
          "@[<2>begin %s@ in@ %a@]@\nend;@\n"
          caml
          (fun formatter ts ->
             List.iter (fun t -> print formatter t) ts)
          ts

    | Tmpl_Iter (symbol, list, ts) ->
        Format.fprintf formatter "@[<2>begin@\n";
        Format.fprintf formatter "@[<2>List.iter@\n";
        Format.fprintf formatter "@[<2>(fun %s -> begin@\n%a@]"
          symbol
          (fun formatter () -> List.iter (fun t -> print formatter t) ts) ();
        Format.fprintf formatter "end)@\n";
        Format.fprintf formatter "%s@]@]@\n" list;
        Format.fprintf formatter "end;@\n"

    | Tmpl_If (caml, ts) ->
        Format.fprintf formatter
          "@[<2>if (%s) then begin@\n%a@\nend;@\n"
          caml
          (fun formatter () -> List.iter (fun t -> print formatter t) ts) ()

    | Tmpl_For (symbol, ocaml, ts) ->
        Format.fprintf formatter "@[<2>begin@\n";
        Format.fprintf formatter "@[<2>let (min, max) = (%s)@ in @\n" ocaml;
        Format.fprintf formatter "for %s = min to max do@\n%a@\ndone;"
          symbol
          (fun formatter () -> List.iter (fun t -> print formatter t) ts) ();
        Format.fprintf formatter "@]@]@\n";
        Format.fprintf formatter "end;@\n"

    | Tmpl_Caml caml ->
        Format.fprintf formatter "@[<2>begin@\n";
        Format.fprintf formatter "@[<2>let string = (%s)@ in@\n" caml;
        Format.fprintf formatter "Pervasives.output_string tmpl__channel string";
        Format.fprintf formatter "@]@]@\n";
        Format.fprintf formatter "end;@\n"
  in
    fun (Tmpl (init, template)) ->
      let formatter = formatter_of_out_channel chan in
        begin match init with
          | None   -> ()
          | Some s -> Format.fprintf formatter "%s@\n@\n" s
        end;
        Format.fprintf formatter
          "@[<2>let print = fun tmpl__env tmpl__channel ->@\n%a@]\n"
          (fun formatter () -> List.iter (print formatter) template) ();
        Format.pp_print_flush formatter