let rec on_keyword lexbuf = function
    AND ->
      (
       match last_and_associated_indent () with
         Some (n, off) ->
           set_indent (n+off);
           if_first_token_on_line n
       | None -> if_first_token_on_line !cur_indent
      )
  | AS
  | ASSERT -> if_first_token_on_line !cur_indent
  | BAR ->
      (* can be associated to a WITH, a LBRACKET or a FUNCTION *)
      (
       match !blocks with
         (WITH,n,_) :: _ ->
           if_first_token_on_line n;
       | (LBRACKET,n,_) :: _ ->
           if_first_token_on_line n;
       | (FUNCTION,n,_) :: _ ->
           if_first_token_on_line n;
       | (ELSE,_,_) :: q
       | (THEN,_,_) :: q ->
           (* A bar is the end of a then or else if we're in a match/try *)
           blocks := q;
           on_keyword lexbuf BAR
       | _ ->
           if_first_token_on_line !cur_indent
      )
  | (BEGIN | STRUCT | SIG | OBJECTas token ->
      if token = BEGIN then push_nl_info ();
      if_first_token_on_line !cur_indent;
      let cst =
        match token with
          BEGIN -> !cst_indent.ind_begin
        | STRUCT | SIG -> !cst_indent.ind_struct
        | OBJECT -> !cst_indent.ind_object
        | _ -> assert false
      in
      push token !cur_indent cst;
      inc_indent cst
  | (CLASS | MODULE | CONSTRAINT | INCLUDEas token ->
      (
       let ind =
         match token with
           CLASS -> !cst_indent.ind_class
         | _ -> !cst_indent.ind_module
       in
       match last_begin_struct_sig_indent () with
         None ->
           if_first_token_on_line 0;
           push token 0 ind;
           set_indent ind
       | Some (n, off) ->
           let n = n + off in
           if_first_token_on_line n;
           push token n ind;
           set_indent (n + ind);
      );
      prerr_endline "CLASS";
      prerr_blocks_stack()
  | DO ->
      (
       set_indent (fst (pop (begin_tokens_of_token DO"do" lexbuf)) ;
       if_first_token_on_line !cur_indent;
       push DO !cur_indent !cst_indent.ind_loop;
       inc_indent !cst_indent.ind_loop
      )
  | DONE ->
      set_indent (fst (pop (begin_tokens_of_token DONE"done" lexbuf));
      if_first_token_on_line !cur_indent
  | DOWNTO ->
      if_first_token_on_line !cur_indent
  | THEN ->
      set_indent (fst (pop (begin_tokens_of_token THEN"then" lexbuf));
      push THEN !cur_indent !cst_indent.ind_if;
      if_first_token_on_line !cur_indent;
      inc_indent !cst_indent.ind_if
  | ELSE ->
      set_indent (fst (pop (begin_tokens_of_token ELSE"else" lexbuf));
      push ELSE !cur_indent !cst_indent.ind_if;
      if_first_token_on_line !cur_indent;
      inc_indent !cst_indent.ind_if;
  | END ->
      (
       (* if it is the end of a sig, a struct or an object, then
          we must pop also the previous module or class *)

       prerr_blocks_stack();
       let (t,n,off) =
         ignore(pop (begin_tokens_of_token END"end" lexbuf);
         match !last_popped with
           None -> assert false
         | Some info -> info
       in
       if_first_token_on_line n;
       match t with
         OBJECT | SIG | STRUCT ->
           set_indent (fst (last_block_indent ()))
       | _ ->
           set_indent ~touch_next_line: false n;
           pop_nl_info ();
      )

  | (EXCEPTION | EXTERNALas token ->
      (
       match last_begin_struct_sig_indent () with
         None ->
           if_first_token_on_line 0;
           set_indent !cst_indent.ind_exception
       | Some (n, off) ->
           let n = n + off in
           if_first_token_on_line n;
           push token n !cst_indent.ind_exception;
           set_indent (n + !cst_indent.ind_exception);
      )
  | FALSE | TRUE ->
      if_first_token_on_line !cur_indent
  | FOR ->
      if_first_token_on_line !cur_indent;
      push FOR !cur_indent 0;
  | FUN ->
      if !next_token_is_first then
        (
         if_first_token_on_line !cur_indent;
         push FUN !cur_indent !cst_indent.ind_fun;
         inc_indent !cst_indent.ind_fun
        )
      else
        (
         (* to prevent incrementing various times for sequences
            of fun ... -> fun ... -> on a same line *)

         match !blocks with
           (LET, n, _) :: _
         | (METHOD, n, _) :: _
         | (VAL, n, _) :: _ ->
             ()
         | _ ->
             if push_if_different FUN !cur_indent !cst_indent.ind_fun then
               inc_indent !cst_indent.ind_fun
        )
  | FUNCTION ->
      if !next_token_is_first then
        (
         if_first_token_on_line !cur_indent;
         push FUNCTION !cur_indent !cst_indent.ind_fun;
         inc_indent !cst_indent.ind_fun
        )
      else
        (
         match !blocks with
           (LET, n, _) :: _
         | (METHOD, n, _) :: _
         | (VAL, n, _) :: _ ->
             push FUNCTION n (2 * !cst_indent.ind_fun);
             set_indent (n + !cst_indent.ind_fun)
         | _ ->
             push FUNCTION !cur_indent (2 * !cst_indent.ind_fun);
             inc_indent (2 * !cst_indent.ind_fun)
        )
  | FUNCTOR ->
      if_first_token_on_line !cur_indent;
      (* to prevent incrementing various times for sequences
         of functor ... -> functor ... -> *)

      if push_if_different FUNCTOR !cur_indent !cst_indent.ind_fun then
        inc_indent !cst_indent.ind_fun
  | IF ->
      let p = last_block_inner_indent () in
      if_first_token_on_line p;
      push IF p !cst_indent.ind_if;
      set_indent (p + !cst_indent.ind_if)
  | IN ->
      set_indent (fst (pop (begin_tokens_of_token IN"in" lexbuf));
      if_first_token_on_line !cur_indent;
  | (INHERIT | INITIALIZER | METHODas token  ->
      (
       match last_begin_object_indent () with
         None ->
           if_first_token_on_line !cur_indent;
           if token = METHOD or token = INITIALIZER then
             push token !cur_indent !cst_indent.ind_field;
           inc_indent !cst_indent.ind_field;
       | Some (n,off) ->
           if_first_token_on_line (n+off);
           if token = METHOD or token = INITIALIZER then
             push token (n + off) !cst_indent.ind_field;
           set_indent (n + off + !cst_indent.ind_field);
      )
  | VIRTUAL ->
      if_first_token_on_line !cur_indent
  | VAL ->
       (* same heuristic as for LET *)
      if !next_token_is_first then
        (
         let loc = lexbuf.Lexing.lex_start_p in
         let pos_on_line = loc.Lexing.pos_cnum - loc.Lexing.pos_bol in
         let (top_align,off) =
           match last_begin_sig_object_indent () with
             None -> (0, 0)
           | Some (n, off) -> (n, off)
          in
         let pos =
           if top_align + off >= pos_on_line then
             top_align + off
            else
             !cur_indent
         in
         if_first_token_on_line pos;
         push VAL pos !cst_indent.ind_val;
         set_indent (pos + !cst_indent.ind_val)
        )
      else
        (
         push VAL !cur_indent !cst_indent.ind_val;
         inc_indent !cst_indent.ind_val
        )
  | LAZY ->
      if_first_token_on_line !cur_indent

  | LET ->
      (* heuristic: if the let is at the beginning of a line
         with at most n blanks before, with n being the current
         struct indentation, then consider it is a "top let" and
         align it on the other elements of the struct *)

      if !next_token_is_first then
        (
         let loc = lexbuf.Lexing.lex_start_p in
         let pos_on_line = loc.Lexing.pos_cnum - loc.Lexing.pos_bol in
         let (top_align, off) =
           match last_begin_struct_sig_indent () with
             None -> (0, 0)
           | Some (n, off) -> (n, off)
         in
         let pos =
           if top_align + off >= pos_on_line then
             top_align + off
           else
             last_block_inner_indent ()
         in
         if_first_token_on_line pos;
         push LET pos !cst_indent.ind_let;
         set_indent (pos + !cst_indent.ind_let)
        )
      else
        (
         push LET !cur_indent !cst_indent.ind_let;
         inc_indent !cst_indent.ind_let
        )
  | (MATCH | TRYas token ->
      if_first_token_on_line !cur_indent;
      push token !cur_indent !cst_indent.ind_match;
      inc_indent !cst_indent.ind_match
  | MINUSGREATER ->
      (
       if_first_token_on_line !cur_indent;
       (* can be associated to FUN, WITH and FUNCTOR ...
          or nothing. *)

       try
         match !blocks with
           (FUN,_,_) :: _
         | (FUNCTOR,_,_) :: _ ->
             ()
         | (FUNCTION,n,_) :: _ ->
             set_indent (n + 2 * !cst_indent.ind_fun)
         | (WITH,n,_) :: _ ->
             set_indent (n + 2 * !cst_indent.ind_match)
         | _ ->
             ()
       with
         Not_found ->
           inc_indent !cst_indent.ind_fun
      )
  | MUTABLE ->
      if_first_token_on_line !cur_indent;
  | NEW ->
      if_first_token_on_line !cur_indent;
  | OF | OPEN | OR | PRIVATE | REC | TO ->
      if_first_token_on_line !cur_indent;
  | TYPE ->
      (
       match !blocks with
         (MODULE,_,_) :: _
       | (CLASS,_,_) :: _ ->
           (* a module/class type, indentation has already been done
              when we encounterd MODULE/CLASS; do nothing *)

           prerr_endline "nothing to be done for type";
           prerr_blocks_stack ()
       | _ ->
           match last_begin_struct_sig_indent () with
             None ->
               if_first_token_on_line 0;
               set_indent !cst_indent.ind_type
           | Some (n, off) ->
               if_first_token_on_line (n + off);
               push TYPE (n + off) !cst_indent.ind_type;
               set_indent (n + off + !cst_indent.ind_type)
      )
  | WHEN ->
      if_first_token_on_line !cur_indent;
  | WHILE ->
      if_first_token_on_line !cur_indent;
      push WHILE !cur_indent !cst_indent.ind_loop;
      inc_indent !cst_indent.ind_loop
  | WITH ->
      (
       let (n,_) = pop (begin_tokens_of_token WITH"with" lexbuf in
       match !last_popped with
         Some (LBRACE,n,off) ->
           set_indent (n + off);
           if_first_token_on_line !cur_indent;
           push LBRACE n off
       | Some (MATCH,n,off) | Some (TRY,n,off) ->
           set_indent n;
           if_first_token_on_line !cur_indent;
           push WITH n (2 * !cst_indent.ind_match);
           inc_indent !cst_indent.ind_match
       | _ ->
           if_first_token_on_line n
      )
  | INFIXOP0 | INFIXOP1 | INFIXOP2 | INFIXOP3 | INFIXOP4 ->
      if_first_token_on_line !cur_indent

  | SEMI ->
      (
       match !blocks with
         (t,n,off) :: q ->
           let indent =
             match t with
               WITH | FUNCTION -> n + off
             | ELSE | THEN ->
                 blocks := q;
                 n
             | _ -> n + off
           in
           set_indent indent;
           if_first_token_on_line !cur_indent;
       | _ ->
           if_first_token_on_line !cur_indent;
      )
  | COMMA ->
      (
       match !blocks with
         (t,n,off) :: q ->
           let indent = n + off in
           set_indent indent;
           if_first_token_on_line !cur_indent;
       | _ ->
           if_first_token_on_line !cur_indent;
      )
  | _ ->
      if_first_token_on_line !cur_indent