(* Standalone lexer for debugging purposes *)

let sprintf = Printf.sprintf

let file =
  match EvalOpt.input with
    None | Some "-" -> false
  |         Some _  -> true

module type S =
  sig
    module Lexer : Lexer.S

    val output_token :
      ?offsets:bool -> [`Byte | `Point] ->
      EvalOpt.command -> out_channel ->
      Markup.t list -> Lexer.token -> unit

    type file_path = string

    val trace :
      ?offsets:bool -> [`Byte | `Point] ->
      file_path option -> EvalOpt.command -> unit
  end

module Make (Lexer: Lexer.S) : (S with module Lexer = Lexer) =
  struct

    module Lexer = Lexer
    module Token = Lexer.Token

    (* Pretty-printing in a string the lexemes making up the markup
       between two tokens, concatenated with the last lexeme
       itself. *)

    let output_token ?(offsets=true) mode command
                     channel left_mark token : unit =
      let output    str = Printf.fprintf channel "%s%!" str in
      let output_nl str = output (str ^ "\n") in
      match command with
        EvalOpt.Quiet -> ()
      | EvalOpt.Tokens -> Token.to_string token ~offsets mode |> output_nl
      | EvalOpt.Copy ->
          let lexeme = Token.to_lexeme token
          and apply acc markup = Markup.to_lexeme markup :: acc
          in List.fold_left apply [lexeme] left_mark
             |> String.concat "" |> output
      | EvalOpt.Units ->
          let abs_token = Token.to_string token ~offsets mode
          and apply acc markup =
            Markup.to_string markup ~offsets mode :: acc
          in List.fold_left apply [abs_token] left_mark
             |> String.concat "\n" |> output_nl

    type file_path = string

    let trace ?(offsets=true) mode file_path_opt command : unit =
      try
        let Lexer.{read; buffer; close; _} =
          Lexer.open_token_stream file_path_opt
        and cout = stdout in
        let log = output_token ~offsets mode command cout
        and close_all () = close (); close_out cout in
        let rec iter () =
          match read ~log buffer with
            token ->
              if Token.is_eof token then close_all ()
              else iter ()
          | exception Lexer.Error e ->
              Lexer.print_error ~offsets mode e ~file;
              close_all ()
        in iter ()
      with Sys_error msg -> Utils.highlight (sprintf "%s\n" msg)

  end
